diff --git a/src/dparse/ast.d b/src/dparse/ast.d index e7de2b39..8bed5a88 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); } @@ -179,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); } @@ -228,6 +228,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); } @@ -242,7 +243,10 @@ 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 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); } @@ -255,6 +259,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); } @@ -268,6 +273,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); } @@ -287,6 +293,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); } @@ -817,19 +824,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 { @@ -953,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 { @@ -1671,14 +1678,11 @@ final class FunctionBody : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(inStatements, outStatements, bodyStatement, - blockStatement)); + mixin (visitIfNotNull!(specifiedFunctionBody, missingFunctionBody)); } - /** */ BlockStatement blockStatement; - /** */ BodyStatement bodyStatement; - /** */ OutStatement[] outStatements; - /** */ InStatement[] inStatements; + /** */ SpecifiedFunctionBody specifiedFunctionBody; + /** */ MissingFunctionBody missingFunctionBody; mixin OpEquals; } @@ -1696,6 +1700,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 { @@ -1726,11 +1742,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; @@ -1909,6 +1925,18 @@ final class IndexExpression : ExpressionNode mixin OpEquals; } +/// +final class InContractExpression : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(assertArguments)); + } + /** */ size_t inTokenLocation; + /** */ AssertArguments assertArguments; + mixin OpEquals; +} + /// final class InExpression : ExpressionNode { @@ -1921,6 +1949,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 { @@ -1977,9 +2029,10 @@ final class Invariant : ASTNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(blockStatement)); + mixin (visitIfNotNull!(blockStatement, assertArguments)); } /** */ BlockStatement blockStatement; + /** */ AssertArguments assertArguments; /** */ string comment; size_t line; size_t index; @@ -2076,6 +2129,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 { @@ -2288,6 +2352,19 @@ final class OrOrExpression : ExpressionNode mixin OpEquals; } +/// +final class OutContractExpression : ASTNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(parameter, assertArguments)); + } + /** */ size_t outTokenLocation; + /** */ Token parameter; + /** */ AssertArguments assertArguments; + mixin OpEquals; +} + /// final class OutStatement : ASTNode { @@ -2542,6 +2619,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 5012dbd7..fa4eb66a 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(")"); } } @@ -533,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"); @@ -1435,17 +1439,8 @@ class Formatter(Sink) with(functionBody) { - if (blockStatement) - { - format(blockStatement); - return; - } - foreach(inStatement; inStatements) - format(inStatement); - foreach(outStatement; outStatements) - format(outStatement); - if (bodyStatement) - format(bodyStatement); + if (specifiedFunctionBody) format(specifiedFunctionBody); + if (missingFunctionBody) format(missingFunctionBody); } } @@ -1469,6 +1464,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"); @@ -1518,7 +1529,7 @@ class Formatter(Sink) /** ExpressionNode assignExpression; FunctionAttribute[] functionAttributes; - FunctionBody functionBody; + SpecifiedFunctionBody specifiedFunctionBody; IdType functionOrDelegate; MemberFunctionAttribute[] memberFunctionAttributes; Parameters parameters; @@ -1543,8 +1554,8 @@ class Formatter(Sink) } ignoreNewlines = true; - if (functionBody) - format(functionBody); + if (specifiedFunctionBody) + format(specifiedFunctionBody); else { format(identifier); @@ -1834,6 +1845,15 @@ class Formatter(Sink) } } + void format(const InContractExpression expression) + { + debug(verbose) writeln("InContractExpression"); + + put("in ("); + format(expression.assertArguments); + put(")"); + } + void format(const InExpression inExpression) { debug(verbose) writeln("InExpression"); @@ -1846,6 +1866,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"); @@ -1916,8 +1959,17 @@ 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_.assertArguments); + put(")"); + } } void format(const IsExpression isExpression) @@ -2058,6 +2110,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"); @@ -2249,6 +2313,18 @@ 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.assertArguments); + put(")"); + } + void format(const OutStatement stmnt) { debug(verbose) writeln("OutStatement"); @@ -2564,6 +2640,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 cf53055e..da6f5032 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; } @@ -1237,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 * @@ -3080,130 +3071,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 outStatements; - 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; - const size_t inTokenLocation = current.index; - advance(); - advance(); - if (InStatement s = parseContractExpression!InStatement()) - { - s.inTokenLocation = inTokenLocation; - inStatements.put(s); - } - 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; - 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); - } - else return null; - } - else - { - error("`(` expected"); - return null; - } - } - else break; - } - - ownArray(node.inStatements, inStatements); - ownArray(node.outStatements, outStatements); - - 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; } @@ -3246,6 +3134,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 * @@ -3326,10 +3242,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) @@ -3377,7 +3293,7 @@ class Parser mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); } else - mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); + mixin(parseNodeQ!(`node.specifiedFunctionBody`, `SpecifiedFunctionBody`)); return node; } @@ -3860,6 +3776,26 @@ class Parser return node; } + /** + * Parses an InContractExpression + * + * $(GRAMMAR $(RULEDEF inContractExpression): + * $(LITERAL 'in') $(LITERAL '$(LPAREN)') $(RULE assertArguments) $(LITERAL '$(RPAREN)') + * ;) + */ + InContractExpression parseInContractExpression() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + auto node = allocator.make!InContractExpression; + const i = expect(tok!"in"); + mixin(nullCheck!`i`); + node.inTokenLocation = i.index; + mixin(tokenCheck!"("); + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); + mixin(tokenCheck!")"); + return node; + } + /** * Parses an InExpression * @@ -3869,6 +3805,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!"!")) @@ -3881,16 +3818,56 @@ 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 * * $(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() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!InStatement; const i = expect(tok!"in"); mixin(nullCheck!`i`); @@ -3909,6 +3886,7 @@ class Parser */ Initializer parseInitializer() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!Initializer; if (currentIs(tok!"void") && peekIsOneOf(tok!",", tok!";")) advance(); @@ -3938,46 +3916,41 @@ 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() { + mixin(traceEnterAndExit!(__FUNCTION__)); + 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(tokenCheck!";"); - node.index = idx; - node.line = lne; - return node; - } - else return null; + mixin(parseNodeQ!(`node.assertArguments`, `AssertArguments`)); + mixin(tokenCheck!")"); } else return null; + return node; } /** @@ -4177,6 +4150,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 (moreTokens() && (currentIs(tok!"do") || current.text == "body")) + return null; + return node; + } + /** * Parses a MixinDeclaration * @@ -4550,16 +4553,39 @@ class Parser tok!"||")(); } + /** + * Parses an OutContractExpression + * + * $(GRAMMAR $(RULEDEF outContractExpression): + * $(LITERAL 'out') $(LITERAL '$(LPAREN)') $(LITERAL Identifier)? $(LITERAL ';') $(RULE assertArguments) $(LITERAL '$(RPAREN)') + * ;) + */ + OutContractExpression parseOutContractExpression() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + 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.assertArguments`, `AssertArguments`)); + 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() { + mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!OutStatement; const o = expect(tok!"out"); mixin(nullCheck!`o`); @@ -5201,6 +5227,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 (currentIs(tok!"do") + || (currentIs(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 * @@ -7999,54 +8067,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;