From 78b9ee490d1b328623d4e54722d8804ffd5149ab Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 23 Mar 2023 05:42:52 +0100 Subject: [PATCH] Flatten unary expressions Step 1/2 for #409 --- src/dparse/ast.d | 369 ++++++++++++++++++++++---- src/dparse/astprinter.d | 36 +-- src/dparse/formatter.d | 165 +++++++----- src/dparse/parser.d | 154 ++++++++--- test/ast_checks/assert_args.txt | 8 +- test/ast_checks/throw_expressions.txt | 10 +- test/ast_checks/while_condition.txt | 8 +- 7 files changed, 564 insertions(+), 186 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index a76fda8b..d9a69a27 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); } @@ -379,7 +473,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); } @@ -924,7 +1031,7 @@ final class AssertArguments : BaseNode } /// -final class AssertExpression : ExpressionNode +final class AssertExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -1121,7 +1228,7 @@ final class CaseStatement: BaseNode } /// -final class CastExpression: BaseNode +final class CastExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -1129,7 +1236,7 @@ final class CastExpression: BaseNode } /** */ Type type; /** */ CastQualifier castQualifier; - /** */ UnaryExpression unaryExpression; + /** */ UnaryExpressionNode unaryExpression; mixin OpEquals; } @@ -1484,13 +1591,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; @@ -1799,14 +1906,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; @@ -2075,7 +2182,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; @@ -2143,13 +2250,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; } @@ -2468,7 +2575,7 @@ final class NamespaceList : BaseNode mixin (visitIfNotNull!(items)); } mixin OpEquals; - /** */ TernaryExpression[] items; + /** */ ExpressionNode[] items; } /// @@ -2487,7 +2594,7 @@ final class NewAnonClassExpression : ExpressionNode } /// -final class NewExpression : ExpressionNode +final class NewExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -2725,7 +2832,7 @@ final class PragmaStatement : BaseNode } /// -final class PrimaryExpression : ExpressionNode +final class PrimaryExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -3338,7 +3445,7 @@ deprecated("Replaced by ExpressionStatement + ThrowExpression") alias ThrowStatement = ThrowExpression; /// -final class ThrowExpression: ExpressionNode +final class ThrowExpression : UnaryExpressionNode { override void accept(ASTVisitor visitor) const { @@ -3466,32 +3573,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, argumentList, unaryExpression, - type, identifierOrTemplateInstance, assertExpression, throwExpression, - indexExpression)); } - /** */ Type type; - /** */ PrimaryExpression primaryExpression; - /** */ Token prefix; - /** */ Token suffix; - /** */ UnaryExpression unaryExpression; - /** */ NewExpression newExpression; - /** */ DeleteExpression deleteExpression; - /** */ CastExpression castExpression; - /** */ FunctionCallExpression functionCallExpression; - /** */ ArgumentList argumentList; - /** */ 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; } @@ -3890,8 +4159,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; } } @@ -4032,9 +4301,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"); } } } @@ -4057,9 +4326,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]) @@ -4067,9 +4336,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 f0fa5793..9641ea56 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(""); @@ -1204,6 +1182,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 2b1fbde0..79cd1cfe 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -661,7 +661,7 @@ class Formatter(Sink) /** Type type; CastQualifier castQualifier; - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; **/ with(castExpression) @@ -1307,7 +1307,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); } @@ -1479,7 +1479,7 @@ class Formatter(Sink) /** Type type; - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; TemplateArguments templateArguments; Arguments arguments; **/ @@ -1863,7 +1863,7 @@ class Formatter(Sink) debug(verbose) writeln("IndexExpression"); /** - UnaryExpression unaryExpression; + UnaryExpressionNode unaryExpression; ArgumentList argumentList; **/ @@ -3555,70 +3555,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) - { - // handle things like (void*).sizeof - if (identifierOrTemplateInstance) - { - put("("); - format(type); - put(")"); - } - else - { - format(type); - put("("); - if (argumentList) - format(argumentList); - 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) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 0aee2ed3..1f3b6a87 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -1587,7 +1587,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; } @@ -2696,7 +2696,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; } @@ -3478,7 +3478,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; @@ -3496,13 +3502,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]; @@ -4335,12 +4341,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) @@ -5552,7 +5564,7 @@ class Parser ExpressionNode parsePowExpression() { mixin (traceEnterAndExit!(__FUNCTION__)); - return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpression, + return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpressionNode, tok!"^^")(); } @@ -7642,7 +7654,7 @@ class Parser } /** - * Parses a UnaryExpression + * Parses a UnaryExpression (flattened from parsed child) * * $(GRAMMAR $(RULEDEF unaryExpression): * $(RULE primaryExpression) @@ -7668,13 +7680,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": @@ -7697,33 +7709,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 @@ -7742,10 +7791,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 @@ -7755,7 +7807,7 @@ class Parser goto default; } default: - mixin(parseNodeQ!(`node.primaryExpression`, `PrimaryExpression`)); + mixin(parseNodeQ!(`node`, `PrimaryExpression`)); break; } @@ -7777,46 +7829,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; } @@ -8598,6 +8664,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/throw_expressions.txt b/test/ast_checks/throw_expressions.txt index 1acfe687..6f807fbe 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/argumentList/unaryExpression[1]/throwExpression//*[identifier='someThrowable'] -//functionCallExpression/arguments/argumentList/unaryExpression[2]/primaryExpression/*[identifier='bar'] +//functionCallExpression/primaryExpression/identifierOrTemplateInstance[identifier='foo'] +//functionCallExpression/arguments/argumentList/throwExpression//*[identifier='someThrowable'] +//functionCallExpression/arguments/argumentList/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']