#!/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.IOException; import java.io.Reader; import java.nio.file.Path; import javax.xml.stream.XMLStreamException; import static Breccia.parser.plain.Project.newSourceReader; import static Breccia.XML.translator.BrecciaXCursor.EMPTY; import static java.lang.System.err; import static java.lang.System.out; import static javax.xml.stream.XMLStreamConstants.*; /** A shell command to smoke test the Breccia to X-Breccia translator. * * @see * Usage instructions */ public final class SmokeTestCommand { // [AFN] private SmokeTestCommand( Path sourceFile ) { this.sourceFile = sourceFile; } public static void main( final String[] arguments ) throws IOException, XMLStreamException { new SmokeTestCommand( Path.of( arguments[0] )).execute(); } //// P r i v a t e //////////////////////////////////////////////////////////////////////////////////// private void execute() throws IOException, XMLStreamException { try( final Reader sourceReader = newSourceReader​( sourceFile ); final BrecciaXCursor sourceXCursor = new BrecciaXCursor() ) { final BrecciaCursor sourceCursor = new BrecciaCursor(); sourceCursor.source( sourceReader ); sourceXCursor.source( sourceCursor ); for( final BrecciaXCursor in = sourceXCursor;; ) { switch( in.getEventType() ) { case CHARACTERS -> {} case EMPTY -> out.println( "Empty source file" ); case END_DOCUMENT -> {} case END_ELEMENT -> { indent(); out.print( in.getLocalName() ); out.println(); --indent; } case START_DOCUMENT -> {} case START_ELEMENT -> { indent(); out.print( in.getLocalName() ); out.println(); ++indent; } default -> throw new IllegalStateException(); } /* The event type being either `HALT`, or one not actually emitted by `BrecciaXCursor` at the time of coding. For the event types emitted, see the `assert` statement and comment at the foot of method `BrecciaXCursor.next`. */ if( !in.hasNext() ) break; try { in.next(); } catch( final XMLStreamException x ) { throw (ParseError)(x.getCause()); }}} catch( final ParseError x ) { err.print( sourceFile ); err.print( ':' ); err.print( x.lineNumber ); err.print( ": " ); err.println( x ); }} private int indent; private void indent() { for( int i = 0; i < indent; ++i ) out.print( " " ); } private final Path sourceFile; } // NOTE // ──── // 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”.