package org.smoothbuild.parse; import static org.smoothbuild.lang.message.CodeLocation.codeLocation; import static org.smoothbuild.parse.LocationHelpers.locationOf; import java.io.IOException; import java.io.InputStream; import java.util.BitSet; import org.antlr.v4.runtime.ANTLRErrorListener; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.atn.ATNConfigSet; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.misc.Nullable; import org.smoothbuild.antlr.SmoothLexer; import org.smoothbuild.antlr.SmoothParser; import org.smoothbuild.antlr.SmoothParser.ModuleContext; import org.smoothbuild.cli.Console; import org.smoothbuild.io.fs.base.Path; import org.smoothbuild.lang.message.CodeLocation; public class ScriptParser { public static ModuleContext parseScript(Console console, InputStream inputStream, Path scriptFile) { ErrorListener errorListener = new ErrorListener(console); ANTLRInputStream antlrInputStream; try { antlrInputStream = new ANTLRInputStream(inputStream); } catch (IOException e) { console.error("error: Cannot read build script " + scriptFile + "\n" + e.getMessage()); throw new ParsingException(); } SmoothLexer lexer = new SmoothLexer(antlrInputStream); lexer.removeErrorListeners(); lexer.addErrorListener(errorListener); SmoothParser parser = new SmoothParser(new CommonTokenStream(lexer)); parser.removeErrorListeners(); parser.addErrorListener(errorListener); ModuleContext result = parser.module(); if (console.isErrorReported()) { throw new ParsingException(); } return result; } public static class ErrorListener implements ANTLRErrorListener { private final Console console; public ErrorListener(Console console) { this.console = console; } public void syntaxError(Recognizer<?, ?> recognizer, @Nullable Object offendingSymbol, int line, int charPositionInLine, String msg, @Nullable RecognitionException e) { CodeLocation location = createLocation(offendingSymbol, line); console.error(location, msg); } private CodeLocation createLocation(Object offendingSymbol, int line) { if (offendingSymbol == null) { return codeLocation(line); } else { return locationOf((Token) offendingSymbol); } } public void reportAmbiguity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, boolean exact, @NotNull BitSet ambigAlts, @NotNull ATNConfigSet configs) { reportError(recognizer, startIndex, "Ambiguity in grammar"); } public void reportAttemptingFullContext(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, @Nullable BitSet conflictingAlts, @NotNull ATNConfigSet configs) { reportError(recognizer, startIndex, "Attempting full context"); } public void reportContextSensitivity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, int prediction, @NotNull ATNConfigSet configs) { reportError(recognizer, startIndex, "Context sensitivity"); } private void reportError(Parser recognizer, int startIndex, String message) { Token token = recognizer.getTokenStream().get(startIndex); console.error(locationOf(token), message); } } }