#!/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.