From df180830a016b8529bc1789a73ef8b74d386fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sat, 3 Nov 2018 16:57:39 +0100 Subject: [PATCH 1/8] Implement DIP1009 correctly, close #303 --- src/dparse/ast.d | 38 ++++++++- src/dparse/parser.d | 189 ++++++++++++++++++++++---------------------- 2 files changed, 130 insertions(+), 97 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index e7de2b39..45923e7a 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -242,6 +242,7 @@ abstract class ASTVisitor /** */ void visit(const ImportDeclaration importDeclaration) { importDeclaration.accept(this); } /** */ void visit(const ImportExpression importExpression) { importExpression.accept(this); } /** */ void visit(const IndexExpression indexExpression) { indexExpression.accept(this); } + /** */ void visit(const InContractExpression inContractExpression) { inContractExpression.accept(this); } /** */ void visit(const InExpression inExpression) { inExpression.accept(this); } /** */ void visit(const InStatement inStatement) { inStatement.accept(this); } /** */ void visit(const Initialize initialize) { initialize.accept(this); } @@ -268,6 +269,7 @@ abstract class ASTVisitor /** */ void visit(const Operands operands) { operands.accept(this); } /** */ void visit(const OrExpression orExpression) { orExpression.accept(this); } /** */ void visit(const OrOrExpression orOrExpression) { orOrExpression.accept(this); } + /** */ void visit(const OutContractExpression outContractExpression) { outContractExpression.accept(this); } /** */ void visit(const OutStatement outStatement) { outStatement.accept(this); } /** */ void visit(const ParameterAttribute parameterAttribute) { parameterAttribute.accept(this); } /** */ void visit(const Parameter parameter) { parameter.accept(this); } @@ -1671,14 +1673,17 @@ final class FunctionBody : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(inStatements, outStatements, bodyStatement, + mixin (visitIfNotNull!(inStatements, inContractExpressions, + outStatements, outContractExpressions, bodyStatement, blockStatement)); } /** */ BlockStatement blockStatement; /** */ BodyStatement bodyStatement; /** */ OutStatement[] outStatements; + /** */ OutContractExpression[] outContractExpressions; /** */ InStatement[] inStatements; + /** */ InContractExpression[] inContractExpressions; mixin OpEquals; } @@ -1909,6 +1914,19 @@ final class IndexExpression : ExpressionNode mixin OpEquals; } +/// +final class InContractExpression : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(assertion, message)); + } + /** */ size_t inTokenLocation; + /** */ ExpressionNode assertion; + /** */ ExpressionNode message; + mixin OpEquals; +} + /// final class InExpression : ExpressionNode { @@ -1977,9 +1995,11 @@ final class Invariant : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(blockStatement)); + mixin (visitIfNotNull!(blockStatement, assertion, message)); } /** */ BlockStatement blockStatement; + /** */ ExpressionNode assertion; + /** */ ExpressionNode message; /** */ string comment; size_t line; size_t index; @@ -2288,6 +2308,20 @@ final class OrOrExpression : ExpressionNode mixin OpEquals; } +/// +final class OutContractExpression : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(parameter, assertion, message)); + } + /** */ size_t outTokenLocation; + /** */ Token parameter; + /** */ ExpressionNode assertion; + /** */ ExpressionNode message; + mixin OpEquals; +} + /// final class OutStatement : ASTNode { diff --git a/src/dparse/parser.d b/src/dparse/parser.d index cf53055e..21a682bc 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -3095,7 +3095,9 @@ class Parser } StackBuffer inStatements; + StackBuffer inContractExpressions; StackBuffer outStatements; + StackBuffer outContractExpressions; bool requireDo; while (currentIsOneOf(tok!"in", tok!"out")) @@ -3116,14 +3118,8 @@ class Parser else if (next.type == tok!"(") { requireDo = false; - const size_t inTokenLocation = current.index; - advance(); - advance(); - if (InStatement s = parseContractExpression!InStatement()) - { - s.inTokenLocation = inTokenLocation; - inStatements.put(s); - } + if (auto e = parseInContractExpression()) + inContractExpressions.put(e); else return null; } else @@ -3146,28 +3142,8 @@ class Parser else if (next.type == tok!"(") { requireDo = false; - const size_t outTokenLocation = current.index; - advance(); - advance(); - if (currentIs(tok!";")) - { - advance(); - } - else if (currentIs(tok!"identifier") && peekIs(tok!";")) - { - advance(); - advance(); - } - else - { - error("`;` or identifier expected"); - return null; - } - if (OutStatement s = parseContractExpression!OutStatement()) - { - s.outTokenLocation = outTokenLocation; - outStatements.put(s); - } + if (auto e = parseOutContractExpression()) + outContractExpressions.put(e); else return null; } else @@ -3180,7 +3156,9 @@ class Parser } ownArray(node.inStatements, inStatements); + ownArray(node.inContractExpressions, inContractExpressions); ownArray(node.outStatements, outStatements); + ownArray(node.outContractExpressions, outContractExpressions); if (currentIs(tok!"{") && !requireDo) { @@ -3860,6 +3838,37 @@ class Parser return node; } + /** + * Parses an InContractExpression + * + * $(GRAMMAR $(RULEDEF inContractExpression): + * $(LITERAL 'in') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * ;) + */ + InContractExpression parseInContractExpression() + { + auto node = allocator.make!InContractExpression; + const i = expect(tok!"in"); + mixin(nullCheck!`i`); + node.inTokenLocation = i.index; + mixin(tokenCheck!"("); + mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); + if (currentIs(tok!",")) + { + advance(); + if (currentIs(tok!")")) + { + advance(); + return node; + } + mixin(parseNodeQ!(`node.message`, `AssignExpression`)); + } + if (currentIs(tok!",")) + advance(); + mixin(tokenCheck!")"); + return node; + } + /** * Parses an InExpression * @@ -3885,8 +3894,7 @@ class Parser * Parses an InStatement * * $(GRAMMAR $(RULEDEF inStatement): - * $(LITERAL 'in') $(RULE blockStatement) - * | $(LITERAL 'in') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'in') $(RULE blockStatement) * ;) */ InStatement parseInStatement() @@ -3944,40 +3952,46 @@ class Parser */ Invariant parseInvariant() { + auto node = allocator.make!Invariant; + node.index = current.index; + node.line = current.line; mixin(tokenCheck!"invariant"); + bool mustHaveBlock; if (currentIs(tok!"(") && peekIs(tok!")")) { + mustHaveBlock = true; advance(); advance(); } if (currentIs(tok!"{")) { - Invariant node = allocator.make!Invariant; - node.index = current.index; - node.line = current.line; if (currentIs(tok!"(")) { advance(); mixin(tokenCheck!")"); } mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); - return node; } - else if (currentIs(tok!"(")) + else if (!mustHaveBlock && currentIs(tok!"(")) { - const idx = current.index; - const lne = current.line; advance(); - if (Invariant node = parseContractExpression!Invariant()) + mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); + if (currentIs(tok!",")) { - mixin(tokenCheck!";"); - node.index = idx; - node.line = lne; - return node; + advance(); + if (currentIs(tok!")")) + { + advance(); + return node; + } + mixin(parseNodeQ!(`node.message`, `AssignExpression`)); } - else return null; + if (currentIs(tok!",")) + advance(); + mixin(tokenCheck!")"); } else return null; + return node; } /** @@ -4550,12 +4564,45 @@ class Parser tok!"||")(); } + /** + * Parses an OutContractExpression + * + * $(GRAMMAR $(RULEDEF outContractExpression): + * $(LITERAL 'out') $(LITERAL '$(LPAREN)') $(LITERAL Identifier)? $(LITERAL ';') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * ;) + */ + OutContractExpression parseOutContractExpression() + { + auto node = allocator.make!OutContractExpression; + const o = expect(tok!"out"); + mixin(nullCheck!`o`); + node.outTokenLocation = o.index; + mixin(tokenCheck!"("); + if (currentIs(tok!"identifier")) + node.parameter = advance(); + mixin(tokenCheck!";"); + mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); + if (currentIs(tok!",")) + { + advance(); + if (currentIs(tok!")")) + { + advance(); + return node; + } + mixin(parseNodeQ!(`node.message`, `AssignExpression`)); + } + if (currentIs(tok!",")) + advance(); + mixin(tokenCheck!")"); + return node; + } + /** * Parses an OutStatement * * $(GRAMMAR $(RULEDEF outStatement): - * $(LITERAL 'out') ($(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)'))? $(RULE blockStatement) - * | $(LITERAL 'out') $(LITERAL '$(LPAREN)') $(LITERAL Identifier)? $(LITERAL ';') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'out') ($(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)'))? $(RULE blockStatement) * ;) */ OutStatement parseOutStatement() @@ -7999,54 +8046,6 @@ protected: final: return node; } - AssertExpression parseAssertForContractExp() - { - auto node = allocator.make!AssertExpression; - node.line = current.line; - node.column = current.column; - mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); - if (currentIs(tok!",")) - { - advance(); - if (currentIs(tok!")")) - { - advance(); - return node; - } - mixin(parseNodeQ!(`node.message`, `AssignExpression`)); - } - if (currentIs(tok!",")) - advance(); - mixin(tokenCheck!")"); - return node; - } - - T parseContractExpression(T)() - { - - AssertExpression ae = parseAssertForContractExp(); - if (!ae) - return null; - T inOrOut = allocator.make!T(); - inOrOut.blockStatement = allocator.make!BlockStatement(); - DeclarationsAndStatements d = allocator.make!DeclarationsAndStatements(); - inOrOut.blockStatement.declarationsAndStatements = d; - StackBuffer dos; - dos.put(allocator.make!DeclarationOrStatement()); - ownArray(d.declarationsAndStatements, dos); - Statement s = allocator.make!Statement(); - d.declarationsAndStatements[0].statement = s; - s.statementNoCaseNoDefault = allocator.make!StatementNoCaseNoDefault(); - s.statementNoCaseNoDefault.expressionStatement = allocator.make!ExpressionStatement(); - Expression e = allocator.make!Expression(); - s.statementNoCaseNoDefault.expressionStatement.expression = e; - StackBuffer en; - en.put(ae); - ownArray(e.items, en); - - return inOrOut; - } - int suppressMessages; size_t index; int _traceDepth; From e531024bdeb182cece3f20ef178a8845c0d0c8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sat, 3 Nov 2018 17:43:22 +0100 Subject: [PATCH 2/8] Handle expression-based contracts in formatter --- src/dparse/formatter.d | 53 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index 5012dbd7..948d70b4 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -1442,8 +1442,12 @@ class Formatter(Sink) } foreach(inStatement; inStatements) format(inStatement); + foreach(inContractExpression; inContractExpressions) + format(inContractExpression); foreach(outStatement; outStatements) format(outStatement); + foreach(outContractExpression; outContractExpressions) + format(outContractExpression); if (bodyStatement) format(bodyStatement); } @@ -1834,6 +1838,20 @@ class Formatter(Sink) } } + void format(const InContractExpression expression) + { + debug(verbose) writeln("InContractExpression"); + + put("in ("); + format(expression.assertion); + if (expression.message !is null) + { + put(", "); + format(expression.message); + } + put(")"); + } + void format(const InExpression inExpression) { debug(verbose) writeln("InExpression"); @@ -1916,8 +1934,22 @@ class Formatter(Sink) putComment(invariant_.comment); putAttrs(attrs); - put("invariant()"); - format(invariant_.blockStatement); + put("invariant("); + if (invariant_.blockStatement !is null) + { + put(")"); + format(invariant_.blockStatement); + } + else + { + format(invariant_.assertion); + if (invariant_.message !is null) + { + put("; "); + format(invariant_.message); + } + put(")"); + } } void format(const IsExpression isExpression) @@ -2249,6 +2281,23 @@ class Formatter(Sink) mixin(binary("orOrExpression", "||")); } + void format(const OutContractExpression expression) + { + debug(verbose) writeln("OutContractExpression"); + + put("out ("); + if (expression.parameter != tok!"") + format(expression.parameter); + put("; "); + format(expression.assertion); + if (expression.message !is null) + { + put(", "); + format(expression.message); + } + put(")"); + } + void format(const OutStatement stmnt) { debug(verbose) writeln("OutStatement"); From f0e70bc31d42ea1d7ba27ecc749ff70ab4c7e5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 11:22:07 +0100 Subject: [PATCH 3/8] Introduce AssertArguments --- src/dparse/ast.d | 33 ++++++++++------ src/dparse/formatter.d | 41 ++++++++++---------- src/dparse/parser.d | 87 +++++++++++++++--------------------------- 3 files changed, 71 insertions(+), 90 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 45923e7a..278d2afe 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -170,6 +170,7 @@ abstract class ASTVisitor /** */ void visit(const AsmTypePrefix asmTypePrefix) { asmTypePrefix.accept(this); } /** */ void visit(const AsmUnaExp asmUnaExp) { asmUnaExp.accept(this); } /** */ void visit(const AsmXorExp asmXorExp) { asmXorExp.accept(this); } + /** */ void visit(const AssertArguments assertArguments) { assertArguments.accept(this); } /** */ void visit(const AssertExpression assertExpression) { assertExpression.accept(this); } /** */ void visit(const AssignExpression assignExpression) { assignExpression.accept(this); } /** */ void visit(const AssocArrayLiteral assocArrayLiteral) { assocArrayLiteral.accept(this); } @@ -819,19 +820,30 @@ final class AsmXorExp : ExpressionNode } /// -final class AssertExpression : ExpressionNode +final class AssertArguments : ASTNode { override void accept(ASTVisitor visitor) const { mixin (visitIfNotNull!(assertion, message)); } - /** */ size_t line; - /** */ size_t column; /** */ ExpressionNode assertion; /** */ ExpressionNode message; mixin OpEquals; } +/// +final class AssertExpression : ExpressionNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(assertArguments)); + } + /** */ size_t line; + /** */ size_t column; + /** */ AssertArguments assertArguments; + mixin OpEquals; +} + /// final class AssignExpression : ExpressionNode { @@ -1919,11 +1931,10 @@ final class InContractExpression : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(assertion, message)); + mixin (visitIfNotNull!(assertArguments)); } /** */ size_t inTokenLocation; - /** */ ExpressionNode assertion; - /** */ ExpressionNode message; + /** */ AssertArguments assertArguments; mixin OpEquals; } @@ -1995,11 +2006,10 @@ final class Invariant : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(blockStatement, assertion, message)); + mixin (visitIfNotNull!(blockStatement, assertArguments)); } /** */ BlockStatement blockStatement; - /** */ ExpressionNode assertion; - /** */ ExpressionNode message; + /** */ AssertArguments assertArguments; /** */ string comment; size_t line; size_t index; @@ -2313,12 +2323,11 @@ final class OutContractExpression : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(parameter, assertion, message)); + mixin (visitIfNotNull!(parameter, assertArguments)); } /** */ size_t outTokenLocation; /** */ Token parameter; - /** */ ExpressionNode assertion; - /** */ ExpressionNode message; + /** */ AssertArguments assertArguments; mixin OpEquals; } diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index 948d70b4..07b4b6fb 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -373,7 +373,7 @@ class Formatter(Sink) assert(false); } - void format(const AssertExpression assertExpression) + void format(const AssertArguments assertArguments) { debug(verbose) writeln("AssertExpression"); @@ -382,15 +382,29 @@ class Formatter(Sink) AssignExpression message; **/ - with(assertExpression) + with(assertArguments) { - put("assert ("); format(assertion); if (message) { put(", "); format(message); } + } + } + + void format(const AssertExpression assertExpression) + { + debug(verbose) writeln("AssertExpression"); + + /** + AssertArguments assertArguments; + **/ + + with(assertExpression) + { + put("assert ("); + format(assertArguments); put(")"); } } @@ -1843,12 +1857,7 @@ class Formatter(Sink) debug(verbose) writeln("InContractExpression"); put("in ("); - format(expression.assertion); - if (expression.message !is null) - { - put(", "); - format(expression.message); - } + format(expression.assertArguments); put(")"); } @@ -1942,12 +1951,7 @@ class Formatter(Sink) } else { - format(invariant_.assertion); - if (invariant_.message !is null) - { - put("; "); - format(invariant_.message); - } + format(invariant_.assertArguments); put(")"); } } @@ -2289,12 +2293,7 @@ class Formatter(Sink) if (expression.parameter != tok!"") format(expression.parameter); put("; "); - format(expression.assertion); - if (expression.message !is null) - { - put(", "); - format(expression.message); - } + format(expression.assertArguments); put(")"); } diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 21a682bc..4a87e63f 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -895,11 +895,32 @@ class Parser return parseLeftAssocBinaryExpression!(AsmXorExp, AsmAndExp, tok!"^")(); } + /** + * Parses an AssertArguments + * + * $(GRAMMAR $(RULEDEF assertArguments): + * $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? + * ;) + */ + AssertArguments parseAssertArguments() + { + auto node = allocator.make!AssertArguments; + mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); + if (currentIs(tok!",")) + advance(); + if (currentIs(tok!")")) + return node; + mixin(parseNodeQ!(`node.message`, `AssignExpression`)); + if (currentIs(tok!",")) + advance(); + return node; + } + /** * Parses an AssertExpression * * $(GRAMMAR $(RULEDEF assertExpression): - * $(LITERAL 'assert') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'assert') $(LITERAL '$(LPAREN)') $(RULE assertArguments) $(LITERAL '$(RPAREN)') * ;) */ AssertExpression parseAssertExpression() @@ -910,19 +931,7 @@ class Parser node.column = current.column; advance(); // "assert" mixin(tokenCheck!"("); - mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); - if (currentIs(tok!",")) - { - advance(); - if (currentIs(tok!")")) - { - advance(); - return node; - } - mixin(parseNodeQ!(`node.message`, `AssignExpression`)); - } - if (currentIs(tok!",")) - advance(); + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); mixin(tokenCheck!")"); return node; } @@ -3842,7 +3851,7 @@ class Parser * Parses an InContractExpression * * $(GRAMMAR $(RULEDEF inContractExpression): - * $(LITERAL 'in') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'in') $(LITERAL '$(LPAREN)') $(RULE assertArguments) $(LITERAL '$(RPAREN)') * ;) */ InContractExpression parseInContractExpression() @@ -3852,19 +3861,7 @@ class Parser mixin(nullCheck!`i`); node.inTokenLocation = i.index; mixin(tokenCheck!"("); - mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); - if (currentIs(tok!",")) - { - advance(); - if (currentIs(tok!")")) - { - advance(); - return node; - } - mixin(parseNodeQ!(`node.message`, `AssignExpression`)); - } - if (currentIs(tok!",")) - advance(); + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); mixin(tokenCheck!")"); return node; } @@ -3946,8 +3943,8 @@ class Parser * Parses an Invariant * * $(GRAMMAR $(RULEDEF invariant): - * $(LITERAL 'invariant') $(RULE blockStatement) - * | $(LITERAL 'invariant') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') $(LITERAL ';') + * $(LITERAL 'invariant') ($(LITERAL '$(LPAREN)') $(LITERAL '$(LPAREN)'))? $(RULE blockStatement) + * | $(LITERAL 'invariant') $(LITERAL '$(LPAREN)') $(RULE assertArguments) $(LITERAL '$(RPAREN)') $(LITERAL ';') * ;) */ Invariant parseInvariant() @@ -3975,19 +3972,7 @@ class Parser else if (!mustHaveBlock && currentIs(tok!"(")) { advance(); - mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); - if (currentIs(tok!",")) - { - advance(); - if (currentIs(tok!")")) - { - advance(); - return node; - } - mixin(parseNodeQ!(`node.message`, `AssignExpression`)); - } - if (currentIs(tok!",")) - advance(); + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); mixin(tokenCheck!")"); } else return null; @@ -4568,7 +4553,7 @@ class Parser * Parses an OutContractExpression * * $(GRAMMAR $(RULEDEF outContractExpression): - * $(LITERAL 'out') $(LITERAL '$(LPAREN)') $(LITERAL Identifier)? $(LITERAL ';') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'out') $(LITERAL '$(LPAREN)') $(LITERAL Identifier)? $(LITERAL ';') $(RULE assertArguments) $(LITERAL '$(RPAREN)') * ;) */ OutContractExpression parseOutContractExpression() @@ -4581,19 +4566,7 @@ class Parser if (currentIs(tok!"identifier")) node.parameter = advance(); mixin(tokenCheck!";"); - mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); - if (currentIs(tok!",")) - { - advance(); - if (currentIs(tok!")")) - { - advance(); - return node; - } - mixin(parseNodeQ!(`node.message`, `AssignExpression`)); - } - if (currentIs(tok!",")) - advance(); + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); mixin(tokenCheck!")"); return node; } From 3d0017c1ec92a62c25dbbb4864a866b0f17b7b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 14:27:12 +0100 Subject: [PATCH 4/8] Add missing trace calls --- src/dparse/parser.d | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 4a87e63f..55f3a68b 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -3856,6 +3856,7 @@ class Parser */ InContractExpression parseInContractExpression() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!InContractExpression; const i = expect(tok!"in"); mixin(nullCheck!`i`); @@ -3875,6 +3876,7 @@ class Parser */ ExpressionNode parseInExpression(ExpressionNode shift = null) { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!InExpression; mixin(nullCheck!`node.left = shift is null ? parseShiftExpression() : shift`); if (currentIs(tok!"!")) @@ -3896,6 +3898,7 @@ class Parser */ InStatement parseInStatement() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!InStatement; const i = expect(tok!"in"); mixin(nullCheck!`i`); @@ -3914,6 +3917,7 @@ class Parser */ Initializer parseInitializer() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!Initializer; if (currentIs(tok!"void") && peekIsOneOf(tok!",", tok!";")) advance(); @@ -3949,6 +3953,7 @@ class Parser */ Invariant parseInvariant() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!Invariant; node.index = current.index; node.line = current.line; @@ -4558,6 +4563,7 @@ class Parser */ OutContractExpression parseOutContractExpression() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!OutContractExpression; const o = expect(tok!"out"); mixin(nullCheck!`o`); @@ -4580,6 +4586,7 @@ class Parser */ OutStatement parseOutStatement() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!OutStatement; const o = expect(tok!"out"); mixin(nullCheck!`o`); From 16019830ca4b05319fa8711619863b47951fc80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 18:28:37 +0100 Subject: [PATCH 5/8] Better follow DIP1009 syntax changes --- src/dparse/ast.d | 80 +++++++++++-- src/dparse/formatter.d | 87 +++++++++++--- src/dparse/parser.d | 255 +++++++++++++++++++++++++---------------- 3 files changed, 295 insertions(+), 127 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 278d2afe..03e8173a 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -229,6 +229,7 @@ abstract class ASTVisitor /** */ void visit(const FunctionAttribute functionAttribute) { functionAttribute.accept(this); } /** */ void visit(const FunctionBody functionBody) { functionBody.accept(this); } /** */ void visit(const FunctionCallExpression functionCallExpression) { functionCallExpression.accept(this); } + /** */ void visit(const FunctionContract functionContract) { functionContract.accept(this); } /** */ void visit(const FunctionDeclaration functionDeclaration) { functionDeclaration.accept(this); } /** */ void visit(const FunctionLiteralExpression functionLiteralExpression) { functionLiteralExpression.accept(this); } /** */ void visit(const GotoStatement gotoStatement) { gotoStatement.accept(this); } @@ -245,6 +246,8 @@ abstract class ASTVisitor /** */ void visit(const IndexExpression indexExpression) { indexExpression.accept(this); } /** */ void visit(const InContractExpression inContractExpression) { inContractExpression.accept(this); } /** */ void visit(const InExpression inExpression) { inExpression.accept(this); } + /** */ void visit(const InOutContractExpression inOutContractExpression) { inOutContractExpression.accept(this); } + /** */ void visit(const InOutStatement inOutStatement) { inOutStatement.accept(this); } /** */ void visit(const InStatement inStatement) { inStatement.accept(this); } /** */ void visit(const Initialize initialize) { initialize.accept(this); } /** */ void visit(const Initializer initializer) { initializer.accept(this); } @@ -257,6 +260,7 @@ abstract class ASTVisitor /** */ void visit(const LastCatch lastCatch) { lastCatch.accept(this); } /** */ void visit(const LinkageAttribute linkageAttribute) { linkageAttribute.accept(this); } /** */ void visit(const MemberFunctionAttribute memberFunctionAttribute) { memberFunctionAttribute.accept(this); } + /** */ void visit(const MissingFunctionBody missingFunctionBody) { missingFunctionBody.accept(this); } /** */ void visit(const MixinDeclaration mixinDeclaration) { mixinDeclaration.accept(this); } /** */ void visit(const MixinExpression mixinExpression) { mixinExpression.accept(this); } /** */ void visit(const MixinTemplateDeclaration mixinTemplateDeclaration) { mixinTemplateDeclaration.accept(this); } @@ -290,6 +294,7 @@ abstract class ASTVisitor /** */ void visit(const ShiftExpression shiftExpression) { shiftExpression.accept(this); } /** */ void visit(const SingleImport singleImport) { singleImport.accept(this); } /** */ void visit(const Index index) { index.accept(this); } + /** */ void visit(const SpecifiedFunctionBody specifiedFunctionBody) { specifiedFunctionBody.accept(this); } /** */ void visit(const Statement statement) { statement.accept(this); } /** */ void visit(const StatementNoCaseNoDefault statementNoCaseNoDefault) { statementNoCaseNoDefault.accept(this); } /** */ void visit(const StaticAssertDeclaration staticAssertDeclaration) { staticAssertDeclaration.accept(this); } @@ -1685,17 +1690,11 @@ final class FunctionBody : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(inStatements, inContractExpressions, - outStatements, outContractExpressions, bodyStatement, - blockStatement)); + mixin (visitIfNotNull!(specifiedFunctionBody, missingFunctionBody)); } - /** */ BlockStatement blockStatement; - /** */ BodyStatement bodyStatement; - /** */ OutStatement[] outStatements; - /** */ OutContractExpression[] outContractExpressions; - /** */ InStatement[] inStatements; - /** */ InContractExpression[] inContractExpressions; + /** */ SpecifiedFunctionBody specifiedFunctionBody; + /** */ MissingFunctionBody missingFunctionBody; mixin OpEquals; } @@ -1713,6 +1712,18 @@ final class FunctionCallExpression : ExpressionNode mixin OpEquals; } +/// +final class FunctionContract : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(inOutContractExpression, inOutStatement)); + } + /** */ InOutContractExpression inOutContractExpression; + /** */ InOutStatement inOutStatement; + mixin OpEquals; +} + /// final class FunctionDeclaration : ASTNode { @@ -1743,11 +1754,11 @@ final class FunctionLiteralExpression : ExpressionNode override void accept(ASTVisitor visitor) const { mixin (visitIfNotNull!(returnType, parameters, functionAttributes, - memberFunctionAttributes, functionBody, assignExpression)); + memberFunctionAttributes, specifiedFunctionBody, assignExpression)); } /** */ ExpressionNode assignExpression; /** */ FunctionAttribute[] functionAttributes; - /** */ FunctionBody functionBody; + /** */ SpecifiedFunctionBody specifiedFunctionBody; /** */ IdType functionOrDelegate; /** */ MemberFunctionAttribute[] memberFunctionAttributes; /** */ Parameters parameters; @@ -1950,6 +1961,30 @@ final class InExpression : ExpressionNode mixin OpEquals; } +/// +final class InOutContractExpression : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(inContractExpression, outContractExpression)); + } + /** */ InContractExpression inContractExpression; + /** */ OutContractExpression outContractExpression; + mixin OpEquals; +} + +/// +final class InOutStatement : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(inStatement, outStatement)); + } + /** */ InStatement inStatement; + /** */ OutStatement outStatement; + mixin OpEquals; +} + /// final class InStatement : ASTNode { @@ -2106,6 +2141,17 @@ final class MemberFunctionAttribute : ASTNode mixin OpEquals; } +/// +final class MissingFunctionBody : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(functionContracts)); + } + /** */ FunctionContract[] functionContracts; + mixin OpEquals; +} + /// final class MixinDeclaration : ASTNode { @@ -2585,6 +2631,18 @@ final class SingleImport : ASTNode mixin OpEquals; } +/// +final class SpecifiedFunctionBody : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(functionContracts, blockStatement)); + } + /** */ FunctionContract[] functionContracts; + /** */ BlockStatement blockStatement; + mixin OpEquals; +} + /// final class Statement : ASTNode { diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index 07b4b6fb..e13cabed 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -1449,21 +1449,8 @@ class Formatter(Sink) with(functionBody) { - if (blockStatement) - { - format(blockStatement); - return; - } - foreach(inStatement; inStatements) - format(inStatement); - foreach(inContractExpression; inContractExpressions) - format(inContractExpression); - foreach(outStatement; outStatements) - format(outStatement); - foreach(outContractExpression; outContractExpressions) - format(outContractExpression); - if (bodyStatement) - format(bodyStatement); + if (specifiedFunctionBody) format(specifiedFunctionBody); + if (missingFunctionBody) format(missingFunctionBody); } } @@ -1487,6 +1474,22 @@ class Formatter(Sink) } } + void format(const FunctionContract functionContract) + { + debug(verbose) writeln("FunctionContract"); + + /** + InOutContractExpression inOutContractExpression; + InOutStatement inOutStatement; + **/ + + with(functionContract) + { + if (inOutContractExpression) format(inOutContractExpression); + if (inOutStatement) format(inOutStatement); + } + } + void format(const FunctionDeclaration decl, const Attribute[] attrs = null) { debug(verbose) writeln("FunctionDeclaration"); @@ -1536,7 +1539,7 @@ class Formatter(Sink) /** ExpressionNode assignExpression; FunctionAttribute[] functionAttributes; - FunctionBody functionBody; + SpecifiedFunctionBody specifiedFunctionBody; IdType functionOrDelegate; MemberFunctionAttribute[] memberFunctionAttributes; Parameters parameters; @@ -1561,8 +1564,8 @@ class Formatter(Sink) } ignoreNewlines = true; - if (functionBody) - format(functionBody); + if (specifiedFunctionBody) + format(specifiedFunctionBody); else { format(identifier); @@ -1873,6 +1876,29 @@ class Formatter(Sink) } } + void format(const InOutContractExpression inOutContractExpression) + { + debug(verbose) writeln("InOutContractExpression"); + + with(inOutContractExpression) + { + if (inContractExpression) format(inContractExpression); + if (outContractExpression) format(outContractExpression); + newline(); + } + } + + void format(const InOutStatement inOutStatement) + { + debug(verbose) writeln("InOutStatement"); + + with(inOutStatement) + { + if (inStatement) format(inStatement); + if (outStatement) format(outStatement); + } + } + void format(const InStatement inStatement) { debug(verbose) writeln("InStatement"); @@ -2094,6 +2120,18 @@ class Formatter(Sink) } } + void format(const MissingFunctionBody missingFunctionBody) + { + debug(verbose) writeln("MissingFunctionBody"); + + with(missingFunctionBody) + { + foreach (contract; functionContracts) + format(contract); + put(";"); + } + } + void format(const MixinDeclaration mixinDeclaration, const Attribute[] attrs = null) { debug(verbose) writeln("MixinDeclaration"); @@ -2612,6 +2650,19 @@ class Formatter(Sink) format(singleImport.identifierChain); } + void format(const SpecifiedFunctionBody specifiedFunctionBody) + { + debug(verbose) writeln("SpecifiedFunctionBody"); + + with(specifiedFunctionBody) + { + foreach (contract; functionContracts) + format(contract); + put("do"); + format(blockStatement); + } + } + void format(const Statement statement) { debug(verbose) writeln("Statement"); diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 55f3a68b..841bc1d6 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -3089,108 +3089,27 @@ class Parser * $(LINK2 https://github.com/dlang-community/dsymbol/blob/master/src/dsymbol/conversion/package.d, here). * * $(GRAMMAR $(RULEDEF functionBody): - * $(RULE blockStatement) - * | ($(RULE inStatement) | $(RULE outStatement))* $(RULE bodyStatement)? + * $(RULE specifiedFunctionBody) + * | $(RULE missingFunctionBody) * ;) */ FunctionBody parseFunctionBody() { mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!FunctionBody; - if (currentIs(tok!";")) - { - advance(); - return node; - } - - StackBuffer inStatements; - StackBuffer inContractExpressions; - StackBuffer outStatements; - StackBuffer outContractExpressions; - bool requireDo; - - while (currentIsOneOf(tok!"in", tok!"out")) - { - const(Token)* next = peek(); - if (next is null) - return null; - - if (currentIs(tok!"in")) - { - if (next.type == tok!"{") - { - requireDo = true; - if (auto s = parseInStatement()) - inStatements.put(s); - else return null; - } - else if (next.type == tok!"(") - { - requireDo = false; - if (auto e = parseInContractExpression()) - inContractExpressions.put(e); - else return null; - } - else - { - error("`{` or `(` expected"); - return null; - } - } - else if (currentIs(tok!"out")) - { - if (next.type == tok!"{" || (index < tokens.length - 3 && - tokens[index + 2].type == tok!("identifier") && - tokens[index + 3].type == tok!(")"))) - { - requireDo = true; - if (auto s = parseOutStatement()) - outStatements.put(s); - else return null; - } - else if (next.type == tok!"(") - { - requireDo = false; - if (auto e = parseOutContractExpression()) - outContractExpressions.put(e); - else return null; - } - else - { - error("`(` expected"); - return null; - } - } - else break; - } - - ownArray(node.inStatements, inStatements); - ownArray(node.inContractExpressions, inContractExpressions); - ownArray(node.outStatements, outStatements); - ownArray(node.outContractExpressions, outContractExpressions); - - if (currentIs(tok!"{") && !requireDo) - { - mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); - } - else if (currentIs(tok!";")) - { - advance(); - return node; - } - else if (currentIs(tok!"do") || (currentIs(tok!"identifier") && current.text == "body")) - { - mixin(parseNodeQ!(`node.bodyStatement`, `BodyStatement`)); - } - else if (requireDo && currentIs(tok!"{")) + immutable b = setBookmark(); + immutable c = allocator.setCheckpoint(); + auto missingFunctionBody = parseMissingFunctionBody(); + if (missingFunctionBody !is null) { - error("`do` expected after InStatement or OutStatement"); - return null; + abandonBookmark(b); + node.missingFunctionBody = missingFunctionBody; } - else if (!inStatements.length && !outStatements.length) + else { - error("`in`, `out`, `body`, or block statement expected"); - return null; + allocator.rollback(c); + goToBookmark(b); + mixin(parseNodeQ!(`node.specifiedFunctionBody`, `SpecifiedFunctionBody`)); } return node; } @@ -3233,6 +3152,34 @@ class Parser return node; } + /** + * Parses a FunctionContract + * + * $(GRAMMAR $(RULEDEF functionContract): + * $(RULE inOutContractExpression) + * | $(RULE inOutStatement) + * ;) + */ + FunctionContract parseFunctionContract() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!FunctionContract; + if (peekIs(tok!"{") || (currentIs(tok!"out") && + index < tokens.length - 3 && + tokens[index + 1].type == tok!("(") && + tokens[index + 2].type == tok!("identifier") && + tokens[index + 3].type == tok!(")"))) + mixin(parseNodeQ!(`node.inOutStatement`, `InOutStatement`)); + else if (peekIs(tok!"(")) + mixin(parseNodeQ!(`node.inOutContractExpression`, `InOutContractExpression`)); + else + { + error("`{` or `(` expected"); + return null; + } + return node; + } + /** * Parses a FunctionDeclaration * @@ -3313,10 +3260,10 @@ class Parser * Parses a FunctionLiteralExpression * * $(GRAMMAR $(RULEDEF functionLiteralExpression): - * | $(LITERAL 'delegate') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody) - * | $(LITERAL 'function') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody) - * | $(RULE parameters) $(RULE functionAttribute)* $(RULE functionBody) - * | $(RULE functionBody) + * | $(LITERAL 'delegate') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE specifiedFunctionBody) + * | $(LITERAL 'function') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE specifiedFunctionBody) + * | $(RULE parameters) $(RULE functionAttribute)* $(RULE specifiedFunctionBody) + * | $(RULE specifiedFunctionBody) * | $(LITERAL Identifier) $(LITERAL '=>') $(RULE assignExpression) * | $(LITERAL 'function') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression) * | $(LITERAL 'delegate') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression) @@ -3364,7 +3311,7 @@ class Parser mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); } else - mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); + mixin(parseNodeQ!(`node.specifiedFunctionBody`, `SpecifiedFunctionBody`)); return node; } @@ -3889,6 +3836,46 @@ class Parser return node; } + /** + * Parses an InOutContractExpression + * + * $(GRAMMAR $(RULEDEF inOutContractExpression): + * $(RULE inContractExpression) + * | $(RULE outContractExpression) + * ;) + */ + InOutContractExpression parseInOutContractExpression() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!InOutContractExpression; + if (currentIs(tok!"in")) + mixin(parseNodeQ!(`node.inContractExpression`, `InContractExpression`)); + else if (currentIs(tok!"out")) + mixin(parseNodeQ!(`node.outContractExpression`, `OutContractExpression`)); + else return null; + return node; + } + + /** + * Parses an InOutStatement + * + * $(GRAMMAR $(RULEDEF inOutStatement): + * $(RULE inStatement) + * | $(RULE outStatement) + * ;) + */ + InOutStatement parseInOutStatement() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!InOutStatement; + if (currentIs(tok!"in")) + mixin(parseNodeQ!(`node.inStatement`, `InStatement`)); + else if (currentIs(tok!"out")) + mixin(parseNodeQ!(`node.outStatement`, `OutStatement`)); + else return null; + return node; + } + /** * Parses an InStatement * @@ -4181,6 +4168,36 @@ class Parser return node; } + /** + * Parses a MissingFunctionBody + * + * $(GRAMMAR $(RULEDEF missingFunctionBody): + * $(LITERAL ';') + * | $(RULE functionContract)* $(LITERAL ';') + * ;) + */ + MissingFunctionBody parseMissingFunctionBody() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!MissingFunctionBody; + StackBuffer contracts; + while (currentIsOneOf(tok!"in", tok!"out")) + { + if (auto c = parseFunctionContract()) + contracts.put(c); + } + ownArray(node.functionContracts, contracts); + if (node.functionContracts.length == 0 + || node.functionContracts[$ - 1].inOutContractExpression !is null) + { + if (expect(tok!";") is null) + return null; + } + else if (currentIs(tok!"do") || current.text == "body") + return null; + return node; + } + /** * Parses a MixinDeclaration * @@ -5228,6 +5245,48 @@ class Parser return node; } + /** + * Parses a SpecifiedFunctionBody + * + * $(GRAMMAR $(RULEDEF specifiedFunctionBody): + * $(LITERAL 'do')? $(RULE blockStatement) + * | $(RULE functionContract)* $(RULE inOutContractExpression) $(LITERAL 'do')? $(RULE blockStatement) + * | $(RULE functionContract)* $(RULE inOutStatement) $(LITERAL 'do') $(RULE blockStatement) + * ;) + */ + SpecifiedFunctionBody parseSpecifiedFunctionBody() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!SpecifiedFunctionBody; + StackBuffer contracts; + bool requireDo; + + while (currentIsOneOf(tok!"in", tok!"out")) + { + if (auto c = parseFunctionContract()) + { + requireDo = c.inOutStatement !is null; + contracts.put(c); + } + } + ownArray(node.functionContracts, contracts); + + if (current.type == tok!"do" + || (current.type == tok!"identifier" && current.text == "body")) + { + requireDo = false; + advance(); + } + if (requireDo) + { + error("`do` expected after InStatement or OutStatement"); + return null; + } + + mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); + return node; + } + /** * Parses a Statement * From 7a7be30ce417e4fe77c4e93da7ca0508d8f8fbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 18:29:01 +0100 Subject: [PATCH 6/8] Remove obsolete BodyStatement --- src/dparse/ast.d | 12 ------------ src/dparse/formatter.d | 10 ---------- src/dparse/parser.d | 18 ------------------ 3 files changed, 40 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 03e8173a..8bed5a88 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -180,7 +180,6 @@ abstract class ASTVisitor /** */ void visit(const AutoDeclaration autoDeclaration) { autoDeclaration.accept(this); } /** */ void visit(const AutoDeclarationPart autoDeclarationPart) { autoDeclarationPart.accept(this); } /** */ void visit(const BlockStatement blockStatement) { blockStatement.accept(this); } - /** */ void visit(const BodyStatement bodyStatement) { bodyStatement.accept(this); } /** */ void visit(const BreakStatement breakStatement) { breakStatement.accept(this); } /** */ void visit(const BaseClass baseClass) { baseClass.accept(this); } /** */ void visit(const BaseClassList baseClassList) { baseClassList.accept(this); } @@ -972,17 +971,6 @@ final class BlockStatement : ASTNode mixin OpEquals; } -/// -final class BodyStatement : ASTNode -{ - override void accept(ASTVisitor visitor) const - { - mixin (visitIfNotNull!(blockStatement)); - } - /** */ BlockStatement blockStatement; - mixin OpEquals; -} - /// final class BreakStatement : ASTNode { diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index e13cabed..fa4eb66a 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -547,16 +547,6 @@ class Formatter(Sink) endBlock(); } } - - void format(const BodyStatement bodyStatement) - { - debug(verbose) writeln("BodyStatement"); - - newline(); - put("do"); - format(bodyStatement.blockStatement); - } - void format(const BreakStatement breakStatement) { debug(verbose) writeln("BreakStatement"); diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 841bc1d6..5ef55237 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -1246,24 +1246,6 @@ class Parser return node; } - /** - * Parses a BodyStatement - * - * $(GRAMMAR $(RULEDEF bodyStatement): - * ($(LITERAL 'body') | $(LITERAL 'do')) $(RULE blockStatement) - * ;) - */ - BodyStatement parseBodyStatement() - { - mixin(traceEnterAndExit!(__FUNCTION__)); - auto node = allocator.make!BodyStatement; - if (!currentIs(tok!"do") && current.text != "body") - return null; - advance(); - mixin(simpleParseItem!("blockStatement|parseBlockStatement")); - return node; - } - /** * Parses a BreakStatement * From c97d121e6da5a73946392d0bd02b26408031e8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 21:45:07 +0100 Subject: [PATCH 7/8] Use moreToken() to prevent RangeError's --- src/dparse/parser.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 5ef55237..d0046b59 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -4175,7 +4175,7 @@ class Parser if (expect(tok!";") is null) return null; } - else if (currentIs(tok!"do") || current.text == "body") + else if (moreTokens() && (currentIs(tok!"do") || current.text == "body")) return null; return node; } From 6d828b43b1164995fefd8796c4defe276d3dffbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Tr=C3=A9guier?= Date: Sun, 4 Nov 2018 21:55:29 +0100 Subject: [PATCH 8/8] Use currentIs instead of current.type --- src/dparse/parser.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index d0046b59..da6f5032 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -5253,8 +5253,8 @@ class Parser } ownArray(node.functionContracts, contracts); - if (current.type == tok!"do" - || (current.type == tok!"identifier" && current.text == "body")) + if (currentIs(tok!"do") + || (currentIs(tok!"identifier") && current.text == "body")) { requireDo = false; advance();