diff --git a/build.bat b/build.bat index 7802267..2cd4266 100644 --- a/build.bat +++ b/build.bat @@ -1 +1 @@ -dmd main.d stats.d imports.d highlighter.d ctags.d astprinter.d formatter.d outliner.d stdx/allocator.d stdx/lexer.d stdx/d/ast.d stdx/d/parser.d stdx/d/lexer.d analysis/.d analysis/base.d analysis/del.d analysis/enumarrayliteral.d analysis/fish.d analysis/numbers.d analysis/objectconst.d analysis/package.d analysis/pokemon.d analysis/range.d analysis/run.d analysis/style.d -ofdscanner.exe -O -release -noboundscheck -inline +dmd main.d stats.d imports.d highlighter.d ctags.d astprinter.d formatter.d outliner.d stdx/allocator.d stdx/lexer.d stdx/d/ast.d stdx/d/parser.d stdx/d/lexer.d analysis/base.d analysis/del.d analysis/enumarrayliteral.d analysis/fish.d analysis/numbers.d analysis/objectconst.d analysis/package.d analysis/pokemon.d analysis/range.d analysis/run.d analysis/style.d -ofdscanner.exe -O -release -noboundscheck -inline diff --git a/stdx/d/ast.d b/stdx/d/ast.d index 636b516..03c1a82 100644 --- a/stdx/d/ast.d +++ b/stdx/d/ast.d @@ -1996,6 +1996,7 @@ public: mixin (visitIfNotNull!(functionBody)); } /** */ FunctionBody functionBody; + /** */ MemberFunctionAttribute[] memberFunctionAttributes; } /// diff --git a/stdx/d/lexer.d b/stdx/d/lexer.d index 23bca67..91f7146 100644 --- a/stdx/d/lexer.d +++ b/stdx/d/lexer.d @@ -1272,8 +1272,26 @@ public struct DLexer range.popFront(); break; case 'x': - // TODO range.popFront(); + foreach (i; 0 .. 2) + { + if (range.empty) + { + error("Error: 2 hex digits expected."); + return false; + } + switch (range.front) + { + case '0': .. case '9': + case 'a': .. case 'f': + case 'A': .. case 'F': + range.popFront(); + break; + default: + error("Error: 2 hex digits expected."); + return false; + } + } break; case '1': .. case '7': for (size_t i = 0; i < 3 && !range.empty && range.front >= '0' && range.front <= '7'; i++) @@ -1526,3 +1544,24 @@ unittest assert (tokens.map!"a.type"().equal([tok!"import", tok!"identifier", tok!".", tok!"identifier", tok!";"])); } + +/// Test \x char sequence +unittest +{ + auto toks = (string s) => byToken(cast(ubyte[])s); + + // valid + enum hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']; + auto source = ""; + foreach(h1; hex) + foreach(h2; hex) + source ~= "'\\x" ~ h1 ~ h2 ~ "'"; + assert(toks(source).filter!(t => t.type != tok!"characterLiteral").empty); + + // invalid + assert(toks(`'\x'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true)); + assert(toks(`'\x_'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true)); + assert(toks(`'\xA'`).messages[0] == DLexer.Message(1,5,"Error: 2 hex digits expected.",true)); + assert(toks(`'\xAY'`).messages[0] == DLexer.Message(1,5,"Error: 2 hex digits expected.",true)); + assert(toks(`'\xXX'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true)); +} diff --git a/stdx/d/parser.d b/stdx/d/parser.d index ee48209..f55490a 100644 --- a/stdx/d/parser.d +++ b/stdx/d/parser.d @@ -1309,7 +1309,7 @@ incorrect; * Parses a ClassDeclaration * * $(GRAMMAR $(RULEDEF classDeclaration): - * $(LITERAL 'class') $(LITERAL Identifier) ($(RULE templateParameters) $(RULE constraint)?)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) + * $(LITERAL 'class') $(LITERAL Identifier) ($(LITERAL ';') | ($(RULE templateParameters) $(RULE constraint)?)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)) * ;) */ ClassDeclaration parseClassDeclaration() @@ -1322,6 +1322,11 @@ incorrect; node.name = *ident; node.comment = comment; comment = null; + if (currentIs(tok!";")) + { + advance(); + return node; + } if (currentIs(tok!"(")) { node.templateParameters = parseTemplateParameters(); @@ -1731,6 +1736,7 @@ class ClassFour(A, B) if (someTest()) : Super {}}c; if (currentIs(tok!":")) { node.attributeDeclaration = parseAttributeDeclaration(attr); + node.attributes = ownArray(attributes); return node; } else @@ -3185,7 +3191,7 @@ import core.stdc.stdio, std.string : KeepTerminator; * Parses an InterfaceDeclaration * * $(GRAMMAR $(RULEDEF interfaceDeclaration): - * $(LITERAL 'interface') $(LITERAL Identifier) ($(RULE templateParameters) $(RULE constraint)?)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) + * $(LITERAL 'interface') $(LITERAL Identifier) ($(LITERAL ';') | ($(RULE templateParameters) $(RULE constraint)?)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)) * ;) */ InterfaceDeclaration parseInterfaceDeclaration() @@ -3197,6 +3203,11 @@ import core.stdc.stdio, std.string : KeepTerminator; node.name = *ident; node.comment = comment; comment = null; + if (currentIs(tok!";")) + { + advance(); + return node; + } if (currentIs(tok!"(")) { node.templateParameters = parseTemplateParameters(); @@ -3875,7 +3886,13 @@ invariant() foo(); mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocate!NonVoidInitializer; if (currentIs(tok!"{")) - node.structInitializer = parseStructInitializer(); + { + auto b = peekPastBraces(); + if (b !is null && (b.type == tok!"(")) + node.assignExpression = parseAssignExpression(); + else + node.structInitializer = parseStructInitializer(); + } else if (currentIs(tok!"[")) { auto b = peekPastBrackets(); @@ -4134,7 +4151,7 @@ q{(int a, ...) * Parses a Postblit * * $(GRAMMAR $(RULEDEF postblit): - * $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL 'this') $(LITERAL '$(RPAREN)') ($(RULE functionBody) | $(LITERAL ';')) + * $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL 'this') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';')) * ;) */ Postblit parsePostblit() @@ -4144,6 +4161,10 @@ q{(int a, ...) expect(tok!"("); expect(tok!"this"); expect(tok!")"); + MemberFunctionAttribute[] memberFunctionAttributes; + while (currentIsMemberFunctionAttribute()) + memberFunctionAttributes ~= parseMemberFunctionAttribute(); + node.memberFunctionAttributes = ownArray(memberFunctionAttributes); if (currentIs(tok!";")) advance(); else