From d87964a12fc4bd338e95e14fb989cd3e0efbef83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B3=D9=84=D9=8A=D9=85=D8=A7=D9=86=20=D8=A7=D9=84=D8=B3?= =?UTF-8?q?=D9=87=D9=85=D9=8A=20=28sahmi=20soolayman=29?= Date: Fri, 1 Sep 2017 23:04:23 +0100 Subject: [PATCH 1/5] tests --- test/pass_files/declarations.d | 10 ++++++++++ test/pass_files/statements.d | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/test/pass_files/declarations.d b/test/pass_files/declarations.d index 9ba11ec5..df5fcf04 100644 --- a/test/pass_files/declarations.d +++ b/test/pass_files/declarations.d @@ -70,3 +70,13 @@ idouble a = 4Li; idouble a = 4i; ifloat a = 4fi; ifloat a = 4Fi; + +static foreach (n; ['a', 'b', 'c']) +{ + mixin("char " ~ n ~ ";"); +} + +static foreach_reverse (i; '0' .. '5') +{ + mixin("int _" ~ i ~ ";"); +} diff --git a/test/pass_files/statements.d b/test/pass_files/statements.d index ca7379bd..aac229ba 100644 --- a/test/pass_files/statements.d +++ b/test/pass_files/statements.d @@ -60,4 +60,15 @@ deprecated void foo() i++; } label: + + + static foreach (n; ['a', 'b', 'c']) + {{ + mixin(n ~ "++;"); + }} + + static foreach_reverse (i; 1 .. 10) + { + assert(i-- > 0); + } } From 4320a4405851c02c4998834adc8cc39517635fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B3=D9=84=D9=8A=D9=85=D8=A7=D9=86=20=D8=A7=D9=84=D8=B3?= =?UTF-8?q?=D9=87=D9=85=D9=8A=20=28sahmi=20soolayman=29?= Date: Fri, 1 Sep 2017 23:17:04 +0100 Subject: [PATCH 2/5] parse static foreach --- src/dparse/ast.d | 41 ++++++++++++++++++++---- src/dparse/parser.d | 77 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 10 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 8362c715..09d8b7fb 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -221,6 +221,8 @@ public: /** */ void visit(const Finally finally_) { finally_.accept(this); } /** */ void visit(const ForStatement forStatement) { forStatement.accept(this); } /** */ void visit(const ForeachStatement foreachStatement) { foreachStatement.accept(this); } + /** */ void visit(const StaticForeachDeclaration staticForeachDeclaration) { staticForeachDeclaration.accept(this); } + /** */ void visit(const StaticForeachStatement staticForeachStatement) { staticForeachStatement.accept(this); } /** */ void visit(const ForeachType foreachType) { foreachType.accept(this); } /** */ void visit(const ForeachTypeList foreachTypeList) { foreachTypeList.accept(this); } /** */ void visit(const FunctionAttribute functionAttribute) { functionAttribute.accept(this); } @@ -1304,7 +1306,7 @@ public: SharedStaticConstructor, SharedStaticDestructor, StaticAssertDeclaration, StaticConstructor, StaticDestructor, StructDeclaration, TemplateDeclaration, UnionDeclaration, Unittest, VariableDeclaration, - VersionSpecification); + VersionSpecification, StaticForeachDeclaration); private Algebraic!(DeclarationTypes) storage; @@ -1347,6 +1349,7 @@ public: mixin(generateProperty("Unittest", "unittest_")); mixin(generateProperty("VariableDeclaration", "variableDeclaration")); mixin(generateProperty("VersionSpecification", "versionSpecification")); + mixin(generateProperty("StaticForeachDeclaration", "staticForeachDeclaration")); override bool opEquals(Object other) const { @@ -1629,22 +1632,47 @@ public: mixin OpEquals; } + /// -final class ForeachStatement : ASTNode +final class Foreach(bool declOnly) : ASTNode { public: override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(foreachType, foreachTypeList, low, high, - declarationOrStatement)); + mixin (visitIfNotNull!(foreachType, foreachTypeList, low, high)); + static if (declOnly) + mixin (visitIfNotNull!(declarations)); + else + mixin (visitIfNotNull!(declarationOrStatement)); } /** */ IdType type; /** */ ForeachTypeList foreachTypeList; /** */ ForeachType foreachType; /** */ Expression low; /** */ Expression high; - /** */ DeclarationOrStatement declarationOrStatement; /** */ size_t startIndex; + static if (declOnly) + /** */ Declaration[] declarations; + else + /** */ DeclarationOrStatement declarationOrStatement; + mixin OpEquals; +} + +/// +alias StaticForeachDeclaration = Foreach!true; + +/// +alias ForeachStatement = Foreach!false; + +/// +final class StaticForeachStatement : ASTNode +{ +public: + override void accept(ASTVisitor visitor) const + { + mixin (visitIfNotNull!(foreachStatement)); + } + /** */ ForeachStatement foreachStatement; mixin OpEquals; } @@ -2264,7 +2292,7 @@ public: synchronizedStatement, tryStatement, throwStatement, scopeGuardStatement, asmStatement, pragmaStatement, conditionalStatement, staticAssertStatement, versionSpecification, - debugSpecification, expressionStatement)); + debugSpecification, expressionStatement, staticForeachStatement)); } /** */ LabeledStatement labeledStatement; /** */ BlockStatement blockStatement; @@ -2273,6 +2301,7 @@ public: /** */ DoStatement doStatement; /** */ ForStatement forStatement; /** */ ForeachStatement foreachStatement; + /** */ StaticForeachStatement staticForeachStatement; /** */ SwitchStatement switchStatement; /** */ FinalSwitchStatement finalSwitchStatement; /** */ ContinueStatement continueStatement; diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 6a3a41b9..9291448c 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -2097,6 +2097,8 @@ class Parser mixin (nullCheck!`node.conditionalDeclaration = parseConditionalDeclaration(strict)`); else if (peekIs(tok!"assert")) mixin(parseNodeQ!(`node.staticAssertDeclaration`, `StaticAssertDeclaration`)); + else if (peekIs(tok!"foreach") || peekIs(tok!"foreach_reverse")) + mixin(parseNodeQ!(`node.staticForeachDeclaration`, `StaticForeachDeclaration`)); else goto type; break; @@ -2741,6 +2743,37 @@ class Parser return node; } + /** + * Parses a StaticForeachDeclaration + * + * $(GRAMMAR $(RULEDEF staticForeachDeclaration): + * $(LITERAL 'static') ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachTypeList) $(LITERAL ';') $(RULE expression) $(LITERAL '$(RPAREN)') + * ($(RULE declaration) | $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')) + * | $(LITERAL 'static') ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachType) $(LITERAL ';') $(RULE expression) $(LITERAL '..') $(RULE expression) $(LITERAL '$(RPAREN)') + * ($(RULE declaration) | $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')) + * ;) + */ + StaticForeachDeclaration parseStaticForeachDeclaration() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + mixin(tokenCheck!"static"); + return parseForeach!true(); + } + + /** + * Parses a StaticForeachStatement + * + * $(GRAMMAR $(RULEDEF staticForeachStatement): + * $(LITERAL 'static') $(RULE foreachStatement) + * ;) + */ + StaticForeachStatement parseStaticForeachStatement() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + mixin(simpleParse!(StaticForeachStatement, + tok!"static", "foreachStatement|parseForeachStatement")); + } + /** * Parses a ForeachStatement * @@ -2752,7 +2785,13 @@ class Parser ForeachStatement parseForeachStatement() { mixin(traceEnterAndExit!(__FUNCTION__)); - ForeachStatement node = allocator.make!ForeachStatement; + return parseForeach!false(); + } + + Foreach!declOnly parseForeach(bool declOnly = false)() + { + mixin(traceEnterAndExit!(__FUNCTION__)); + Foreach!declOnly node = allocator.make!(Foreach!declOnly); if (currentIsOneOf(tok!"foreach", tok!"foreach_reverse")) node.type = advance().type; else @@ -2791,7 +2830,33 @@ class Parser error("Statement expected", false); return node; // this line makes DCD better } - mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); + static if (declOnly) + { + StackBuffer declarations; + if (currentIs(tok!"{")) + { + advance(); + while (moreTokens() && !currentIs(tok!"}")) + { + immutable b = setBookmark(); + immutable c = allocator.setCheckpoint(); + if (declarations.put(parseDeclaration(true, true))) + abandonBookmark(b); + else + { + goToBookmark(b); + allocator.rollback(c); + return null; + } + } + mixin(tokenCheck!"}"); + } + else if (!declarations.put(parseDeclaration(true, true))) + return null; + ownArray(node.declarations, declarations); + } + else + mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); return node; } @@ -4966,9 +5031,11 @@ class Parser mixin(parseNodeQ!(`node.conditionalStatement`, `ConditionalStatement`)); else if (peekIs(tok!"assert")) mixin(parseNodeQ!(`node.staticAssertStatement`, `StaticAssertStatement`)); + else if (peekIs(tok!"foreach") || peekIs(tok!"foreach_reverse")) + mixin(parseNodeQ!(`node.staticForeachStatement`, `StaticForeachStatement`)); else { - error("'if' or 'assert' expected."); + error("'if' or 'assert' or 'foreach' or 'foreach_reverse' expected."); return null; } break; @@ -6861,6 +6928,8 @@ protected: case tok!"static": if (peekIs(tok!"if")) return false; + else if (peekIs(tok!"foreach") || peekIs(tok!"foreach_reverse")) + goto default; goto case; case tok!"scope": if (peekIs(tok!"(")) @@ -6975,7 +7044,7 @@ protected: case tok!"scope": return !peekIs(tok!"("); case tok!"static": - return !peekIsOneOf(tok!"assert", tok!"this", tok!"if", tok!"~"); + return !peekIsOneOf(tok!"assert", tok!"this", tok!"if", tok!"~", tok!"foreach", tok!"foreach_reverse"); case tok!"shared": return !(startsWith(tok!"shared", tok!"static", tok!"this") || startsWith(tok!"shared", tok!"static", tok!"~") From c4107f32f238b120f5f2116b6ec616fdc3cf650f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B3=D9=84=D9=8A=D9=85=D8=A7=D9=86=20=D8=A7=D9=84=D8=B3?= =?UTF-8?q?=D9=87=D9=85=D9=8A=20=28sahmi=20soolayman=29?= Date: Sat, 2 Sep 2017 20:31:57 +0100 Subject: [PATCH 3/5] unittest for type attributes `alias` and `enum` --- test/pass_files/declarations.d | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/pass_files/declarations.d b/test/pass_files/declarations.d index df5fcf04..eb4b1c88 100644 --- a/test/pass_files/declarations.d +++ b/test/pass_files/declarations.d @@ -80,3 +80,8 @@ static foreach_reverse (i; '0' .. '5') { mixin("int _" ~ i ~ ";"); } + +static foreach (enum i, alias T; AliasSeq!(int, bool)) +{ + T a = i; +} From a355f589ad347523af38df8bd340876b3bf7e226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B3=D9=84=D9=8A=D9=85=D8=A7=D9=86=20=D8=A7=D9=84=D8=B3?= =?UTF-8?q?=D9=87=D9=85=D9=8A=20=28sahmi=20soolayman=29?= Date: Sat, 2 Sep 2017 21:21:07 +0100 Subject: [PATCH 4/5] [experimental] parse `alias` and `enum` foreach type attributes --- src/dparse/parser.d | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 9291448c..00917e1c 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -2864,29 +2864,32 @@ class Parser * Parses a ForeachType * * $(GRAMMAR $(RULEDEF foreachType): - * $(LITERAL 'ref')? $(RULE typeConstructors)? $(RULE type)? $(LITERAL Identifier) - * | $(RULE typeConstructors)? $(LITERAL 'ref')? $(RULE type)? $(LITERAL Identifier) + * ($(LITERAL 'ref') | $(LITERAL 'alias') | $(LITERAL 'enum') | $(RULE typeConstructor))* $(RULE type)? $(LITERAL Identifier) * ;) */ ForeachType parseForeachType() { mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocator.make!ForeachType; - if (currentIs(tok!"ref")) - { - node.isRef = true; - advance(); - } - if (currentIsOneOf(tok!"const", tok!"immutable", - tok!"inout", tok!"shared") && !peekIs(tok!"(")) - { - trace("\033[01;36mType constructor"); - mixin(parseNodeQ!(`node.typeConstructors`, `TypeConstructors`)); - } - if (currentIs(tok!"ref")) + while (moreTokens()) { - node.isRef = true; - advance(); + IdType typeConstructor; + if (currentIs(tok!"ref")) + { + node.isRef = true; + advance(); + } + else if (currentIs(tok!"alias")) + advance(); // TODO: where should I put this + else if (currentIs(tok!"enum")) + advance(); // TODO: where should I put this + else if (tok!"" != (typeConstructor = parseTypeConstructor(false))) + { + trace("\033[01;36mType constructor"); + node.typeConstructors ~= typeConstructor; + } + else + break; } if (currentIs(tok!"identifier") && peekIsOneOf(tok!",", tok!";")) { From 1dcb9e6946388232132047bf44506889318a6a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B3=D9=84=D9=8A=D9=85=D8=A7=D9=86=20=D8=A7=D9=84=D8=B3?= =?UTF-8?q?=D9=87=D9=85=D9=8A=20=28sahmi=20soolayman=29?= Date: Tue, 5 Sep 2017 08:46:00 +0100 Subject: [PATCH 5/5] parse `alias` and `enum` foreach type attributes --- src/dparse/ast.d | 2 ++ src/dparse/parser.d | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 09d8b7fb..127e061a 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -1684,6 +1684,8 @@ public: { mixin (visitIfNotNull!(type, identifier)); } + /** */ bool isAlias; + /** */ bool isEnum; /** */ bool isRef; /** */ IdType[] typeConstructors; /** */ Type type; diff --git a/src/dparse/parser.d b/src/dparse/parser.d index 00917e1c..96c5aeb0 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -2880,9 +2880,15 @@ class Parser advance(); } else if (currentIs(tok!"alias")) - advance(); // TODO: where should I put this + { + node.isAlias = true; + advance(); + } else if (currentIs(tok!"enum")) - advance(); // TODO: where should I put this + { + node.isEnum = true; + advance(); + } else if (tok!"" != (typeConstructor = parseTypeConstructor(false))) { trace("\033[01;36mType constructor");