From ec459196b1afa1f8a864a3c79d760f549ea535f9 Mon Sep 17 00:00:00 2001 From: 0-v-0 Date: Tue, 7 Apr 2026 22:46:33 +0800 Subject: [PATCH 1/3] Fix #526, support `int*[0].init` --- src/dparse/ast.d | 24 ++++++++++++++++++++++++ src/dparse/parser.d | 23 ++++++++++++++++++----- test/pass_files/issue0526.d | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 test/pass_files/issue0526.d diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 35e287d7..966ab611 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -4141,6 +4141,30 @@ unittest // issue #398: Support extern(C++, ) checkText(ns[2], `"baz"`); } +unittest // issue #526 +{ + import dparse.formatter, dparse.lexer, dparse.parser, dparse.rollback_allocator; + string src = q{enum E : int*[0] { a = int*[0].init }}; + final class Test : ASTVisitor + { + } + RollbackAllocator ra; + auto cf = LexerConfig("", StringBehavior.source); + auto ca = StringCache(16); + Module m = ParserConfig(getTokensForParser(src, cf, &ca), "", &ra).parseModule(); + auto t = new Test; + t.visit(m); + assert(m.declarations.length == 1); + auto ed = m.declarations[0].enumDeclaration; + assert(ed); + auto type = ed.type; + auto app = appender!string(); + auto formatter = new Formatter!(typeof(app))(app); + formatter.format(type); + assert(app[] == "int*[0]"); + assert(ed.type.typeSuffixes.length == 2); +} + unittest // Differentiate between no and empty DDOC comments, e.g. for DDOC unittests { import dparse.lexer, dparse.parser, dparse.rollback_allocator; diff --git a/src/dparse/parser.d b/src/dparse/parser.d index d2ba1c46..d8ce71e9 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -5923,18 +5923,31 @@ class Parser break; } foreach (B; BasicTypes) { case B: } - node.basicType = advance(); + { + auto bookmark = setBookmark(); + auto c = allocator.setCheckpoint(); + if (auto t = parseType()) + { + abandonBookmark(bookmark); + node.type = t; + } + else + { + allocator.rollback(c); + goToBookmark(bookmark); + node.basicType = advance(); + } if (currentIs(tok!".")) { advance(); - const t = expect(tok!"identifier"); - if (t !is null) - node.primary = *t; + if (const ident = expect(tok!"identifier")) + node.primary = *ident; } else if (currentIs(tok!"(")) mixin(parseNodeQ!(`node.arguments`, `Arguments`)); else goto default; - break; + } + break; case tok!"function": case tok!"delegate": case tok!"{": diff --git a/test/pass_files/issue0526.d b/test/pass_files/issue0526.d new file mode 100644 index 00000000..28501f69 --- /dev/null +++ b/test/pass_files/issue0526.d @@ -0,0 +1 @@ +enum E : int*[0] { a = int*[0].init } From 09b8a3d5019ffbeff49f28694bd925f1bb9907a0 Mon Sep 17 00:00:00 2001 From: 0-v-0 Date: Thu, 9 Apr 2026 16:48:56 +0800 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Jan Jurzitza --- src/dparse/parser.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dparse/parser.d b/src/dparse/parser.d index d8ce71e9..ef3633cf 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -5848,9 +5848,9 @@ class Parser * $(GRAMMAR $(RULEDEF primaryExpression): * $(RULE identifierOrTemplateInstance) * | $(LITERAL '.') $(RULE identifierOrTemplateInstance) - * | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE basicType) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(LITERAL Identifier) - * | $(RULE basicType) $(LITERAL '.') $(LITERAL Identifier) - * | $(RULE basicType) $(RULE arguments) + * | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(LITERAL Identifier) + * | $(RULE builtinType) $(RULE typeSuffix)* $(LITERAL '.') $(LITERAL Identifier) + * | $(RULE builtinType) $(RULE typeSuffix)* $(RULE arguments) * | $(RULE typeofExpression) * | $(RULE typeidExpression) * | $(RULE vector) From cb77def735eb720ab94ff5d4960350b0c5fe752c Mon Sep 17 00:00:00 2001 From: 0-v-0 Date: Thu, 9 Apr 2026 17:02:12 +0800 Subject: [PATCH 3/3] Remove bookmark/checkpoint --- src/dparse/ast.d | 8 ++++++++ src/dparse/parser.d | 14 +------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 966ab611..be05a453 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -2932,6 +2932,14 @@ final class PrimaryExpression : ExpressionNode /** */ Arguments arguments; /** */ InterpolatedString interpolatedString; mixin OpEquals; + + IdType builtinType() inout @property @safe nothrow @nogc pure + { + if (type) + if (auto t2 = type.type2) + return t2.builtinType ? t2.builtinType : IdType.init; + return IdType.init; + } } /// diff --git a/src/dparse/parser.d b/src/dparse/parser.d index ef3633cf..5dce6553 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -5924,19 +5924,7 @@ class Parser } foreach (B; BasicTypes) { case B: } { - auto bookmark = setBookmark(); - auto c = allocator.setCheckpoint(); - if (auto t = parseType()) - { - abandonBookmark(bookmark); - node.type = t; - } - else - { - allocator.rollback(c); - goToBookmark(bookmark); - node.basicType = advance(); - } + node.type = parseType(); if (currentIs(tok!".")) { advance();