#!/usr/bin/env --split-string=${JDK_HOME}/bin/java @Makeshift/java_arguments @Makeshift/java_javac_arguments
import Breccia.parser.ParseError;
import Breccia.parser.plain.BrecciaCursor;
import Breccia.XML.translator.BrecciaXCursor;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import Java.Unhandled;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import static Breccia.parser.plain.Project.newSourceReader;
import static java.lang.System.err;
import static javax.xml.transform.OutputKeys.*;
/** A shell command that runs the Breccia to X-Breccia translator on the standard in and output streams.
*
* @see
* Usage instructions
*/
public final class TranslateCommand { // [AFN]
private TranslateCommand() {}
public static void main( final String[] _arguments ) throws IOException, XMLStreamException {
new TranslateCommand().execute(); }
//// P r i v a t e ////////////////////////////////////////////////////////////////////////////////////
private void execute() throws IOException, XMLStreamException {
try( final Reader reader = new BufferedReader( new InputStreamReader( System.in ));
final BrecciaXCursor sourceXCursor = new BrecciaXCursor() ) {
final BrecciaCursor sourceCursor = new BrecciaCursor();
sourceCursor.source( reader );
sourceXCursor.source( sourceCursor );
try { identityTransformer.transform( new StAXSource(sourceXCursor), toOut ); } // [SNR]
catch( final TransformerException xT ) {
if( xT.getCause() instanceof XMLStreamException ) {
final XMLStreamException xS = (XMLStreamException)(xT.getCause());
throw (ParseError)(xS.getCause()); } /* So advertising that the location data
of `ParseError` is available for the exception, in case the caller wants it. */
throw new Unhandled( xT ); }}
catch( final ParseError x ) {
err.print( "" );
err.print( ':' );
err.print( x.lineNumber );
err.print( ": " );
err.println( x ); }}
private final Transformer identityTransformer; {
Transformer t;
try { t = TransformerFactory.newInstance().newTransformer(); }
catch( TransformerConfigurationException x ) { throw new Unhandled( x ); }
t.setOutputProperty( ENCODING, "UTF-8" );
t.setOutputProperty( METHOD, "XML" );
t.setOutputProperty( OMIT_XML_DECLARATION, "yes" );
identityTransformer = t; }
private final StreamResult toOut = new StreamResult( System.out); }
// NOTES
// ─────
// AFN Atypical file naming is allowed here. ‘The compiler does not enforce the optional restriction
// defined at the end of JLS §7.6, that a type in a named package should exist in a file whose
// name is composed from the type name followed by the .java extension.’
//
//
//
// No longer, however, does this allowance extend to the package name. While in JDK releases
// prior to 22 “the launcher's source-file mode was permissive about which package, if any,
// was declared”, current releases enforce a correspondence between the declared package name
// and the file path. Failing this, the launcher aborts with “end of path to source file
// does not match its package name”.
//
// SNR `StAXSource` is ‘not reusable’ according to its API. This is puzzling, however,
// given that it’s a pure wrapper.