Skip to content

Commit

Permalink
In parser tests, make sure there are no characters after the expressi…
Browse files Browse the repository at this point in the history
…on being parsed

Achieve this by adding declEof(), expressionEof(),
literalEof(), statementEof() productions to the parser.
  • Loading branch information
julianhyde committed Dec 4, 2021
1 parent 81c62f4 commit beabace
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
31 changes: 29 additions & 2 deletions src/main/javacc/MorelParser.jj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ Literal literal() :
e = charLiteral() { return e; }
}

/** Parses a literal expression followed by end-of-file. */
Literal literalEof() :
{
final Literal n;
}
{
n = literal() <EOF> { return n; }
}

/** Parses a numeric literal */
Literal numericLiteral() :
{
Expand Down Expand Up @@ -127,9 +136,9 @@ Literal numericLiteral() :
}
final int exponent;
if (token.image.startsWith("~", e + 1)) {
exponent = -Integer.valueOf(token.image.substring(e + 2));
exponent = -Integer.parseInt(token.image.substring(e + 2));
} else {
exponent = Integer.valueOf(token.image.substring(e + 1));
exponent = Integer.parseInt(token.image.substring(e + 1));
}
return ast.realLiteral(pos(), d.scaleByPowerOfTen(exponent));
}
Expand Down Expand Up @@ -920,6 +929,15 @@ Ast.Decl decl() :
n = funDecl() { return n; }
}

/** Parses a declaration followed by end-of-file. */
Ast.Decl declEof() :
{
Ast.Decl d;
}
{
d = decl() <EOF> { return d; }
}

/** Parses a type declaration, e.g.
* {@code datatype 'a option = NONE | SOME of 'a}
*/
Expand Down Expand Up @@ -1298,6 +1316,15 @@ AstNode statementSemicolon() :
n = statement() <SEMICOLON> { return n; }
}

/** Parses a statement followed by end-of-file. */
AstNode statementEof() :
{
final AstNode n;
}
{
n = statement() <EOF> { return n; }
}

<DEFAULT> TOKEN :
{
< AND: "and" >
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/net/hydromatic/morel/MainTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1784,7 +1784,7 @@ public class MainTest {
+ "group sum = x + y")
.assertType(is("int list"))
.assertEvalIter(equalsUnordered(3, 7));
ml("from {c, a, ...} in [{a=1.0,b=true,c=3},{a=1.5,b=true,c=4}];")
ml("from {c, a, ...} in [{a=1.0,b=true,c=3},{a=1.5,b=true,c=4}]")
.assertParse("from {a = a, c = c, ...}"
+ " in [{a = 1.0, b = true, c = 3}, {a = 1.5, b = true, c = 4}]")
.assertType("{a:real, c:int} list");
Expand Down
19 changes: 10 additions & 9 deletions src/test/java/net/hydromatic/morel/Ml.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Ml withParser(Consumer<MorelParserImpl> action) {
Ml assertParseLiteral(Matcher<Ast.Literal> matcher) {
return withParser(parser -> {
try {
final Ast.Literal literal = parser.literal();
final Ast.Literal literal = parser.literalEof();
assertThat(literal, matcher);
} catch (ParseException e) {
throw new RuntimeException(e);
Expand All @@ -120,7 +120,7 @@ Ml assertParseLiteral(Matcher<Ast.Literal> matcher) {
Ml assertParseDecl(Matcher<Ast.Decl> matcher) {
return withParser(parser -> {
try {
final Ast.Decl decl = parser.decl();
final Ast.Decl decl = parser.declEof();
assertThat(decl, matcher);
} catch (ParseException e) {
throw new RuntimeException(e);
Expand All @@ -136,7 +136,7 @@ Ml assertParseDecl(Class<? extends Ast.Decl> clazz,
Ml assertParseStmt(Matcher<AstNode> matcher) {
return withParser(parser -> {
try {
final AstNode statement = parser.statement();
final AstNode statement = parser.statementEof();
assertThat(statement, matcher);
} catch (ParseException e) {
throw new RuntimeException(e);
Expand Down Expand Up @@ -178,7 +178,7 @@ Ml assertParseThrowsIllegalArgumentException(Matcher<String> matcher) {
Ml assertParseThrows(Matcher<Throwable> matcher) {
try {
final MorelParserImpl parser = new MorelParserImpl(new StringReader(ml));
final AstNode statement = parser.statement();
final AstNode statement = parser.statementEof();
fail("expected error, got " + statement);
} catch (Throwable e) {
assertThat(e, matcher);
Expand All @@ -189,7 +189,7 @@ Ml assertParseThrows(Matcher<Throwable> matcher) {
private Ml withValidate(BiConsumer<TypeResolver.Resolved, Calcite> action) {
return withParser(parser -> {
try {
final AstNode statement = parser.statement();
final AstNode statement = parser.statementEof();
final Calcite calcite = Calcite.withDataSets(dataSetMap);
final TypeResolver.Resolved resolved =
Compiles.validateExpression(statement, calcite.foreignValues());
Expand Down Expand Up @@ -222,7 +222,7 @@ Ml withPrepare(Consumer<CompiledStatement> action) {
return withParser(parser -> {
try {
final TypeSystem typeSystem = new TypeSystem();
final AstNode statement = parser.statement();
final AstNode statement = parser.statementEof();
final Environment env = Environments.empty();
final Session session = new Session();
final CompiledStatement compiled =
Expand All @@ -238,7 +238,7 @@ Ml withPrepare(Consumer<CompiledStatement> action) {
Ml assertCalcite(Matcher<String> matcher) {
try {
final MorelParserImpl parser = new MorelParserImpl(new StringReader(ml));
final AstNode statement = parser.statement();
final AstNode statement = parser.statementEof();
final TypeSystem typeSystem = new TypeSystem();

final Calcite calcite = Calcite.withDataSets(dataSetMap);
Expand Down Expand Up @@ -275,7 +275,7 @@ public Ml assertCoreString(@Nullable Matcher<String> beforeMatcher,
final AstNode statement;
try {
final MorelParserImpl parser = new MorelParserImpl(new StringReader(ml));
statement = parser.statement();
statement = parser.statementEof();
} catch (ParseException parseException) {
throw new RuntimeException(parseException);
}
Expand Down Expand Up @@ -324,7 +324,7 @@ Ml assertAnalyze(Matcher<Object> matcher) {
final AstNode statement;
try {
final MorelParserImpl parser = new MorelParserImpl(new StringReader(ml));
statement = parser.statement();
statement = parser.statementEof();
} catch (ParseException parseException) {
throw new RuntimeException(parseException);
}
Expand All @@ -348,6 +348,7 @@ Ml assertPlan(Matcher<Code> planMatcher) {
return assertEval(null, planMatcher);
}

@SuppressWarnings({"unchecked", "rawtypes"})
<E> Ml assertEvalIter(Matcher<Iterable<E>> matcher) {
return assertEval((Matcher) matcher);
}
Expand Down

0 comments on commit beabace

Please sign in to comment.