diff --git a/README.md b/README.md index 3e5eb93..f2b72a1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The following examples assume that we are analyzing a simple file called hellowo ### Token Count The "--tokenCount" or "-t" option prints the number of tokens in the given file - $ dscanner --tokencount helloworld.d + $ dscanner --tokenCount helloworld.d 20 ### Import Listing @@ -52,13 +52,15 @@ given source files. * Left side of a *foreach* or *foreach\_reverse* range expression is larger than the right. * Left side of a slice expression is larger than the right * Variable, struct, class, union, module, package, and interface names that do not comply with Phobos style guidelines +* Struct constructors that have a single parameter that has a default argument. +* Assign expressions where the left side of the '=' operator is the same as the right +* 'if' statements where the 'else' block is the same as the 'if' block. #### Wishlish * Assigning to foreach variables that are not "ref". * Unused variables. * Unused imports. * Unused parameters (check is skipped if function is marked "override") -* Struct constructors that have a single parameter that has a default argument. * Variables that are never modified and not declared immutable. * Public declarations not documented * Declaring opEquals without toHash @@ -196,6 +198,6 @@ but not yet implemented. # Useful code The source code for DScanner has a complete lexer, parser, and abstact syntax -tree library for D code under the stdx/d/ directory. It is intended that these +tree library for D code under the std/d/ directory. It is intended that these modules eventually end up in Phobos, so feel free to use them for your own D tools. diff --git a/analysis/base.d b/analysis/base.d index 58b0c08..c152e1f 100644 --- a/analysis/base.d +++ b/analysis/base.d @@ -2,7 +2,7 @@ module analysis.base; import std.container; import std.string; -import stdx.d.ast; +import std.d.ast; import std.array; struct Message diff --git a/analysis/constructors.d b/analysis/constructors.d new file mode 100644 index 0000000..ed4dd76 --- /dev/null +++ b/analysis/constructors.d @@ -0,0 +1,86 @@ +module analysis.constructors; + +import std.d.ast; +import std.d.lexer; +import analysis.base; + +class ConstructorCheck : BaseAnalyzer +{ + alias visit = BaseAnalyzer.visit; + + this(string fileName) + { + super(fileName); + } + + override void visit(const ClassDeclaration classDeclaration) + { + bool oldHasDefault = hasDefaultArgConstructor; + bool oldHasNoArg = hasNoArgConstructor; + hasNoArgConstructor = false; + hasDefaultArgConstructor = false; + State prev = state; + state = State.inClass; + classDeclaration.accept(this); + if (hasNoArgConstructor && hasDefaultArgConstructor) + { + addErrorMessage(classDeclaration.name.line, + classDeclaration.name.column, "This class has a zero-argument" + ~ " constructor as well as a constructor with one default" + ~ " argument. This can be confusing"); + } + hasDefaultArgConstructor = oldHasDefault; + hasNoArgConstructor = oldHasNoArg; + state = prev; + } + + override void visit(const StructDeclaration structDeclaration) + { + State prev = state; + state = State.inStruct; + structDeclaration.accept(this); + state = prev; + } + + override void visit(const Constructor constructor) + { + final switch (state) + { + case State.inStruct: + if (constructor.parameters.parameters.length == 1 + && constructor.parameters.parameters[0].default_ !is null) + { + addErrorMessage(constructor.line, constructor.column, + "This struct constructor can never be called with its " + ~ "default argument."); + } + break; + case State.inClass: + if (constructor.parameters.parameters.length == 1 + && constructor.parameters.parameters[0].default_ !is null) + { + hasDefaultArgConstructor = true; + } + else if (constructor.parameters.parameters.length == 0) + hasNoArgConstructor = true; + break; + case State.ignoring: + break; + } + } + + +private: + + enum State: ubyte + { + ignoring, + inClass, + inStruct + } + + State state; + + bool hasNoArgConstructor; + bool hasDefaultArgConstructor; +} diff --git a/analysis/del.d b/analysis/del.d index 60df118..5ef4472 100644 --- a/analysis/del.d +++ b/analysis/del.d @@ -5,8 +5,8 @@ module analysis.del; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** diff --git a/analysis/enumarrayliteral.d b/analysis/enumarrayliteral.d index 0eae919..6c065ac 100644 --- a/analysis/enumarrayliteral.d +++ b/analysis/enumarrayliteral.d @@ -5,8 +5,8 @@ module analysis.enumarrayliteral; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; void doNothing(string, size_t, size_t, string, bool) {} diff --git a/analysis/fish.d b/analysis/fish.d index de66d11..71309d7 100644 --- a/analysis/fish.d +++ b/analysis/fish.d @@ -5,8 +5,8 @@ module analysis.fish; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** @@ -24,6 +24,7 @@ class FloatOperatorCheck : BaseAnalyzer override void visit(const RelExpression r) { if (r.operator == tok!"<>" + || r.operator == tok!"<>=" || r.operator == tok!"!<>" || r.operator == tok!"!>" || r.operator == tok!"!<" diff --git a/analysis/ifelsesame.d b/analysis/ifelsesame.d new file mode 100644 index 0000000..dc2bcc3 --- /dev/null +++ b/analysis/ifelsesame.d @@ -0,0 +1,43 @@ +// Copyright Brian Schott (Sir Alaran) 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module analysis.ifelsesame; + +import std.d.ast; +import std.d.lexer; +import analysis.base; + +/** + * Checks for if statements whose "then" block is the same as the "else" block + */ +class IfElseSameCheck : BaseAnalyzer +{ + alias visit = BaseAnalyzer.visit; + + this(string fileName) + { + super(fileName); + } + + override void visit(const IfStatement ifStatement) + { + if (ifStatement.thenStatement == ifStatement.elseStatement) + addErrorMessage(ifStatement.line, ifStatement.column, + "\"Else\" branch is identical to \"Then\" branch."); + ifStatement.accept(this); + } + + override void visit(const AssignExpression assignExpression) + { + const AssignExpression e = cast(const AssignExpression) assignExpression.assignExpression; + if (e !is null && assignExpression.operator == tok!"=" + && e.ternaryExpression == assignExpression.ternaryExpression) + { + addErrorMessage(assignExpression.line, assignExpression.column, + "Left side of assignment operatior is identical to the right side"); + } + assignExpression.accept(this); + } +} diff --git a/analysis/linespan.d b/analysis/linespan.d index cedbef5..ec65cef 100644 --- a/analysis/linespan.d +++ b/analysis/linespan.d @@ -5,7 +5,6 @@ module analysis.linespan; - /** * Used for determining which lines to include as context in the generated HTML * report. diff --git a/analysis/numbers.d b/analysis/numbers.d index b3b209c..da483c1 100644 --- a/analysis/numbers.d +++ b/analysis/numbers.d @@ -6,8 +6,8 @@ module analysis.numbers; import std.regex; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** diff --git a/analysis/objectconst.d b/analysis/objectconst.d index 136b3af..d64c8c4 100644 --- a/analysis/objectconst.d +++ b/analysis/objectconst.d @@ -6,12 +6,13 @@ module analysis.objectconst; import std.regex; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** - * Checks for use of the deprecated "delete" keyword + * Checks that opEquals, opCmp, toHash, and toString are either const, + * immutable, or inout. */ class ObjectConstCheck : BaseAnalyzer { @@ -35,7 +36,7 @@ class ObjectConstCheck : BaseAnalyzer && !hasConst(d.functionDeclaration.memberFunctionAttributes))) { addErrorMessage(d.functionDeclaration.name.line, - d.functionDeclaration.name.column, "opCmp, ToHash, opEquals," + d.functionDeclaration.name.column, "opCmp, toHash, opEquals," ~ " and toString should be declared const"); } d.accept(this); @@ -51,7 +52,9 @@ class ObjectConstCheck : BaseAnalyzer private static bool hasConst(const MemberFunctionAttribute[] attributes) { import std.algorithm; - return attributes.any!(a => a.tokenType == tok!"const"); + return attributes.any!(a => a.tokenType == tok!"const" + || a.tokenType == tok!"immutable" + || a.tokenType == tok!"inout"); } private static bool isInteresting(string name) diff --git a/analysis/pokemon.d b/analysis/pokemon.d index bc22530..82cb42d 100644 --- a/analysis/pokemon.d +++ b/analysis/pokemon.d @@ -5,8 +5,8 @@ module analysis.pokemon; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** diff --git a/analysis/range.d b/analysis/range.d index a9e911c..a30e43d 100644 --- a/analysis/range.d +++ b/analysis/range.d @@ -5,8 +5,8 @@ module analysis.range; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import analysis.base; /** @@ -64,24 +64,37 @@ class BackwardsRangeCheck : BaseAnalyzer override void visit(const PrimaryExpression primary) { - import std.conv; - import std.string; if (state == State.ignore || !isNumberLiteral(primary.primary.type)) return; if (state == State.left) { line = primary.primary.line; this.column = primary.primary.column; - left = to!long(primary.primary.text.removechars("_uUlL")); + left = parseNumber(primary.primary.text); hasLeft = true; } else { - right = to!long(primary.primary.text.removechars("_uUlL")); + right = parseNumber(primary.primary.text); hasRight = true; } } + long parseNumber(string te) + { + import std.conv; + import std.string; + string t = te.removechars("_uUlL"); + if (t.length > 2) + { + if (t[1] == 'x' || t[1] == 'X') + return to!long(t[2..$], 16); + if (t[1] == 'b' || t[1] == 'B') + return to!long(t[2..$], 2); + } + return to!long(t); + } + override void visit(const SliceExpression sliceExpression) { if (sliceExpression.lower !is null && sliceExpression.upper !is null) diff --git a/analysis/run.d b/analysis/run.d index 74971e1..c86a24a 100644 --- a/analysis/run.d +++ b/analysis/run.d @@ -6,10 +6,9 @@ import std.conv; import std.algorithm; import std.range; import std.array; - -import stdx.d.lexer; -import stdx.d.parser; -import stdx.d.ast; +import std.d.lexer; +import std.d.parser; +import std.d.ast; import analysis.base; import analysis.style; @@ -20,6 +19,8 @@ import analysis.fish; import analysis.numbers; import analysis.objectconst; import analysis.range; +import analysis.constructors; +import analysis.ifelsesame; void messageFunction(string fileName, size_t line, size_t column, string message, bool isError) @@ -70,6 +71,8 @@ void analyze(File output, string[] fileNames, bool staticAnalyze = true) checks ~= new NumberStyleCheck(fileName); checks ~= new ObjectConstCheck(fileName); checks ~= new BackwardsRangeCheck(fileName); + checks ~= new IfElseSameCheck(fileName); + checks ~= new ConstructorCheck(fileName); foreach (check; checks) { diff --git a/analysis/style.d b/analysis/style.d index 13f9b53..136e2c2 100644 --- a/analysis/style.d +++ b/analysis/style.d @@ -5,8 +5,8 @@ module analysis.style; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; import std.regex; import std.array; import std.conv; diff --git a/astprinter.d b/astprinter.d index 011e66d..f78a97b 100644 --- a/astprinter.d +++ b/astprinter.d @@ -3,8 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -import stdx.d.lexer; -import stdx.d.ast; +import std.d.lexer; +import std.d.ast; import std.stdio; import std.string; import std.array; @@ -133,7 +133,7 @@ class XMLPrinter : ASTVisitor output.writeln(""); else output.writeln(""); + xmlEscape(str(assignExpression.operator)), "\">"); assignExpression.accept(this); output.writeln(""); } @@ -479,7 +479,7 @@ class XMLPrinter : ASTVisitor override void visit(const ForStatement forStatement) { output.writeln(""); - if (forStatement.declarationOrStatement !is null) + if (forStatement.initialization !is null) { output.writeln(""); visit(forStatement.initialization); @@ -497,7 +497,8 @@ class XMLPrinter : ASTVisitor visit(forStatement.increment); output.writeln(""); } - visit(forStatement.declarationOrStatement); + if (forStatement.declarationOrStatement !is null) + visit(forStatement.declarationOrStatement); output.writeln(""); } @@ -592,7 +593,8 @@ class XMLPrinter : ASTVisitor { output.writeln(""); output.writeln(""); - visit(gotoStatement.expression); + if (gotoStatement.expression) + visit(gotoStatement.expression); output.writeln(""); output.writeln(""); } @@ -665,10 +667,10 @@ class XMLPrinter : ASTVisitor override void visit(const ImportBind importBind) { if (importBind.right.type == tok!"") - output.writeln(""); + output.writeln(""); else output.writeln(""); + "\" rename=\"", importBind.left.text, "\"/>"); } override void visit(const ImportBindings importBindings) @@ -779,7 +781,7 @@ class XMLPrinter : ASTVisitor output.writeln(""); output.writeln(""); visit(keyValuePair.value); - output.writeln(""); + output.writeln(""); output.writeln(""); } @@ -1312,8 +1314,9 @@ class XMLPrinter : ASTVisitor case tok!"stringLiteral": tagName = "stringLiteral"; break; case tok!"dstringLiteral": tagName = "dstringLiteral"; break; case tok!"wstringLiteral": tagName = "wstringLiteral"; break; + case tok!"scriptLine": tagName = "scriptLine"; break; case tok!"$": output.writeln(""); return; - default: output.writeln("<", str(token.type), "/>"); return; + default: tagName = "token"; break; } output.writeln("<", tagName, ">", xmlEscape(token.text), ""); } diff --git a/build.bat b/build.bat index 2cd4266..56decbb 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/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 std/allocator.d std/lexer.d std/d/ast.d std/d/parser.d std/d/lexer.d analysis/base.d analysis/del.d analysis/enumarrayliteral.d analysis/constructors.d analysis/ifelsesame.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 -version=DIP61 -O -release -noboundscheck -inline diff --git a/build.sh b/build.sh index 5076df3..2b3cd32 100755 --- a/build.sh +++ b/build.sh @@ -7,12 +7,13 @@ dmd\ astprinter.d\ formatter.d\ outliner.d\ - stdx/*.d\ - stdx/d/*.d\ + std/*.d\ + std/d/*.d\ analysis/*.d\ + -version=DIP61\ -ofdscanner\ - -m64 -g\ - -O -release -noboundscheck -inline + -g\ + -O -release #gdc\ # main.d\ @@ -23,8 +24,8 @@ dmd\ # astprinter.d\ # formatter.d\ # outliner.d\ -# stdx/*.d\ -# stdx/d/*.d\ +# std/*.d\ +# std/d/*.d\ # analysis/*.d\ # -O3 -frelease -fno-bounds-check\ # -odscanner\ @@ -38,8 +39,8 @@ dmd\ # astprinter.d\ # formatter.d\ # outliner.d\ -# stdx/*.d\ -# stdx/d/*.d\ +# std/*.d\ +# std/d/*.d\ # analysis/*.d\ # -O3 -release\ # -oq -of=dscanner\ diff --git a/ctags.d b/ctags.d index a679b4d..97e99ea 100644 --- a/ctags.d +++ b/ctags.d @@ -5,9 +5,9 @@ module ctags; -import stdx.d.parser; -import stdx.d.lexer; -import stdx.d.ast; +import std.d.parser; +import std.d.lexer; +import std.d.ast; import std.algorithm; import std.range; import std.stdio; @@ -71,7 +71,9 @@ class CTagsPrinter : ASTVisitor override void visit(const TemplateDeclaration dec) { - tagLines ~= "%s\t%s\t%d;\"\tT%s\n".format(dec.name.text, fileName, dec.name.line, context); + auto name = dec.eponymousTemplateDeclaration is null ? dec.name + : dec.eponymousTemplateDeclaration.name; + tagLines ~= "%s\t%s\t%d;\"\tT%s\n".format(name.text, fileName, name.line, context); auto c = context; context = "\ttemplate:" ~ dec.name.text; dec.accept(this); @@ -88,6 +90,26 @@ class CTagsPrinter : ASTVisitor context = c; } + override void visit(const Constructor dec) + { + tagLines ~= "this\t%s\t%d;\"\tf\tarity:%d%s\n".format(fileName, + dec.line, dec.parameters.parameters.length, context); + auto c = context; + context = "\tfunction: this"; + dec.accept(this); + context = c; + } + + override void visit(const Destructor dec) + { + tagLines ~= "~this\t%s\t%d;\"\tf%s\n".format(fileName, dec.line, + context); + auto c = context; + context = "\tfunction: this"; + dec.accept(this); + context = c; + } + override void visit(const EnumDeclaration dec) { if (dec.name == tok!"") @@ -134,6 +156,11 @@ class CTagsPrinter : ASTVisitor dec.accept(this); } + override void visit(const Invariant dec) + { + tagLines ~= "invariant\t%s\t%d;\"\tv%s\n".format(fileName, dec.line, context); + } + alias visit = ASTVisitor.visit; string fileName; diff --git a/dub.json b/dub.json index 086d89e..c67d6fb 100644 --- a/dub.json +++ b/dub.json @@ -9,7 +9,7 @@ { "name": "library", "targetType": "library", - "sourcePaths": ["stdx"], + "sourcePaths": ["std"], }, { "name": "dscanner", diff --git a/formatter.d b/formatter.d index b98ac75..b2008d2 100644 --- a/formatter.d +++ b/formatter.d @@ -1,7 +1,7 @@ module formatter; -import stdx.d.ast; -import stdx.d.lexer; +import std.d.ast; +import std.d.lexer; /** * The only brace styles worth using. @@ -489,6 +489,7 @@ class Formatter(Sink) foreach (attribute; parameter.parameterAttributes) { sink.put(str(attribute)); + sink.put(" "); } if (parameter.type !is null) format(parameter.type); @@ -682,16 +683,11 @@ class Formatter(Sink) void format(const Type type) { - bool first = true; foreach (constructor; type.typeConstructors) { - if (first) - sink.put(" "); - first = false; sink.put(str(constructor)); + sink.put(" "); } - if (type.typeConstructors.length > 0) - sink.put(" "); format(type.type2); foreach (suffix; type.typeSuffixes) { diff --git a/highlighter.d b/highlighter.d index 3b24e2f..cf48e27 100644 --- a/highlighter.d +++ b/highlighter.d @@ -8,7 +8,7 @@ module highlighter; import std.stdio; import std.array; -import stdx.d.lexer; +import std.d.lexer; // http://ethanschoonover.com/solarized void highlight(R)(ref R tokens, string fileName) @@ -49,6 +49,8 @@ html { background-color: #fdf6e3; color: #002b36; } writeSpan("num", t.text); else if (isOperator(t.type)) writeSpan("op", str(t.type)); + else if (t.type == tok!"specialTokenSequence" || t.type == tok!"scriptLine") + writeSpan("cons", t.text.replace("<", "<")); else { version(Windows) diff --git a/imports.d b/imports.d index bc13d66..fccadf6 100644 --- a/imports.d +++ b/imports.d @@ -5,16 +5,21 @@ module imports; -import stdx.d.ast; +import std.d.ast; import std.stdio; +import std.container; class ImportPrinter : ASTVisitor { + this() + { + imports = new RedBlackTree!string; + } + override void visit(const SingleImport singleImport) { ignore = false; singleImport.accept(this); - writeln(); ignore = true; } @@ -22,15 +27,19 @@ class ImportPrinter : ASTVisitor { if (ignore) return; bool first = true; + string s; foreach (ident; identifierChain.identifiers) { if (!first) - write("."); - write(ident.text); + s ~= "."; + s ~= ident.text; first = false; } + imports.insert(s); } + RedBlackTree!string imports; + alias visit = ASTVisitor.visit; bool ignore = true; diff --git a/main.d b/main.d index ee5dd5b..cb011f8 100644 --- a/main.d +++ b/main.d @@ -13,9 +13,9 @@ import std.getopt; import std.path; import std.stdio; import std.range; -import stdx.lexer; -import stdx.d.lexer; -import stdx.d.parser; +import std.lexer; +import std.d.lexer; +import std.d.parser; import highlighter; import stats; @@ -101,6 +101,7 @@ int main(string[] args) config.whitespaceBehavior = WhitespaceBehavior.include; config.stringBehavior = StringBehavior.source; config.commentBehavior = CommentBehavior.include; + config.specialTokenBehavior = SpecialTokenBehavior.include; auto tokens = byToken(bytes, config, cache); if (highlight) { @@ -169,11 +170,14 @@ int main(string[] args) else if (imports || ast || outline) { auto tokens = byToken(usingStdin ? readStdin() : readFile(args[1])); - auto mod = parseModule(tokens.array(), usingStdin ? "stdin" : args[1]); + auto mod = parseModule(tokens.array(), usingStdin ? "stdin" : args[1], + null, &doNothing); if (imports) { auto visitor = new ImportPrinter; visitor.visit(mod); + foreach (imp; visitor.imports[]) + writeln(imp); } else if (ast) { @@ -291,3 +295,5 @@ options: directories and its sub-directories.`, programName); } + +void doNothing(string, size_t, size_t, string, bool) {} diff --git a/outliner.d b/outliner.d index 0acbb6d..919d8fc 100644 --- a/outliner.d +++ b/outliner.d @@ -3,8 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -import stdx.d.lexer; -import stdx.d.ast; +import std.d.lexer; +import std.d.ast; import std.stdio; import std.string; import std.array; diff --git a/stats.d b/stats.d index 533a948..e09d5e5 100644 --- a/stats.d +++ b/stats.d @@ -7,7 +7,7 @@ module stats; import std.stdio; import std.algorithm; -import stdx.d.lexer; +import std.d.lexer; pure nothrow bool isLineOfCode(IdType t) { diff --git a/stdx/allocator.d b/std/allocator.d similarity index 93% rename from stdx/allocator.d rename to std/allocator.d index fb6db9e..f9c5796 100644 --- a/stdx/allocator.d +++ b/std/allocator.d @@ -246,7 +246,7 @@ uses an array of allocators, one per bucket, to satisfy requests.)) ) */ -module stdx.allocator; +module std.allocator; // Example in the synopsis above unittest @@ -422,6 +422,99 @@ unittest static assert(stateSize!C3 == 2 * size_t.sizeof + char.sizeof); } +/** + * Shortcut that encapsulates a cast and a call to emplace() + * Params: + * a = the allocator to use + * args = the arguments to $(D T)'s constructor + * Returns: a pointer to an instance of $(D T). + */ +T* allocate(T, Allocator, Args...)(auto ref Allocator a, auto ref Args args) + @trusted if (is (T == struct)) +{ + import std.conv : emplace; + void[] mem = a.allocate(T.sizeof); + return emplace(cast(T*) mem.ptr, args); +} + +/// +unittest +{ + auto allocator = Mallocator.it; + struct TestStruct { int x = 5; } + TestStruct* p = allocate!TestStruct(allocator); + assert (p !is null); + assert (p.x == 5); + Mallocator.it.deallocate((cast(void*) p)[0 .. TestStruct.sizeof]); +} + +/** + * Shortcut that encapsulates a cast and a call to emplace() + * Params: + * a = the allocator to use + * args = the arguments to $(D T)'s constructor + * Returns: a reference to an instance of $(D T). + */ +T allocate(T, Allocator, Args...)(auto ref Allocator a, auto ref Args args) + @trusted if (is (T == class)) +{ + import std.conv : emplace; + void[] mem = a.allocate(__traits(classInstanceSize, T)); + return emplace!T(mem, args); +} + +/// +unittest +{ + auto allocator = Mallocator.it; + class TestClass { int x; this(int x) { this.x = x; } } + TestClass tc = allocate!TestClass(allocator, 10); + assert (tc !is null); + assert (tc.x == 10); + Mallocator.it.deallocate((cast(void*) tc)[0 .. __traits(classInstanceSize, TestClass)]); +} + +/** + * Encapsulates some casts and pointer slicing to deallocate $(D structInstance). + * This function does NOT call T's destructor. + */ +void deallocate(T, Allocator)(auto ref Allocator a, T* structInstance) + pure nothrow @trusted if (is (T == struct)) +{ + a.deallocate((cast(void*) structInstance)[0 .. T.sizeof]); +} + +/// +unittest +{ + auto allocator = Mallocator.it; + bool d = false; + struct TestStruct { float f; } + TestStruct* ts = allocate!TestStruct(allocator); + deallocate(allocator, ts); +} + +/** + * Encapsulates some casts and pointer slicing to deallocate $(D classInstance). + * This function does NOT call T's destructor. + */ +void deallocate(T, Allocator)(auto ref Allocator a, T classInstance) + pure nothrow @trusted if (is (T == class)) +{ + a.deallocate((cast(void*) classInstance)[0 .. __traits(classInstanceSize, T)]); +} + +/// +unittest +{ + import std.math; + auto allocator = Mallocator.it; + class TestClass { double z; } + TestClass tc = allocate!TestClass(allocator); + assert (isnan(tc.z)); + deallocate(allocator, tc); +} + /** $(D chooseAtRuntime) is a compile-time constant of type $(D size_t) that several parameterized structures in this module recognize to mean deferral to runtime of @@ -452,7 +545,7 @@ enum uint platformAlignment = std.algorithm.max(double.alignof, real.alignof); The default good size allocation is deduced as $(D n) rounded up to the allocator's alignment. */ -size_t goodAllocSize(A)(auto ref A a, size_t n) +size_t goodAllocSize(A)(auto ref A a, size_t n) pure nothrow { return n.roundUpToMultipleOf(a.alignment); } @@ -528,10 +621,16 @@ struct NullAllocator No-op. */ void deallocateAll() shared { } + + static shared(NullAllocator) it() pure nothrow @property @trusted + { + return cast(typeof(return)) _it; + } + /** Returns the $(D shared) global instance of the $(D NullAllocator). */ - static shared NullAllocator it; + private static shared const NullAllocator _it; } unittest @@ -557,16 +656,18 @@ struct GCAllocator enum uint alignment = platformAlignment; /** - Standard allocator methods per the semantics defined above. The $(D deallocate) and $(D reallocate) methods are $(D @system) because they may move memory around, leaving dangling pointers in user code. + Standard allocator methods per the semantics defined above. The + $(D deallocate) and $(D reallocate) methods are $(D @system) because they + may move memory around, leaving dangling pointers in user code. */ - @trusted void[] allocate(size_t bytes) shared + @trusted void[] allocate(size_t bytes) shared nothrow pure { auto p = GC.malloc(bytes); return p ? p[0 .. bytes] : null; } /// Ditto - @trusted bool expand(ref void[] b, size_t delta) shared + @trusted bool expand(ref void[] b, size_t delta) shared nothrow pure { auto newSize = GC.extend(b.ptr, b.length + delta, b.length + delta); @@ -581,7 +682,7 @@ struct GCAllocator } /// Ditto - @system bool reallocate(ref void[] b, size_t newSize) shared + @system bool reallocate(ref void[] b, size_t newSize) shared nothrow pure { import core.exception : OutOfMemoryError; try @@ -598,15 +699,20 @@ struct GCAllocator } /// Ditto - @system void deallocate(void[] b) shared + @system void deallocate(void[] b) shared nothrow pure { GC.free(b.ptr); } + static shared(GCAllocator) it() pure nothrow @property @trusted + { + return cast(typeof(return)) _it; + } + /** Returns the global instance of this allocator type. The garbage collected allocator is thread-safe, therefore all of its methods and $(D it) itself are $(D shared). */ - static shared GCAllocator it; + private static shared const GCAllocator _it; // Leave it undocummented for now. @trusted void collect() shared @@ -629,12 +735,19 @@ unittest assert(GCAllocator.it.expand(b, 1)); } +private extern (C) +{ + void* malloc(size_t) pure nothrow @trusted; + void free(void*) pure nothrow @trusted; + void* realloc(void*, size_t) pure nothrow @trusted; +} + /** The C heap allocator. */ struct Mallocator { - private import core.stdc.stdlib; +// private import core.stdc.stdlib; /** The alignment is a static constant equal to $(D platformAlignment), which ensures proper alignment for any D data type. @@ -642,22 +755,26 @@ struct Mallocator enum uint alignment = platformAlignment; /** - Standard allocator methods per the semantics defined above. The $(D deallocate) and $(D reallocate) methods are $(D @system) because they may move memory around, leaving dangling pointers in user code. Somewhat paradoxically, $(D malloc) is $(D @safe) but that's only useful to safe programs that can afford to leak memory allocated. + Standard allocator methods per the semantics defined above. The + $(D deallocate) and $(D reallocate) methods are $(D @system) because they + may move memory around, leaving dangling pointers in user code. Somewhat + paradoxically, $(D malloc) is $(D @safe) but that's only useful to safe + programs that can afford to leak memory allocated. */ - @trusted void[] allocate(size_t bytes) shared + void[] allocate(size_t bytes) shared pure nothrow @trusted { auto p = malloc(bytes); return p ? p[0 .. bytes] : null; } /// Ditto - @system void deallocate(void[] b) shared + void deallocate(void[] b) shared pure nothrow @system { free(b.ptr); } /// Ditto - @system bool reallocate(ref void[] b, size_t s) shared + bool reallocate(ref void[] b, size_t s) shared pure nothrow @system { if (!s) { @@ -673,10 +790,15 @@ struct Mallocator return true; } + static shared(Mallocator) it() pure nothrow @property @trusted + { + return cast(typeof(return)) _it; + } + /** Returns the global instance of this allocator type. The C heap allocator is thread-safe, therefore all of its methods and $(D it) itself are $(D shared). */ - static shared Mallocator it; + private static shared const Mallocator _it; } /// @@ -854,7 +976,7 @@ unittest /** Returns s rounded up to a multiple of base. */ -private size_t roundUpToMultipleOf(size_t s, uint base) +private size_t roundUpToMultipleOf(size_t s, uint base) pure nothrow @safe { assert(base); auto rem = s % base; @@ -872,7 +994,7 @@ unittest /** Returns s rounded up to a multiple of base. */ -private void[] roundStartToMultipleOf(void[] s, uint base) +private void[] roundStartToMultipleOf(void[] s, uint base) pure nothrow @trusted { assert(base); auto p = cast(void*) roundUpToMultipleOf( @@ -892,7 +1014,7 @@ unittest /** Returns $(D s) rounded up to the nearest power of 2. */ -private size_t roundUpToPowerOf2(size_t s) +private size_t roundUpToPowerOf2(size_t s) pure nothrow @safe { assert(s <= (size_t.max >> 1) + 1); --s; @@ -943,7 +1065,7 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void) static assert( !stateSize!Prefix || Allocator.alignment >= Prefix.alignof, "AffixAllocator does not work with allocators offering a smaller" - " alignment than the prefix alignment."); + ~ " alignment than the prefix alignment."); static assert(alignment % Suffix.alignof == 0, "This restriction could be relaxed in the future."); @@ -960,11 +1082,11 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void) parent allocator. */ static if (stateSize!Allocator) Allocator parent; - else alias Allocator.it parent; + else alias parent = Allocator.it; template Impl() { - size_t goodAllocSize(size_t s) + size_t goodAllocSize(size_t s) pure nothrow const { return parent.goodAllocSize(actualAllocationSize(s)); } @@ -1064,27 +1186,30 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void) which may use the global default). Also, the methods will be $(D shared) if the parent allocator defines them as such. */ - size_t goodAllocSize(size_t); + size_t goodAllocSize(size_t) pure nothrow const; /// Ditto - void[] allocate(size_t); + void[] allocate(size_t) pure nothrow; /// Ditto - bool owns(void[]); + bool owns(void[]) pure nothrow; /// Ditto - bool expand(ref void[] b, size_t delta); + bool expand(ref void[] b, size_t delta) pure nothrow; /// Ditto - bool reallocate(ref void[] b, size_t s); + bool reallocate(ref void[] b, size_t s)pure nothrow; /// Ditto - void deallocate(void[] b); + void deallocate(void[] b) pure nothrow; /// Ditto - void deallocateAll(); + void deallocateAll() pure nothrow; /** - The $(D it) singleton is defined if and only if the parent allocator has no state and defines its own $(D it) object. + The $(D it) singleton is defined if and only if the parent allocator has + no state and defines its own $(D it) object. */ static AffixAllocator it; /** - Affix access functions offering mutable references to the affixes of a block previously allocated with this allocator. $(D b) may not be null. They are defined if and only if the corresponding affix is not $(D void). + Affix access functions offering mutable references to the affixes of a + block previously allocated with this allocator. $(D b) may not be null. + They are defined if and only if the corresponding affix is not $(D void). Precondition: $(D b !is null) */ @@ -1118,7 +1243,7 @@ unittest unittest { - alias AffixAllocator!(Mallocator, size_t) A; + alias A = AffixAllocator!(Mallocator, size_t); auto b = A.it.allocate(10); A.it.prefix(b) = 10; assert(A.it.prefix(b) == 10); @@ -1129,9 +1254,10 @@ unittest } /** -Returns the number of most significant ones before a zero can be found in $(D x). If $(D x) contains no zeros (i.e. is equal to $(D ulong.max)), returns 64. +Returns the number of most significant ones before a zero can be found in $(D x). +If $(D x) contains no zeros (i.e. is equal to $(D ulong.max)), returns 64. */ -private uint leadingOnes(ulong x) +private uint leadingOnes(ulong x) pure nothrow @safe { uint result = 0; while (cast(long) x < 0) @@ -1156,7 +1282,7 @@ unittest /** Finds a run of contiguous ones in $(D x) of length at least $(D n). */ -private uint findContigOnes(ulong x, uint n) +private uint findContigOnes(ulong x, uint n) pure nothrow @safe { while (n > 1) { @@ -1184,7 +1310,7 @@ unittest /** Returns the number of trailing zeros of $(D x). */ -private uint trailingZeros(ulong x) +private uint trailingZeros(ulong x) pure nothrow @safe { uint result; while (result < 64 && !(x & (1UL << result))) @@ -1206,7 +1332,7 @@ unittest /* Unconditionally sets the bits from lsb through msb in w to zero. */ -private void setBits(ref ulong w, uint lsb, uint msb) +private void setBits(ref ulong w, uint lsb, uint msb) pure nothrow @safe { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); @@ -1225,7 +1351,7 @@ unittest /* Are bits from lsb through msb in w zero? If so, make then 1 and return the resulting w. Otherwise, just return 0. */ -private bool setBitsIfZero(ref ulong w, uint lsb, uint msb) +private bool setBitsIfZero(ref ulong w, uint lsb, uint msb) pure nothrow @safe { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); @@ -1234,14 +1360,24 @@ private bool setBitsIfZero(ref ulong w, uint lsb, uint msb) return true; } +unittest +{ + // TODO +} + // Assigns bits in w from lsb through msb to zero. -private void resetBits(ref ulong w, uint lsb, uint msb) +private void resetBits(ref ulong w, uint lsb, uint msb) pure nothrow @safe { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); w &= ~mask; } +unittest +{ + // TODO +} + /** $(D HeapBlock) implements a simple heap consisting of one contiguous area @@ -1329,7 +1465,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, _blocks = blocks; } - private void initialize() + private void initialize() pure nothrow @trusted { assert(_blocks); const controlBytes = ((_blocks + 63) / 64) * 8; @@ -1344,11 +1480,11 @@ struct HeapBlock(Allocator, size_t theBlockSize, _control = m[0 .. controlBytes / 8]; _control[] = 0; _payload = m[controlBytesRounded / 8 .. $]; - assert(_payload.length == _blocks * blockSize, - text(_payload.length, " != ", _blocks * blockSize)); + assert(_payload.length == _blocks * blockSize/+, + text(_payload.length, " != ", _blocks * blockSize)+/); } - private void initialize(void[] store) + private void initialize(void[] store) pure nothrow @trusted { assert(store.length); // Round store to be ulong-aligned @@ -1363,9 +1499,9 @@ struct HeapBlock(Allocator, size_t theBlockSize, auto blocks = cast(size_t) (approxBlocks + nextDown(1.0)); assert(blocks > 0); assert(blockSize); - assert(blocks * blockSize + ((blocks + 63) / 64) * 8 >= store.length, + assert(blocks * blockSize + ((blocks + 63) / 64) * 8 >= store.length/+, text(approxBlocks, " ", blocks, " ", blockSize, " ", - store.length)); + store.length)+/); while (blocks * blockSize + ((blocks + 63) / 64) * 8 > store.length) { --blocks; @@ -1385,13 +1521,13 @@ struct HeapBlock(Allocator, size_t theBlockSize, } private void initialize(ulong[] control, void[] payload, size_t blockSize) + pure nothrow @trusted { - enforce(payload.length % blockSize == 0, - text(payload.length, " % ", blockSize, " != 0")); + assert(payload.length % blockSize == 0); assert(payload.length / blockSize <= uint.max); _blocks = cast(uint) (payload.length / blockSize); const controlWords = (_blocks + 63) / 64; - enforce(controlWords == control.length); + assert(controlWords == control.length); _control = control; assert(control.equal(repeat(0, control.length))); _payload = payload; @@ -1434,7 +1570,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, BUGS: Neither $(D deallocateAll) nor the destructor free the original memory block. Either user code or the parent allocator should carry that. */ - @trusted void[] allocate(const size_t s) + void[] allocate(const size_t s) pure nothrow @trusted { if (!_control) { @@ -1486,7 +1622,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, } /// Ditto - bool owns(void[] b) const + bool owns(void[] b) const pure nothrow @trusted { return b.ptr >= _payload.ptr && b.ptr + b.length <= _payload.ptr + _payload.length @@ -1500,7 +1636,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, 0). Otherwise, returns a tuple with the next position to search. */ private Tuple!(size_t, uint) allocateAt(size_t wordIdx, uint msbIdx, - size_t blocks, ref void[] result) + size_t blocks, ref void[] result) pure nothrow @trusted { assert(blocks > 0); assert(wordIdx < _control.length); @@ -1557,9 +1693,9 @@ struct HeapBlock(Allocator, size_t theBlockSize, return available; } - private void[] smallAlloc(uint blocks) + private void[] smallAlloc(uint blocks) pure nothrow @trusted { - assert(blocks >= 2 && blocks <= 64, text(blocks)); + assert(blocks >= 2 && blocks <= 64/+, text(blocks)+/); foreach (i; _startIdx .. _control.length) { // Test within the current 64-bit word @@ -1589,7 +1725,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, return null; } - private void[] hugeAlloc(size_t blocks) + private void[] hugeAlloc(size_t blocks) pure nothrow @trusted { assert(blocks > 64); void[] result; @@ -1629,7 +1765,7 @@ struct HeapBlock(Allocator, size_t theBlockSize, } /// Ditto - @trusted bool expand(ref void[] b, size_t delta) + bool expand(ref void[] b, size_t delta) pure nothrow @trusted { //debug writefln("expand(%s, %s, %s)", b, minDelta, desiredDelta); if (b is null) @@ -1664,14 +1800,14 @@ struct HeapBlock(Allocator, size_t theBlockSize, return false; } // Expansion successful - assert(p.ptr == b.ptr + blocksOld * blockSize, - text(p.ptr, " != ", b.ptr + blocksOld * blockSize)); + assert(p.ptr == b.ptr + blocksOld * blockSize/+, + text(p.ptr, " != ", b.ptr + blocksOld * blockSize)+/); b = b.ptr[0 .. b.length + delta]; return true; } /// Ditto - @system bool reallocate(ref void[] b, size_t newSize) + bool reallocate(ref void[] b, size_t newSize) pure nothrow @system { if (newSize == 0) { @@ -1902,10 +2038,10 @@ struct FallbackAllocator(Primary, Fallback) If both $(D Primary) and $(D Fallback) are stateless, $(D FallbackAllocator) defines a static instance $(D it). */ - static if (!stateSize!Primary && !stateSize!Fallback) + /+static if (!stateSize!Primary && !stateSize!Fallback) { static FallbackAllocator it; - } + }+/ /** The alignment offered is the minimum of the two allocators' alignment. @@ -1916,7 +2052,7 @@ struct FallbackAllocator(Primary, Fallback) Allocates memory trying the primary allocator first. If it returns $(D null), the fallback allocator is tried. */ - void[] allocate(size_t s) + void[] allocate(size_t s) pure nothrow @safe { auto result = primary.allocate(s); return result ? result : fallback.allocate(s); @@ -1959,12 +2095,12 @@ struct FallbackAllocator(Primary, Fallback) allocation from $(D fallback) to $(D primary). */ - bool reallocate(ref void[] b, size_t newSize) + bool reallocate(ref void[] b, size_t newSize) pure nothrow @trusted { - bool crossAllocatorMove(From, To)(ref From from, ref To to) + bool crossAllocatorMove(From, To)(auto ref From from, auto ref To to) { auto b1 = to.allocate(newSize); - if (!b1) return false; + if (b1 is null) return false; if (b.length < newSize) b1[0 .. b.length] = b[]; else b1[] = b[0 .. newSize]; static if (hasMember!(From, "deallocate")) @@ -2004,7 +2140,7 @@ struct FallbackAllocator(Primary, Fallback) */ static if (hasMember!(Primary, "deallocate") || hasMember!(Fallback, "deallocate")) - void deallocate(void[] b) + void deallocate(void[] b) pure nothrow @trusted { if (primary.owns(b)) { @@ -2014,7 +2150,7 @@ struct FallbackAllocator(Primary, Fallback) else { static if (hasMember!(Fallback, "deallocate")) - return fallback.deallocate(b); + fallback.deallocate(b); } } } @@ -2022,7 +2158,7 @@ struct FallbackAllocator(Primary, Fallback) /// unittest { - FallbackAllocator!(InSituRegion!16384, GCAllocator) a; + FallbackAllocator!(InSituRegion!16_384, GCAllocator) a; // This allocation uses the stack auto b1 = a.allocate(1024); assert(b1.length == 1024, text(b1.length)); @@ -2079,7 +2215,7 @@ struct Freelist(ParentAllocator, else { size_t _min = chooseAtRuntime; - @property size_t min() const + @property size_t min() const nothrow pure @safe { assert(_min != chooseAtRuntime); return _min; @@ -2102,7 +2238,7 @@ struct Freelist(ParentAllocator, } } - private bool tooSmall(size_t n) const + private bool tooSmall(size_t n) const nothrow pure @safe { static if (minSize == 0) return false; else return n < min; @@ -2123,13 +2259,13 @@ struct Freelist(ParentAllocator, } } - private bool tooLarge(size_t n) const + private bool tooLarge(size_t n) const nothrow pure @safe { static if (maxSize == unbounded) return false; else return n > max; } - private bool inRange(size_t n) const + private bool inRange(size_t n) const nothrow pure @safe { static if (minSize == maxSize && minSize != chooseAtRuntime) return n == maxSize; @@ -2206,7 +2342,7 @@ struct Freelist(ParentAllocator, Returns $(D max) for sizes in the interval $(D [min, max]), and $(D parent.goodAllocSize(bytes)) otherwise. */ - size_t goodAllocSize(size_t bytes) + size_t goodAllocSize(size_t bytes) const nothrow pure @safe { if (inRange(bytes)) return maxSize == unbounded ? bytes : max; return parent.goodAllocSize(bytes); @@ -2215,12 +2351,7 @@ struct Freelist(ParentAllocator, /** Allocates memory either off of the free list or from the parent allocator. */ - void[] allocate(size_t bytes) - in - { - assert (_root !is null); - } - body + void[] allocate(size_t bytes) pure nothrow @trusted { assert(bytes < size_t.max / 2); if (!inRange(bytes)) return parent.allocate(bytes); @@ -2234,7 +2365,7 @@ struct Freelist(ParentAllocator, return result; } - private void[] allocateFresh(const size_t bytes) + private void[] allocateFresh(const size_t bytes) pure nothrow @trusted { assert(!_root); assert(bytes == max || max == unbounded); @@ -2251,9 +2382,9 @@ struct Freelist(ParentAllocator, } else { - assert((parent.alignment + bytes) % Node.alignof == 0, + assert((parent.alignment + bytes) % Node.alignof == 0/+, text("(", parent.alignment, " + ", bytes, ") % ", - Node.alignof)); + Node.alignof)+/); } auto data = parent.allocate(nodesAtATime * bytes); @@ -2282,7 +2413,7 @@ struct Freelist(ParentAllocator, Freelist) handle deallocations of objects of the appropriate size, even for allocators that don't support $(D owns) (such as $(D Mallocator)). */ - bool owns(void[] b) + bool owns(void[] b) const pure nothrow @safe { if (inRange(b.length)) return true; static if (hasMember!(ParentAllocator, "owns")) @@ -2560,7 +2691,7 @@ struct SharedFreelist(ParentAllocator, do { oldRoot = _root; // atomic load - next = oldRoot.next; // atomic load + next = oldRoot is null ? null : oldRoot.next; // atomic load } while (!cas(&_root, oldRoot, next)); // great, snatched the root @@ -2657,7 +2788,8 @@ struct SharedFreelist(ParentAllocator, } } -unittest +// This deadlocks +version (none) unittest { import core.thread, std.concurrency; @@ -2723,14 +2855,14 @@ private struct BasicRegion(uint minAlign = platformAlignment) /** Constructs a region backed by a user-provided store. */ - this(void[] store) + this(void[] store) pure nothrow @trusted { static if (minAlign > 1) { auto newStore = cast(void*) roundUpToMultipleOf( - cast(ulong) store.ptr, + cast(size_t) store.ptr, alignment); - enforce(newStore <= store.ptr + store.length); + assert(newStore <= store.ptr + store.length); _current = newStore; } else @@ -2752,7 +2884,7 @@ private struct BasicRegion(uint minAlign = platformAlignment) enum uint alignment = minAlign; /// Ditto - void[] allocate(size_t bytes) + void[] allocate(size_t bytes) pure nothrow @trusted { static if (minAlign > 1) const rounded = bytes.roundUpToMultipleOf(alignment); @@ -2772,7 +2904,7 @@ private struct BasicRegion(uint minAlign = platformAlignment) // Just bump the pointer to the next good allocation auto save = _current; _current = cast(void*) roundUpToMultipleOf( - cast(ulong) _current, a); + cast(size_t) _current, a); if (auto b = allocate(bytes)) return b; // Failed, rollback _current = save; @@ -2829,7 +2961,7 @@ struct Region(uint minAlign = platformAlignment) Constructs a $(D Region) object backed by $(D buffer), which must be aligned to $(D minAlign). */ - this(void[] buffer) + this(void[] buffer) pure nothrow @safe { base = BasicRegion!minAlign(buffer); assert(buffer.ptr !is &this); @@ -2932,7 +3064,7 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) { assert(!_crt); _crt = cast(void*) roundUpToMultipleOf( - cast(ulong) _store.ptr, alignment); + cast(size_t) _store.ptr, alignment); _end = _store.ptr + _store.length; } @@ -2941,7 +3073,12 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) accommodate the request. For efficiency reasons, if $(D bytes == 0) the function returns an empty non-null slice. */ - void[] allocate(size_t bytes) + void[] allocate(size_t bytes) pure nothrow @trusted + out (result) + { + assert (result is null || owns(result)); + } + body { // Oddity: we don't return null for null allocation. Instead, we return // an empty slice with a non-null ptr. @@ -2972,7 +3109,7 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) // Just bump the pointer to the next good allocation auto save = _crt; _crt = cast(void*) roundUpToMultipleOf( - cast(ulong) _crt, a); + cast(size_t) _crt, a); if (auto b = allocate(bytes)) return b; // Failed, rollback _crt = save; @@ -2984,7 +3121,7 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) allocation. For efficiency reasons, if $(D b is null) the function returns $(D false). */ - bool owns(void[] b) const + bool owns(const void[] b) const nothrow pure @trusted { // No nullptr return b.ptr >= _store.ptr @@ -2994,7 +3131,7 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) /** Deallocates all memory allocated with this allocator. */ - void deallocateAll() + void deallocateAll() pure nothrow @safe { _crt = _store.ptr; } @@ -3715,7 +3852,14 @@ struct CascadingAllocator(alias make) enum uint alignment = Allocator.alignment; /// Ditto - void[] allocate(size_t s) + void[] allocate(size_t s) pure nothrow @trusted + out (res) + { + import std.string; + assert (res.length == 0 || res.length == s, + "res.length = %d, s = %d".format(res.length, s)); + } + body { auto result = allocateNoGrow(s); if (result) return result; @@ -3805,7 +3949,8 @@ struct CascadingAllocator(alias make) if (!_root) return false; for (auto n = _root; ; n = n.next) { - if (n.a.owns(b) && n.a.reallocate(b, s)) return true; + static if (hasMember!(Allocator, "owns")) + if (n.a.owns(b) && n.a.reallocate(b, s)) return true; if (!n.nextIsInitialized) break; } // Failed, but we may find new memory in a new node. @@ -3870,7 +4015,7 @@ struct CascadingAllocator(alias make) unittest { // Create an allocator based upon 4MB regions, fetched from the GC heap. - CascadingAllocator!({ return Region!()(new void[1024 * 4096]); }) a; + CascadingAllocator!(function() nothrow { return Region!()(new void[1024 * 4096]); }) a; auto b1 = a.allocate(1024 * 8192); assert(b1 is null); // can't allocate more than 4MB at a time b1 = a.allocate(1024 * 10); @@ -3997,21 +4142,21 @@ struct Segregator(size_t threshold, SmallAllocator, LargeAllocator) template Impl() { - void[] allocate(size_t s) + void[] allocate(size_t s) nothrow pure @trusted { return s <= threshold ? _small.allocate(s) : _large.allocate(s); } static if (hasMember!(SmallAllocator, "deallocate") && hasMember!(LargeAllocator, "deallocate")) - void deallocate(void[] data) + void deallocate(void[] data) nothrow pure @trusted { data.length <= threshold ? _small.deallocate(data) : _large.deallocate(data); } - size_t goodAllocSize(size_t s) + size_t goodAllocSize(size_t s) const nothrow pure @safe { return s <= threshold ? _small.goodAllocSize(s) @@ -4020,7 +4165,7 @@ struct Segregator(size_t threshold, SmallAllocator, LargeAllocator) static if (hasMember!(SmallAllocator, "owns") && hasMember!(LargeAllocator, "owns")) - bool owns(void[] b) + bool owns(void[] b) const nothrow pure @safe { return b.length <= threshold ? _small.owns(b) : _large.owns(b); } @@ -4087,7 +4232,11 @@ struct Segregator(size_t threshold, SmallAllocator, LargeAllocator) static if (sharedMethods) { - static shared Segregator it; + static shared(typeof(this)) it() pure nothrow @property @trusted + { + return cast(typeof(return)) _it; + } + private static const shared Segregator _it; shared { mixin Impl!(); } } else @@ -4312,7 +4461,7 @@ class CAllocator { /// Returns the alignment offered. By default this method returns $(D /// platformAlignment). - @property uint alignment() + uint alignment() pure nothrow const @property { return platformAlignment; } @@ -4323,7 +4472,7 @@ class CAllocator throw an exception if it does allow setting the alignment but an invalid value is passed. */ - @property bool alignment(uint) + @property bool alignment(uint) pure nothrow @property { return false; } @@ -4333,7 +4482,7 @@ class CAllocator fragmentation. By default returns $(D s) rounded up to the nearest multiple of $(D alignment). */ - size_t goodAllocSize(size_t s) + size_t goodAllocSize(size_t s) pure nothrow const @property { return s.roundUpToMultipleOf(alignment); } @@ -4341,7 +4490,7 @@ class CAllocator /** Allocates memory. */ - abstract void[] allocate(size_t); + abstract void[] allocate(size_t) pure nothrow @safe; /** Returns $(D true) if the allocator supports $(D owns). By default returns @@ -4362,17 +4511,17 @@ class CAllocator } /// Expands a memory block in place. - abstract bool expand(ref void[], size_t); + abstract bool expand(ref void[], size_t) pure nothrow; /// Reallocates a memory block. - abstract bool reallocate(ref void[] b, size_t); + abstract bool reallocate(ref void[] b, size_t) pure nothrow; /// Deallocates a memory block. Returns $(D false) if deallocation is not /// supported. - abstract bool deallocate(void[]); + abstract bool deallocate(void[]) pure nothrow; /// Deallocates all memory. Returns $(D false) if not supported. - abstract bool deallocateAll(); + abstract bool deallocateAll() pure nothrow; /// Returns $(D true) if allocator supports $(D allocateAll). By default /// returns $(D false). @@ -4405,7 +4554,7 @@ class CAllocatorImpl(Allocator) : CAllocator else alias impl = Allocator.it; /// Returns $(D impl.alignment). - override @property uint alignment() + override uint alignment() pure nothrow const @property { return impl.alignment; } @@ -4414,7 +4563,7 @@ class CAllocatorImpl(Allocator) : CAllocator If $(D Allocator) supports alignment setting, performs it and returns $(D true). Otherwise, returns $(D false). */ - override @property bool alignment(uint a) + override bool alignment(uint a) pure nothrow const @property { static if (is(typeof(impl.alignment = a))) { @@ -4430,7 +4579,7 @@ class CAllocatorImpl(Allocator) : CAllocator /** Returns $(D impl.goodAllocSize(s)). */ - override size_t goodAllocSize(size_t s) + override size_t goodAllocSize(size_t s) pure nothrow const @property { return impl.goodAllocSize(s); } @@ -4438,7 +4587,7 @@ class CAllocatorImpl(Allocator) : CAllocator /** Returns $(D impl.allocate(s)). */ - override void[] allocate(size_t s) + override void[] allocate(size_t s) pure nothrow @safe { return impl.allocate(s); } @@ -4446,7 +4595,7 @@ class CAllocatorImpl(Allocator) : CAllocator /** Returns $(D true) if $(D Allocator) supports $(D owns). */ - override bool supportsOwns() + override bool supportsOwns() pure nothrow const @safe { return hasMember!(Allocator, "owns"); } @@ -4462,7 +4611,7 @@ class CAllocatorImpl(Allocator) : CAllocator } /// Returns $(D impl.expand(b, s)) if defined, $(D false) otherwise. - override bool expand(ref void[] b, size_t s) + override bool expand(ref void[] b, size_t s) pure nothrow { static if (hasMember!(Allocator, "expand")) return impl.expand(b, s); @@ -4478,7 +4627,7 @@ class CAllocatorImpl(Allocator) : CAllocator /// Calls $(D impl.deallocate(b)) and returns $(D true) if defined, /// otherwise returns $(D false). - override bool deallocate(void[] b) + override bool deallocate(void[] b) pure nothrow { static if (hasMember!(Allocator, "deallocate")) { @@ -4493,7 +4642,7 @@ class CAllocatorImpl(Allocator) : CAllocator /// Calls $(D impl.deallocateAll()) and returns $(D true) if defined, /// otherwise returns $(D false). - override bool deallocateAll() + override bool deallocateAll() pure nothrow { static if (hasMember!(Allocator, "deallocateAll")) { @@ -4508,7 +4657,7 @@ class CAllocatorImpl(Allocator) : CAllocator /// Returns $(D true) if allocator supports $(D allocateAll). By default /// returns $(D false). - override bool supportsAllocateAll() + override bool supportsAllocateAll() pure nothrow const { return hasMember!(Allocator, "allocateAll"); } @@ -4518,7 +4667,7 @@ class CAllocatorImpl(Allocator) : CAllocator returns $(D impl.allocateAll()). */ static if (hasMember!(Allocator, "allocateAll")) - override void[] allocateAll() + override void[] allocateAll() pure nothrow { return impl.allocateAll(); } diff --git a/stdx/d/ast.d b/std/d/ast.d similarity index 88% rename from stdx/d/ast.d rename to std/d/ast.d index 03c1a82..04a5c71 100644 --- a/stdx/d/ast.d +++ b/std/d/ast.d @@ -14,9 +14,9 @@ * Source: $(PHOBOSSRC std/d/_ast.d) */ -module stdx.d.ast; +module std.d.ast; -import stdx.d.lexer; +import std.d.lexer; import std.traits; import std.algorithm; import std.array; @@ -32,56 +32,56 @@ abstract class ASTVisitor { public: - void visit(const ExpressionNode n) - { - if (cast(AddExpression) n) visit(cast(AddExpression) n); - else if (cast(AndAndExpression) n) visit(cast(AndAndExpression) n); - else if (cast(AndExpression) n) visit(cast(AndExpression) n); - else if (cast(AsmAddExp) n) visit(cast(AsmAddExp) n); - else if (cast(AsmAndExp) n) visit(cast(AsmAndExp) n); - else if (cast(AsmEqualExp) n) visit(cast(AsmEqualExp) n); - else if (cast(AsmLogAndExp) n) visit(cast(AsmLogAndExp) n); - else if (cast(AsmLogOrExp) n) visit(cast(AsmLogOrExp) n); - else if (cast(AsmMulExp) n) visit(cast(AsmMulExp) n); - else if (cast(AsmOrExp) n) visit(cast(AsmOrExp) n); - else if (cast(AsmRelExp) n) visit(cast(AsmRelExp) n); - else if (cast(AsmShiftExp) n) visit(cast(AsmShiftExp) n); - else if (cast(AssertExpression) n) visit(cast(AssertExpression) n); - else if (cast(AssignExpression) n) visit(cast(AssignExpression) n); - else if (cast(CmpExpression) n) visit(cast(CmpExpression) n); - else if (cast(DeleteExpression) n) visit(cast(DeleteExpression) n); - else if (cast(EqualExpression) n) visit(cast(EqualExpression) n); - else if (cast(Expression) n) visit(cast(Expression) n); - else if (cast(FunctionCallExpression) n) visit(cast(FunctionCallExpression) n); - else if (cast(FunctionLiteralExpression) n) visit(cast(FunctionLiteralExpression) n); - else if (cast(IdentityExpression) n) visit(cast(IdentityExpression) n); - else if (cast(ImportExpression) n) visit(cast(ImportExpression) n); - else if (cast(IndexExpression) n) visit(cast(IndexExpression) n); - else if (cast(InExpression) n) visit(cast(InExpression) n); - else if (cast(IsExpression) n) visit(cast(IsExpression) n); - else if (cast(LambdaExpression) n) visit(cast(LambdaExpression) n); - else if (cast(MixinExpression) n) visit(cast(MixinExpression) n); - else if (cast(MulExpression) n) visit(cast(MulExpression) n); - else if (cast(NewAnonClassExpression) n) visit(cast(NewAnonClassExpression) n); - else if (cast(NewExpression) n) visit(cast(NewExpression) n); - else if (cast(OrExpression) n) visit(cast(OrExpression) n); - else if (cast(OrOrExpression) n) visit(cast(OrOrExpression) n); - else if (cast(PostIncDecExpression) n) visit(cast(PostIncDecExpression) n); - else if (cast(PowExpression) n) visit(cast(PowExpression) n); - else if (cast(PragmaExpression) n) visit(cast(PragmaExpression) n); - else if (cast(PreIncDecExpression) n) visit(cast(PreIncDecExpression) n); - else if (cast(PrimaryExpression) n) visit(cast(PrimaryExpression) n); - else if (cast(RelExpression) n) visit(cast(RelExpression) n); - else if (cast(ShiftExpression) n) visit(cast(ShiftExpression) n); - else if (cast(SliceExpression) n) visit(cast(SliceExpression) n); - else if (cast(TemplateMixinExpression) n) visit(cast(TemplateMixinExpression) n); - else if (cast(TernaryExpression) n) visit(cast(TernaryExpression) n); - else if (cast(TraitsExpression) n) visit(cast(TraitsExpression) n); - else if (cast(TypeidExpression) n) visit(cast(TypeidExpression) n); - else if (cast(TypeofExpression) n) visit(cast(TypeofExpression) n); - else if (cast(UnaryExpression) n) visit(cast(UnaryExpression) n); - else if (cast(XorExpression) n) visit(cast(XorExpression) n); - } + void visit(const ExpressionNode n) + { + if (cast(AddExpression) n) visit(cast(AddExpression) n); + else if (cast(AndAndExpression) n) visit(cast(AndAndExpression) n); + else if (cast(AndExpression) n) visit(cast(AndExpression) n); + else if (cast(AsmAddExp) n) visit(cast(AsmAddExp) n); + else if (cast(AsmAndExp) n) visit(cast(AsmAndExp) n); + else if (cast(AsmEqualExp) n) visit(cast(AsmEqualExp) n); + else if (cast(AsmLogAndExp) n) visit(cast(AsmLogAndExp) n); + else if (cast(AsmLogOrExp) n) visit(cast(AsmLogOrExp) n); + else if (cast(AsmMulExp) n) visit(cast(AsmMulExp) n); + else if (cast(AsmOrExp) n) visit(cast(AsmOrExp) n); + else if (cast(AsmRelExp) n) visit(cast(AsmRelExp) n); + else if (cast(AsmShiftExp) n) visit(cast(AsmShiftExp) n); + else if (cast(AssertExpression) n) visit(cast(AssertExpression) n); + else if (cast(AssignExpression) n) visit(cast(AssignExpression) n); + else if (cast(CmpExpression) n) visit(cast(CmpExpression) n); + else if (cast(DeleteExpression) n) visit(cast(DeleteExpression) n); + else if (cast(EqualExpression) n) visit(cast(EqualExpression) n); + else if (cast(Expression) n) visit(cast(Expression) n); + else if (cast(FunctionCallExpression) n) visit(cast(FunctionCallExpression) n); + else if (cast(FunctionLiteralExpression) n) visit(cast(FunctionLiteralExpression) n); + else if (cast(IdentityExpression) n) visit(cast(IdentityExpression) n); + else if (cast(ImportExpression) n) visit(cast(ImportExpression) n); + else if (cast(IndexExpression) n) visit(cast(IndexExpression) n); + else if (cast(InExpression) n) visit(cast(InExpression) n); + else if (cast(IsExpression) n) visit(cast(IsExpression) n); + else if (cast(LambdaExpression) n) visit(cast(LambdaExpression) n); + else if (cast(MixinExpression) n) visit(cast(MixinExpression) n); + else if (cast(MulExpression) n) visit(cast(MulExpression) n); + else if (cast(NewAnonClassExpression) n) visit(cast(NewAnonClassExpression) n); + else if (cast(NewExpression) n) visit(cast(NewExpression) n); + else if (cast(OrExpression) n) visit(cast(OrExpression) n); + else if (cast(OrOrExpression) n) visit(cast(OrOrExpression) n); + else if (cast(PostIncDecExpression) n) visit(cast(PostIncDecExpression) n); + else if (cast(PowExpression) n) visit(cast(PowExpression) n); + else if (cast(PragmaExpression) n) visit(cast(PragmaExpression) n); + else if (cast(PreIncDecExpression) n) visit(cast(PreIncDecExpression) n); + else if (cast(PrimaryExpression) n) visit(cast(PrimaryExpression) n); + else if (cast(RelExpression) n) visit(cast(RelExpression) n); + else if (cast(ShiftExpression) n) visit(cast(ShiftExpression) n); + else if (cast(SliceExpression) n) visit(cast(SliceExpression) n); + else if (cast(TemplateMixinExpression) n) visit(cast(TemplateMixinExpression) n); + else if (cast(TernaryExpression) n) visit(cast(TernaryExpression) n); + else if (cast(TraitsExpression) n) visit(cast(TraitsExpression) n); + else if (cast(TypeidExpression) n) visit(cast(TypeidExpression) n); + else if (cast(TypeofExpression) n) visit(cast(TypeofExpression) n); + else if (cast(UnaryExpression) n) visit(cast(UnaryExpression) n); + else if (cast(XorExpression) n) visit(cast(XorExpression) n); + } /** */ void visit(const AddExpression addExpression) { addExpression.accept(this); } /** */ void visit(const AliasDeclaration aliasDeclaration) { aliasDeclaration.accept(this); } @@ -311,21 +311,58 @@ template visitIfNotNull(fields ...) } } +mixin template OpEquals() +{ + override bool opEquals(Object other) const + { + mixin (generateOpEquals!(typeof(this))); + } +} + +template generateOpEquals(T) +{ + template opEqualsPart(p ...) + { + import std.traits; + static if (p.length == 0) + enum opEqualsPart = ""; + else static if (!isSomeFunction!(__traits(getMember, T, p[0])) + && p[0] != "line" && p[0] != "column" && p[0] != "startLocation" + && p[0] != "endLocation") + { + static if (typeof(__traits(getMember, T, p[0])).stringof[$ - 2 .. $] == "[]") + { + enum opEqualsPart = "\nif (obj." ~ p[0] ~ ".length != this." ~ p[0] ~ ".length) return false;\n" + ~ "foreach (i; 0 .. this." ~ p[0] ~ ".length)\n" + ~ "\tif (this." ~ p[0] ~ "[i] != obj." ~ p[0] ~ "[i]) return false;"; + } + else + enum opEqualsPart = "\nif (obj." ~ p[0] ~ " != this." ~ p[0] ~ ") return false;" ~ opEqualsPart!(p[1 .. $]); + } + else + enum opEqualsPart = opEqualsPart!(p[1 .. $]); + } + enum generateOpEquals = T.stringof ~ " obj = cast(" ~ T.stringof ~ ") other;\n" + ~ "if (obj is null) return false;" + ~ opEqualsPart!(__traits(derivedMembers, T)) ~ "\n" + ~ "return true;"; +} + abstract class ExpressionNode : ASTNode { public: - override void accept(ASTVisitor visitor) const - { - assert (false); - } + override void accept(ASTVisitor visitor) const + { + assert (false); + } } mixin template BinaryExpressionBody() { ExpressionNode left; ExpressionNode right; - size_t line; - size_t column; + size_t line; + size_t column; } /// @@ -336,6 +373,7 @@ public: { mixin (visitIfNotNull!(left, right)); } + mixin OpEquals; /** */ IdType operator; mixin BinaryExpressionBody; } @@ -348,6 +386,7 @@ public: { mixin (visitIfNotNull!(linkageAttribute, type, name, initializers)); } + mixin OpEquals; /** */ LinkageAttribute linkageAttribute; /** */ Type type; /** */ Token name; @@ -363,7 +402,7 @@ public: { mixin (visitIfNotNull!(name, type)); } - + mixin OpEquals; /** */ Token name; /** */ Type type; } @@ -376,6 +415,7 @@ public: { mixin (visitIfNotNull!(identifier)); } + mixin OpEquals; /** */ Token identifier; } @@ -387,6 +427,7 @@ public: { mixin (visitIfNotNull!(intLiteral)); } + mixin OpEquals; /** */ Token intLiteral; } @@ -398,6 +439,7 @@ public: { mixin (visitIfNotNull!(left, right)); } + mixin OpEquals; mixin BinaryExpressionBody; } @@ -409,6 +451,7 @@ public: { mixin (visitIfNotNull!(left, right)); } + mixin OpEquals; mixin BinaryExpressionBody; } @@ -420,6 +463,7 @@ public: { mixin (visitIfNotNull!(items)); } + mixin OpEquals; /** */ AssignExpression[] items; } @@ -431,6 +475,7 @@ public: { mixin (visitIfNotNull!(argumentList)); } + mixin OpEquals; /** */ ArgumentList argumentList; } @@ -442,6 +487,7 @@ public: { mixin (visitIfNotNull!(arrayMemberInitializations)); } + mixin OpEquals; /** */ ArrayMemberInitialization[] arrayMemberInitializations; } @@ -453,6 +499,7 @@ public: { mixin (visitIfNotNull!(argumentList)); } + mixin OpEquals; /** */ ArgumentList argumentList; } @@ -464,6 +511,7 @@ public: { mixin (visitIfNotNull!(assignExpression, nonVoidInitializer)); } + mixin OpEquals; /** */ AssignExpression assignExpression; /** */ NonVoidInitializer nonVoidInitializer; } @@ -473,6 +521,7 @@ final class AsmAddExp : ExpressionNode { public: mixin (DEFAULT_ACCEPT); + mixin OpEquals; /** */ IdType operator; mixin BinaryExpressionBody; } @@ -482,6 +531,7 @@ final class AsmAndExp : ExpressionNode { public: mixin (DEFAULT_ACCEPT); + mixin OpEquals; mixin BinaryExpressionBody; } @@ -490,6 +540,7 @@ final class AsmBrExp : ASTNode { public: mixin (DEFAULT_ACCEPT); + mixin OpEquals; /** */ AsmBrExp asmBrExp; /** */ AsmEqualExp asmEqualExp; /** */ AsmUnaExp asmUnaExp; @@ -501,6 +552,7 @@ final class AsmEqualExp : ExpressionNode public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; + mixin OpEquals; /** */ Token operator; } @@ -509,6 +561,7 @@ final class AsmExp : ASTNode { public: mixin (DEFAULT_ACCEPT); + mixin OpEquals; /** */ AsmLogOrExp left; /** */ AsmExp middle; /** */ AsmExp right; @@ -519,6 +572,7 @@ final class AsmInstruction : ASTNode { public: mixin (DEFAULT_ACCEPT); + mixin OpEquals; /** */ Token identifierOrIntegerOrOpcode; /** */ bool hasAlign; /** */ AsmExp asmExp; @@ -531,6 +585,7 @@ final class AsmLogAndExp : ExpressionNode public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -539,6 +594,7 @@ final class AsmLogOrExp : ExpressionNode public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -548,6 +604,7 @@ public: mixin (DEFAULT_ACCEPT); /** */ IdType operator; mixin BinaryExpressionBody; + mixin OpEquals; } @@ -557,6 +614,7 @@ final class AsmOrExp : ExpressionNode public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -567,6 +625,7 @@ public: /** */ IdentifierChain identifierChain; /** */ Register register; /** */ Token token; + mixin OpEquals; } /// @@ -576,6 +635,7 @@ public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; /** */ Token operator; + mixin OpEquals; } /// @@ -585,6 +645,7 @@ public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; /** */ Token operator; + mixin OpEquals; } /// @@ -593,6 +654,7 @@ final class AsmStatement : ASTNode public: mixin (DEFAULT_ACCEPT); /** */ AsmInstruction[] asmInstructions; + mixin OpEquals; } /// @@ -602,6 +664,7 @@ public: mixin (DEFAULT_ACCEPT); /** */ Token left; /** */ Token right; + mixin OpEquals; } /// @@ -614,6 +677,7 @@ public: /** */ Token prefix; /** */ AsmPrimaryExp asmPrimaryExp; /** */ AsmUnaExp asmUnaExp; + mixin OpEquals; } /// @@ -622,6 +686,7 @@ final class AsmXorExp : ASTNode public: mixin (DEFAULT_ACCEPT); mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -634,6 +699,7 @@ public: } /** */ AssignExpression assertion; /** */ AssignExpression message; + mixin OpEquals; } /// @@ -647,6 +713,9 @@ public: /** */ ExpressionNode ternaryExpression; /** */ ExpressionNode assignExpression; /** */ IdType operator; + size_t line; + size_t column; + mixin OpEquals; } /// @@ -658,6 +727,7 @@ public: mixin (visitIfNotNull!(keyValuePairs)); } /** */ KeyValuePairs keyValuePairs; + mixin OpEquals; } /// @@ -671,6 +741,7 @@ public: /** */ FunctionCallExpression functionCallExpression; /** */ ArgumentList argumentList; /** */ Token identifier; + mixin OpEquals; } /// @@ -687,6 +758,7 @@ public: /** */ PragmaExpression pragmaExpression; /** */ StorageClass storageClass; /** */ IdType attribute; + mixin OpEquals; } /// @@ -697,6 +769,7 @@ final class AttributeDeclaration : ASTNode mixin (visitIfNotNull!(attribute)); } /** */ Attribute attribute; + mixin OpEquals; } /// @@ -712,6 +785,7 @@ public: } /** */ Token[] identifiers; /** */ Initializer[] initializers; + mixin OpEquals; } /// @@ -734,6 +808,7 @@ public: size_t endLocation; /** */ DeclarationsAndStatements declarationsAndStatements; + mixin OpEquals; } /// @@ -745,6 +820,7 @@ public: mixin (visitIfNotNull!(blockStatement)); } /** */ BlockStatement blockStatement; + mixin OpEquals; } /// @@ -756,6 +832,7 @@ public: mixin (visitIfNotNull!(label)); } /** */ Token label; + mixin OpEquals; } /// @@ -768,6 +845,7 @@ public: } /** */ IdentifierOrTemplateChain identifierOrTemplateChain; /** */ TypeofExpression typeofExpression; + mixin OpEquals; } /// @@ -779,6 +857,7 @@ public: mixin (visitIfNotNull!(items)); } /** */ BaseClass[] items; + mixin OpEquals; } /// @@ -792,6 +871,7 @@ public: /** */ AssignExpression low; /** */ AssignExpression high; /** */ DeclarationsAndStatements declarationsAndStatements; + mixin OpEquals; } /// @@ -804,6 +884,7 @@ public: } /** */ ArgumentList argumentList; /** */ DeclarationsAndStatements declarationsAndStatements; + mixin OpEquals; } /// @@ -817,6 +898,7 @@ public: /** */ Type type; /** */ CastQualifier castQualifier; /** */ UnaryExpression unaryExpression; + mixin OpEquals; } /// @@ -829,6 +911,7 @@ public: } /** */ Token first; /** */ Token second; + mixin OpEquals; } /// @@ -841,6 +924,7 @@ public: } /** */ Catch[] catches; /** */ LastCatch lastCatch; + mixin OpEquals; } /// @@ -854,6 +938,7 @@ public: /** */ Type type; /** */ Token identifier; /** */ DeclarationOrStatement declarationOrStatement; + mixin OpEquals; } /// @@ -872,6 +957,7 @@ public: /** */ BaseClassList baseClassList; /** */ StructBody structBody; /** */ string comment; + mixin OpEquals; } /// @@ -888,6 +974,7 @@ public: /** */ ExpressionNode identityExpression; /** */ ExpressionNode relExpression; /** */ ExpressionNode inExpression; + mixin OpEquals; } /// @@ -901,6 +988,7 @@ public: /** */ VersionCondition versionCondition; /** */ DebugCondition debugCondition; /** */ StaticIfCondition staticIfCondition; + mixin OpEquals; } /// @@ -914,6 +1002,7 @@ public: /** */ CompileCondition compileCondition; /** */ Declaration[] trueDeclarations; /** */ Declaration falseDeclaration; + mixin OpEquals; } /// @@ -927,6 +1016,7 @@ public: /** */ CompileCondition compileCondition; /** */ DeclarationOrStatement trueStatement; /** */ DeclarationOrStatement falseStatement; + mixin OpEquals; } /// @@ -938,6 +1028,7 @@ public: mixin (visitIfNotNull!(expression)); } /** */ Expression expression; + mixin OpEquals; } /// @@ -955,7 +1046,10 @@ public: /** */ MemberFunctionAttribute[] memberFunctionAttributes; /** */ TemplateParameters templateParameters; /** */ size_t location; + /** */ size_t line; + /** */ size_t column; /** */ string comment; + mixin OpEquals; } /// @@ -967,6 +1061,7 @@ public: mixin (visitIfNotNull!(label)); } /** */ Token label; + mixin OpEquals; } /// @@ -978,6 +1073,7 @@ public: mixin (visitIfNotNull!(identifierOrInteger)); } /** */ Token identifierOrInteger; + mixin OpEquals; } /// @@ -989,6 +1085,7 @@ public: mixin (visitIfNotNull!(identifierOrInteger)); } /** */ Token identifierOrInteger; + mixin OpEquals; } /// @@ -1008,7 +1105,7 @@ public: destructor, staticConstructor, staticDestructor, sharedStaticDestructor, sharedStaticConstructor, conditionalDeclaration, pragmaDeclaration, versionSpecification, - invariant_, postblit, declarations)); + invariant_, postblit, declarations)); } /** */ Attribute[] attributes; @@ -1040,6 +1137,7 @@ public: /** */ Invariant invariant_; /** */ Postblit postblit; /** */ Declaration[] declarations; + mixin OpEquals; } /// @@ -1051,6 +1149,7 @@ final class DeclarationsAndStatements : ASTNode } /** */ DeclarationOrStatement[] declarationsAndStatements; + mixin OpEquals; } /// @@ -1064,6 +1163,7 @@ public: /** */ Declaration declaration; /** */ Statement statement; + mixin OpEquals; } /// @@ -1076,6 +1176,7 @@ public: } /** */ Token name; /** */ Initializer initializer; + mixin OpEquals; } /// @@ -1087,6 +1188,7 @@ public: mixin (visitIfNotNull!(declarationsAndStatements)); } /** */ DeclarationsAndStatements declarationsAndStatements; + mixin OpEquals; } /// @@ -1098,8 +1200,9 @@ public: mixin (visitIfNotNull!(unaryExpression)); } /** */ UnaryExpression unaryExpression; - /** */ size_t line; - /** */ size_t column; + /** */ size_t line; + /** */ size_t column; + mixin OpEquals; } /// @@ -1111,6 +1214,7 @@ public: mixin (visitIfNotNull!(deleteExpression)); } /** */ DeleteExpression deleteExpression; + mixin OpEquals; } /// @@ -1122,6 +1226,7 @@ public: mixin (visitIfNotNull!(assignExpression)); } /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -1130,11 +1235,15 @@ final class Destructor : ASTNode public: override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(functionBody)); + mixin (visitIfNotNull!(memberFunctionAttributes, functionBody)); } + /** */ MemberFunctionAttribute[] memberFunctionAttributes; /** */ FunctionBody functionBody; - /** */ size_t location; + /** */ size_t line; + /** */ size_t column; + /** */ size_t index; /** */ string comment; + mixin OpEquals; } /// @@ -1147,6 +1256,7 @@ public: } /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; /** */ Expression expression; + mixin OpEquals; } /// @@ -1168,6 +1278,7 @@ public: * Byte position of the closing brace */ size_t endLocation; + mixin OpEquals; } /// @@ -1182,6 +1293,7 @@ public: /** */ Type type; /** */ EnumBody enumBody; /** */ string comment; + mixin OpEquals; } /// @@ -1196,6 +1308,7 @@ public: /** */ Type type; /** */ AssignExpression assignExpression; /** */ string comment; + mixin OpEquals; } /// @@ -1209,6 +1322,7 @@ public: /** */ Token name; /** */ TemplateParameters templateParameters; /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -1221,6 +1335,7 @@ public: } /** */ IdType operator; mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -1232,6 +1347,7 @@ public: mixin (visitIfNotNull!(items)); } /** */ AssignExpression[] items; + mixin OpEquals; } /// @@ -1243,6 +1359,7 @@ public: mixin (visitIfNotNull!(expression)); } /** */ Expression expression; + mixin OpEquals; } /// @@ -1254,6 +1371,7 @@ public: mixin (visitIfNotNull!(switchStatement)); } /** */ SwitchStatement switchStatement; + mixin OpEquals; } /// @@ -1265,6 +1383,7 @@ public: mixin (visitIfNotNull!(declarationOrStatement)); } /** */ DeclarationOrStatement declarationOrStatement; + mixin OpEquals; } /// @@ -1280,7 +1399,8 @@ public: /** */ ExpressionStatement test; /** */ Expression increment; /** */ DeclarationOrStatement declarationOrStatement; - /** */ size_t startIndex; + /** */ size_t startIndex; + mixin OpEquals; } /// @@ -1294,11 +1414,12 @@ public: } /** */ IdType type; /** */ ForeachTypeList foreachTypeList; - /** */ ForeachType foreachType; + /** */ ForeachType foreachType; /** */ Expression low; /** */ Expression high; /** */ DeclarationOrStatement declarationOrStatement; - /** */ size_t startIndex; + /** */ size_t startIndex; + mixin OpEquals; } /// @@ -1312,6 +1433,7 @@ public: /** */ IdType[] typeConstructors; /** */ Type type; /** */ Token identifier; + mixin OpEquals; } /// @@ -1323,6 +1445,7 @@ public: mixin (visitIfNotNull!(items)); } /** */ ForeachType[] items; + mixin OpEquals; } /// @@ -1335,6 +1458,7 @@ public: } /** */ Token token; /** */ AtAttribute atAttribute; + mixin OpEquals; } /// @@ -1351,6 +1475,7 @@ public: /** */ BodyStatement bodyStatement; /** */ OutStatement outStatement; /** */ InStatement inStatement; + mixin OpEquals; } /// @@ -1361,10 +1486,11 @@ public: { mixin (visitIfNotNull!(type, unaryExpression, templateArguments, arguments)); } - /** */ Type type; + /** */ Type type; /** */ UnaryExpression unaryExpression; /** */ TemplateArguments templateArguments; /** */ Arguments arguments; + mixin OpEquals; } /// @@ -1376,6 +1502,7 @@ public: mixin (visitIfNotNull!(functionCallExpression)); } /** */ FunctionCallExpression functionCallExpression; + mixin OpEquals; } /// @@ -1397,6 +1524,7 @@ public: /** */ FunctionBody functionBody; /** */ MemberFunctionAttribute[] memberFunctionAttributes; /** */ string comment; + mixin OpEquals; } /// @@ -1413,6 +1541,7 @@ public: /** */ Parameters parameters; /** */ FunctionAttribute[] functionAttributes; /** */ FunctionBody functionBody; + mixin OpEquals; } /// @@ -1425,6 +1554,7 @@ public: } /** */ Expression expression; /** */ Token label; + mixin OpEquals; } /// @@ -1436,6 +1566,7 @@ public: mixin (visitIfNotNull!(identifiers)); } /** */ Token[] identifiers; + mixin OpEquals; } /// @@ -1447,6 +1578,7 @@ public: mixin (visitIfNotNull!(identifiers)); } /** */ Token[] identifiers; + mixin OpEquals; } /// @@ -1459,6 +1591,7 @@ public: } /** */ IdentifierOrTemplateInstance[] identifiersOrTemplateInstances; + mixin OpEquals; } /// @@ -1472,6 +1605,7 @@ public: /** */ Token identifier; /** */ TemplateInstance templateInstance; + mixin OpEquals; } /// @@ -1484,6 +1618,7 @@ public: } /** */ bool negated; mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -1500,7 +1635,10 @@ public: /** */ Expression expression; /** */ DeclarationOrStatement thenStatement; /** */ DeclarationOrStatement elseStatement; - /** */ size_t startIndex; + /** */ size_t startIndex; + /** */ size_t line; + /** */ size_t column; + mixin OpEquals; } /// @@ -1513,6 +1651,7 @@ public: } /** */ Token left; /** */ Token right; + mixin OpEquals; } /// @@ -1525,6 +1664,7 @@ public: } /** */ SingleImport singleImport; /** */ ImportBind[] importBinds; + mixin OpEquals; } /// @@ -1537,6 +1677,7 @@ public: } /** */ SingleImport[] singleImports; /** */ ImportBindings importBindings; + mixin OpEquals; } /// @@ -1548,6 +1689,7 @@ public: mixin (visitIfNotNull!(assignExpression)); } /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -1560,6 +1702,7 @@ public: } /** */ UnaryExpression unaryExpression; /** */ ArgumentList argumentList; + mixin OpEquals; } /// @@ -1572,6 +1715,7 @@ public: } mixin BinaryExpressionBody; bool negated; + mixin OpEquals; } /// @@ -1583,6 +1727,7 @@ public: mixin (visitIfNotNull!(blockStatement)); } /** */ BlockStatement blockStatement; + mixin OpEquals; } /// @@ -1594,6 +1739,7 @@ public: mixin (visitIfNotNull!(statementNoCaseNoDefault)); } /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; + mixin OpEquals; } /// @@ -1605,6 +1751,7 @@ public: mixin (visitIfNotNull!(nonVoidInitializer)); } /** */ NonVoidInitializer nonVoidInitializer; + mixin OpEquals; } /// @@ -1622,6 +1769,7 @@ public: /** */ BaseClassList baseClassList; /** */ StructBody structBody; /** */ string comment; + mixin OpEquals; } /// @@ -1634,6 +1782,9 @@ public: } /** */ BlockStatement blockStatement; /** */ string comment; + size_t line; + size_t index; + mixin OpEquals; } /// @@ -1650,6 +1801,7 @@ public: /** */ TypeSpecialization typeSpecialization; /** */ TemplateParameterList templateParameterList; /** */ IdType equalsOrColon; + mixin OpEquals; } /// @@ -1662,6 +1814,7 @@ public: } /** */ AssignExpression key; /** */ AssignExpression value; + mixin OpEquals; } /// @@ -1673,6 +1826,7 @@ public: mixin (visitIfNotNull!(keyValuePairs)); } /** */ KeyValuePair[] keyValuePairs; + mixin OpEquals; } /// @@ -1685,6 +1839,7 @@ public: } Token identifier; /** */ DeclarationOrStatement declarationOrStatement; + mixin OpEquals; } /// @@ -1701,6 +1856,7 @@ public: /** */ Parameters parameters; /** */ FunctionAttribute[] functionAttributes; /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -1712,6 +1868,7 @@ public: mixin (visitIfNotNull!(statementNoCaseNoDefault)); } /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; + mixin OpEquals; } /// @@ -1720,10 +1877,13 @@ final class LinkageAttribute : ASTNode public: override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(identifier)); + version (DIP61) mixin (visitIfNotNull!(identifier, identifierChain)); + else mixin (visitIfNotNull!(identifier)); } /** */ Token identifier; /** */ bool hasPlusPlus; + version (DIP61) /** */ IdentifierChain identifierChain; + mixin OpEquals; } /// @@ -1736,6 +1896,7 @@ public: } /** */ IdType tokenType; /** */ AtAttribute atAttribute; + mixin OpEquals; } /// @@ -1748,6 +1909,7 @@ public: } /** */ MixinExpression mixinExpression; /** */ TemplateMixinExpression templateMixinExpression; + mixin OpEquals; } /// @@ -1759,6 +1921,7 @@ public: mixin (visitIfNotNull!(assignExpression)); } /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -1770,6 +1933,7 @@ public: mixin (visitIfNotNull!(templateDeclaration)); } /** */ TemplateDeclaration templateDeclaration; + mixin OpEquals; } /// @@ -1783,6 +1947,7 @@ public: /** */ Symbol symbol; /** */ IdentifierOrTemplateChain identifierOrTemplateChain; /** */ TypeofExpression typeofExpression; + mixin OpEquals; } /// @@ -1791,10 +1956,12 @@ final class Module : ASTNode public: override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(moduleDeclaration, declarations)); + mixin (visitIfNotNull!(scriptLine, moduleDeclaration, declarations)); } + /** */ Token scriptLine; /** */ ModuleDeclaration moduleDeclaration; /** */ Declaration[] declarations; + mixin OpEquals; } /// @@ -1806,6 +1973,7 @@ public: mixin (visitIfNotNull!(moduleName)); } /** */ IdentifierChain moduleName; + mixin OpEquals; } @@ -1819,6 +1987,7 @@ public: } /** */ IdType operator; mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -1834,6 +2003,7 @@ public: /** */ Arguments constructorArguments; /** */ BaseClassList baseClassList; /** */ StructBody structBody; + mixin OpEquals; } /// @@ -1849,6 +2019,7 @@ public: /** */ NewAnonClassExpression newAnonClassExpression; /** */ Arguments arguments; /** */ AssignExpression assignExpression; + mixin OpEquals; } @@ -1892,6 +2063,7 @@ public: /** */ DebugSpecification debugSpecification; /** */ FunctionCallStatement functionCallStatement; /** */ ExpressionStatement expressionStatement; + mixin OpEquals; } /// @@ -1900,12 +2072,15 @@ final class NonVoidInitializer : ASTNode public: override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(assignExpression, arrayInitializer, structInitializer)); + mixin (visitIfNotNull!(assignExpression, arrayInitializer, + structInitializer, functionBody)); } /** */ AssignExpression assignExpression; /** */ ArrayInitializer arrayInitializer; /** */ StructInitializer structInitializer; + /** */ FunctionBody functionBody; + mixin OpEquals; } /// @@ -1914,6 +2089,7 @@ final class Operand : ASTNode public: mixin (DEFAULT_ACCEPT); /** */ AsmExp asmExp; + mixin OpEquals; } /// @@ -1922,6 +2098,7 @@ final class Operands : ASTNode public: mixin (DEFAULT_ACCEPT); /** */ Operand[] operands; + mixin OpEquals; } /// @@ -1933,6 +2110,7 @@ public: mixin (visitIfNotNull!(left, right)); } mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -1944,6 +2122,7 @@ public: mixin (visitIfNotNull!(left, right)); } mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -1956,6 +2135,7 @@ public: } /** */ Token parameter; /** */ BlockStatement blockStatement; + mixin OpEquals; } /// @@ -1972,6 +2152,7 @@ public: /** */ Token name; /** */ bool vararg; /** */ AssignExpression default_; + mixin OpEquals; } /// @@ -1985,6 +2166,7 @@ public: /** */ Parameter[] parameters; /** */ bool hasVarargs; + mixin OpEquals; } /// @@ -1997,6 +2179,7 @@ public: } /** */ FunctionBody functionBody; /** */ MemberFunctionAttribute[] memberFunctionAttributes; + mixin OpEquals; } /// @@ -2009,6 +2192,7 @@ public: } /** */ IdType operator; /** */ UnaryExpression unaryExpression; + mixin OpEquals; } /// @@ -2020,6 +2204,7 @@ public: mixin (visitIfNotNull!(left, right)); } mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -2031,6 +2216,7 @@ public: mixin (visitIfNotNull!(pragmaExpression)); } /** */ PragmaExpression pragmaExpression; + mixin OpEquals; } /// @@ -2043,6 +2229,7 @@ public: } /** */ Token identifier; /** */ ArgumentList argumentList; + mixin OpEquals; } /// @@ -2055,6 +2242,7 @@ public: } /** */ IdType operator; /** */ UnaryExpression unaryExpression; + mixin OpEquals; } /// @@ -2085,6 +2273,7 @@ public: /** */ MixinExpression mixinExpression; /** */ ImportExpression importExpression; /** */ Vector vector; + mixin OpEquals; } /// @@ -2095,6 +2284,7 @@ public: /** */ Token identifier; /** */ Token intLiteral; /** */ bool hasIntegerLiteral; + mixin OpEquals; } /// @@ -2107,6 +2297,7 @@ public: } /** */ IdType operator; mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -2118,6 +2309,9 @@ public: mixin (visitIfNotNull!(expression)); } /** */ Expression expression; + /** */ size_t startLocation; + /** */ size_t endLocation; + mixin OpEquals; } /// @@ -2130,6 +2324,7 @@ public: } /** */ Token identifier; /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; + mixin OpEquals; } /// @@ -2143,6 +2338,7 @@ public: /** */ FunctionBody functionBody; /** */ size_t location; /** */ string comment; + mixin OpEquals; } /// @@ -2156,6 +2352,7 @@ public: /** */ FunctionBody functionBody; /** */ size_t location; /** */ string comment; + mixin OpEquals; } /// @@ -2168,6 +2365,7 @@ public: } /** */ IdType operator; mixin BinaryExpressionBody; + mixin OpEquals; } /// @@ -2180,6 +2378,7 @@ public: } /** */ Token rename; /** */ IdentifierChain identifierChain; + mixin OpEquals; } /// @@ -2193,6 +2392,7 @@ public: /** */ UnaryExpression unaryExpression; /** */ AssignExpression lower; /** */ AssignExpression upper; + mixin OpEquals; } /// @@ -2208,6 +2408,7 @@ public: /** */ CaseStatement caseStatement; /** */ CaseRangeStatement caseRangeStatement; /** */ DefaultStatement defaultStatement; + mixin OpEquals; } /// @@ -2219,6 +2420,7 @@ public: mixin (visitIfNotNull!(staticAssertStatement)); } /** */ StaticAssertStatement staticAssertStatement; + mixin OpEquals; } /// @@ -2230,6 +2432,7 @@ public: mixin (visitIfNotNull!(assertExpression)); } /** */ AssertExpression assertExpression; + mixin OpEquals; } /// @@ -2242,7 +2445,8 @@ public: } /** */ FunctionBody functionBody; /** */ size_t location; - /** */ string comment; + /** */ string comment; + mixin OpEquals; } /// @@ -2255,7 +2459,8 @@ public: } /** */ FunctionBody functionBody; /** */ size_t location; - /** */ string comment; + /** */ string comment; + mixin OpEquals; } /// @@ -2267,6 +2472,7 @@ public: mixin (visitIfNotNull!(assignExpression)); } /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -2280,6 +2486,7 @@ public: /** */ AtAttribute atAttribute; /** */ Deprecated deprecated_; /** */ Token token; + mixin OpEquals; } /// @@ -2301,6 +2508,7 @@ public: */ size_t endLocation; /** */ Declaration[] declarations; + mixin OpEquals; } /// @@ -2316,6 +2524,7 @@ public: /** */ Constraint constraint; /** */ StructBody structBody; /** */ string comment; + mixin OpEquals; } /// @@ -2328,6 +2537,7 @@ public: } /** */ StructMemberInitializers structMemberInitializers; + mixin OpEquals; } /// @@ -2340,6 +2550,7 @@ public: } /** */ Token identifier; /** */ NonVoidInitializer nonVoidInitializer; + mixin OpEquals; } /// @@ -2351,6 +2562,7 @@ public: mixin (visitIfNotNull!(structMemberInitializers)); } /** */ StructMemberInitializer[] structMemberInitializers; + mixin OpEquals; } /// @@ -2363,6 +2575,7 @@ public: } /** */ Expression expression; /** */ Statement statement; + mixin OpEquals; } /// @@ -2376,6 +2589,7 @@ public: /** */ IdentifierOrTemplateChain identifierOrTemplateChain; /** */ bool dot; + mixin OpEquals; } /// @@ -2388,6 +2602,7 @@ public: } /** */ Expression expression; /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; + mixin OpEquals; } /// @@ -2405,6 +2620,7 @@ public: /** */ AssignExpression colonExpression; /** */ Type assignType; /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -2417,6 +2633,7 @@ public: } /** */ Type type; /** */ AssignExpression assignExpression; + mixin OpEquals; } /// @@ -2428,6 +2645,7 @@ public: mixin (visitIfNotNull!(items)); } /** */ TemplateArgument[] items; + mixin OpEquals; } /// @@ -2440,6 +2658,7 @@ public: } /** */ TemplateArgumentList templateArgumentList; /** */ TemplateSingleArgument templateSingleArgument; + mixin OpEquals; } /// @@ -2457,6 +2676,7 @@ public: /** */ Declaration[] declarations; /** */ EponymousTemplateDeclaration eponymousTemplateDeclaration; /** */ string comment; + mixin OpEquals; } /// @@ -2469,6 +2689,7 @@ public: } /** */ Token identifier; /** */ TemplateArguments templateArguments; + mixin OpEquals; } /// @@ -2482,6 +2703,7 @@ public: /** */ Token identifier; /** */ TemplateArguments templateArguments; /** */ MixinTemplateName mixinTemplateName; + mixin OpEquals; } /// @@ -2499,6 +2721,7 @@ public: /** */ TemplateAliasParameter templateAliasParameter; /** */ TemplateTupleParameter templateTupleParameter; /** */ TemplateThisParameter templateThisParameter; + mixin OpEquals; } /// @@ -2510,6 +2733,7 @@ public: mixin (visitIfNotNull!(items)); } /** */ TemplateParameter[] items; + mixin OpEquals; } /// @@ -2521,6 +2745,7 @@ public: mixin (visitIfNotNull!(templateParameterList)); } /** */ TemplateParameterList templateParameterList; + mixin OpEquals; } /// @@ -2532,6 +2757,7 @@ public: mixin (visitIfNotNull!(token)); } /** */ Token token; + mixin OpEquals; } /// @@ -2543,6 +2769,7 @@ public: mixin (visitIfNotNull!(templateTypeParameter)); } /** */ TemplateTypeParameter templateTypeParameter; + mixin OpEquals; } /// @@ -2554,6 +2781,7 @@ public: mixin (visitIfNotNull!(identifier)); } /** */ Token identifier; + mixin OpEquals; } /// @@ -2567,6 +2795,7 @@ public: /** */ Token identifier; /** */ Type colonType; /** */ Type assignType; + mixin OpEquals; } /// @@ -2582,6 +2811,7 @@ public: /** */ Token identifier; /** */ Expression expression; /** */ TemplateValueParameterDefault templateValueParameterDefault; + mixin OpEquals; } /// @@ -2594,6 +2824,7 @@ public: } /** */ AssignExpression assignExpression; /** */ Token token; + mixin OpEquals; } /// @@ -2607,6 +2838,7 @@ public: /** */ ExpressionNode orOrExpression; /** */ ExpressionNode expression; /** */ ExpressionNode ternaryExpression; + mixin OpEquals; } /// @@ -2618,6 +2850,7 @@ public: mixin (visitIfNotNull!(expression)); } /** */ Expression expression; + mixin OpEquals; } /// @@ -2630,6 +2863,7 @@ public: } /** */ Token identifier; /** */ TemplateArgumentList templateArgumentList; + mixin OpEquals; } /// @@ -2643,6 +2877,7 @@ public: /** */ DeclarationOrStatement declarationOrStatement; /** */ Catches catches; /** */ Finally finally_; + mixin OpEquals; } /// @@ -2657,6 +2892,7 @@ public: /** */ IdType[] typeConstructors; /** */ TypeSuffix[] typeSuffixes; /** */ Type2 type2; + mixin OpEquals; } /// @@ -2675,6 +2911,7 @@ public: /** */ IdentifierOrTemplateChain identifierOrTemplateChain; /** */ IdType typeConstructor; /** */ Type type; + mixin OpEquals; } /// @@ -2687,6 +2924,7 @@ public: } /** */ Token token; /** */ Type type; + mixin OpEquals; } /// @@ -2707,6 +2945,7 @@ public: /** */ AssignExpression high; /** */ Parameters parameters; /** */ MemberFunctionAttribute[] memberFunctionAttributes; + mixin OpEquals; } /// @@ -2719,6 +2958,7 @@ public: } /** */ Type type; /** */ Expression expression; + mixin OpEquals; } /// @@ -2731,6 +2971,7 @@ public: } /** */ Expression expression; /** */ Token return_; + mixin OpEquals; } /// @@ -2760,6 +3001,7 @@ public: /** */ AssertExpression assertExpression; /** */ SliceExpression sliceExpression; /** */ IndexExpression indexExpression; + mixin OpEquals; } /// @@ -2776,6 +3018,7 @@ public: /** */ Constraint constraint; /** */ StructBody structBody; /** */ string comment; + mixin OpEquals; } /// @@ -2788,6 +3031,7 @@ public: } /** */ BlockStatement blockStatement; /** */ string comment; + mixin OpEquals; } /// @@ -2803,6 +3047,7 @@ public: /** */ StorageClass storageClass; /** */ AutoDeclaration autoDeclaration; /** */ string comment; + mixin OpEquals; } /// @@ -2814,6 +3059,7 @@ public: mixin (visitIfNotNull!(type)); } /** */ Type type; + mixin OpEquals; } /// @@ -2825,6 +3071,7 @@ public: mixin (visitIfNotNull!(token)); } /** */ Token token; + mixin OpEquals; } /// @@ -2836,6 +3083,7 @@ public: mixin (visitIfNotNull!(token)); } /** */ Token token; + mixin OpEquals; } /// @@ -2849,7 +3097,8 @@ public: /** */ Expression expression; /** */ DeclarationOrStatement declarationOrStatement; - /** */ size_t startIndex; + /** */ size_t startIndex; + mixin OpEquals; } /// @@ -2863,6 +3112,7 @@ public: /** */ Expression expression; /** */ StatementNoCaseNoDefault statementNoCaseNoDefault; + mixin OpEquals; } /// @@ -2874,4 +3124,5 @@ public: mixin (visitIfNotNull!(left, right)); } mixin BinaryExpressionBody; + mixin OpEquals; } diff --git a/stdx/d/entities.d b/std/d/entities.d similarity index 99% rename from stdx/d/entities.d rename to std/d/entities.d index 7b967d7..65aa8ce 100644 --- a/stdx/d/entities.d +++ b/std/d/entities.d @@ -9,7 +9,7 @@ * Source: $(PHOBOSSRC std/d/_entities.d) */ -module stdx.d.entities; +module std.d.entities; /** * Generated from $(LINK http://www.w3.org/TR/html5/entities.json) diff --git a/stdx/d/lexer.d b/std/d/lexer.d similarity index 96% rename from stdx/d/lexer.d rename to std/d/lexer.d index a179b1f..42e8270 100644 --- a/stdx/d/lexer.d +++ b/std/d/lexer.d @@ -1,12 +1,12 @@ -module stdx.d.lexer; +module std.d.lexer; import std.typecons; import std.typetuple; import std.array; import std.algorithm; import std.range; -import stdx.lexer; -public import stdx.lexer : StringCache; +import std.lexer; +public import std.lexer : StringCache; private enum operators = [ ",", ".", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", @@ -41,7 +41,7 @@ private enum dynamicTokens = [ "whitespace", "doubleLiteral", "floatLiteral", "idoubleLiteral", "ifloatLiteral", "intLiteral", "longLiteral", "realLiteral", "irealLiteral", "uintLiteral", "ulongLiteral", "characterLiteral", - "dstringLiteral", "stringLiteral", "wstringLiteral", "scriptLine" + "dstringLiteral", "stringLiteral", "wstringLiteral" ]; private enum pseudoTokenHandlers = [ @@ -91,7 +91,7 @@ private enum extraFields = q{ return 0; } }; -public alias Token = stdx.lexer.TokenStructure!(IdType, extraFields); +public alias Token = std.lexer.TokenStructure!(IdType, extraFields); /** * Configure string lexing behavior @@ -119,6 +119,18 @@ public enum WhitespaceBehavior : ubyte /// Whitespace is treated as a token include } + +/** + * Configure special token handling behavior + */ +public enum SpecialTokenBehavior : ubyte +{ + /// Special tokens are skipped + skip, + /// Special tokens are treated as a token + include +} + /** * Configure comment handling behavior */ @@ -136,6 +148,7 @@ public struct LexerConfig StringBehavior stringBehavior; WhitespaceBehavior whitespaceBehavior; CommentBehavior commentBehavior; + SpecialTokenBehavior specialTokenBehavior; } public bool isBasicType(IdType type) nothrow pure @safe @@ -412,8 +425,8 @@ public struct DLexer private static bool isDocComment(string comment) pure nothrow @safe { - return comment.length >= 3 && (comment[2] == '/' - || comment[2] == '*' || comment[2] == '+'); + return comment.length >= 3 && (comment[0 .. 3] == "///" + || comment[0 .. 3] == "/++" || comment[0 .. 3] == "/**"); } public void popFront() pure @@ -434,6 +447,7 @@ public struct DLexer } do _popFront(); while (front == tok!"comment"); if (front == tok!"whitespace") goto case tok!"whitespace"; + if (front == tok!"specialTokenSequence") goto case tok!"specialTokenSequence"; } break; case tok!"whitespace": @@ -441,6 +455,15 @@ public struct DLexer { do _popFront(); while (front == tok!"whitespace"); if (front == tok!"comment") goto case tok!"comment"; + if (front == tok!"specialTokenSequence") goto case tok!"specialTokenSequence"; + } + break; + case tok!"specialTokenSequence": + if (config.specialTokenBehavior == SpecialTokenBehavior.skip) + { + do _popFront(); while (front == tok!"specialTokenSequence"); + if (front == tok!"comment") goto case tok!"comment"; + if (front == tok!"whitespace") goto case tok!"whitespace"; } break; default: @@ -557,7 +580,7 @@ public struct DLexer Token lexNumber() pure nothrow { mixin (tokenStart); - if (range.canPeek(1) && range.front == '0') + if (range.front == '0' && range.canPeek(1)) { auto ahead = range.peek(1)[1]; switch (ahead) @@ -742,13 +765,18 @@ public struct DLexer // "double identifier". if (range.canPeek(1)) { - switch (range.peekAt(1)) + auto ch = range.peekAt(1); + if (ch <= 0x2f + || (ch >= '0' && ch <= '9') + || (ch >= ':' && ch <= '@') + || (ch >= '[' && ch <= '^') + || (ch >= '{' && ch <= '~') + || ch == '`' || ch == '_') { - case '0': .. case '9': goto doubleLiteral; - default: - break decimalLoop; } + else + break decimalLoop; } else { diff --git a/stdx/d/parser.d b/std/d/parser.d similarity index 98% rename from stdx/d/parser.d rename to std/d/parser.d index a2415a3..f6e84e6 100644 --- a/stdx/d/parser.d +++ b/std/d/parser.d @@ -2,17 +2,17 @@ /** * MACROS: - * GRAMMAR =
$0
+ * GRAMMAR =
$0
* RULEDEF = $(B $(DDOC_ANCHOR $0) $0) * RULE = $(LINK2 #$0, $0) * LITERAL = $(D_STRING $(I $0)) */ -module stdx.d.parser; +module std.d.parser; -import stdx.d.lexer; -import stdx.d.ast; -import stdx.allocator; +import std.d.lexer; +import std.d.ast; +import std.allocator; import std.conv; import std.algorithm; import std.array; @@ -23,113 +23,7 @@ import std.string : format; // Caution: generates 180 megabytes of logging for std.datetime //version = std_parser_verbose; -/** - * The parse allocator is designed so that very large number of node instances - * allocated by the parser can be deallocated all at once. This saves time by - * preventing the GC from having to scan the nodes. - */ -class ParseAllocator : CAllocator -{ -public: - - this(string name = "none") - { - this.name = name; - } - - string name; - - override void[] allocate(size_t size) - in - { - assert (size > 0); - assert (size < blockSize); - } - out (result) - { - assert (result.length == size); - } - body - { - enum size_t mask = ~ (cast(size_t) 7); - enum s = ((Node.sizeof - 1) & mask) + 8; - Node* current = root; - while (true) - { - while (current !is null) - { - immutable size_t blockLength = current.block.length; - immutable size_t oldUsed = current.used; - immutable size_t newUsed = oldUsed + size; - if (newUsed > blockLength) - current = current.next; - else - { - current.used = ((newUsed - 1) & mask) + 8; -// assert (current.used >= oldUsed + size); -// assert (current.block.ptr + blockSize > current.block.ptr + newUsed); -// assert (newUsed > oldUsed); -// writefln("Allocating 0x%012x - 0x%012x", -// cast(size_t) current.block.ptr + oldUsed, -// cast(size_t) current.block.ptr + newUsed); - current.block[oldUsed .. newUsed] = 0; - return current.block[oldUsed .. newUsed]; - } - } - import core.memory; -// stderr.writeln("Allocating new block while processing ", name); - ubyte* newBlock = cast(ubyte*) GC.malloc(blockSize, GC.BlkAttr.NO_SCAN); -// assert (newBlock !is null); -// stderr.writefln("Memory spans from 0x%012x to 0x%012x", -// cast(size_t) newBlock, cast(size_t) newBlock + blockSize); - root = new Node (root, s, newBlock[0 .. blockSize]); -// assert (root.block.length == blockSize); - current = root; - } - assert (false); - } - - /** - * Deallocates all memory held by this allocator. All node instances created - * by a parser using this allocator instance are invalid after calling this - * function. - */ - override bool deallocateAll() - { - deallocateRecursive(root); - root = null; - return true; - } - - override bool expand(ref void[], size_t) { return false; } - override bool reallocate(ref void[], size_t) { return false; } - override bool deallocate(void[]) { return false; } - -private: - - void deallocateRecursive(Node* node) - { - import core.memory; -// import std.c.stdlib; -// node.block[] = 0; -// free(node.block.ptr); - GC.free(node.block.ptr); - if (node.next !is null) - deallocateRecursive(node.next); - node.next = null; - } - - Node* root; - - enum blockSize = 1024 * 1024 * 4; - - struct Node - { - Node* next; - size_t used; - ubyte[] block; - } -} +alias ParseAllocator = CAllocatorImpl!(Mallocator); /** * Params: @@ -219,7 +113,7 @@ class Parser node.linkageAttribute = parseLinkageAttribute(); } warn("Prefer the new \"'alias' identifier '=' type ';'\" syntax" - ~ " to the old \"'alias' type identifier ';'\" syntax"); + ~ " to the old \"'alias' type identifier ';'\" syntax"); if ((node.type = parseType()) is null) return null; auto ident = expect(tok!"identifier"); if (ident is null) @@ -431,7 +325,7 @@ alias core.sys.posix.stdio.fileno fileno; * Parses an ArrayLiteral * * $(GRAMMAR $(RULEDEF arrayLiteral): - * $(LITERAL '[') ($(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))*)? $(LITERAL ']') + * $(LITERAL '[') $(RULE argumentList)? $(LITERAL ']') * ;) */ ArrayLiteral parseArrayLiteral() @@ -780,6 +674,8 @@ alias core.sys.posix.stdio.fileno fileno; { mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocate!AssignExpression; + node.line = current().line; + node.column = current().column; node.ternaryExpression = parseTernaryExpression(); if (currentIsOneOf(tok!"=", tok!">>>=", tok!">>=", tok!"<<=", @@ -1574,6 +1470,8 @@ class ClassFour(A, B) if (someTest()) : Super {}}c; auto t = expect(tok!"this"); if (t is null) return null; node.location = t.index; + node.line = t.line; + node.column = t.column; auto p = peekPastParens(); bool isTemplate = false; if (p !is null && p.type == tok!"(") @@ -2068,7 +1966,7 @@ class ClassFour(A, B) if (someTest()) : Super {}}c; * Parses a Destructor * * $(GRAMMAR $(RULEDEF destructor): - * $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') ($(RULE functionBody) | $(LITERAL ';')) + * $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';')) * ;) */ Destructor parseDestructor() @@ -2078,13 +1976,22 @@ class ClassFour(A, B) if (someTest()) : Super {}}c; node.comment = comment; comment = null; if (expect(tok!"~") is null) return null; + node.index = current.index; + node.line = current.line; + node.column = current.column; if (expect(tok!"this") is null) return null; if (expect(tok!"(") is null) return null; if (expect(tok!")") is null) return null; if (currentIs(tok!";")) advance(); else + { + MemberFunctionAttribute[] memberFunctionAttributes; + while(moreTokens() && currentIsMemberFunctionAttribute()) + memberFunctionAttributes ~= parseMemberFunctionAttribute(); + node.memberFunctionAttributes = ownArray(memberFunctionAttributes); node.functionBody = parseFunctionBody(); + } return node; } @@ -2377,7 +2284,7 @@ class ClassFour(A, B) if (someTest()) : Super {}}c; { if (!canBeRange) { - error(`Cannot have more than one foreach varible for a foreach range statement`); + error(`Cannot have more than one foreach variable for a foreach range statement`); return null; } advance(); @@ -2878,6 +2785,8 @@ body {} // six { mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocate!IfStatement; + node.line = current().line; + node.column = current().column; if (expect(tok!"if") is null) return null; node.startIndex = current().index; if (expect(tok!"(") is null) return null; @@ -3278,6 +3187,8 @@ interface "Four" Invariant parseInvariant() { auto node = allocate!Invariant; + node.index = current.index; + node.line = current.line; if (expect(tok!"invariant") is null) return null; if (currentIs(tok!"(")) { @@ -3491,7 +3402,7 @@ invariant() foo(); * Parses a LinkageAttribute * * $(GRAMMAR $(RULEDEF linkageAttribute): - * $(LITERAL 'extern') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '++')? $(LITERAL '$(RPAREN)') + * $(LITERAL 'extern') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL '++') ($(LITERAL ',') $(RULE identifierChain))?)? $(LITERAL '$(RPAREN)') * ;) */ LinkageAttribute parseLinkageAttribute() @@ -3507,6 +3418,11 @@ invariant() foo(); { advance(); node.hasPlusPlus = true; + version(DIP61) if (currentIs(tok!",")) + { + advance(); + node.identifierChain = parseIdentifierChain(); + } } expect(tok!")"); return node; @@ -3645,7 +3561,7 @@ invariant() foo(); mixin(traceEnterAndExit!(__FUNCTION__)); Module m = allocate!Module; if (currentIs(tok!"scriptLine")) - advance(); + m.scriptLine = advance(); if (currentIs(tok!"module")) m.moduleDeclaration = parseModuleDeclaration(); while (moreTokens()) @@ -3879,6 +3795,7 @@ invariant() foo(); * $(RULE assignExpression) * | $(RULE arrayInitializer) * | $(RULE structInitializer) + * | $(RULE functionBody) * ;) */ NonVoidInitializer parseNonVoidInitializer() @@ -3890,6 +3807,8 @@ invariant() foo(); auto b = peekPastBraces(); if (b !is null && (b.type == tok!"(")) node.assignExpression = parseAssignExpression(); + else if (hasMagicDelimiter!(tok!"{", tok!";")()) + node.functionBody = parseFunctionBody(); else node.structInitializer = parseStructInitializer(); } @@ -3907,8 +3826,15 @@ invariant() foo(); else node.assignExpression = parseAssignExpression(); } + else if (currentIsOneOf(tok!"in", tok!"out", tok!"body")) + node.functionBody = parseFunctionBody(); else node.assignExpression = parseAssignExpression(); + if (node.assignExpression is null && node.arrayInitializer is null + && node.structInitializer is null && node.functionBody is null) + { + return null; + } return node; } @@ -4508,10 +4434,14 @@ q{(int a, ...) { mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocate!ReturnStatement; - if (expect(tok!"return") is null) return null; + auto start = expect(tok!"return"); + if (start is null) return null; + node.startLocation = start.index; if (!currentIs(tok!";")) node.expression = parseExpression(); - if (expect(tok!";") is null) return null; + auto semicolon = expect(tok!";"); + if (semicolon is null) return null; + node.endLocation = semicolon.index; return node; } @@ -4619,8 +4549,18 @@ q{(int a, ...) if (!currentIs(tok!"]")) { node.lower = parseAssignExpression(); + if (node.lower is null) + { + error("assignExpression expected"); + return null; + } expect(tok!".."); node.upper = parseAssignExpression(); + if (node.upper is null) + { + error("assignExpression expected"); + return null; + } } if (expect(tok!"]") is null) return null; return node; @@ -4874,8 +4814,13 @@ q{(int a, ...) mixin(traceEnterAndExit!(__FUNCTION__)); auto node = allocate!StructInitializer; expect(tok!"{"); - node.structMemberInitializers = parseStructMemberInitializers(); - expect(tok!"}"); + if (currentIs(tok!"}")) + advance(); + else + { + node.structMemberInitializers = parseStructMemberInitializers(); + expect(tok!"}"); + } return node; } @@ -6069,6 +6014,7 @@ q{doStuff(5)}c; * * $(GRAMMAR $(RULEDEF variableDeclaration): * $(RULE _type) $(RULE declarator) ($(LITERAL ',') $(RULE declarator))* $(LITERAL ';') + * | $(RULE _type) $(RULE declarator) $(LITERAL '=') $(RULE functionBody) * | $(RULE autoDeclaration) * ;) */ @@ -6096,8 +6042,18 @@ q{doStuff(5)}c; break; } node.declarators = ownArray(declarators); - expect(tok!";"); - return node; +// if (node.declarators.length == 1 +// && node.declarators[0].initializer !is null +// && node.declarators[0].initializer.nonVoidInitializer !is null +// && node.declarators[0].initializer.nonVoidInitializer.functionBody !is null) +// { +// return node; +// } +// else + { + expect(tok!";"); + return node; + } } /** @@ -6248,7 +6204,7 @@ q{doStuff(5)}c; mixin(traceEnterAndExit!(__FUNCTION__)); if (startsWith(tok!"[", tok!"]")) return true; - return hasMagicDelimiter!(tok!"..")(); + return hasMagicDelimiter!(tok!"[", tok!"..")(); } void setTokens(const(Token)[] tokens) @@ -6271,6 +6227,7 @@ protected: if (allocator is null) return from; T[] to = cast(T[]) allocator.allocate(T.sizeof * from.length); + assert (to.length == from.length, format("from.length = %d, to.length = %d", from.length, to.length)); to[] = from[]; return to; } @@ -6282,6 +6239,7 @@ protected: return new T(args); enum numBytes = __traits(classInstanceSize, T); void[] mem = allocator.allocate(numBytes); + assert (mem.length == numBytes, format("%d", mem.length)); T t = emplace!T(mem, args); assert (cast(void*) t == mem.ptr, "%x, %x".format(cast(void*) t, mem.ptr)); return t; @@ -6306,22 +6264,25 @@ protected: bool isAssociativeArrayLiteral() { - return hasMagicDelimiter!(tok!":")(); + auto b = setBookmark(); + scope(exit) goToBookmark(b); + advance(); + return !currentIs(tok!"]") && parseExpression() !is null && currentIs(tok!":"); } - bool hasMagicDelimiter(alias T)() + bool hasMagicDelimiter(alias L, alias T)() { mixin(traceEnterAndExit!(__FUNCTION__)); auto i = index; scope(exit) index = i; - assert(currentIs(tok!"[")); + assert(currentIs(L)); advance(); while (moreTokens()) switch (current.type) { case tok!"{": skipBraces(); break; case tok!"(": skipParens(); break; case tok!"[": skipBrackets(); break; - case tok!"]": return false; + case tok!"]": case tok!"}": return false; case T: return true; default: advance(); break; } @@ -6392,8 +6353,9 @@ protected: case tok!"abstract": case tok!"pure": case tok!"nothrow": - mixin(BASIC_TYPE_CASES); return true; + mixin(BASIC_TYPE_CASES); + return !peekIs(tok!"."); case tok!"case": case tok!"default": case tok!"return": @@ -6479,6 +6441,14 @@ protected: return true; } return true; + case tok!"pragma": + auto b = setBookmark(); + scope(exit) goToBookmark(b); + advance(); + auto past = peekPastParens(); + if (past is null || *past == tok!";") + return false; + return true; case tok!"deprecated": case tok!"private": case tok!"package": diff --git a/stdx/lexer.d b/std/lexer.d similarity index 97% rename from stdx/lexer.d rename to std/lexer.d index 1df674d..5a7c185 100644 --- a/stdx/lexer.d +++ b/std/lexer.d @@ -33,7 +33,7 @@ * ) * Examples: * $(UL - * $(LI A _lexer for D is available $(LINK2 https://github.com/Hackerpilot/Dscanner/blob/master/stdx/d/lexer.d, here).) + * $(LI A _lexer for D is available $(LINK2 https://github.com/Hackerpilot/Dscanner/blob/master/std/d/lexer.d, here).) * $(LI A _lexer for Lua is available $(LINK2 https://github.com/Hackerpilot/lexer-demo/blob/master/lualexer.d, here).) * $(LI A _lexer for JSON is available $(LINK2 https://github.com/Hackerpilot/lexer-demo/blob/master/jsonlexer.d, here).) * ) @@ -112,7 +112,7 @@ * Source: $(PHOBOSSRC std/_lexer.d) */ -module stdx.lexer; +module std.lexer; /** * Template for determining the type used for a token type. Selects the smallest @@ -249,6 +249,11 @@ struct TokenStructure(IdType, string extraFields = "") { public: + bool opEquals(ref const typeof(this) other) const pure nothrow @safe + { + return this.type == other.type && this.text == other.text; + } + /** * Returs: true if the token has the given type, false otherwise. */ @@ -420,6 +425,7 @@ mixin template Lexer(Token, alias defaultTokenFunction, private static string generateCaseStatements() { + import std.algorithm; import std.conv; import std.string; import std.range; @@ -443,6 +449,7 @@ mixin template Lexer(Token, alias defaultTokenFunction, private static string printCase(string[] tokens, string[] pseudoTokens) { + import std.algorithm; string[] t = tokens; string[] sortedTokens = stupidToArray(sort!"a.length > b.length"(t)); import std.conv; @@ -727,7 +734,8 @@ struct LexerRange } /** - * Implements the algorithm _popFrontN more efficiently. + * Implements the algorithm _popFrontN more efficiently. This function does + * not detect or handle newlines. */ void popFrontN(size_t n) pure nothrow @safe { @@ -765,9 +773,6 @@ struct LexerRange size_t line; } -/** - * FREAKIN' MAAAGIC - */ shared struct StringCache { import core.sync.mutex; @@ -784,6 +789,20 @@ public: allocating = false; } + ~this() + { + import core.memory; + shared(Block)* current = rootBlock; + while (current !is null) + { + shared(Block)* prev = current; + current = current.next; + free(cast(void*) prev.bytes.ptr); + } + rootBlock = null; + buckets = []; + } + /** * Caches a string. * Params: str = the string to intern @@ -854,7 +873,6 @@ private: if (bytes is null || bytes.length == 0) return ""; import core.atomic; - import core.memory; shared ubyte[] mem; shared(Node*)* oldBucketRoot = &buckets[hash % buckets.length]; while (true) @@ -928,7 +946,7 @@ private: import core.atomic; import core.memory; if (numBytes > (blockSize / 4)) - return cast(shared) (cast(ubyte*) GC.malloc(numBytes, GC.BlkAttr.NO_SCAN))[0 .. numBytes]; + return cast(shared) (cast(ubyte*) malloc(numBytes))[0 .. numBytes]; shared(Block)* r = rootBlock; while (true) { @@ -949,7 +967,7 @@ private: if (cas(&allocating, false, true)) { shared(Block)* b = new shared Block( - cast(shared) (cast(ubyte*) GC.malloc(blockSize, GC.BlkAttr.NO_SCAN))[0 .. blockSize], + cast(shared) (cast(ubyte*) malloc(blockSize))[0 .. blockSize], numBytes, r); atomicStore(rootBlock, b); @@ -1048,3 +1066,6 @@ private: shared(Node)*[] buckets; shared(Block)* rootBlock; } + +private extern(C) void* malloc(size_t) nothrow pure; +private extern(C) void free(void*) nothrow pure;