bazel syntax: break dependency on lib.events.Event This change removes nearly all dependencies on lib.event.Event, in preparation for reversing the lib.syntax->lib.event dependency. SyntaxError is renamed to SyntaxError.Exception, and SyntaxError itself is a simple event-like location+message type. PiperOrigin-RevId: 304262913
diff --git a/src/main/java/com/google/devtools/build/lib/events/Event.java b/src/main/java/com/google/devtools/build/lib/events/Event.java index 7a64c71..fbb3405 100644 --- a/src/main/java/com/google/devtools/build/lib/events/Event.java +++ b/src/main/java/com/google/devtools/build/lib/events/Event.java
@@ -20,6 +20,7 @@ import com.google.devtools.build.lib.util.io.FileOutErr.OutputReference; import java.io.Serializable; import java.util.Arrays; +import java.util.List; import java.util.Objects; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -227,6 +228,22 @@ } } + /** + * An Eventable is an event-like value that can be converted to an event. This interface is a + * transitional hack until the lib.syntax-to-lib.events dependency can be reversed, at which point + * its use in {@link #replayEventsOn} will be replaced with a direct reference to {@code + * lib.syntax.SyntaxError}. + */ + public interface Eventable { + Event toEvent(); + } + + public static void replayEventsOn(EventHandler eventHandler, List<? extends Eventable> events) { + for (Eventable event : events) { + eventHandler.handle(event.toEvent()); + } + } + public static Event of(EventKind kind, @Nullable Location location, String message) { return new Event(kind, location, message, null, null); }
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/ThreadHandler.java b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/ThreadHandler.java index b2f3f58..c8267ec 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/ThreadHandler.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/ThreadHandler.java
@@ -280,7 +280,7 @@ try { Object result = doEvaluate(thread, statement); return DebuggerSerialization.getValueProto(objectMap, "Evaluation result", result); - } catch (SyntaxError | EvalException | InterruptedException e) { + } catch (SyntaxError.Exception | EvalException | InterruptedException e) { throw new DebugRequestException(e.getMessage()); } } @@ -294,7 +294,7 @@ * running. */ private Object doEvaluate(StarlarkThread thread, String content) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { try { servicingEvalRequest.set(true); @@ -388,7 +388,7 @@ } try { return Starlark.truth(doEvaluate(thread, condition)); - } catch (SyntaxError | EvalException | InterruptedException e) { + } catch (SyntaxError.Exception | EvalException | InterruptedException e) { throw new ConditionalBreakpointException(e.getMessage()); } }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java index 0fca831..6540f0a 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
@@ -741,10 +741,10 @@ */ public static void exec( ParserInput input, FileOptions options, Module module, StarlarkThread thread) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { StarlarkFile file = parseAndValidate(input, options, module); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } exec(file, module, thread); } @@ -772,7 +772,7 @@ */ public static Object eval( ParserInput input, FileOptions options, Module module, StarlarkThread thread) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { Expression expr = Expression.parse(input, options); ValidationEnvironment.validateExpr(expr, module, options); @@ -802,11 +802,11 @@ @Nullable public static Object execAndEvalOptionalFinalExpression( ParserInput input, FileOptions options, Module module, StarlarkThread thread) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { StarlarkFile file = StarlarkFile.parse(input, options); ValidationEnvironment.validateFile(file, module); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } // If the final statement is an expression, synthesize a return statement.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Expression.java b/src/main/java/com/google/devtools/build/lib/syntax/Expression.java index d730763..cb1cb3d 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Expression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Expression.java
@@ -52,12 +52,13 @@ public abstract Kind kind(); /** Parses an expression with the default options. */ - public static Expression parse(ParserInput input) throws SyntaxError { + public static Expression parse(ParserInput input) throws SyntaxError.Exception { return parse(input, FileOptions.DEFAULT); } /** Parses an expression. */ - public static Expression parse(ParserInput input, FileOptions options) throws SyntaxError { + public static Expression parse(ParserInput input, FileOptions options) + throws SyntaxError.Exception { return Parser.parseExpression(input, options); }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java index f7e7a86..0756b5e 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
@@ -17,7 +17,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import java.util.ArrayList; @@ -73,7 +72,7 @@ private int openParenStackDepth = 0; // List of errors appended to by Lexer and Parser. - private final List<Event> errors; + private final List<SyntaxError> errors; /** * True after a NEWLINE token. @@ -84,7 +83,7 @@ private int dents; // number of saved INDENT (>0) or OUTDENT (<0) tokens to return /** Constructs a lexer which tokenizes the parser input. Errors are appended to {@code errors}. */ - Lexer(ParserInput input, FileOptions options, List<Event> errors) { + Lexer(ParserInput input, FileOptions options, List<SyntaxError> errors) { this.lnt = LineNumberTable.create(input.getContent(), input.getFile()); this.options = options; this.buffer = input.getContent(); @@ -137,7 +136,7 @@ } private void error(String message, int start, int end) { - errors.add(Event.error(createLocation(start, end), message)); + errors.add(new SyntaxError(createLocation(start, end), message)); } LexerLocation createLocation(int start, int end) { @@ -416,13 +415,13 @@ default: // unknown char escape => "\literal" if (options.restrictStringEscapes()) { - errors.add( - Event.error( - createLocation(pos - 1, pos), - "invalid escape sequence: \\" - + c - + ". You can enable unknown escape sequences by passing the flag " - + "--incompatible_restrict_string_escapes=false")); + error( + "invalid escape sequence: \\" + + c + + ". You can enable unknown escape sequences by passing the flag" + + " --incompatible_restrict_string_escapes=false", + pos - 1, + pos); } literal.append('\\'); literal.append(c);
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ParamDescriptor.java b/src/main/java/com/google/devtools/build/lib/syntax/ParamDescriptor.java index c0c8c65..2e9cd94 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/ParamDescriptor.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/ParamDescriptor.java
@@ -217,7 +217,7 @@ x = EvalUtils.eval(ParserInput.fromLines(expr), FileOptions.DEFAULT, module, thread); } catch (InterruptedException ex) { throw new IllegalStateException(ex); // can't happen - } catch (SyntaxError | EvalException ex) { + } catch (SyntaxError.Exception | EvalException ex) { throw new IllegalArgumentException( String.format( "failed to evaluate default value '%s' of parameter '%s': %s",
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java index 01fe5d2..bbb8ed4 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
@@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.ProfilerTask; @@ -52,13 +51,13 @@ // Errors encountered during scanning or parsing. // These lists are ultimately owned by StarlarkFile. - final List<Event> errors; + final List<SyntaxError> errors; ParseResult( List<Statement> statements, List<Comment> comments, Lexer.LexerLocation location, - List<Event> errors) { + List<SyntaxError> errors) { // No need to copy here; when the object is created, the parser instance is just about to go // out of scope and be garbage collected. this.statements = Preconditions.checkNotNull(statements); @@ -106,7 +105,7 @@ private static final boolean DEBUGGING = false; private final Lexer lexer; - private final List<Event> errors; + private final List<SyntaxError> errors; // TODO(adonovan): opt: compute this by subtraction. private static final Map<TokenKind, TokenKind> augmentedAssignments = @@ -155,7 +154,7 @@ // Intern string literals, as some files contain many literals for the same string. private final Map<String, String> stringInterner = new HashMap<>(); - private Parser(Lexer lexer, List<Event> errors) { + private Parser(Lexer lexer, List<SyntaxError> errors) { this.lexer = lexer; this.errors = errors; nextToken(); @@ -179,7 +178,7 @@ // Main entry point for parsing a file. static ParseResult parseFile(ParserInput input, FileOptions options) { - List<Event> errors = new ArrayList<>(); + List<SyntaxError> errors = new ArrayList<>(); Lexer lexer = new Lexer(input, options, errors); Parser parser = new Parser(lexer, errors); List<Statement> statements; @@ -208,8 +207,9 @@ } /** Parses an expression, possibly followed by newline tokens. */ - static Expression parseExpression(ParserInput input, FileOptions options) throws SyntaxError { - List<Event> errors = new ArrayList<>(); + static Expression parseExpression(ParserInput input, FileOptions options) + throws SyntaxError.Exception { + List<SyntaxError> errors = new ArrayList<>(); Lexer lexer = new Lexer(input, options, errors); Parser parser = new Parser(lexer, errors); Expression result = parser.parseExpression(); @@ -218,7 +218,7 @@ } parser.expect(TokenKind.EOF); if (!errors.isEmpty()) { - throw new SyntaxError(errors); + throw new SyntaxError.Exception(errors); } return result; } @@ -252,7 +252,7 @@ errorsCount++; // Limit the number of reported errors to avoid spamming output. if (errorsCount <= 5) { - errors.add(Event.error(location, message)); + errors.add(new SyntaxError(location, message)); } }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java b/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java index 08d309c..7da88ee 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java
@@ -487,7 +487,7 @@ */ public static Module exec( StarlarkThread thread, ParserInput input, Map<String, Object> predeclared) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { // Pseudocode: // file = StarlarkFile.parse(input) // validateFile(file, predeclared.keys, thread.semantics) @@ -505,7 +505,7 @@ * exception. */ public static Object eval(StarlarkThread thread, ParserInput input, Map<String, Object> env) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { // Pseudocode: // StarlarkFunction fn = exprFunc(input, env, thread.semantics) // return call(thread, fn) @@ -517,8 +517,9 @@ * it. If the final statement is an expression, return its value. * * <p>This complicated function, which combines exec and eval, is intended for use in a REPL or - * debugger. In case of parse of validation error, it throws SyntaxError. In case of execution - * error, the function returns partial results: the incomplete module plus the exception. + * debugger. In case of parse of validation error, it throws SyntaxError.Exception. In case of + * execution error, the function returns partial results: the incomplete module plus the + * exception. * * <p>Assignments in the input act as updates to a new module created by this function, which is * returned. @@ -538,7 +539,7 @@ */ public static ModuleAndValue execAndEval( StarlarkThread thread, ParserInput input, Map<String, Object> predeclared) - throws SyntaxError { + throws SyntaxError.Exception { // Pseudocode: // file = StarlarkFile.parse(input) // validateFile(file, predeclared.keys, thread.semantics) @@ -568,7 +569,7 @@ /** * Parse the input as a file, validates it in the specified predeclared environment (a set of * names, optionally filtered by the semantics), and compiles it to a Program. It throws - * SyntaxError in case of scan/parse/validation error. + * SyntaxError.Exception in case of scan/parse/validation error. * * <p>In addition to the program, it returns the validated syntax tree. This permits clients such * as Bazel to inspect the syntax (for BUILD dialect checks, glob prefetching, etc.) @@ -577,7 +578,7 @@ ParserInput input, // Set<String> predeclared, StarlarkSemantics semantics) - throws SyntaxError { + throws SyntaxError.Exception { // Pseudocode: // file = StarlarkFile.parse(input) // validateFile(file, predeclared.keys, thread.semantics) @@ -621,7 +622,7 @@ ParserInput input, // Map<String, Object> env, StarlarkSemantics semantics) - throws SyntaxError { + throws SyntaxError.Exception { // Pseudocode: // expr = Expression.parse(input) // validateExpr(expr, env.keys, semantics)
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFile.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFile.java index c009711..b5d222d 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFile.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFile.java
@@ -15,7 +15,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.hash.HashCode; -import com.google.devtools.build.lib.events.Event; import java.io.IOException; import java.util.Collections; import java.util.List; @@ -32,14 +31,14 @@ private final ImmutableList<Statement> statements; private final FileOptions options; private final ImmutableList<Comment> comments; - final List<Event> errors; // appended to by ValidationEnvironment + final List<SyntaxError> errors; // appended to by ValidationEnvironment @Nullable private final String contentHashCode; private StarlarkFile( ImmutableList<Statement> statements, FileOptions options, ImmutableList<Comment> comments, - List<Event> errors, + List<SyntaxError> errors, String contentHashCode, Lexer.LexerLocation location) { this.statements = statements; @@ -81,7 +80,7 @@ * Returns an unmodifiable view of the list of scanner, parser, and (perhaps) resolver errors * accumulated in this Starlark file. */ - public List<Event> errors() { + public List<SyntaxError> errors() { return Collections.unmodifiableList(errors); }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxError.java b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxError.java index 112fcce..e7a0e35 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxError.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxError.java
@@ -14,54 +14,92 @@ package com.google.devtools.build.lib.syntax; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.events.Event; // TODO(adonovan): break dependency +import com.google.devtools.build.lib.events.Location; import java.util.List; /** - * An exception that indicates a static error associated with the syntax, such as scanner or parse - * error, a structural problem, or a failure of identifier resolution. The exception records one or - * more errors, each with a syntax location. - * - * <p>SyntaxError is thrown by operations such as {@link Expression#parse}, which are "all or - * nothing". By contrast, {@link StarlarkFile#parse} does not throw an exception; instead, it - * records the accumulated scanner, parser, and optionally validation errors within the syntax tree, - * so that clients may obtain partial information from a damaged file. - * - * <p>Clients that fail abruptly when encountering parse errors are encouraged to use SyntaxError, - * as in this example: - * - * <pre> - * StarlarkFile file = StarlarkFile.parse(input); - * if (!file.ok()) { - * throw new SyntaxError(file.errors()); - * } - * </pre> + * A SyntaxError represents a static error associated with the syntax, such as a scanner or parse + * error, a structural problem, or a failure of identifier resolution. It records a description of + * the error and its location in the syntax. */ -public final class SyntaxError extends Exception { +public final class SyntaxError implements Event.Eventable { - private final ImmutableList<Event> errors; + private final Location location; + private final String message; - /** Construct a SyntaxError from a non-empty list of errors. */ - public SyntaxError(List<Event> errors) { - if (errors.isEmpty()) { - throw new IllegalArgumentException("no errors"); - } - this.errors = ImmutableList.copyOf(errors); + public SyntaxError(Location location, String message) { + this.location = Preconditions.checkNotNull(location); + this.message = Preconditions.checkNotNull(message); } - /** Returns an immutable non-empty list of errors. */ - public ImmutableList<Event> errors() { - return errors; + /** Returns the location of the error. */ + public Location location() { + return location; + } + + /** Returns a description of the error. */ + public String message() { + return message; + } + + /** Returns a string of the form {@code "foo.star:1:2: oops"}. */ + @Override + public String toString() { + return location + ": " + message; } @Override - public String getMessage() { - String first = errors.get(0).getMessage(); - if (errors.size() > 1) { - return String.format("%s (+ %d more)", first, errors.size() - 1); - } else { - return first; + public Event toEvent() { + return Event.error(location, message); + } + + /** + * A SyntaxError.Exception is an exception holding one or more syntax errors. + * + * <p>SyntaxError.Exception is thrown by operations such as {@link Expression#parse}, which are + * "all or nothing". By contrast, {@link StarlarkFile#parse} does not throw an exception; instead, + * it records the accumulated scanner, parser, and optionally validation errors within the syntax + * tree, so that clients may obtain partial information from a damaged file. + * + * <p>Clients that fail abruptly when encountering parse errors are encouraged to throw + * SyntaxError.Exception, as in this example: + * + * <pre> + * StarlarkFile file = StarlarkFile.parse(input); + * if (!file.ok()) { + * throw new SyntaxError.Exception(file.errors()); + * } + * </pre> + */ + public static final class Exception extends java.lang.Exception { + + private final ImmutableList<SyntaxError> errors; + + /** Construct a SyntaxError from a non-empty list of errors. */ + public Exception(List<SyntaxError> errors) { + if (errors.isEmpty()) { + throw new IllegalArgumentException("no errors"); + } + this.errors = ImmutableList.copyOf(errors); + } + + /** Returns an immutable non-empty list of errors. */ + public ImmutableList<SyntaxError> errors() { + return errors; + } + + @Override + public String getMessage() { + String first = errors.get(0).message(); + if (errors.size() > 1) { + // TODO(adonovan): say ("+ n more errors") to avoid ambiguity. + return String.format("%s (+ %d more)", first, errors.size() - 1); + } else { + return first; + } } } }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java index 3de6a0f..524ae6d 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java
@@ -15,7 +15,6 @@ package com.google.devtools.build.lib.syntax; import com.google.common.base.Preconditions; -import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.util.SpellChecker; import java.util.ArrayList; @@ -40,9 +39,9 @@ * nodes. (In the future, it will attach additional information to functions to support lexical * scope, and even compilation of the trees to bytecode.) Validation errors are reported in the * analogous manner to scan/parse errors: for a StarlarkFile, they are appended to {@code - * StarlarkFile.errors}; for an expression they are reported by an SyntaxError exception. It is - * legal to validate a file that already contains scan/parse errors, though it may lead to secondary - * validation errors. + * StarlarkFile.errors}; for an expression they are reported by an SyntaxError.Exception exception. + * It is legal to validate a file that already contains scan/parse errors, though it may lead to + * secondary validation errors. */ // TODO(adonovan): make this class private. Call it through the EvalUtils facade. public final class ValidationEnvironment extends NodeVisitor { @@ -105,13 +104,13 @@ } } - private final List<Event> errors; + private final List<SyntaxError> errors; private final FileOptions options; private final Module module; private Block block; private int loopCount; - private ValidationEnvironment(List<Event> errors, Module module, FileOptions options) { + private ValidationEnvironment(List<SyntaxError> errors, Module module, FileOptions options) { this.errors = errors; this.module = module; this.options = options; @@ -122,7 +121,7 @@ } void addError(Location loc, String message) { - errors.add(Event.error(loc, message)); + errors.add(new SyntaxError(loc, message)); } /** @@ -486,14 +485,14 @@ * defined by {@code module}. This operation mutates the Expression. */ public static void validateExpr(Expression expr, Module module, FileOptions options) - throws SyntaxError { - List<Event> errors = new ArrayList<>(); + throws SyntaxError.Exception { + List<SyntaxError> errors = new ArrayList<>(); ValidationEnvironment venv = new ValidationEnvironment(errors, module, options); venv.visit(expr); if (!errors.isEmpty()) { - throw new SyntaxError(errors); + throw new SyntaxError.Exception(errors); } }
diff --git a/src/main/java/com/google/devtools/starlark/cmd/BUILD b/src/main/java/com/google/devtools/starlark/cmd/BUILD index e33f97f..5e28606 100644 --- a/src/main/java/com/google/devtools/starlark/cmd/BUILD +++ b/src/main/java/com/google/devtools/starlark/cmd/BUILD
@@ -19,10 +19,7 @@ ], main_class = "com.google.devtools.starlark.cmd.Starlark", visibility = ["//visibility:public"], - deps = [ - "//src/main/java/com/google/devtools/build/lib:events", - "//src/main/java/com/google/devtools/build/lib:syntax", - ], + deps = ["//src/main/java/com/google/devtools/build/lib:syntax"], ) filegroup(
diff --git a/src/main/java/com/google/devtools/starlark/cmd/Starlark.java b/src/main/java/com/google/devtools/starlark/cmd/Starlark.java index 5cc353d..72375a4 100644 --- a/src/main/java/com/google/devtools/starlark/cmd/Starlark.java +++ b/src/main/java/com/google/devtools/starlark/cmd/Starlark.java
@@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.starlark.cmd; -import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.EvalUtils; import com.google.devtools.build.lib.syntax.FileOptions; @@ -104,9 +103,9 @@ if (result != null) { System.out.println(com.google.devtools.build.lib.syntax.Starlark.repr(result)); } - } catch (SyntaxError ex) { - for (Event ev : ex.errors()) { - System.err.println(ev); + } catch (SyntaxError.Exception ex) { + for (SyntaxError error : ex.errors()) { + System.err.println(error); } } catch (EvalException ex) { System.err.println(ex.print()); @@ -133,9 +132,9 @@ try { EvalUtils.exec(ParserInput.create(content, filename), options, module, thread); return 0; - } catch (SyntaxError ex) { - for (Event ev : ex.errors()) { - System.err.println(ev); + } catch (SyntaxError.Exception ex) { + for (SyntaxError error : ex.errors()) { + System.err.println(error); } return 1; } catch (EvalException ex) {
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java b/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java index 5984f04..7bec95b 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java
@@ -34,7 +34,8 @@ @RunWith(JUnit4.class) public class SelectTest { - private static Object eval(String expr) throws SyntaxError, EvalException, InterruptedException { + private static Object eval(String expr) + throws SyntaxError.Exception, EvalException, InterruptedException { ParserInput input = ParserInput.fromLines(expr); StarlarkThread thread = StarlarkThread.builder(Mutability.create("test"))
diff --git a/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java b/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java index b1f30bc..8cb0d92 100644 --- a/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java +++ b/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java
@@ -188,7 +188,8 @@ assertThat(rules).containsExactly("myrule", new RuleBytes("myrule").addBytes(128L)); } - private void exec(String... lines) throws SyntaxError, EvalException, InterruptedException { + private void exec(String... lines) + throws SyntaxError.Exception, EvalException, InterruptedException { ParserInput input = ParserInput.create(Joiner.on("\n").join(lines), "a.star"); Mutability mu = Mutability.create("test"); StarlarkThread thread =
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java index 62cf58e..f653a64 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -738,7 +738,7 @@ Module module = thread.getGlobals(); StarlarkFile file = EvalUtils.parseAndValidate(input, FileOptions.DEFAULT, module); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } SkylarkImportLookupFunction.execAndExport(file, FAKE_LABEL, ev.getEventHandler(), thread); }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java index 5ee621c..99c63be 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
@@ -17,9 +17,10 @@ import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.events.EventCollector; import com.google.devtools.build.lib.syntax.util.EvaluationTestCase; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -32,8 +33,9 @@ @Test public void testExecutionStopsAtFirstError() throws Exception { - EventCollector printEvents = new EventCollector(); - StarlarkThread thread = createStarlarkThread(StarlarkThread.makeDebugPrintHandler(printEvents)); + List<String> printEvents = new ArrayList<>(); + StarlarkThread thread = + createStarlarkThread(/*printHandler=*/ (_thread, msg) -> printEvents.add(msg)); ParserInput input = ParserInput.fromLines("print('hello'); x = 1//0; print('goodbye')"); Module module = thread.getGlobals(); @@ -41,14 +43,16 @@ EvalException.class, () -> EvalUtils.exec(input, FileOptions.DEFAULT, module, thread)); // Only expect hello, should have been an error before goodbye. - assertThat(printEvents).hasSize(1); - assertThat(printEvents.iterator().next().getMessage()).isEqualTo("hello"); + assertThat(printEvents.toString()).isEqualTo("[hello]"); } @Test public void testExecutionNotStartedOnInterrupt() throws Exception { - EventCollector printEvents = new EventCollector(); - StarlarkThread thread = createStarlarkThread(StarlarkThread.makeDebugPrintHandler(printEvents)); + StarlarkThread thread = + createStarlarkThread( + /*printHandler=*/ (_thread, msg) -> { + throw new AssertionError("print statement was reached"); + }); ParserInput input = ParserInput.fromLines("print('hello');"); Module module = thread.getGlobals(); @@ -61,8 +65,6 @@ // Reset interrupt bit in case the test failed to do so. Thread.interrupted(); } - - assertThat(printEvents).isEmpty(); } @Test @@ -564,7 +566,7 @@ } private static void execBUILD(String... lines) - throws SyntaxError, EvalException, InterruptedException { + throws SyntaxError.Exception, EvalException, InterruptedException { ParserInput input = ParserInput.fromLines(lines); StarlarkThread thread = StarlarkThread.builder(Mutability.create("test")).useDefaultSemantics().build();
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java b/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java index 8d35d8f..f2f2f22 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java
@@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; import com.google.devtools.build.lib.syntax.util.EvaluationTestCase; -import com.google.devtools.build.lib.testutil.MoreAsserts; import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -40,18 +39,6 @@ } @Test - public void testFunctionDefDuplicateArguments() throws Exception { - // TODO(adonovan): move to ParserTest. - ParserInput input = - ParserInput.fromLines( - "def func(a,b,a):", // - " a = 1\n"); - StarlarkFile file = StarlarkFile.parse(input); - MoreAsserts.assertContainsEvent( - file.errors(), "duplicate parameter name in function definition"); - } - - @Test public void testFunctionDefCallOuterFunc() throws Exception { List<Object> params = new ArrayList<>(); createOuterFunction(params);
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/LValueBoundNamesTest.java b/src/test/java/com/google/devtools/build/lib/syntax/LValueBoundNamesTest.java index df33118..425286a 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/LValueBoundNamesTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/LValueBoundNamesTest.java
@@ -14,7 +14,6 @@ package com.google.devtools.build.lib.syntax; import com.google.common.truth.Truth; -import com.google.devtools.build.lib.events.Event; import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; @@ -54,8 +53,8 @@ private static void assertBoundNames(String assignment, String... expectedBoundNames) { ParserInput input = ParserInput.fromLines(assignment); StarlarkFile file = StarlarkFile.parse(input); - for (Event error : file.errors()) { - throw new AssertionError(error); + if (!file.ok()) { + throw new AssertionError(new SyntaxError.Exception(file.errors())); } Expression lhs = ((AssignmentStatement) file.getStatements().get(0)).getLHS(); Set<String> boundNames =
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java b/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java index 3b727eb..831052c 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java
@@ -15,7 +15,7 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.devtools.build.lib.events.Event; +import com.google.common.base.Joiner; import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester; import java.util.ArrayList; import java.util.List; @@ -31,7 +31,7 @@ // TODO(adonovan): make these these tests less unnecessarily stateful. - private final List<Event> errors = new ArrayList<>(); + private final List<SyntaxError> errors = new ArrayList<>(); private String lastError; /** @@ -53,9 +53,8 @@ result.add(tok.copy()); } while (tok.kind != TokenKind.EOF); - for (Event error : errors) { - lastError = - error.getLocation().file() + ":" + error.getLocation().line() + ": " + error.getMessage(); + for (SyntaxError error : errors) { + lastError = error.location().file() + ":" + error.location().line() + ": " + error.message(); } return result; @@ -516,4 +515,24 @@ public void testLexerLocationCodec() throws Exception { new SerializationTester(createLexer("foo").createLocation(0, 2)).runTests(); } + + /** + * Returns the first error whose string form contains the specified substring, or throws an + * informative AssertionError if there is none. + * + * <p>Exposed for use by other frontend tests. + */ + static SyntaxError assertContainsError(List<SyntaxError> errors, String substr) { + for (SyntaxError error : errors) { + if (error.toString().contains(substr)) { + return error; + } + } + if (errors.isEmpty()) { + throw new AssertionError("no errors, want '" + substr + "'"); + } else { + throw new AssertionError( + "error '" + substr + "' not found, but got these:\n" + Joiner.on("\n").join(errors)); + } + } }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/NodeVisitorTest.java b/src/test/java/com/google/devtools/build/lib/syntax/NodeVisitorTest.java index 9ae38aa..2b7dcaa 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/NodeVisitorTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/NodeVisitorTest.java
@@ -25,11 +25,11 @@ @RunWith(JUnit4.class) public final class NodeVisitorTest { - private static StarlarkFile parse(String... lines) throws SyntaxError { + private static StarlarkFile parse(String... lines) throws SyntaxError.Exception { ParserInput input = ParserInput.fromLines(lines); StarlarkFile file = StarlarkFile.parse(input); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } return file; }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java index f1a402b..3aebe9a 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
@@ -20,10 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.events.EventCollector; import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.testutil.MoreAsserts; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -35,11 +32,11 @@ @RunWith(JUnit4.class) public final class ParserTest { - private final EventCollector events = new EventCollector(); + private final List<SyntaxError> events = new ArrayList<>(); private boolean failFast = true; - private Event assertContainsError(String expectedMessage) { - return MoreAsserts.assertContainsEvent(events, expectedMessage); + private SyntaxError assertContainsError(String expectedMessage) { + return LexerTest.assertContainsError(events, expectedMessage); } private void setFailFast(boolean failFast) { @@ -47,7 +44,7 @@ } // Joins the lines, parse, and returns an expression. - private static Expression parseExpression(String... lines) throws SyntaxError { + private static Expression parseExpression(String... lines) throws SyntaxError.Exception { ParserInput input = ParserInput.fromLines(lines); return Expression.parse(input); } @@ -59,32 +56,33 @@ try { Expression.parse(input); throw new AssertionError("parseExpression(%s) succeeded unexpectedly: " + src); - } catch (SyntaxError ex) { - return ex.errors().get(0).getMessage(); + } catch (SyntaxError.Exception ex) { + return ex.errors().get(0).message(); } } // Joins the lines, parses, and returns a file. // Errors are added to this.events, or thrown if this.failFast; - private StarlarkFile parseFile(String... lines) throws SyntaxError { + private StarlarkFile parseFile(String... lines) throws SyntaxError.Exception { ParserInput input = ParserInput.fromLines(lines); StarlarkFile file = StarlarkFile.parse(input); if (!file.ok()) { if (failFast) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } - Event.replayEventsOn(events, file.errors()); + // TODO(adonovan): return these, and eliminate a stateful field. + events.addAll(file.errors()); } return file; } // Joins the lines, parses, and returns the sole statement. - private Statement parseStatement(String... lines) throws SyntaxError { + private Statement parseStatement(String... lines) throws SyntaxError.Exception { return Iterables.getOnlyElement(parseStatements(lines)); } // Joins the lines, parses, and returns the statements. - private List<Statement> parseStatements(String... lines) throws SyntaxError { + private ImmutableList<Statement> parseStatements(String... lines) throws SyntaxError.Exception { return parseFile(lines).getStatements(); } @@ -341,7 +339,8 @@ assertLocation(0, 14, slice); } - private static void evalSlice(String statement, Object... expectedArgs) throws SyntaxError { + private static void evalSlice(String statement, Object... expectedArgs) + throws SyntaxError.Exception { SliceExpression e = (SliceExpression) parseExpression(statement); // There is no way to evaluate the expression here, so we rely on string comparison. @@ -401,7 +400,7 @@ } @Test - public void testSecondaryLocation() throws SyntaxError { + public void testSecondaryLocation() throws SyntaxError.Exception { String expr = "f(1 % 2)"; CallExpression call = (CallExpression) parseExpression(expr); Argument arg = call.getArguments().get(0); @@ -409,7 +408,7 @@ } @Test - public void testPrimaryLocation() throws SyntaxError { + public void testPrimaryLocation() throws SyntaxError.Exception { String expr = "f(1 + 2)"; CallExpression call = (CallExpression) parseExpression(expr); Argument arg = call.getArguments().get(0); @@ -621,7 +620,7 @@ assertStatementLocationCorrect("def foo():\n pass"); } - private void assertStatementLocationCorrect(String stmtStr) throws SyntaxError { + private void assertStatementLocationCorrect(String stmtStr) throws SyntaxError.Exception { Statement stmt = parseStatement(stmtStr); assertThat(getText(stmtStr, stmt)).isEqualTo(stmtStr); // Also try it with another token at the end (newline), which broke the location in the past. @@ -629,7 +628,7 @@ assertThat(getText(stmtStr, stmt)).isEqualTo(stmtStr); } - private static void assertExpressionLocationCorrect(String exprStr) throws SyntaxError { + private static void assertExpressionLocationCorrect(String exprStr) throws SyntaxError.Exception { Expression expr = parseExpression(exprStr); assertThat(getText(exprStr, expr)).isEqualTo(exprStr); // Also try it with another token at the end (newline), which broke the location in the past. @@ -866,10 +865,10 @@ " b = 2 * * 5", // parse error ""); - assertThat(events).hasSize(3); assertContainsError("syntax error at 'for': expected newline"); assertContainsError("syntax error at 'ada': expected newline"); assertContainsError("syntax error at '*': expected expression"); + assertThat(events).hasSize(3); assertThat(statements).hasSize(3); } @@ -1182,7 +1181,7 @@ } private void runLoadAliasTestForSymbols(String loadSymbolString, String... expectedSymbols) - throws SyntaxError { + throws SyntaxError.Exception { List<Statement> statements = parseStatements(String.format("load('//foo/bar:file.bzl', %s)\n", loadSymbolString)); LoadStatement stmt = (LoadStatement) statements.get(0); @@ -1335,6 +1334,15 @@ } @Test + public void testFunctionDefDuplicateArguments() throws Exception { + setFailFast(false); + parseFile( + "def func(a,b,a):", // + " a = 1\n"); + assertContainsError("duplicate parameter name in function definition"); + } + + @Test public void testStringsAreDeduped() throws Exception { StarlarkFile file = parseFile("L1 = ['cat', 'dog', 'fish']", "L2 = ['dog', 'fish', 'cat']"); Set<String> uniqueStringInstances = Sets.newIdentityHashSet();
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/PrettyPrintTest.java b/src/test/java/com/google/devtools/build/lib/syntax/PrettyPrintTest.java index e2a9a0f..cf420bb 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/PrettyPrintTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/PrettyPrintTest.java
@@ -26,20 +26,20 @@ @RunWith(JUnit4.class) public final class PrettyPrintTest { - private static StarlarkFile parseFile(String... lines) throws SyntaxError { + private static StarlarkFile parseFile(String... lines) throws SyntaxError.Exception { ParserInput input = ParserInput.fromLines(lines); StarlarkFile file = StarlarkFile.parse(input); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } return file; } - private static Statement parseStatement(String... lines) throws SyntaxError { + private static Statement parseStatement(String... lines) throws SyntaxError.Exception { return parseFile(lines).getStatements().get(0); } - private static Expression parseExpression(String... lines) throws SyntaxError { + private static Expression parseExpression(String... lines) throws SyntaxError.Exception { return Expression.parse(ParserInput.fromLines(lines)); } @@ -50,24 +50,24 @@ /** * Asserts that the given node's pretty print at a given indent level matches the given string. */ - private void assertPrettyMatches(Node node, int indentLevel, String expected) { + private static void assertPrettyMatches(Node node, int indentLevel, String expected) { StringBuilder buf = new StringBuilder(); new NodePrinter(buf, indentLevel).printNode(node); assertThat(buf.toString()).isEqualTo(expected); } /** Asserts that the given node's pretty print with no indent matches the given string. */ - private void assertPrettyMatches(Node node, String expected) { + private static void assertPrettyMatches(Node node, String expected) { assertPrettyMatches(node, 0, expected); } /** Asserts that the given node's pretty print with one indent matches the given string. */ - private void assertIndentedPrettyMatches(Node node, String expected) { + private static void assertIndentedPrettyMatches(Node node, String expected) { assertPrettyMatches(node, 1, expected); } /** Asserts that the given node's {@code toString} matches the given string. */ - private void assertTostringMatches(Node node, String expected) { + private static void assertTostringMatches(Node node, String expected) { assertThat(node.toString()).isEqualTo(expected); } @@ -75,7 +75,8 @@ * Parses the given string as an expression, and asserts that its pretty print matches the given * string. */ - private void assertExprPrettyMatches(String source, String expected) throws SyntaxError { + private static void assertExprPrettyMatches(String source, String expected) + throws SyntaxError.Exception { Expression node = parseExpression(source); assertPrettyMatches(node, expected); } @@ -84,7 +85,8 @@ * Parses the given string as an expression, and asserts that its {@code toString} matches the * given string. */ - private void assertExprTostringMatches(String source, String expected) throws SyntaxError { + private static void assertExprTostringMatches(String source, String expected) + throws SyntaxError.Exception { Expression node = parseExpression(source); assertThat(node.toString()).isEqualTo(expected); } @@ -93,7 +95,7 @@ * Parses the given string as an expression, and asserts that both its pretty print and {@code * toString} return the original string. */ - private void assertExprBothRoundTrip(String source) throws SyntaxError { + private static void assertExprBothRoundTrip(String source) throws SyntaxError.Exception { assertExprPrettyMatches(source, source); assertExprTostringMatches(source, source); } @@ -102,7 +104,8 @@ * Parses the given string as a statement, and asserts that its pretty print with one indent * matches the given string. */ - private void assertStmtIndentedPrettyMatches(String source, String expected) throws SyntaxError { + private static void assertStmtIndentedPrettyMatches(String source, String expected) + throws SyntaxError.Exception { Statement node = parseStatement(source); assertIndentedPrettyMatches(node, expected); } @@ -111,7 +114,8 @@ * Parses the given string as an statement, and asserts that its {@code toString} matches the * given string. */ - private void assertStmtTostringMatches(String source, String expected) throws SyntaxError { + private static void assertStmtTostringMatches(String source, String expected) + throws SyntaxError.Exception { Statement node = parseStatement(source); assertThat(node.toString()).isEqualTo(expected); } @@ -119,14 +123,14 @@ // Expressions. @Test - public void abstractComprehension() throws SyntaxError { + public void abstractComprehension() throws SyntaxError.Exception { // Covers DictComprehension and ListComprehension. assertExprBothRoundTrip("[z for y in x if True for z in y]"); assertExprBothRoundTrip("{z: x for y in x if True for z in y}"); } @Test - public void binaryOperatorExpression() throws SyntaxError { + public void binaryOperatorExpression() throws SyntaxError.Exception { assertExprPrettyMatches("1 + 2", "(1 + 2)"); assertExprTostringMatches("1 + 2", "1 + 2"); @@ -135,22 +139,22 @@ } @Test - public void conditionalExpression() throws SyntaxError { + public void conditionalExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("1 if True else 2"); } @Test - public void dictExpression() throws SyntaxError { + public void dictExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("{1: \"a\", 2: \"b\"}"); } @Test - public void dotExpression() throws SyntaxError { + public void dotExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("o.f"); } @Test - public void funcallExpression() throws SyntaxError { + public void funcallExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("f()"); assertExprBothRoundTrip("f(a)"); assertExprBothRoundTrip("f(a, b = B, c = C, *d, **e)"); @@ -158,22 +162,22 @@ } @Test - public void identifier() throws SyntaxError { + public void identifier() throws SyntaxError.Exception { assertExprBothRoundTrip("foo"); } @Test - public void indexExpression() throws SyntaxError { + public void indexExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("a[i]"); } @Test - public void integerLiteral() throws SyntaxError { + public void integerLiteral() throws SyntaxError.Exception { assertExprBothRoundTrip("5"); } @Test - public void listLiteralShort() throws SyntaxError { + public void listLiteralShort() throws SyntaxError.Exception { assertExprBothRoundTrip("[]"); assertExprBothRoundTrip("[5]"); assertExprBothRoundTrip("[5, 6]"); @@ -183,7 +187,7 @@ } @Test - public void listLiteralLong() throws SyntaxError { + public void listLiteralLong() throws SyntaxError.Exception { // List literals with enough elements to trigger the abbreviated toString() format. assertExprPrettyMatches("[1, 2, 3, 4, 5, 6]", "[1, 2, 3, 4, 5, 6]"); assertExprTostringMatches("[1, 2, 3, 4, 5, 6]", "[1, 2, 3, 4, <2 more arguments>]"); @@ -193,7 +197,7 @@ } @Test - public void listLiteralNested() throws SyntaxError { + public void listLiteralNested() throws SyntaxError.Exception { // Make sure that the inner list doesn't get abbreviated when the outer list is printed using // prettyPrint(). assertExprPrettyMatches( @@ -205,7 +209,7 @@ } @Test - public void sliceExpression() throws SyntaxError { + public void sliceExpression() throws SyntaxError.Exception { assertExprBothRoundTrip("a[b:c:d]"); assertExprBothRoundTrip("a[b:c]"); assertExprBothRoundTrip("a[b:]"); @@ -216,13 +220,13 @@ } @Test - public void stringLiteral() throws SyntaxError { + public void stringLiteral() throws SyntaxError.Exception { assertExprBothRoundTrip("\"foo\""); assertExprBothRoundTrip("\"quo\\\"ted\""); } @Test - public void unaryOperatorExpression() throws SyntaxError { + public void unaryOperatorExpression() throws SyntaxError.Exception { assertExprPrettyMatches("not True", "not (True)"); assertExprTostringMatches("not True", "not True"); assertExprPrettyMatches("-5", "-(5)"); @@ -232,25 +236,25 @@ // Statements. @Test - public void assignmentStatement() throws SyntaxError { + public void assignmentStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches("x = y", " x = y\n"); assertStmtTostringMatches("x = y", "x = y\n"); } @Test - public void augmentedAssignmentStatement() throws SyntaxError { + public void augmentedAssignmentStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches("x += y", " x += y\n"); assertStmtTostringMatches("x += y", "x += y\n"); } @Test - public void expressionStatement() throws SyntaxError { + public void expressionStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches("5", " 5\n"); assertStmtTostringMatches("5", "5\n"); } @Test - public void defStatement() throws SyntaxError { + public void defStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches( join("def f(x):", " print(x)"), @@ -287,7 +291,7 @@ } @Test - public void flowStatement() throws SyntaxError { + public void flowStatement() throws SyntaxError.Exception { // The parser would complain if we tried to construct them from source. Node breakNode = new FlowStatement(TokenKind.BREAK); assertIndentedPrettyMatches(breakNode, " break\n"); @@ -299,7 +303,7 @@ } @Test - public void forStatement() throws SyntaxError { + public void forStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches( join("for x in y:", " print(x)"), @@ -324,7 +328,7 @@ } @Test - public void ifStatement() throws SyntaxError { + public void ifStatement() throws SyntaxError.Exception { assertStmtIndentedPrettyMatches( join("if True:", " print(x)"), @@ -361,7 +365,7 @@ } @Test - public void loadStatement() throws SyntaxError { + public void loadStatement() throws SyntaxError.Exception { // load("foo.bzl", a="A", "B") Node loadStatement = new LoadStatement( @@ -378,7 +382,7 @@ } @Test - public void returnStatement() throws SyntaxError { + public void returnStatement() throws SyntaxError.Exception { assertIndentedPrettyMatches( new ReturnStatement(new StringLiteral("foo")), " return \"foo\"\n"); @@ -396,7 +400,7 @@ // Miscellaneous. @Test - public void buildFileAST() throws SyntaxError { + public void buildFileAST() throws SyntaxError.Exception { Node node = parseFile("print(x)\nprint(y)"); assertIndentedPrettyMatches( node, @@ -407,16 +411,15 @@ } @Test - public void comment() throws SyntaxError { + public void comment() throws SyntaxError.Exception { Comment node = new Comment("foo"); assertIndentedPrettyMatches(node, " # foo"); assertTostringMatches(node, "foo"); } /* Not tested explicitly because they're covered implicitly by tests for other nodes: - * - LValue * - DictExpression.Entry - * - passed arguments / formal parameters - * - ConditionalStatements + * - Argument / Parameter + * - IfStatements */ }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java index 1472976..0dd862a 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
@@ -946,7 +946,7 @@ // TODO(adonovan): move this and all tests that use it to Validation tests. private void assertValidationError(String expectedError, final String... lines) throws Exception { - SyntaxError error = assertThrows(SyntaxError.class, () -> exec(lines)); + SyntaxError.Exception error = assertThrows(SyntaxError.Exception.class, () -> exec(lines)); assertThat(error).hasMessageThat().contains(expectedError); }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFileTest.java b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFileTest.java index 4cd28bc..7ffd09a 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFileTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFileTest.java
@@ -16,8 +16,6 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.base.Joiner; -import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.testutil.MoreAsserts; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -86,25 +84,25 @@ public void testFailsIfNewlinesAreMissing() throws Exception { StarlarkFile file = parseFile("foo() bar() something = baz() bar()"); - Event event = - MoreAsserts.assertContainsEvent(file.errors(), "syntax error at \'bar\': expected newline"); - assertThat(event.getLocation().toString()).isEqualTo("foo.star:1:7"); + SyntaxError error = + LexerTest.assertContainsError(file.errors(), "syntax error at \'bar\': expected newline"); + assertThat(error.location().toString()).isEqualTo("foo.star:1:7"); } @Test public void testImplicitStringConcatenationFails() throws Exception { StarlarkFile file = parseFile("a = 'foo' 'bar'"); - Event event = - MoreAsserts.assertContainsEvent( + SyntaxError error = + LexerTest.assertContainsError( file.errors(), "Implicit string concatenation is forbidden, use the + operator"); - assertThat(event.getLocation().toString()).isEqualTo("foo.star:1:10"); + assertThat(error.location().toString()).isEqualTo("foo.star:1:10"); } @Test public void testImplicitStringConcatenationAcrossLinesIsIllegal() throws Exception { StarlarkFile file = parseFile("a = 'foo'\n 'bar'"); - Event event = MoreAsserts.assertContainsEvent(file.errors(), "indentation error"); - assertThat(event.getLocation().toString()).isEqualTo("foo.star:2:2"); + SyntaxError error = LexerTest.assertContainsError(file.errors(), "indentation error"); + assertThat(error.location().toString()).isEqualTo("foo.star:2:2"); } }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadDebuggingTest.java b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadDebuggingTest.java index 053ea1a..c35ce1e 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadDebuggingTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadDebuggingTest.java
@@ -227,9 +227,9 @@ Module module = thread.getGlobals(); module.put("a", 1); - SyntaxError e = + SyntaxError.Exception e = assertThrows( - SyntaxError.class, + SyntaxError.Exception.class, () -> EvalUtils.execAndEvalOptionalFinalExpression( ParserInput.fromLines("b"), FileOptions.DEFAULT, module, thread));
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java index 6b790bb..b8c8230 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java
@@ -58,7 +58,7 @@ @Test public void testReference() throws Exception { setFailFast(false); - SyntaxError e = assertThrows(SyntaxError.class, () -> eval("foo")); + SyntaxError.Exception e = assertThrows(SyntaxError.Exception.class, () -> eval("foo")); assertThat(e).hasMessageThat().isEqualTo("name 'foo' is not defined"); update("foo", "bar"); assertThat(eval("foo")).isEqualTo("bar"); @@ -67,7 +67,7 @@ // Test assign and reference through interpreter: @Test public void testAssignAndReference() throws Exception { - SyntaxError e = assertThrows(SyntaxError.class, () -> eval("foo")); + SyntaxError.Exception e = assertThrows(SyntaxError.Exception.class, () -> eval("foo")); assertThat(e).hasMessageThat().isEqualTo("name 'foo' is not defined"); exec("foo = 'bar'"); assertThat(eval("foo")).isEqualTo("bar");
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java index f3776e6..402dff6 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
@@ -14,10 +14,9 @@ package com.google.devtools.build.lib.syntax; import static com.google.common.truth.Truth.assertThat; -import static com.google.devtools.build.lib.testutil.MoreAsserts.assertContainsEvent; +import static com.google.devtools.build.lib.syntax.LexerTest.assertContainsError; -import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.events.EventCollector; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -29,36 +28,34 @@ private final FileOptions.Builder options = FileOptions.builder(); // Validates a file using the current options. - private StarlarkFile validateFile(String... lines) throws SyntaxError { + private StarlarkFile validateFile(String... lines) throws SyntaxError.Exception { ParserInput input = ParserInput.fromLines(lines); Module module = Module.createForBuiltins(Starlark.UNIVERSE); return EvalUtils.parseAndValidate(input, options.build(), module); } // Assertions that parsing and validation succeeds. - private void assertValid(String... lines) throws SyntaxError { + private void assertValid(String... lines) throws SyntaxError.Exception { StarlarkFile file = validateFile(lines); if (!file.ok()) { - throw new SyntaxError(file.errors()); + throw new SyntaxError.Exception(file.errors()); } } // Asserts that parsing of the program succeeds but validation fails // with at least the specified error. - private void assertInvalid(String expectedError, String... lines) throws SyntaxError { - EventCollector errors = getValidationErrors(lines); - assertContainsEvent(errors, expectedError); + private void assertInvalid(String expectedError, String... lines) throws SyntaxError.Exception { + List<SyntaxError> errors = getValidationErrors(lines); + assertContainsError(errors, expectedError); } // Returns the non-empty list of validation errors of the program. - private EventCollector getValidationErrors(String... lines) throws SyntaxError { + private List<SyntaxError> getValidationErrors(String... lines) throws SyntaxError.Exception { StarlarkFile file = validateFile(lines); if (file.ok()) { throw new AssertionError("validation succeeded unexpectedly"); } - EventCollector errors = new EventCollector(); - Event.replayEventsOn(errors, file.errors()); - return errors; + return file.errors(); } @Test @@ -181,16 +178,16 @@ @Test public void testNoGlobalReassign() throws Exception { - EventCollector errors = getValidationErrors("a = 1", "a = 2"); - assertContainsEvent(errors, ":2:1: cannot reassign global 'a'"); - assertContainsEvent(errors, ":1:1: 'a' previously declared here"); + List<SyntaxError> errors = getValidationErrors("a = 1", "a = 2"); + assertContainsError(errors, ":2:1: cannot reassign global 'a'"); + assertContainsError(errors, ":1:1: 'a' previously declared here"); } @Test public void testTwoFunctionsWithTheSameName() throws Exception { - EventCollector errors = getValidationErrors("def foo(): pass", "def foo(): pass"); - assertContainsEvent(errors, ":2:5: cannot reassign global 'foo'"); - assertContainsEvent(errors, ":1:5: 'foo' previously declared here"); + List<SyntaxError> errors = getValidationErrors("def foo(): pass", "def foo(): pass"); + assertContainsError(errors, ":2:5: cannot reassign global 'foo'"); + assertContainsError(errors, ":1:5: 'foo' previously declared here"); } @Test @@ -308,18 +305,18 @@ @Test public void testDollarErrorDoesNotLeak() throws Exception { - EventCollector errors = + List<SyntaxError> errors = getValidationErrors( "def GenerateMapNames():", // " a = 2", " b = [3, 4]", " if a not b:", " print(a)"); - assertContainsEvent(errors, "syntax error at 'b': expected 'in'"); + assertContainsError(errors, "syntax error at 'b': expected 'in'"); // Parser uses "$error" symbol for error recovery. // It should not be used in error messages. - for (Event event : errors) { - assertThat(event.getMessage()).doesNotContain("$error$"); + for (SyntaxError event : errors) { + assertThat(event.message()).doesNotContain("$error$"); } }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java index f3314b6..5427604 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
@@ -110,7 +110,7 @@ // and evaluation. /** Parses an expression. */ - protected final Expression parseExpression(String... lines) throws SyntaxError { + protected final Expression parseExpression(String... lines) throws SyntaxError.Exception { return Expression.parse(ParserInput.fromLines(lines)); } @@ -132,7 +132,8 @@ } /** Joins the lines, parses them as a file, and executes it. */ - public final void exec(String... lines) throws SyntaxError, EvalException, InterruptedException { + public final void exec(String... lines) + throws SyntaxError.Exception, EvalException, InterruptedException { ParserInput input = ParserInput.fromLines(lines); EvalUtils.exec(input, FileOptions.DEFAULT, thread.getGlobals(), thread); } @@ -141,7 +142,7 @@ try { exec(input); fail("Expected error '" + msg + "' but got no error"); - } catch (SyntaxError | EvalException | EventCollectionApparatus.FailFastException e) { + } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) { assertThat(e).hasMessageThat().isEqualTo(msg); } } @@ -150,7 +151,7 @@ try { exec(input); fail("Expected error containing '" + msg + "' but got no error"); - } catch (SyntaxError | EvalException | EventCollectionApparatus.FailFastException e) { + } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) { assertThat(e).hasMessageThat().contains(msg); } } @@ -158,7 +159,7 @@ public void checkEvalErrorDoesNotContain(String msg, String... input) throws Exception { try { exec(input); - } catch (SyntaxError | EvalException | EventCollectionApparatus.FailFastException e) { + } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) { assertThat(e).hasMessageThat().doesNotContain(msg); } }