From 54b82c69fe02d5069aae902cac8144b89f76ecc5 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 23 Mar 2023 05:42:52 +0100 Subject: [PATCH 1/4] Flatten unary expressions Step 1/2 for #409 --- src/dparse/ast.d | 368 ++++++++++++++++++++++---- src/dparse/astprinter.d | 36 +-- src/dparse/formatter.d | 157 +++++++---- src/dparse/parser.d | 154 ++++++++--- test/ast_checks/assert_args.txt | 8 +- test/ast_checks/named_arguments.txt | 10 +- test/ast_checks/throw_expressions.txt | 10 +- test/ast_checks/while_condition.txt | 8 +- 8 files changed, 572 insertions(+), 179 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 90967c17..8f5a210a 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -22,6 +22,7 @@ import std.array; import std.string; private immutable uint[TypeInfo] typeMap; +private immutable uint[TypeInfo] unaryExpressionTypeMap; shared static this() { @@ -71,8 +72,47 @@ shared static this() typeMap[typeid(TraitsExpression)] = 44; typeMap[typeid(TypeidExpression)] = 45; typeMap[typeid(TypeofExpression)] = 46; - typeMap[typeid(UnaryExpression)] = 47; + typeMap[typeid(UnaryExpressionNode)] = 47; typeMap[typeid(XorExpression)] = 48; + typeMap[typeid(RefPrefixUnaryExpression)] = 49; + typeMap[typeid(NotPrefixUnaryExpression)] = 50; + typeMap[typeid(DerefPrefixUnaryExpression)] = 51; + typeMap[typeid(PlusPrefixUnaryExpression)] = 52; + typeMap[typeid(MinusPrefixUnaryExpression)] = 53; + typeMap[typeid(TildePrefixUnaryExpression)] = 54; + typeMap[typeid(PlusPlusPrefixUnaryExpression)] = 55; + typeMap[typeid(MinusMinusPrefixUnaryExpression)] = 56; + typeMap[typeid(PlusPlusPostfixUnaryExpression)] = 57; + typeMap[typeid(MinusMinusPostfixUnaryExpression)] = 58; + typeMap[typeid(UnaryDotIdentifierExpression)] = 59; + typeMap[typeid(UnaryDotNewExpression)] = 60; + typeMap[typeid(TypeDotIdentifierExpression)] = 61; + typeMap[typeid(CastExpression)] = 62; + typeMap[typeid(ThrowExpression)] = 63; + typeMap[typeid(DummyUnaryExpression)] = 64; + + unaryExpressionTypeMap[typeid(RefPrefixUnaryExpression)] = 1; + unaryExpressionTypeMap[typeid(NotPrefixUnaryExpression)] = 2; + unaryExpressionTypeMap[typeid(DerefPrefixUnaryExpression)] = 3; + unaryExpressionTypeMap[typeid(PlusPrefixUnaryExpression)] = 4; + unaryExpressionTypeMap[typeid(MinusPrefixUnaryExpression)] = 5; + unaryExpressionTypeMap[typeid(TildePrefixUnaryExpression)] = 6; + unaryExpressionTypeMap[typeid(PlusPlusPrefixUnaryExpression)] = 7; + unaryExpressionTypeMap[typeid(MinusMinusPrefixUnaryExpression)] = 8; + unaryExpressionTypeMap[typeid(PlusPlusPostfixUnaryExpression)] = 9; + unaryExpressionTypeMap[typeid(MinusMinusPostfixUnaryExpression)] = 10; + unaryExpressionTypeMap[typeid(UnaryDotIdentifierExpression)] = 12; + unaryExpressionTypeMap[typeid(UnaryDotNewExpression)] = 13; + unaryExpressionTypeMap[typeid(TypeDotIdentifierExpression)] = 14; + unaryExpressionTypeMap[typeid(AssertExpression)] = 15; + unaryExpressionTypeMap[typeid(CastExpression)] = 16; + unaryExpressionTypeMap[typeid(DeleteExpression)] = 17; + unaryExpressionTypeMap[typeid(FunctionCallExpression)] = 18; + unaryExpressionTypeMap[typeid(IndexExpression)] = 19; + unaryExpressionTypeMap[typeid(NewExpression)] = 20; + unaryExpressionTypeMap[typeid(PrimaryExpression)] = 21; + unaryExpressionTypeMap[typeid(ThrowExpression)] = 22; + unaryExpressionTypeMap[typeid(DummyUnaryExpression)] = 23; } /// Describes which syntax was used in a list of declarations in the containing AST node @@ -165,12 +205,66 @@ abstract class ASTVisitor case 44: visit(cast(TraitsExpression) n); break; case 45: visit(cast(TypeidExpression) n); break; case 46: visit(cast(TypeofExpression) n); break; - case 47: visit(cast(UnaryExpression) n); break; + case 47: dynamicDispatch(cast(UnaryExpressionNode) n); break; case 48: visit(cast(XorExpression) n); break; - default: assert(false, __MODULE__ ~ " has a bug"); + case 49: visit(cast(RefPrefixUnaryExpression) n); break; + case 50: visit(cast(NotPrefixUnaryExpression) n); break; + case 51: visit(cast(DerefPrefixUnaryExpression) n); break; + case 52: visit(cast(PlusPrefixUnaryExpression) n); break; + case 53: visit(cast(MinusPrefixUnaryExpression) n); break; + case 54: visit(cast(TildePrefixUnaryExpression) n); break; + case 55: visit(cast(PlusPlusPrefixUnaryExpression) n); break; + case 56: visit(cast(MinusMinusPrefixUnaryExpression) n); break; + case 57: visit(cast(PlusPlusPostfixUnaryExpression) n); break; + case 58: visit(cast(MinusMinusPostfixUnaryExpression) n); break; + case 59: visit(cast(UnaryDotIdentifierExpression) n); break; + case 60: visit(cast(UnaryDotNewExpression) n); break; + case 61: visit(cast(TypeDotIdentifierExpression) n); break; + case 62: visit(cast(CastExpression) n); break; + case 63: visit(cast(ThrowExpression) n); break; + case 64: visit(cast(DummyUnaryExpression) n); break; + default: assert(false, __MODULE__ ~ " has a bug: " ~ typeid(n).toString); } } + /// ditto + void dynamicDispatch(const UnaryExpressionNode n) + { + switch (unaryExpressionTypeMap.get(typeid(n), 0)) + { + case 1: visit(cast(RefPrefixUnaryExpression) n); break; + case 2: visit(cast(NotPrefixUnaryExpression) n); break; + case 3: visit(cast(DerefPrefixUnaryExpression) n); break; + case 4: visit(cast(PlusPrefixUnaryExpression) n); break; + case 5: visit(cast(MinusPrefixUnaryExpression) n); break; + case 6: visit(cast(TildePrefixUnaryExpression) n); break; + case 7: visit(cast(PlusPlusPrefixUnaryExpression) n); break; + case 8: visit(cast(MinusMinusPrefixUnaryExpression) n); break; + case 9: visit(cast(PlusPlusPostfixUnaryExpression) n); break; + case 10: visit(cast(MinusMinusPostfixUnaryExpression) n); break; + case 12: visit(cast(UnaryDotIdentifierExpression) n); break; + case 13: visit(cast(UnaryDotNewExpression) n); break; + case 14: visit(cast(TypeDotIdentifierExpression) n); break; + case 15: visit(cast(AssertExpression) n); break; + case 16: visit(cast(CastExpression) n); break; + case 17: visit(cast(DeleteExpression) n); break; + case 18: visit(cast(FunctionCallExpression) n); break; + case 19: visit(cast(IndexExpression) n); break; + case 20: visit(cast(NewExpression) n); break; + case 21: visit(cast(PrimaryExpression) n); break; + case 22: visit(cast(ThrowExpression) n); break; + case 23: visit(cast(DummyUnaryExpression) n); break; + default: assert(false, __MODULE__ ~ " has a bug: " ~ typeid(n).toString); + } + } + + /// ditto + void dynamicDispatch(const TokenUnaryExpression n) + { + // unary expression handles all cases + dynamicDispatch(cast(UnaryExpressionNode) n); + } + /** */ void visit(const AddExpression addExpression) { addExpression.accept(this); } /** */ void visit(const AliasDeclaration aliasDeclaration) { aliasDeclaration.accept(this); } /** */ void visit(const AliasAssign aliasAssign) { aliasAssign.accept(this); } @@ -383,7 +477,20 @@ abstract class ASTVisitor /** */ void visit(const TypeSuffix typeSuffix) { typeSuffix.accept(this); } /** */ void visit(const TypeidExpression typeidExpression) { typeidExpression.accept(this); } /** */ void visit(const TypeofExpression typeofExpression) { typeofExpression.accept(this); } - /** */ void visit(const UnaryExpression unaryExpression) { unaryExpression.accept(this); } + /** */ void visit(const RefPrefixUnaryExpression refPrefixUnaryExpression) { refPrefixUnaryExpression.accept(this); } + /** */ void visit(const NotPrefixUnaryExpression notPrefixUnaryExpression) { notPrefixUnaryExpression.accept(this); } + /** */ void visit(const DerefPrefixUnaryExpression derefPrefixUnaryExpression) { derefPrefixUnaryExpression.accept(this); } + /** */ void visit(const PlusPrefixUnaryExpression plusPrefixUnaryExpression) { plusPrefixUnaryExpression.accept(this); } + /** */ void visit(const MinusPrefixUnaryExpression minusPrefixUnaryExpression) { minusPrefixUnaryExpression.accept(this); } + /** */ void visit(const TildePrefixUnaryExpression tildePrefixUnaryExpression) { tildePrefixUnaryExpression.accept(this); } + /** */ void visit(const PlusPlusPrefixUnaryExpression plusPlusPrefixUnaryExpression) { plusPlusPrefixUnaryExpression.accept(this); } + /** */ void visit(const MinusMinusPrefixUnaryExpression minusMinusPrefixUnaryExpression) { minusMinusPrefixUnaryExpression.accept(this); } + /** */ void visit(const PlusPlusPostfixUnaryExpression plusPlusPostfixUnaryExpression) { plusPlusPostfixUnaryExpression.accept(this); } + /** */ void visit(const MinusMinusPostfixUnaryExpression minusMinusPostfixUnaryExpression) { minusMinusPostfixUnaryExpression.accept(this); } + /** */ void visit(const UnaryDotIdentifierExpression unaryDotIdentifierExpression) { unaryDotIdentifierExpression.accept(this); } + /** */ void visit(const UnaryDotNewExpression unaryDotNewExpression) { unaryDotNewExpression.accept(this); } + /** */ void visit(const TypeDotIdentifierExpression typeDotIdentifierExpression) { typeDotIdentifierExpression.accept(this); } + /** */ void visit(const DummyUnaryExpression dummyUnaryExpression) { dummyUnaryExpression.accept(this); } /** */ void visit(const UnionDeclaration unionDeclaration) { unionDeclaration.accept(this); } /** */ void visit(const Unittest unittest_) { unittest_.accept(this); } /** */ void visit(const VariableDeclaration variableDeclaration) { variableDeclaration.accept(this); } @@ -955,7 +1062,7 @@ final class AssertArguments : BaseNode } /// -final class AssertExpression : ExpressionNode +final class AssertExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -1186,7 +1293,7 @@ final class CaseStatement: BaseNode } /// -final class CastExpression: BaseNode +final class CastExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -1194,7 +1301,7 @@ final class CastExpression: BaseNode } /** */ Type type; /** */ CastQualifier castQualifier; - /** */ UnaryExpression unaryExpression; + /** */ UnaryExpressionNode unaryExpression; mixin OpEquals; } @@ -1549,13 +1656,13 @@ final class DefaultStatement : BaseNode } /// -final class DeleteExpression : ExpressionNode +final class DeleteExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { mixin (visitIfNotNull!(unaryExpression)); } - /** */ UnaryExpression unaryExpression; + /** */ UnaryExpressionNode unaryExpression; /** */ size_t line; /** */ size_t column; mixin OpEquals; @@ -1864,14 +1971,14 @@ final class FunctionBody : BaseNode } /// -final class FunctionCallExpression : ExpressionNode +final class FunctionCallExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { mixin (visitIfNotNull!(type, unaryExpression, templateArguments, arguments)); } /** */ Type type; - /** */ UnaryExpression unaryExpression; + /** */ UnaryExpressionNode unaryExpression; /** */ TemplateArguments templateArguments; /** */ Arguments arguments; mixin OpEquals; @@ -2140,7 +2247,7 @@ final class IfCondition : BaseNode /** In an assignment-condition, this is the part after the equals sign. Otherwise this is any other expression that is evaluated to be a boolean. - (e.g. UnaryExpression, AndAndExpression, CmpExpression, etc.) + (e.g. UnaryExpressionNode, AndAndExpression, CmpExpression, etc.) */ Expression expression; mixin OpEquals; @@ -2208,13 +2315,13 @@ final class Index : BaseNode } /// -final class IndexExpression : ExpressionNode +final class IndexExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { mixin (visitIfNotNull!(unaryExpression, indexes)); } - /** */ UnaryExpression unaryExpression; + /** */ UnaryExpressionNode unaryExpression; /** */ Index[] indexes; mixin OpEquals; } @@ -2533,7 +2640,7 @@ final class NamespaceList : BaseNode mixin (visitIfNotNull!(items)); } mixin OpEquals; - /** */ TernaryExpression[] items; + /** */ ExpressionNode[] items; } /// @@ -2552,7 +2659,7 @@ final class NewAnonClassExpression : ExpressionNode } /// -final class NewExpression : ExpressionNode +final class NewExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -2790,7 +2897,7 @@ final class PragmaStatement : BaseNode } /// -final class PrimaryExpression : ExpressionNode +final class PrimaryExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -3427,7 +3534,7 @@ deprecated("Replaced by ExpressionStatement + ThrowExpression") alias ThrowStatement = ThrowExpression; /// -final class ThrowExpression: ExpressionNode +final class ThrowExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -3555,31 +3662,194 @@ final class TypeofExpression : ExpressionNode } /// -final class UnaryExpression : ExpressionNode +abstract class UnaryExpressionNode : ExpressionNode +{ +} + +/// +final class DummyUnaryExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { - // TODO prefix, postfix, unary - mixin (visitIfNotNull!(primaryExpression, newExpression, deleteExpression, - castExpression, functionCallExpression, unaryExpression, - type, identifierOrTemplateInstance, assertExpression, throwExpression, - indexExpression)); } - /** */ Type type; - /** */ PrimaryExpression primaryExpression; - /** */ Token prefix; - /** */ Token suffix; - /** */ UnaryExpression unaryExpression; - /** */ NewExpression newExpression; - /** */ DeleteExpression deleteExpression; - /** */ CastExpression castExpression; - /** */ FunctionCallExpression functionCallExpression; - /** */ IdentifierOrTemplateInstance identifierOrTemplateInstance; - /** */ AssertExpression assertExpression; - /** */ ThrowExpression throwExpression; - /** */ IndexExpression indexExpression; - /** */ size_t dotLocation; + // empty, only used as compatibility for now, may be removed in the future. +} + +/// +abstract class TokenUnaryExpression : UnaryExpressionNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(unaryExpression)); + } + + /// Returns the operator token (including source index) before the unary + /// expression or Token.init if constructed manually. Use `tokenType` to + /// always get a valid `IdType`. + final Token token() const @property @safe nothrow pure @nogc + { + return tokens[0]; + } + + abstract IdType tokenType() const @property @safe nothrow pure @nogc; + + /// The unary expression that is affected + UnaryExpressionNode unaryExpression; +} + +/// `&unaryExpression` +final class RefPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"&"; + } + + mixin OpEquals; +} + +/// `!unaryExpression` +final class NotPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"!"; + } + + mixin OpEquals; +} + +/// `*unaryExpression` +final class DerefPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"*"; + } + + mixin OpEquals; +} + +/// `+unaryExpression` +final class PlusPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"+"; + } + + mixin OpEquals; +} + +/// `-unaryExpression` +final class MinusPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"-"; + } + + mixin OpEquals; +} + +/// `~unaryExpression` +final class TildePrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"~"; + } + + mixin OpEquals; +} + +/// `++unaryExpression` +final class PlusPlusPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"++"; + } + + mixin OpEquals; +} + +/// `--unaryExpression` +final class MinusMinusPrefixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"--"; + } + + mixin OpEquals; +} + +/// `unaryExpression++` +final class PlusPlusPostfixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"++"; + } + + mixin OpEquals; +} + +/// `unaryExpression--` +final class MinusMinusPostfixUnaryExpression : TokenUnaryExpression +{ + override IdType tokenType() const @property @safe nothrow pure @nogc + { + return tok!"--"; + } + + mixin OpEquals; +} + +/// `unaryExpression.identifierOrTemplateInstance` +final class UnaryDotIdentifierExpression : UnaryExpressionNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(unaryExpression, identifierOrTemplateInstance)); + } + + /** lhs */ UnaryExpressionNode unaryExpression; + /** dot */ size_t dotLocation; + /** rhs */ IdentifierOrTemplateInstance identifierOrTemplateInstance; + + mixin OpEquals; +} + +/// `unaryExpression.new(...)` +final class UnaryDotNewExpression : UnaryExpressionNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(unaryExpression, newExpression)); + } + + /** lhs */ UnaryExpressionNode unaryExpression; + /** dot */ size_t dotLocation; + /** rhs */ NewExpression newExpression; + + mixin OpEquals; +} + +/// `(Type).identifier` +final class TypeDotIdentifierExpression : UnaryExpressionNode +{ + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(type, identifierOrTemplateInstance)); + } + + /** lhs */ Type type; + /** dot */ size_t dotLocation; + /** rhs */ IdentifierOrTemplateInstance identifierOrTemplateInstance; + mixin OpEquals; } @@ -3978,8 +4248,8 @@ unittest // issue #398: Support extern(C++, ) assert(!namespaces); foreach (const entry; list.items) { - const prim = cast(PrimaryExpression) entry.expression; - assert(prim); + const prim = cast(PrimaryExpression) entry; + assert(prim, (entry ? typeid(entry).toString : "null") ~ " is not PrimaryExpression!"); namespaces ~= prim; } } @@ -4120,9 +4390,9 @@ unittest // Support GCC-sytle asm statements assert(constraint.type == tok!"stringLiteral"); assert(constraint.text == `"=r"`); - auto una = cast(UnaryExpression) expression; - assert(una); - assert(una.primaryExpression.identifierOrTemplateInstance.identifier.text == "var1"); + auto primary = cast(PrimaryExpression) expression; + assert(primary); + assert(primary.identifierOrTemplateInstance.identifier.text == "var1"); } } } @@ -4145,9 +4415,9 @@ unittest // Support GCC-sytle asm statements assert(constraint.type == tok!"stringLiteral"); assert(constraint.text == `"=w"`); - auto una = cast(UnaryExpression) expression; - assert(una); - assert(una.primaryExpression.identifierOrTemplateInstance.identifier.text == "var2"); + auto primary = cast(PrimaryExpression) expression; + assert(primary); + assert(primary.identifierOrTemplateInstance.identifier.text == "var2"); } with (inputOperands.items[1]) @@ -4155,9 +4425,9 @@ unittest // Support GCC-sytle asm statements assert(constraint.type == tok!"stringLiteral"); assert(constraint.text == `"g"`); - auto una = cast(UnaryExpression) expression; - assert(una); - assert(una.primaryExpression.identifierOrTemplateInstance.identifier.text == "var3"); + auto primary = cast(PrimaryExpression) expression; + assert(primary); + assert(primary.identifierOrTemplateInstance.identifier.text == "var3"); } } } diff --git a/src/dparse/astprinter.d b/src/dparse/astprinter.d index ba17f6d6..f9e1a783 100644 --- a/src/dparse/astprinter.d +++ b/src/dparse/astprinter.d @@ -986,28 +986,6 @@ class XMLPrinter : ASTVisitor } } - override void visit(const UnaryExpression unaryExpression) - { - output.writeln(""); - if (unaryExpression.prefix != tok!"") - { - output.writeln("", xmlEscape(str(unaryExpression.prefix.type)), ""); - unaryExpression.unaryExpression.accept(this); - } - else - { - if (unaryExpression.suffix != tok!"") - { - assert(unaryExpression.suffix.text == ""); - unaryExpression.unaryExpression.accept(this); - output.writeln("", str(unaryExpression.suffix.type), ""); - } - else - unaryExpression.accept(this); - } - output.writeln(""); - } - override void visit(const UnionDeclaration unionDeclaration) { output.writeln(""); @@ -1208,6 +1186,20 @@ class XMLPrinter : ASTVisitor override void visit(const WhileStatement whileStatement) { mixin (tagAndAccept!"whileStatement"); } override void visit(const WithStatement withStatement) { mixin (tagAndAccept!"withStatement"); } override void visit(const TypeidExpression typeidExpression) { mixin (tagAndAccept!"typeidExpression"); } + // unary expressions + override void visit(const RefPrefixUnaryExpression refPrefixUnaryExpression) { mixin (tagAndAccept!"refPrefixUnaryExpression"); } + override void visit(const NotPrefixUnaryExpression notPrefixUnaryExpression) { mixin (tagAndAccept!"notPrefixUnaryExpression"); } + override void visit(const DerefPrefixUnaryExpression derefPrefixUnaryExpression) { mixin (tagAndAccept!"derefPrefixUnaryExpression"); } + override void visit(const PlusPrefixUnaryExpression plusPrefixUnaryExpression) { mixin (tagAndAccept!"plusPrefixUnaryExpression"); } + override void visit(const MinusPrefixUnaryExpression minusPrefixUnaryExpression) { mixin (tagAndAccept!"minusPrefixUnaryExpression"); } + override void visit(const TildePrefixUnaryExpression tildePrefixUnaryExpression) { mixin (tagAndAccept!"tildePrefixUnaryExpression"); } + override void visit(const PlusPlusPrefixUnaryExpression plusPlusPrefixUnaryExpression) { mixin (tagAndAccept!"plusPlusPrefixUnaryExpression"); } + override void visit(const MinusMinusPrefixUnaryExpression minusMinusPrefixUnaryExpression) { mixin (tagAndAccept!"minusMinusPrefixUnaryExpression"); } + override void visit(const PlusPlusPostfixUnaryExpression plusPlusPostfixUnaryExpression) { mixin (tagAndAccept!"plusPlusPostfixUnaryExpression"); } + override void visit(const MinusMinusPostfixUnaryExpression minusMinusPostfixUnaryExpression) { mixin (tagAndAccept!"minusMinusPostfixUnaryExpression"); } + override void visit(const UnaryDotIdentifierExpression unaryDotIdentifierExpression) { mixin (tagAndAccept!"unaryDotIdentifierExpression"); } + override void visit(const UnaryDotNewExpression unaryDotNewExpression) { mixin (tagAndAccept!"unaryDotNewExpression"); } + override void visit(const TypeDotIdentifierExpression typeDotIdentifierExpression) { mixin (tagAndAccept!"typeDotIdentifierExpression"); } // dfmt on alias visit = ASTVisitor.visit; diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index a51e3eeb..4ce8dd9b 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -689,7 +689,7 @@ class Formatter(Sink) /** Type type; CastQualifier castQualifier; - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; **/ with(castExpression) @@ -1335,7 +1335,7 @@ class Formatter(Sink) else if (cast(TraitsExpression) n) format(cast(TraitsExpression) n); else if (cast(TypeidExpression) n) format(cast(TypeidExpression) n); else if (cast(TypeofExpression) n) format(cast(TypeofExpression) n); - else if (cast(UnaryExpression) n) format(cast(UnaryExpression) n); + else if (cast(UnaryExpressionNode) n) format(cast(UnaryExpressionNode) n); else if (cast(XorExpression) n) format(cast(XorExpression) n); } @@ -1507,7 +1507,7 @@ class Formatter(Sink) /** Type type; - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; TemplateArguments templateArguments; Arguments arguments; **/ @@ -1891,7 +1891,7 @@ class Formatter(Sink) debug(verbose) writeln("IndexExpression"); /** - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; ArgumentList argumentList; **/ @@ -3611,59 +3611,115 @@ class Formatter(Sink) put(")"); } - void format(const UnaryExpression unary) + void format(const UnaryExpressionNode unary) + { + debug(verbose) writeln("UnaryExpressionNode("); + + if (auto p = cast(RefPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(NotPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(DerefPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(PlusPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(MinusPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(TildePrefixUnaryExpression) unary) format(p); + else if (auto p = cast(PlusPlusPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(MinusMinusPrefixUnaryExpression) unary) format(p); + else if (auto p = cast(PlusPlusPostfixUnaryExpression) unary) format(p); + else if (auto p = cast(MinusMinusPostfixUnaryExpression) unary) format(p); + else if (auto p = cast(UnaryDotIdentifierExpression) unary) format(p); + else if (auto p = cast(UnaryDotNewExpression) unary) format(p); + else if (auto p = cast(TypeDotIdentifierExpression) unary) format(p); + else if (auto p = cast(AssertExpression) unary) format(p); + else if (auto p = cast(CastExpression) unary) format(p); + else if (auto p = cast(DeleteExpression) unary) format(p); + else if (auto p = cast(FunctionCallExpression) unary) format(p); + else if (auto p = cast(IndexExpression) unary) format(p); + else if (auto p = cast(NewExpression) unary) format(p); + else if (auto p = cast(PrimaryExpression) unary) format(p); + else if (auto p = cast(ThrowExpression) unary) format(p); + + debug(verbose) writeln(")"); + } + + void format(const RefPrefixUnaryExpression unary) { - debug(verbose) writeln("UnaryExpression("); + put("&"); + format(unary.unaryExpression); + } - /** - Type type; - PrimaryExpression primaryExpression; - Token prefix; - Token suffix; - UnaryExpression unaryExpression; - NewExpression newExpression; - DeleteExpression deleteExpression; - CastExpression castExpression; - FunctionCallExpression functionCallExpression; - ArgumentList argumentList; - IdentifierOrTemplateInstance identifierOrTemplateInstance; - AssertExpression assertExpression; - SliceExpression sliceExpression; - IndexExpression indexExpression; - **/ + void format(const NotPrefixUnaryExpression unary) + { + put("!"); + format(unary.unaryExpression); + } - with(unary) - { - if (prefix != tok!"") format(prefix); + void format(const DerefPrefixUnaryExpression unary) + { + put("*"); + format(unary.unaryExpression); + } - if (type && identifierOrTemplateInstance) - { - // handle things like (void*).sizeof - put("("); - format(type); - put(")"); - } + void format(const PlusPrefixUnaryExpression unary) + { + put("+"); + format(unary.unaryExpression); + } - if (primaryExpression) format(primaryExpression); - if (newExpression) format(newExpression); - if (deleteExpression) format(deleteExpression); - if (castExpression) format(castExpression); - if (functionCallExpression) format(functionCallExpression); - if (assertExpression) format(assertExpression); - if (throwExpression) format(throwExpression); - if (indexExpression) format(indexExpression); + void format(const MinusPrefixUnaryExpression unary) + { + put("-"); + format(unary.unaryExpression); + } - if (unaryExpression) format(unaryExpression); - if (suffix != tok!"") format(suffix); + void format(const TildePrefixUnaryExpression unary) + { + put("~"); + format(unary.unaryExpression); + } - if (identifierOrTemplateInstance) - { - put("."); - format(identifierOrTemplateInstance); - } - } + void format(const PlusPlusPrefixUnaryExpression unary) + { + put("++"); + format(unary.unaryExpression); + } - debug(verbose) writeln(")"); + void format(const MinusMinusPrefixUnaryExpression unary) + { + put("--"); + format(unary.unaryExpression); + } + + void format(const PlusPlusPostfixUnaryExpression unary) + { + format(unary.unaryExpression); + put("++"); + } + + void format(const MinusMinusPostfixUnaryExpression unary) + { + format(unary.unaryExpression); + put("--"); + } + + void format(const UnaryDotIdentifierExpression unary) + { + format(unary.unaryExpression); + put("."); + format(unary.identifierOrTemplateInstance); + } + + void format(const UnaryDotNewExpression unary) + { + format(unary.unaryExpression); + put("."); + format(unary.newExpression); + } + + void format(const TypeDotIdentifierExpression unary) + { + put("("); + format(unary.type); + put(")."); + format(unary.identifierOrTemplateInstance); } void format(const UnionDeclaration decl, const Attribute[] attrs = null) @@ -4183,6 +4239,9 @@ unittest testFormatNode!(VariableDeclaration)(`T!(0)[] t;`); testFormatNode!(VariableDeclaration)(`T!(0)[dim] t;`); testFormatNode!(VariableDeclaration)(`const shared t = [0, 1];`); + testFormatNode!(VariableDeclaration)(`auto x = foo();`); + testFormatNode!(VariableDeclaration)(`auto x = foo("bar");`); + testFormatNode!(VariableDeclaration)(`auto x = foo(baz: "bar");`); testFormatNode!(OutStatement)( ` diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 533e4468..c90c0580 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -1659,7 +1659,7 @@ class Parser mixin(parseNodeQ!(`node.type`, `Type`)); } mixin(tokenCheck!")"); - mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); + mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpressionNode`)); node.tokens = tokens[startIndex .. index]; return node; } @@ -2771,7 +2771,7 @@ class Parser node.line = current.line; node.column = current.column; mixin(tokenCheck!"delete"); - mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); + mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpressionNode`)); node.tokens = tokens[startIndex .. index]; return node; } @@ -3555,7 +3555,13 @@ class Parser * | $(RULE type) $(RULE arguments) * ;) */ - FunctionCallExpression parseFunctionCallExpression(UnaryExpression unary = null) + FunctionCallExpression parseFunctionCallExpression() + { + return parseFunctionCallExpression(null, false); + } + + /// ditto + FunctionCallExpression parseFunctionCallExpression(UnaryExpressionNode unary, bool fromUnary = true) { mixin(traceEnterAndExit!(__FUNCTION__)); auto startIndex = index; @@ -3573,13 +3579,13 @@ class Parser mixin(parseNodeQ!(`node.arguments`, `Arguments`)); break; default: - if (unary !is null) + if (fromUnary) node.unaryExpression = unary; else - mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); + mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpressionNode`)); if (currentIs(tok!"!")) mixin(parseNodeQ!(`node.templateArguments`, `TemplateArguments`)); - if (unary !is null) + if (fromUnary) mixin(parseNodeQ!(`node.arguments`, `Arguments`)); } node.tokens = tokens[startIndex .. index]; @@ -4413,12 +4419,18 @@ class Parser * ; * ) */ - IndexExpression parseIndexExpression(UnaryExpression unaryExpression = null) + IndexExpression parseIndexExpression() + { + return parseIndexExpression(null, false); + } + + /// ditto + IndexExpression parseIndexExpression(UnaryExpressionNode unaryExpression, bool fromUnary = true) { mixin(traceEnterAndExit!(__FUNCTION__)); auto startIndex = index; auto node = allocator.make!IndexExpression; - mixin(nullCheck!`node.unaryExpression = unaryExpression is null ? parseUnaryExpression() : unaryExpression`); + mixin(nullCheck!`node.unaryExpression = fromUnary ? unaryExpression : parseUnaryExpressionNode()`); mixin(tokenCheck!"["); StackBuffer indexes; while (true) @@ -5636,7 +5648,7 @@ class Parser { pragma(inline, true); mixin (traceEnterAndExit!(__FUNCTION__)); - return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpression, + return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpressionNode, tok!"^^")(); } @@ -7777,7 +7789,7 @@ class Parser } /** - * Parses a UnaryExpression + * Parses a UnaryExpression (flattened from parsed child) * * $(GRAMMAR $(RULEDEF unaryExpression): * $(RULE primaryExpression) @@ -7803,13 +7815,13 @@ class Parser * | $(RULE unaryExpression) $(LITERAL '++') * ;) */ - UnaryExpression parseUnaryExpression() + UnaryExpressionNode parseUnaryExpressionNode() { mixin(traceEnterAndExit!(__FUNCTION__)); auto startIndex = index; if (!moreTokens()) return null; - auto node = allocator.make!UnaryExpression; + UnaryExpressionNode node; switch (current.type) { case tok!"const": @@ -7832,33 +7844,70 @@ class Parser case tok!"scope": case tok!"pure": case tok!"nothrow": - mixin(parseNodeQ!(`node.functionCallExpression`, `FunctionCallExpression`)); + mixin(parseNodeQ!(`node`, `FunctionCallExpression`)); break; case tok!"&": + advance(); + auto n = allocator.make!RefPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"!": + advance(); + auto n = allocator.make!NotPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"*": + advance(); + auto n = allocator.make!DerefPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"+": + advance(); + auto n = allocator.make!PlusPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"-": + advance(); + auto n = allocator.make!MinusPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"~": + advance(); + auto n = allocator.make!TildePrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"++": + advance(); + auto n = allocator.make!PlusPlusPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; + break; case tok!"--": - node.prefix = advance(); - mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); + advance(); + auto n = allocator.make!MinusMinusPrefixUnaryExpression; + mixin(parseNodeQ!(`n.unaryExpression`, `UnaryExpressionNode`)); + node = n; break; case tok!"new": - mixin(parseNodeQ!(`node.newExpression`, `NewExpression`)); + mixin(parseNodeQ!(`node`, `NewExpression`)); break; case tok!"delete": - mixin(parseNodeQ!(`node.deleteExpression`, `DeleteExpression`)); + mixin(parseNodeQ!(`node`, `DeleteExpression`)); break; case tok!"cast": - mixin(parseNodeQ!(`node.castExpression`, `CastExpression`)); + mixin(parseNodeQ!(`node`, `CastExpression`)); break; case tok!"assert": - mixin(parseNodeQ!(`node.assertExpression`, `AssertExpression`)); + mixin(parseNodeQ!(`node`, `AssertExpression`)); break; case tok!"throw": - mixin(parseNodeQ!(`node.throwExpression`, `ThrowExpression`)); + mixin(parseNodeQ!(`node`, `ThrowExpression`)); break; case tok!"(": // handle (type).identifier @@ -7877,10 +7926,13 @@ class Parser goto default; } abandonBookmark(b2); - node.type = t; + auto n = allocator.make!TypeDotIdentifierExpression; + n.type = t; advance(); // ) + n.dotLocation = current.index; advance(); // . - mixin(parseNodeQ!(`node.identifierOrTemplateInstance`, `IdentifierOrTemplateInstance`)); + mixin(parseNodeQ!(`n.identifierOrTemplateInstance`, `IdentifierOrTemplateInstance`)); + node = n; break; } else @@ -7890,7 +7942,7 @@ class Parser goto default; } default: - mixin(parseNodeQ!(`node.primaryExpression`, `PrimaryExpression`)); + mixin(parseNodeQ!(`node`, `PrimaryExpression`)); break; } @@ -7912,46 +7964,60 @@ class Parser else break loop; case tok!"(": - auto newUnary = allocator.make!UnaryExpression(); // Allows DCD to get the call tips // see https://github.com/dlang-community/DCD/issues/405 if (peekIs(tok!"}")) { error("Error, expected parameters or `)`", false); advance(); - if (newUnary) newUnary.tokens = tokens[startIndex .. index]; - return newUnary; + node = allocator.make!DummyUnaryExpression; + node.tokens = tokens[startIndex .. index]; + return node; } - mixin (nullCheck!`newUnary.functionCallExpression = parseFunctionCallExpression(node)`); - node = newUnary; + mixin (nullCheck!`node = parseFunctionCallExpression(node)`); break; case tok!"++": + advance(); + auto n = allocator.make!PlusPlusPostfixUnaryExpression; + n.unaryExpression = node; + node = n; + break; case tok!"--": - auto n = allocator.make!UnaryExpression(); + advance(); + auto n = allocator.make!MinusMinusPostfixUnaryExpression; n.unaryExpression = node; - n.suffix = advance(); node = n; break; case tok!"[": - auto n = allocator.make!UnaryExpression; - n.indexExpression = parseIndexExpression(node); - node = n; + node = parseIndexExpression(node); break; case tok!".": - node.dotLocation = current.index; - advance(); - auto n = allocator.make!UnaryExpression(); - n.unaryExpression = node; - if (currentIs(tok!"new")) - mixin(parseNodeQ!(`node.newExpression`, `NewExpression`)); + if (peekIs(tok!"new")) + { + auto n = allocator.make!UnaryDotNewExpression(); + n.dotLocation = current.index; + advance(); + n.unaryExpression = node; + mixin(parseNodeQ!(`n.newExpression`, `NewExpression`)); + node = n; + } else + { + auto n = allocator.make!UnaryDotIdentifierExpression(); + n.dotLocation = current.index; + advance(); + n.unaryExpression = node; n.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance(); - node = n; + node = n; + } break; default: break loop; } - node.tokens = tokens[startIndex .. index]; + if (node) + node.tokens = tokens[startIndex .. index]; + else + error("Expected UnaryExpression", false); return node; } @@ -8735,6 +8801,12 @@ protected: final: node.line = current.line; node.column = current.column; } + static assert(is(immutable typeof(node.items[0]) == immutable typeof(mixin("parse" ~ ItemType.stringof ~ "()"))), + "cannot use parseCommaSeparatedRule on " ~ ListType.stringof + ~ " with function parse" ~ ItemType.stringof ~ ", since it expects " + ~ "items of type " ~ typeof(node.items[0]).stringof + ~ ", but the parse function returns " + ~ typeof(mixin("parse" ~ ItemType.stringof ~ "()")).stringof); StackBuffer items; while (moreTokens()) { diff --git a/test/ast_checks/assert_args.txt b/test/ast_checks/assert_args.txt index 22e08b9c..37c85f4b 100644 --- a/test/ast_checks/assert_args.txt +++ b/test/ast_checks/assert_args.txt @@ -1,4 +1,4 @@ -./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[1]//identifierOrTemplateInstance/identifier[text()="foo"] -./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[2]/primaryExpression/stringLiteral[text()='"a"'] -./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[3]//identifierOrTemplateInstance/identifier[text()="b"] -./module/declaration/staticAssertDeclaration//assertArguments/unaryExpression[4]/primaryExpression/stringLiteral[text()='"c"'] +./module/declaration/staticAssertDeclaration//assertArguments/primaryExpression[1]/identifierOrTemplateInstance/identifier[text()="foo"] +./module/declaration/staticAssertDeclaration//assertArguments/primaryExpression[2]/stringLiteral[text()='"a"'] +./module/declaration/staticAssertDeclaration//assertArguments/primaryExpression[3]/identifierOrTemplateInstance/identifier[text()="b"] +./module/declaration/staticAssertDeclaration//assertArguments/primaryExpression[4]/stringLiteral[text()='"c"'] diff --git a/test/ast_checks/named_arguments.txt b/test/ast_checks/named_arguments.txt index a7006618..555e4d88 100644 --- a/test/ast_checks/named_arguments.txt +++ b/test/ast_checks/named_arguments.txt @@ -1,5 +1,5 @@ -//functionCallExpression[unaryExpression//identifier='b']//namedArgument[identifier='x'] -//functionCallExpression[unaryExpression//identifier='c']//namedArgument[identifier='x'] -//functionCallExpression[unaryExpression//identifier='c']//namedArgument[identifier='y'] -//functionCallExpression[unaryExpression//identifier='d']//namedTemplateArgument[identifier='a'] -//functionCallExpression[unaryExpression//identifier='d']//namedTemplateArgument[identifier='b'] +//functionCallExpression[primaryExpression//identifier='b']//namedArgument[identifier='x'] +//functionCallExpression[primaryExpression//identifier='c']//namedArgument[identifier='x'] +//functionCallExpression[primaryExpression//identifier='c']//namedArgument[identifier='y'] +//functionCallExpression[primaryExpression//identifier='d']//namedTemplateArgument[identifier='a'] +//functionCallExpression[primaryExpression//identifier='d']//namedTemplateArgument[identifier='b'] diff --git a/test/ast_checks/throw_expressions.txt b/test/ast_checks/throw_expressions.txt index 005c53bd..be9fed43 100644 --- a/test/ast_checks/throw_expressions.txt +++ b/test/ast_checks/throw_expressions.txt @@ -1,8 +1,8 @@ //functionDeclaration[name = 'main'] -//functionCallExpression/unaryExpression/primaryExpression/identifierOrTemplateInstance[identifier='foo'] -//functionCallExpression/arguments/namedArgumentList/namedArgument[1]/unaryExpression/throwExpression//*[identifier='someThrowable'] -//functionCallExpression/arguments/namedArgumentList/namedArgument[2]/unaryExpression/primaryExpression/*[identifier='bar'] +//functionCallExpression/primaryExpression/identifierOrTemplateInstance[identifier='foo'] +//functionCallExpression/arguments/namedArgumentList/namedArgument[1]/throwExpression//*[identifier='someThrowable'] +//functionCallExpression/arguments/namedArgumentList/namedArgument[2]/primaryExpression/*[identifier='bar'] //ternaryExpression/*[1]//*[identifier='foo'] //ternaryExpression/*[2]//*[identifier='bar'] -//ternaryExpression/*[3]/throwExpression/unaryExpression/newExpression/type[@pretty='Exception'] -//ternaryExpression/*[3]/throwExpression/unaryExpression/newExpression/arguments//stringLiteral +//ternaryExpression/*[3]/newExpression/type[@pretty='Exception'] +//ternaryExpression/*[3]/newExpression/arguments//stringLiteral diff --git a/test/ast_checks/while_condition.txt b/test/ast_checks/while_condition.txt index 4cb02888..1e1d310f 100644 --- a/test/ast_checks/while_condition.txt +++ b/test/ast_checks/while_condition.txt @@ -1,20 +1,20 @@ //functionDeclaration[name = 'a']//functionBody//whileStatement/condition/auto not(//functionDeclaration[name = 'a']//functionBody//whileStatement/condition/scope) //functionDeclaration[name = 'a']//functionBody//whileStatement/condition/identifier[text()='line'] -//functionDeclaration[name = 'a']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'a']//functionBody//whileStatement/condition/primaryExpression//identifier[text()='readln'] //functionDeclaration[name = 'a']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line'] //functionDeclaration[name = 'a']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip'] not(//functionDeclaration[name = 'b']//functionBody//whileStatement/condition/auto) //functionDeclaration[name = 'b']//functionBody//whileStatement/condition/scope //functionDeclaration[name = 'b']//functionBody//whileStatement/condition/identifier[text()='line'] -//functionDeclaration[name = 'b']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'b']//functionBody//whileStatement/condition/primaryExpression//identifier[text()='readln'] //functionDeclaration[name = 'b']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line'] //functionDeclaration[name = 'b']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip'] not(//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/auto) not(//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/scope) //functionDeclaration[name = 'c']//functionBody//whileStatement/condition/typeConstructor[text()='const'] //functionDeclaration[name = 'c']//functionBody//whileStatement/condition/identifier[text()='line'] -//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'c']//functionBody//whileStatement/condition/primaryExpression//identifier[text()='readln'] //functionDeclaration[name = 'c']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line'] //functionDeclaration[name = 'c']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip'] not(//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/auto) @@ -23,6 +23,6 @@ not(//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/sc //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/typeConstructor[text()='inout'] //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/type[@pretty='string'] //functionDeclaration[name = 'd']//functionBody//whileStatement/condition/identifier[text()='line'] -//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'd']//functionBody//whileStatement/condition/primaryExpression//identifier[text()='readln'] //functionDeclaration[name = 'd']//functionBody//whileStatement/declarationOrStatement//identifier[text()='line'] //functionDeclaration[name = 'd']//functionBody//whileStatement/declarationOrStatement//identifier[text()='strip'] From 54a6921caaa752155d9614ed7b95311756574f02 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Wed, 5 Apr 2023 11:10:48 +0200 Subject: [PATCH 2/4] Fix isAssociativeArrayLiteral for CI Just calling parseAssignExpression instead of parseExpression in AA checking now, since that's what's being done in the parsing code anyway! Doubled the debug stack limit. Should really investigate what's broken here, since this stack usage is way too much. --- src/dparse/parser.d | 2 +- test/tester.d | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index c90c0580..bfa70c2c 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -8401,7 +8401,7 @@ protected: final: immutable b = setBookmark(); scope(exit) goToBookmark(b); advance(); - immutable bool result = !currentIs(tok!"]") && parseExpression() !is null && currentIs(tok!":"); + immutable bool result = !currentIs(tok!"]") && parseAssignExpression() !is null && currentIs(tok!":"); cachedAAChecks[currentIndex] = result; return result; } diff --git a/test/tester.d b/test/tester.d index 99ff3f3a..23ced520 100644 --- a/test/tester.d +++ b/test/tester.d @@ -310,9 +310,9 @@ int main(string[] args) // increase stack size in case of segfault: // stack usage in debug / non-optimized mode is _much_ higher version (D_Coverage) - enum maxStackSize = 256 * 4096; + enum maxStackSize = 512 * 4096; else debug - enum maxStackSize = 256 * 4096; + enum maxStackSize = 512 * 4096; else enum maxStackSize = 40 * 4096; From c3bac5ba6928c88295ac049b3c6485b2cbe2894c Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Wed, 5 Apr 2023 11:36:31 +0200 Subject: [PATCH 3/4] adjust to review --- src/dparse/parser.d | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index bfa70c2c..c32fedea 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -12,6 +12,7 @@ import std.conv; import std.algorithm; import std.array; import std.string : format; +import std.typecons : Flag; // Uncomment this if you want ALL THE OUTPUT // Caution: generates 180 megabytes of logging for std.datetime @@ -118,6 +119,9 @@ Module parseModule(F)(const(Token)[] tokens, string fileName, RollbackAllocator* */ class Parser { + /// Flag type for some parsing arguments + alias FromUnary = Flag!"fromUnary"; + /** * Parses an AddExpression. * @@ -3557,11 +3561,11 @@ class Parser */ FunctionCallExpression parseFunctionCallExpression() { - return parseFunctionCallExpression(null, false); + return parseFunctionCallExpression(null, FromUnary.no); } /// ditto - FunctionCallExpression parseFunctionCallExpression(UnaryExpressionNode unary, bool fromUnary = true) + FunctionCallExpression parseFunctionCallExpression(UnaryExpressionNode unary, FromUnary fromUnary = FromUnary.yes) { mixin(traceEnterAndExit!(__FUNCTION__)); auto startIndex = index; From ded602558e76b9cd202ed532ed6b2401bc849756 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Fri, 7 Apr 2023 15:52:22 +0200 Subject: [PATCH 4/4] added missing tests --- test/ast_checks/unary_expressions.d | 18 ++++++++++++++++++ test/ast_checks/unary_expressions.txt | 21 +++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 test/ast_checks/unary_expressions.d create mode 100644 test/ast_checks/unary_expressions.txt diff --git a/test/ast_checks/unary_expressions.d b/test/ast_checks/unary_expressions.d new file mode 100644 index 00000000..11497ef6 --- /dev/null +++ b/test/ast_checks/unary_expressions.d @@ -0,0 +1,18 @@ +unittest { i++; } +unittest { ++i; } +unittest { i--; } +unittest { --i; } +unittest { i -= +j; } +unittest { i += -j; } +unittest { i -= ~j; } +unittest { i += !j; } +unittest { i -= *j; } +unittest { i += &j; } +unittest { i = cast(int)j; } +unittest { x = assert(0); } +unittest { x = throw y; } +unittest { x = delete f; } +unittest { x = new F(); } +unittest { + *&~(+1 | (int).init).new T(2); +} \ No newline at end of file diff --git a/test/ast_checks/unary_expressions.txt b/test/ast_checks/unary_expressions.txt new file mode 100644 index 00000000..046dd8ef --- /dev/null +++ b/test/ast_checks/unary_expressions.txt @@ -0,0 +1,21 @@ +/module/declaration[1]/unittest/blockStatement//expression/plusPlusPostfixUnaryExpression//identifier +/module/declaration[2]/unittest/blockStatement//expression/plusPlusPrefixUnaryExpression//identifier +/module/declaration[3]/unittest/blockStatement//expression/minusMinusPostfixUnaryExpression//identifier +/module/declaration[4]/unittest/blockStatement//expression/minusMinusPrefixUnaryExpression//identifier +/module/declaration[5]/unittest/blockStatement//expression/expression[@operator="-="]/plusPrefixUnaryExpression +/module/declaration[6]/unittest/blockStatement//expression/expression[@operator="+="]/minusPrefixUnaryExpression +/module/declaration[7]/unittest/blockStatement//expression/expression[@operator="-="]/tildePrefixUnaryExpression +/module/declaration[8]/unittest/blockStatement//expression/expression[@operator="+="]/notPrefixUnaryExpression +/module/declaration[9]/unittest/blockStatement//expression/expression[@operator="-="]/derefPrefixUnaryExpression +/module/declaration[10]/unittest/blockStatement//expression/expression[@operator="+="]/refPrefixUnaryExpression +/module/declaration[11]/unittest/blockStatement//expression/expression[@operator="="]/castExpression/type[@pretty="int"] +/module/declaration[11]/unittest/blockStatement//expression/expression[@operator="="]/castExpression/primaryExpression/identifierOrTemplateInstance/identifier[text()="j"] +/module/declaration[12]/unittest/blockStatement//expression/expression[@operator="="]/assertExpression/assertArguments/primaryExpression/intLiteral[text()="0"] +/module/declaration[13]/unittest/blockStatement//expression/expression[@operator="="]/throwExpression/primaryExpression/identifierOrTemplateInstance/identifier[text()="y"] +/module/declaration[14]/unittest/blockStatement//expression/expression[@operator="="]/deleteExpression/primaryExpression/identifierOrTemplateInstance/identifier[text()="f"] +/module/declaration[15]/unittest/blockStatement//expression/expression[@operator="="]/newExpression/type[@pretty="F"] +/module/declaration[16]/unittest/blockStatement//expression/derefPrefixUnaryExpression/refPrefixUnaryExpression/tildePrefixUnaryExpression/unaryDotNewExpression/primaryExpression/expression/orExpression/plusPrefixUnaryExpression +/module/declaration[16]/unittest/blockStatement//expression/derefPrefixUnaryExpression/refPrefixUnaryExpression/tildePrefixUnaryExpression/unaryDotNewExpression/primaryExpression/expression/orExpression/typeDotIdentifierExpression/type[@pretty="int"] +/module/declaration[16]/unittest/blockStatement//expression/derefPrefixUnaryExpression/refPrefixUnaryExpression/tildePrefixUnaryExpression/unaryDotNewExpression/primaryExpression/expression/orExpression/typeDotIdentifierExpression/identifierOrTemplateInstance/identifier[text()="init"] +/module/declaration[16]/unittest/blockStatement//expression/derefPrefixUnaryExpression/refPrefixUnaryExpression/tildePrefixUnaryExpression/unaryDotNewExpression/newExpression/type[@pretty="T"] +/module/declaration[16]/unittest/blockStatement//expression/derefPrefixUnaryExpression/refPrefixUnaryExpression/tildePrefixUnaryExpression/unaryDotNewExpression/newExpression/arguments//primaryExpression/intLiteral[text()="2"]