diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..d7fa74b
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "libdparse"]
+ path = libdparse
+ url = https://github.com/Hackerpilot/libdparse.git
+ branch = master
diff --git a/analysis/run.d b/analysis/run.d
index 1866d58..bb9e27f 100644
--- a/analysis/run.d
+++ b/analysis/run.d
@@ -27,6 +27,7 @@ import analysis.opequals_without_tohash;
enum AnalyzerCheck : uint
{
+ none = 0b00000000_00000000,
style_check = 0b00000000_00000001,
enum_array_literal_check = 0b00000000_00000010,
exception_check = 0b00000000_00000100,
@@ -76,12 +77,11 @@ string[] analyze(string fileName, ubyte[] code, AnalyzerCheck analyzers, bool st
import std.parallelism;
auto lexer = byToken(code);
- auto app = appender!(typeof(lexer.front)[])();
- while (!lexer.empty)
- {
- app.put(lexer.front);
- lexer.popFront();
- }
+ LexerConfig config;
+ config.fileName = fileName;
+ config.stringBehavior = StringBehavior.source;
+ StringCache cache = StringCache(StringCache.defaultBucketCount);
+ const(Token)[] tokens = getTokensForParser(code, config, &cache);
foreach (message; lexer.messages)
{
@@ -90,7 +90,7 @@ string[] analyze(string fileName, ubyte[] code, AnalyzerCheck analyzers, bool st
}
ParseAllocator p = new ParseAllocator;
- Module m = parseModule(app.data, fileName, p, &messageFunction);
+ Module m = parseModule(tokens, fileName, p, &messageFunction);
if (!staticAnalyze)
return null;
diff --git a/analysis/unused.d b/analysis/unused.d
index 32eb8db..56e2e9d 100644
--- a/analysis/unused.d
+++ b/analysis/unused.d
@@ -10,6 +10,8 @@ import std.d.lexer;
import analysis.base;
import std.container;
+import std.stdio;
+
/**
* Checks for unused variables.
*/
@@ -53,7 +55,7 @@ class UnusedVariableCheck : BaseAnalyzer
popScope();
}
- override void visit(const Type type) {}
+// override void visit(const Type type) {}
mixin template PartsUseVariables(NodeType)
{
@@ -242,7 +244,6 @@ class UnusedVariableCheck : BaseAnalyzer
{
import std.algorithm;
import std.array;
-// import std.stdio;
if (parameter.name != tok!"")
{
// stderr.writeln("Adding parameter ", parameter.name.text);
@@ -280,7 +281,6 @@ class UnusedVariableCheck : BaseAnalyzer
void variableDeclared(string name, size_t line, size_t column,
bool isParameter, bool isRef)
{
-// import std.stdio;
if (inAggregateScope)
return;
// stderr.writeln("Adding ", name, " ", isParameter, " ", isRef);
@@ -289,6 +289,7 @@ class UnusedVariableCheck : BaseAnalyzer
void variableUsed(string name)
{
+// writeln("Marking ", name, " used");
size_t treeIndex = tree.length - 1;
auto uu = UnUsed(name);
while (true)
diff --git a/astprinter.d b/astprinter.d
index d4a1e03..49726db 100644
--- a/astprinter.d
+++ b/astprinter.d
@@ -5,10 +5,10 @@
import std.d.lexer;
import std.d.ast;
+import std.d.formatter;
import std.stdio;
import std.string;
import std.array;
-import formatter;
template tagAndAccept(string tagName)
{
@@ -372,6 +372,7 @@ class XMLPrinter : ASTVisitor
{
output.writeln("");
output.writeln("", declarator.name.text, "");
+ writeDdoc(declarator.comment);
declarator.accept(this);
output.writeln("");
}
diff --git a/build.sh b/build.sh
deleted file mode 100755
index 1f6e442..0000000
--- a/build.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-dmd\
- main.d\
- stats.d\
- imports.d\
- highlighter.d\
- ctags.d\
- astprinter.d\
- formatter.d\
- outliner.d\
- std/*.d\
- std/d/*.d\
- analysis/*.d\
- -version=DIP61\
- -ofdscanner\
- -g\
- -O -release -inline
-
-#gdc\
-# main.d\
-# stats.d\
-# imports.d\
-# highlighter.d\
-# ctags.d\
-# astprinter.d\
-# formatter.d\
-# outliner.d\
-# std/*.d\
-# std/d/*.d\
-# analysis/*.d\
-# -O3 -frelease -fno-bounds-check\
-# -odscanner\
-
-#ldc2\
-# main.d\
-# stats.d\
-# imports.d\
-# highlighter.d\
-# ctags.d\
-# astprinter.d\
-# formatter.d\
-# outliner.d\
-# std/*.d\
-# std/d/*.d\
-# analysis/*.d\
-# -O3 -release\
-# -oq -of=dscanner\
diff --git a/ctags.d b/ctags.d
index ae7d506..883f6bf 100644
--- a/ctags.d
+++ b/ctags.d
@@ -20,13 +20,13 @@ void printCtags(File output, string[] fileNames)
{
string[] tags;
LexerConfig config;
- StringCache* cache = new StringCache(StringCache.defaultBucketCount);
+ StringCache cache = StringCache(StringCache.defaultBucketCount);
foreach (fileName; fileNames)
{
File f = File(fileName);
auto bytes = uninitializedArray!(ubyte[])(to!size_t(f.size));
f.rawRead(bytes);
- auto tokens = byToken(bytes, config, cache);
+ auto tokens = getTokensForParser(bytes, config, &cache);
Module m = parseModule(tokens.array, fileName, null, &doNothing);
auto printer = new CTagsPrinter;
printer.fileName = fileName;
diff --git a/formatter.d b/formatter.d
deleted file mode 100644
index 85a2c0e..0000000
--- a/formatter.d
+++ /dev/null
@@ -1,3886 +0,0 @@
-module formatter;
-
-import std.algorithm;
-import std.range;
-import std.stdio;
-import std.typetuple;
-
-import std.d.ast;
-import std.d.lexer;
-
-//debug = verbose;
-
-/**
- * The only brace styles worth using.
- */
-enum IndentStyle
-{
- /**
- * ---
- * if (something)
- * {
- * foo();
- * bar();
- * }
- * else
- * {
- * bar();
- * baz();
- * }
- * ---
- */
- allman,
- /**
- * ---
- * if (something) {
- * foo();
- * bar();
- * } else {
- * bar();
- * baz();
- * }
- * ---
- */
- otbs,
-}
-
-/**
- *
- */
-void format(Sink)(Sink sink, Module mod, bool useTabs = false,
- IndentStyle style = IndentStyle.allman, uint indentWith = 4)
-{
- Formatter!Sink formatter = new Formatter!(Sink)(sink, useTabs, style, indentWith);
- formatter.format(mod);
-}
-
-class Formatter(Sink)
-{
- /**
- * Parameters:
- * sink = the output range that the formatted source code is placed in
- * useTabs = if true, tabs are used for indent levels instead of spaces
- * style = the brace style
- * indenteWidth = the number of spaces used for indentation if useTabs is false
- */
- this(Sink sink, bool useTabs = false, IndentStyle style = IndentStyle.allman, uint indentWidth = 4)
- {
- this.sink = sink;
- this.useTabs = useTabs;
- this.indentWidth = indentWidth;
- this.style = style;
- }
-
- void format(const AddExpression addExpression)
- {
- debug(verbose) writeln("AddExpression");
- mixin(binary("addExpression"));
- }
-
- void format(const AliasDeclaration aliasDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("AliasDeclaration");
-
- /**
- LinkageAttribute linkageAttribute;
- Type type;
- Token name;
- AliasInitializer[] initializers;
- string comment;
- **/
-
- with(aliasDeclaration)
- {
- newThing(What.other);
- putComment(comment);
- putAttrs(attrs);
- put("alias ");
-
- if (initializers.length) // alias ident = a, ident2 = b, etc
- {
- foreach(count, init; initializers)
- {
- if (count)
- put(", ");
- format(init);
- }
- }
- else
- {
- foreach (storageClass; storageClasses)
- {
- format(storageClass);
- space();
- }
-
- if (type)
- {
- format(type);
- space();
- }
- format(name);
- }
- put(";");
- }
- }
-
- void format(const AliasInitializer aliasInitializer)
- {
- debug(verbose) writeln("AliasInitializer");
-
- /**
- Token name;
- Type type;
- **/
-
- with(aliasInitializer)
- {
- format(name);
- put(" = ");
- format(type);
- }
- }
-
- void format(const AliasThisDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("AliasThisDeclaration");
-
- /**
- Token identifier;
- **/
-
- putAttrs(attrs);
- put("alias ");
- format(decl.identifier);
- put(" this;");
- }
-
- void format(const AlignAttribute alignAttribute)
- {
- debug(verbose) writeln("AlignAttribute");
-
- /**
- Token intLiteral;
- **/
-
- put("align");
- if (alignAttribute.intLiteral.text)
- {
- put("(");
- format(alignAttribute.intLiteral);
- put(")");
- }
- }
-
- void format(const AndAndExpression andAndExpression)
- {
- debug(verbose) writeln("AndAndExpression");
-
- with(andAndExpression)
- {
- format(left);
- if (right)
- {
- put(" && ");
- format(right);
- }
- }
- }
-
- void format(const AndExpression andExpression)
- {
- debug(verbose) writeln("AndExpression");
-
- with(andExpression)
- {
- format(left);
- if (right)
- {
- put(" & ");
- format(right);
- }
- }
- }
-
- void format(const ArgumentList argumentList)
- {
- debug(verbose) writeln("ArgumentList");
-
- foreach(count, arg; argumentList.items)
- {
- if (count) put(", ");
- format(arg);
- }
- }
-
- void format(const Arguments arguments)
- {
- debug(verbose) writeln("Arguments");
-
- put("(");
- if (arguments.argumentList) format(arguments.argumentList);
- put(")");
- }
-
- void format(const ArrayInitializer arrayInitializer)
- {
- debug(verbose) writeln("ArrayInitializer");
-
- /**
- ArrayMemberInitialization[] arrayMemberInitializations;
- **/
-
- put("[");
- foreach(count, init; arrayInitializer.arrayMemberInitializations)
- {
- format(init);
- if (count < arrayInitializer.arrayMemberInitializations.length - 1)
- put(", ");
- }
- put("]");
- }
-
- void format(const ArrayLiteral arrayLiteral)
- {
- debug(verbose) writeln("ArrayLiteral");
-
- /**
- ArgumentList argumentList;
- **/
- put("[");
- if (arrayLiteral.argumentList)
- format(arrayLiteral.argumentList);
- put("]");
- }
-
- void format(const ArrayMemberInitialization arrayMemberInitialization)
- {
- debug(verbose) writeln("ArrayMemberInitialization");
-
- /**
- AssignExpression assignExpression;
- NonVoidInitializer nonVoidInitializer;
- **/
-
- with(arrayMemberInitialization)
- {
- if (assignExpression)
- {
- format(assignExpression);
- put(":");
- }
- if (nonVoidInitializer)
- format(nonVoidInitializer);
-
- }
- }
-
- void format(const AsmAddExp asmAddExp)
- {
- assert(false);
- }
-
- void format(const AsmAndExp asmAndExp)
- {
- assert(false);
- }
-
- void format(const AsmBrExp asmBrExp)
- {
- assert(false);
- }
-
- void format(const AsmEqualExp asmEqualExp)
- {
- assert(false);
- }
-
- void format(const AsmExp asmExp)
- {
- assert(false);
- }
-
- void format(const AsmInstruction asmInstruction)
- {
- assert(false);
- }
-
- void format(const AsmLogAndExp asmLogAndExp)
- {
- assert(false);
- }
-
- void format(const AsmLogOrExp asmLogOrExp)
- {
- assert(false);
- }
-
- void format(const AsmMulExp asmMulExp)
- {
- assert(false);
- }
-
- void format(const AsmOrExp asmOrExp)
- {
- assert(false);
- }
-
- void format(const AsmPrimaryExp asmPrimaryExp)
- {
- assert(false);
- }
-
- void format(const AsmRelExp asmRelExp)
- {
- assert(false);
- }
-
- void format(const AsmShiftExp asmShiftExp)
- {
- assert(false);
- }
-
- void format(const AsmStatement asmStatement)
- {
- assert(false);
- }
-
- void format(const AsmTypePrefix asmTypePrefix)
- {
- assert(false);
- }
-
- void format(const AsmUnaExp asmUnaExp)
- {
- assert(false);
- }
-
- void format(const AsmXorExp asmXorExp)
- {
- assert(false);
- }
-
- void format(const AssertExpression assertExpression)
- {
- debug(verbose) writeln("AssertExpression");
-
- /**
- AssignExpression assertion;
- AssignExpression message;
- **/
-
- with(assertExpression)
- {
- newThing(What.expr);
- put("assert(");
- format(assertion);
- if (message)
- {
- put(", ");
- format(message);
- }
- put(")");
- }
- }
-
- void format(const AssignExpression assignExpression)
- {
- debug(verbose) writeln("AssignExpression");
-
- /**
- ExpressionNode ternaryExpression;
- ExpressionNode assignExpression;
- IdType operator;
- **/
-
- if (assignExpression.ternaryExpression)
- format(assignExpression.ternaryExpression);
-
- if(assignExpression.assignExpression)
- {
- space();
- put(tokenRep(assignExpression.operator));
- space();
- format(assignExpression.assignExpression);
- }
- }
-
- void format(const AssocArrayLiteral assocArrayLiteral)
- {
- debug(verbose) writeln("AssocArrayLiteral");
-
- /**
- KeyValuePairs keyValuePairs;
- **/
-
- put("[");
- format(assocArrayLiteral.keyValuePairs);
- put("]");
- }
-
- void format(const AtAttribute atAttribute)
- {
- debug(verbose) writeln("AtAttribute");
-
- /**
- FunctionCallExpression functionCallExpression;
- ArgumentList argumentList;
- Token identifier;
- **/
-
- with(atAttribute)
- {
- put("@");
- format(identifier);
- if (functionCallExpression) format(functionCallExpression);
- else if(argumentList) format(argumentList);
- }
- }
-
- void format(const Attribute att)
- {
- debug(verbose) writeln("Attribute");
-
- /**
- LinkageAttribute linkageAttribute;
- AlignAttribute alignAttribute;
- PragmaExpression pragmaExpression;
- StorageClass storageClass;
- IdType attribute;
- **/
-
- with(att)
- {
- if (storageClass) format(storageClass);
- if (pragmaExpression) format(pragmaExpression);
- if (attribute) put(tokenRep(attribute));
- }
- }
-
- void format(const AttributeDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("AttributeDeclaration");
-
- auto cIndent = indentLevel;
- outdent();
- newThing(What.attributeDecl);
- putAttrs(attrs);
- format(decl.attribute);
- put(":");
- indentLevel = cIndent;
- }
-
- void format(const AutoDeclaration decl)
- {
- debug(verbose) writeln("AutoDeclaration");
-
- /**
- Token[] identifiers;
- Initializer[] initializers;
- **/
-
- // zip doesn't work here, dmd 2.064.2
- assert(decl.identifiers.length == decl.initializers.length);
- foreach(i; 0..decl.identifiers.length)
- {
- if (i) put(", ");
- format(decl.identifiers[i]);
- put(" = ");
- format(decl.initializers[i]);
- }
- }
-
- void format(const BlockStatement blockStatement)
- {
- debug(verbose) writeln("BlockStatement");
-
- if (blockStatement.declarationsAndStatements is null)
- {
- space();
- put("{}");
- }
- else
- {
- startBlock();
- format(blockStatement.declarationsAndStatements);
- endBlock();
- }
- }
-
- void format(const BodyStatement bodyStatement)
- {
- debug(verbose) writeln("BodyStatement");
-
- onNewline();
- put("body");
- format(bodyStatement.blockStatement);
- }
-
- void format(const BreakStatement breakStatement)
- {
- debug(verbose) writeln("BreakStatement");
-
- put("break");
- if (breakStatement.label != tok!"")
- {
- space();
- format(breakStatement.label);
- }
- put(";");
- }
-
- void format(const BaseClass baseClass)
- {
- debug(verbose) writeln("BaseClass");
-
- /**
- IdentifierOrTemplateChain identifierOrTemplateChain;
- TypeofExpression typeofExpression;
- **/
-
- with(baseClass)
- {
- if (identifierOrTemplateChain) format(identifierOrTemplateChain);
- else if (typeofExpression) format(typeofExpression);
- }
- }
-
- void format(const BaseClassList baseClassList)
- {
- debug(verbose) writeln("BaseClassList");
- put(" : ");
- foreach(count, item; baseClassList.items)
- {
- format(item);
- if (count < baseClassList.items.length - 1)
- put(", ");
- }
- }
-
- void format(const CaseRangeStatement caseRangeStatement)
- {
- debug(verbose) writeln("CaseRangeStatement");
-
- /**
- AssignExpression low;
- AssignExpression high;
- DeclarationsAndStatements declarationsAndStatements;
- **/
-
- with(caseRangeStatement)
- {
- if (low)
- {
- put("case ");
- format(low);
- put(": .. ");
- }
- put("case ");
- format(high);
- put(":");
-
- formatCaseDecls(declarationsAndStatements);
- }
- }
-
- void format(const CaseStatement caseStatement)
- {
- debug(verbose) writeln("CaseStatement");
-
- /**
- ArgumentList argumentList;
- DeclarationsAndStatements declarationsAndStatements;
- **/
-
- with(caseStatement)
- {
- if (argumentList)
- {
- put("case ");
- format(argumentList);
- put(":");
- }
-
- formatCaseDecls(declarationsAndStatements);
- }
- }
-
- void format(const CastExpression castExpression)
- {
- debug(verbose) writeln("CastExpression");
-
- /**
- Type type;
- CastQualifier castQualifier;
- UnaryExpression unaryExpression;
- **/
-
- with(castExpression)
- {
- put("cast(");
- if (castQualifier)
- {
- format(castQualifier);
- space();
- }
- if (type) format(type);
- put(")");
- if (unaryExpression) format(unaryExpression);
- }
- }
-
- void format(const CastQualifier qual)
- {
- debug(verbose) writeln("CastQualifier");
-
- /**
- Token first;
- Token second;
- **/
-
- format(qual.first);
- if (qual.second != tok!"")
- {
- space();
- format(qual.second);
- }
- }
-
- void format(const Catch catch_)
- {
- debug(verbose) writeln("Catch");
-
- /**
- Type type;
- Token identifier;
- DeclarationOrStatement declarationOrStatement;
- **/
-
- with(catch_)
- {
- newThing(What.catch_);
- put("catch(");
- format(type);
- if (identifier != tok!"")
- {
- space();
- format(identifier);
- }
- put(")");
- if (declarationOrStatement) maybeIndent(declarationOrStatement);
- }
- }
-
- void format(const Catches catches)
- {
- debug(verbose) writeln("Catches");
-
- /**
- Catch[] catches;
- LastCatch lastCatch;
- **/
-
- foreach(c; catches.catches)
- format(c);
- if (catches.lastCatch)
- format(catches.lastCatch);
- }
-
- void format(const ClassDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("ClassDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- Constraint constraint;
- BaseClassList baseClassList;
- StructBody structBody;
- string comment;
- **/
-
- newThing(What.aggregateDecl);
- putComment(decl.comment);
- putAttrs(attrs);
-
- put("class ");
- format(decl.name);
-
- if (decl.templateParameters)
- format(decl.templateParameters);
-
- if (decl.constraint)
- {
- space();
- format(decl.constraint);
- }
-
- if (decl.baseClassList)
- {
- put(": ");
- format(decl.baseClassList);
- }
-
- format(decl.structBody);
- }
-
- void format(const CmpExpression cmpExpression)
- {
- debug(verbose) writeln("CmpExpression");
-
- /**
- ExpressionNode shiftExpression;
- ExpressionNode equalExpression;
- ExpressionNode identityExpression;
- ExpressionNode relExpression;
- ExpressionNode inExpression;
- **/
-
- with(cmpExpression)
- {
- if (shiftExpression) format(shiftExpression);
- else if (equalExpression) format(equalExpression);
- else if (identityExpression) format(identityExpression);
- else if (relExpression) format(relExpression);
- else if (inExpression) format(inExpression);
- }
- }
-
- void format(const CompileCondition compileCondition)
- {
- debug(verbose) writeln("CompileCondition");
-
- /**
- VersionCondition versionCondition;
- DebugCondition debugCondition;
- StaticIfCondition staticIfCondition;
- **/
-
- with(compileCondition)
- {
- if (versionCondition) format(versionCondition);
- else if (debugCondition) format(debugCondition);
- else if (staticIfCondition) format(staticIfCondition);
- }
- }
-
- void format(const ConditionalDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("ConditionalDeclaration");
-
- /**
- CompileCondition compileCondition;
- Declaration[] trueDeclarations;
- Declaration falseDeclaration;
- **/
-
- newThing(What.conditionalDecl);
- putAttrs(attrs);
- format(decl.compileCondition);
-
- assert(decl.trueDeclarations.length <= 1); // spec bug?
-
- if (decl.trueDeclarations.length)
- {
- if (isEmptyDeclaration(decl.trueDeclarations[0]))
- {
- space();
- put("{}");
- }
- else
- maybeIndent(decl.trueDeclarations[0]);
- }
-
- if (decl.falseDeclaration)
- {
- newThing(What.else_);
- sink.put("else ");
-
- if (isEmptyDeclaration(decl.falseDeclaration))
- {
- space();
- put("{}");
- return;
- }
-
- if (decl.falseDeclaration.conditionalDeclaration)
- format(decl.falseDeclaration);
- else
- maybeIndent(decl.falseDeclaration);
- }
- }
-
- void format(const ConditionalStatement stmnt)
- {
- debug(verbose) writeln("ConditionalStatement");
-
- /**
- CompileCondition compileCondition;
- DeclarationOrStatement trueStatement;
- DeclarationOrStatement falseStatement;
- **/
-
- newThing(What.other);
- if (stmnt.compileCondition)
- format(stmnt.compileCondition);
-
- if (stmnt.trueStatement)
- maybeIndent(stmnt.trueStatement);
-
- if (stmnt.falseStatement)
- {
- newThing(What.else_);
- put("else ");
-
- // else if...
- if (stmnt.falseStatement.statement &&
- stmnt.falseStatement.statement.statementNoCaseNoDefault &&
- stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement)
- {
- format(stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement);
- return;
- }
-
- maybeIndent(stmnt.falseStatement);
- }
- }
-
- void format(const Constraint constraint)
- {
- debug(verbose) writeln("Constraint");
-
- if (constraint.expression)
- {
- indent();
- onNewline();
- put("if(");
- format(constraint.expression);
- put(")");
- outdent();
- }
- }
-
- void format(const Constructor constructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("Constructor");
-
- /**
- Parameters parameters;
- FunctionBody functionBody;
- Constraint constraint;
- MemberFunctionAttribute[] memberFunctionAttributes;
- TemplateParameters templateParameters;
- size_t location;
- string comment;
- **/
-
- newThing(What.functionDecl);
- putComment(constructor.comment);
- putAttrs(attrs);
-
- put("this");
-
- if (constructor.templateParameters)
- format(constructor.templateParameters);
-
- if (constructor.parameters)
- format(constructor.parameters);
-
- foreach(att; constructor.memberFunctionAttributes)
- {
- space();
- format(att);
- }
-
- if (constructor.constraint)
- {
- space();
- format(constructor.constraint);
- }
-
- if (constructor.functionBody)
- format(constructor.functionBody);
- else
- put(";");
- }
-
- void format(const ContinueStatement continueStatement)
- {
- debug(verbose) writeln("ContinueStatement");
-
- put("continue");
- if (continueStatement.label != tok!"")
- {
- space();
- format(continueStatement.label);
- }
- put(";");
- }
-
- void format(const DebugCondition debugCondition)
- {
- debug(verbose) writeln("DebugCondition");
-
- put("debug");
- if (debugCondition.identifierOrInteger != tok!"")
- {
- put("(");
- format(debugCondition.identifierOrInteger);
- put(")");
- }
- }
-
- void format(const DebugSpecification debugSpecification)
- {
- debug(verbose) writeln("DebugSpecification");
-
- newThing(What.other);
- put("debug = ");
- format(debugSpecification.identifierOrInteger);
- put(";");
- }
-
- void format(const Declaration declaration)
- {
- debug(verbose) writeln("Declaration");
-
- with(declaration)
- {
- string mix(string[] s) {
- string r;
- foreach(c, d; s)
- r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") { format(" ~ d ~ ", attributes); }";
- return r;
- }
-
- mixin(mix(possibleDeclarations));
-
- if (declarations.length)
- {
- putAttrs(attributes);
- startBlock();
- foreach(d; declarations)
- format(d);
- endBlock();
- }
- }
- }
-
- void format(const DeclarationOrStatement declarationsOrStatement)
- {
- debug(verbose) writeln("DeclarationOrStatement");
-
- with(declarationsOrStatement)
- declaration !is null ? format(declaration) : format(statement);
- }
-
- void format(const DeclarationsAndStatements declarationsAndStatements)
- {
- debug(verbose) writeln("DeclarationsAndStatements");
-
- foreach(ds; declarationsAndStatements.declarationsAndStatements)
- format(ds);
- }
-
- void format(const Declarator declarator)
- {
- debug(verbose) writeln("Declarator");
-
- /**
- Token name;
- Initializer initializer;
- **/
-
- format(declarator.name);
-
- foreach(suffix; declarator.cstyle)
- format(suffix);
-
- if (declarator.initializer)
- {
- put(" = ");
- format(declarator.initializer);
- }
- }
-
- void format(const DefaultStatement defaultStatement)
- {
- debug(verbose) writeln("DefaultStatement");
-
- /**
- DeclarationsAndStatements declarationsAndStatements;
- **/
-
- put("default:");
- formatCaseDecls(defaultStatement.declarationsAndStatements);
- }
-
- void format(const DeleteExpression deleteExpression)
- {
- debug(verbose) writeln("DeleteExpression");
-
- put("delete ");
- format(deleteExpression.unaryExpression);
- }
-
- void format(const DeleteStatement deleteStatement)
- {
- debug(verbose) writeln("DeleteStatement");
-
- format(deleteStatement.deleteExpression);
- put(";");
- }
-
- void format(const Deprecated deprecated_)
- {
- debug(verbose) writeln("Deprecated");
-
- put("deprecated");
- if (deprecated_.assignExpression)
- {
- put("(");
- format(deprecated_.assignExpression);
- put(")");
- newline();
- }
- }
-
- void format(const Destructor destructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("Destructor");
-
- /**
- FunctionBody functionBody;
- **/
-
- newThing(What.functionDecl);
- putAttrs(attrs);
- put("~this()");
-
- if (destructor.functionBody)
- format(destructor.functionBody);
- else
- put(";");
- }
-
- void format(const DoStatement doStatement)
- {
- debug(verbose) writeln("DoStatement");
-
- /**
- StatementNoCaseNoDefault statementNoCaseNoDefault;
- Expression expression;
- **/
-
- with(doStatement)
- {
- newThing(What.other);
- put("do");
- if (statementNoCaseNoDefault) format(statementNoCaseNoDefault);
- space();
- put("while(");
- format(expression);
- put(");");
- }
- }
-
- void format(const EnumBody enumBody)
- {
- debug(verbose) writeln("EnumBody");
-
- onNewline();
- startBlock();
- foreach(count, member; enumBody.enumMembers)
- {
- format(member);
-
- if (count < enumBody.enumMembers.length - 1)
- put(",");
-
- if (member.comment.length)
- {
- space();
- put(member.comment);
- }
- }
- endBlock();
- }
-
- void format(const EnumDeclaration enumDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("EnumDeclaration");
-
- /**
- Token name;
- Type type;
- EnumBody enumBody;
- string comment;
- **/
-
- with(enumDeclaration)
- {
- newThing(What.aggregateDecl);
- putComment(comment);
- putAttrs(attrs);
- put("enum ");
- if (name != tok!"")
- {
- format(name);
- space();
- }
- if (type)
- {
- put(": ");
- format(type);
- space();
- }
- if (enumBody) format(enumBody);
- }
- }
-
- void format(const EnumMember enumMember)
- {
- debug(verbose) writeln("EnumMember");
-
- /**
- Token name;
- Type type;
- AssignExpression assignExpression;
- string comment;
- **/
-
- with(enumMember)
- {
- onNewline();
- if (type) format(type);
- format(name);
- if (assignExpression)
- {
- put(" = ");
- format(assignExpression);
- }
- }
- }
-
- void format(const EponymousTemplateDeclaration decl)
- {
- debug(verbose) writeln("EponymousTemplateDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- AssignExpression assignExpression;
- **/
-
- put("enum ");
- put(tokenRep(decl.name));
- if (decl.templateParameters)
- format(decl.templateParameters);
- if (decl.assignExpression)
- {
- put(" = ");
- format(decl.assignExpression);
- }
- put(";");
- }
-
- void format(const EqualExpression equalExpression)
- {
- debug(verbose) writeln("EqualExpression");
-
- mixin(binary("equalExpression"));
- }
-
- void format(const Expression expression)
- {
- debug(verbose) writeln("Expression");
-
- foreach(count, item; expression.items)
- {
- if (count)
- put(", ");
- format(item);
- }
- }
-
- void format(const ExpressionNode n)
- {
- debug(verbose) writeln("ExpressionNode");
-
- if (cast(AddExpression) n) format(cast(AddExpression) n);
- else if (cast(AndAndExpression) n) format(cast(AndAndExpression) n);
- else if (cast(AndExpression) n) format(cast(AndExpression) n);
- else if (cast(AsmAddExp) n) format(cast(AsmAddExp) n);
- else if (cast(AsmAndExp) n) format(cast(AsmAndExp) n);
- else if (cast(AsmEqualExp) n) format(cast(AsmEqualExp) n);
- else if (cast(AsmLogAndExp) n) format(cast(AsmLogAndExp) n);
- else if (cast(AsmLogOrExp) n) format(cast(AsmLogOrExp) n);
- else if (cast(AsmMulExp) n) format(cast(AsmMulExp) n);
- else if (cast(AsmOrExp) n) format(cast(AsmOrExp) n);
- else if (cast(AsmRelExp) n) format(cast(AsmRelExp) n);
- else if (cast(AsmShiftExp) n) format(cast(AsmShiftExp) n);
- else if (cast(AssertExpression) n) format(cast(AssertExpression) n);
- else if (cast(AssignExpression) n) format(cast(AssignExpression) n);
- else if (cast(CmpExpression) n) format(cast(CmpExpression) n);
- else if (cast(DeleteExpression) n) format(cast(DeleteExpression) n);
- else if (cast(EqualExpression) n) format(cast(EqualExpression) n);
- else if (cast(Expression) n) format(cast(Expression) n);
- else if (cast(FunctionCallExpression) n) format(cast(FunctionCallExpression) n);
- else if (cast(FunctionLiteralExpression) n) format(cast(FunctionLiteralExpression) n);
- else if (cast(IdentityExpression) n) format(cast(IdentityExpression) n);
- else if (cast(ImportExpression) n) format(cast(ImportExpression) n);
- else if (cast(IndexExpression) n) format(cast(IndexExpression) n);
- else if (cast(InExpression) n) format(cast(InExpression) n);
- else if (cast(IsExpression) n) format(cast(IsExpression) n);
- else if (cast(LambdaExpression) n) format(cast(LambdaExpression) n);
- else if (cast(MixinExpression) n) format(cast(MixinExpression) n);
- else if (cast(MulExpression) n) format(cast(MulExpression) n);
- else if (cast(NewAnonClassExpression) n) format(cast(NewAnonClassExpression) n);
- else if (cast(NewExpression) n) format(cast(NewExpression) n);
- else if (cast(OrExpression) n) format(cast(OrExpression) n);
- else if (cast(OrOrExpression) n) format(cast(OrOrExpression) n);
- else if (cast(PostIncDecExpression) n) format(cast(PostIncDecExpression) n);
- else if (cast(PowExpression) n) format(cast(PowExpression) n);
- else if (cast(PragmaExpression) n) format(cast(PragmaExpression) n);
- else if (cast(PreIncDecExpression) n) format(cast(PreIncDecExpression) n);
- else if (cast(PrimaryExpression) n) format(cast(PrimaryExpression) n);
- else if (cast(RelExpression) n) format(cast(RelExpression) n);
- else if (cast(ShiftExpression) n) format(cast(ShiftExpression) n);
- else if (cast(SliceExpression) n) format(cast(SliceExpression) n);
- else if (cast(TemplateMixinExpression) n) format(cast(TemplateMixinExpression) n);
- else if (cast(TernaryExpression) n) format(cast(TernaryExpression) n);
- else if (cast(TraitsExpression) n) format(cast(TraitsExpression) n);
- else if (cast(TypeidExpression) n) format(cast(TypeidExpression) n);
- else if (cast(TypeofExpression) n) format(cast(TypeofExpression) n);
- else if (cast(UnaryExpression) n) format(cast(UnaryExpression) n);
- else if (cast(XorExpression) n) format(cast(XorExpression) n);
- }
-
- void format(const ExpressionStatement expressionStatement)
- {
- debug(verbose) writeln("ExpressionStatement");
-
- if (expressionStatement.expression)
- format(expressionStatement.expression);
- put(";");
- }
-
- void format(const FinalSwitchStatement finalSwitchStatement)
- {
- debug(verbose) writeln("FinalSwitchStatement");
-
- format(finalSwitchStatement.switchStatement, true);
- }
-
- void format(const Finally finally_)
- {
- debug(verbose) writeln("Finally");
-
- put("finally");
- format(finally_.declarationOrStatement);
- }
-
- void format(const ForStatement forStatement)
- {
- debug(verbose) writeln("ForStatement");
-
- /**
- DeclarationOrStatement initialization;
- ExpressionStatement test;
- Expression increment;
- DeclarationOrStatement declarationOrStatement;
- **/
-
- with(forStatement)
- {
- newThing(What.other);
- put("for(");
- if (initialization) format(initialization);
- else put(";");
- space();
- if (test) format(test);
- else put(";");
- space();
- if (increment) format(increment);
- put(")");
-
- if (declarationOrStatement) maybeIndent(declarationOrStatement);
- }
- }
-
- void format(const ForeachStatement foreachStatement)
- {
- debug(verbose) writeln("ForeachStatement");
-
- /**
- IdType type;
- ForeachTypeList foreachTypeList;
- ForeachType foreachType;
- Expression low;
- Expression high;
- DeclarationOrStatement declarationOrStatement;
- size_t startIndex;
- **/
-
- with(foreachStatement)
- {
- newThing(What.loop);
- if (type) put(tokenRep(type));
- else assert(false);
-
- put("(");
- if (foreachTypeList) format(foreachTypeList);
- else if (foreachType) format(foreachType);
-
- put("; ");
-
- if (low) format(low);
- if (high)
- {
- put("..");
- format(high);
- }
- put(")");
- format(declarationOrStatement);
- }
- }
-
- void format(const ForeachType foreachType)
- {
- debug(verbose) writeln("ForeachType");
-
- /**
- IdType[] typeConstructors;
- Type type;
- Token identifier;
- **/
-
- with(foreachType)
- {
- foreach(tp; typeConstructors)
- {
- if (tp) put(tokenRep(tp));
- space();
- }
- if (type)
- {
- format(type);
- space();
- }
- format(identifier);
- }
- }
-
- void format(const ForeachTypeList foreachTypeList)
- {
- debug(verbose) writeln("ForeachTypeList");
-
- /**
- ForeachType[] items;
- **/
-
- foreach(count, item; foreachTypeList.items)
- {
- format(item);
- if (count < foreachTypeList.items.length - 1)
- put(", ");
- }
- }
-
- void format(const FunctionAttribute functionAttribute)
- {
- debug(verbose) writeln("FunctionAttribute");
-
- /**
- Token token;
- AtAttribute atAttribute;
- **/
-
- with(functionAttribute)
- {
- if (token != tok!"")
- {
- format(token);
- space();
- }
- if (atAttribute) format(atAttribute);
- }
- }
-
- void format(const FunctionBody functionBody)
- {
- debug(verbose) writeln("FunctionBody");
-
- with(functionBody)
- {
- if (blockStatement)
- {
- format(blockStatement);
- return;
- }
- if (inStatement)
- format(inStatement);
- if (outStatement)
- format(outStatement);
- if (bodyStatement)
- format(bodyStatement);
- }
- }
-
- void format(const FunctionCallExpression functionCallExpression)
- {
- debug(verbose) writeln("FunctionCallExpression");
-
- /**
- Type type;
- UnaryExpression unaryExpression;
- TemplateArguments templateArguments;
- Arguments arguments;
- **/
-
- with(functionCallExpression)
- {
- if (type) format(type);
- if (unaryExpression) format(unaryExpression);
- if (templateArguments) format(templateArguments);
- if (arguments) format(arguments);
- }
- }
-
- void format(const FunctionCallStatement functionCallStatement)
- {
- debug(verbose) writeln("FunctionCallStatement");
-
- format(functionCallStatement.functionCallExpression);
- put(";");
- }
-
- void format(const FunctionDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("FunctionDeclaration");
-
- /**
- bool hasAuto;
- bool hasRef;
- **/
-
- newThing(What.functionDecl);
- putComment(decl.comment);
- putAttrs(attrs);
-
- if (decl.returnType)
- format(decl.returnType);
-
- space();
- format(decl.name);
-
- if (decl.templateParameters)
- format(decl.templateParameters);
- if (decl.parameters)
- format(decl.parameters);
- foreach(attr; decl.memberFunctionAttributes)
- {
- space();
- format(attr);
- }
- if (decl.constraint)
- {
- space();
- format(decl.constraint);
- }
-
- if (decl.functionBody)
- format(decl.functionBody);
- else
- put(";");
- }
-
- void format(const FunctionLiteralExpression functionLiteralExpression)
- {
- debug(verbose) writeln("FunctionLiteralExpression");
-
- /**
- IdType functionOrDelegate;
- Type type;
- Parameters parameters;
- FunctionAttribute[] functionAttributes;
- FunctionBody functionBody;
- **/
-
- with(functionLiteralExpression)
- {
- put(tokenRep(functionOrDelegate));
-
- space();
- if (type) format(type);
- if (parameters) format(parameters);
-
- foreach(att; functionAttributes)
- {
- space();
- format(att);
- }
-
- ignoreNewlines = true;
- format(functionBody);
- ignoreNewlines = false;
- }
- }
-
- void format(const GotoStatement gotoStatement)
- {
- debug(verbose) writeln("GotoStatement");
-
- put("goto ");
- gotoStatement.label != tok!"" ?
- put(tokenRep(gotoStatement.label)) :
- format(gotoStatement.expression);
- put(";");
- }
-
- void format(const IdentifierChain identifierChain)
- {
- debug(verbose) writeln("IdentifierChain");
-
- foreach(count, ident; identifierChain.identifiers)
- {
- if (count) put(".");
- put(ident.text);
- }
- }
-
- void format(const IdentifierList identifierList)
- {
- debug(verbose) writeln("IdentifierList");
- assert(false);
- }
-
- void format(const IdentifierOrTemplateChain identifierOrTemplateChain)
- {
- debug(verbose) writeln("IdentifierOrTemplateChain");
-
- with(identifierOrTemplateChain)
- {
- foreach(count, ident; identifiersOrTemplateInstances)
- {
- if (count) put(".");
- format(ident);
- }
- }
- }
-
- void format(const IdentifierOrTemplateInstance identifierOrTemplateInstance)
- {
- debug(verbose) writeln("IdentifierOrTemplateInstance");
-
- with(identifierOrTemplateInstance)
- {
- format(identifier);
- if (templateInstance)
- format(templateInstance);
- }
- }
-
- void format(const IdentityExpression identityExpression)
- {
- debug(verbose) writeln("IdentityExpression");
-
- with(identityExpression)
- {
- if (left) format(left);
- put(negated ? " !is " : " is ");
- if (right) format(right);
- }
- }
-
- void format(const IfStatement ifStatement)
- {
- debug(verbose) writeln("IfStatement");
-
- /**
- Token identifier;
- Type type;
- Expression expression;
- DeclarationOrStatement thenStatement;
- DeclarationOrStatement elseStatement;
- **/
-
- with(ifStatement)
- {
- bool isAuto = identifier != tok!"" && !type;
- bool isAssign = isAuto || type;
-
- put("if(");
-
- if (isAuto) put("auto ");
- if (type)
- {
- format(type);
- space();
- }
- if (identifier != tok!"")
- {
- format(identifier);
- space();
- }
- if (isAssign) put("= ");
- if (expression) format(expression);
- put(")");
-
- if (thenStatement)
- maybeIndent(thenStatement);
-
- if (elseStatement)
- {
- newThing(What.else_);
- put("else ");
-
- if (elseStatement.statement &&
- elseStatement.statement.statementNoCaseNoDefault &&
- elseStatement.statement.statementNoCaseNoDefault.ifStatement)
- {
- // this is to stop automatic newline
- format(elseStatement.statement.statementNoCaseNoDefault.ifStatement);
- }
- else
- maybeIndent(elseStatement);
- }
-
- }
- }
-
- void format(const ImportBind importBind)
- {
- debug(verbose) writeln("ImportBind");
-
- format(importBind.left);
- if (importBind.right != tok!"")
- {
- put(" = ");
- format(importBind.right);
- }
- }
-
- void format(const ImportBindings importBindings)
- {
- debug(verbose) writeln("ImportBindings");
-
- /**
- SingleImport singleImport;
- ImportBind[] importBinds;
- **/
-
- with(importBindings)
- {
- format(singleImport);
- put(" : ");
- foreach(count, bind; importBinds)
- {
- if (count) put(", ");
- format(bind);
- }
- }
- }
-
- void format(const ImportDeclaration importDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("ImportDeclaration");
-
- /**
- SingleImport[] singleImports;
- ImportBindings importBindings;
- **/
-
- with(importDeclaration)
- {
- newThing(What.importDecl);
- putAttrs(attrs);
- put("import ");
-
- if (singleImports.length == 1)
- {
- format(singleImports[0]);
- }
- else if (singleImports.length > 1)
- {
- indent();
- newline();
- foreach(count, imp; singleImports)
- {
- format(imp);
- if (count < singleImports.length - 1)
- {
- put(", ");
- newline();
- }
- }
- outdent();
- }
-
- if (importBindings)
- {
- if (singleImports.length)
- put(", ");
- format(importBindings);
- }
- put(";");
- }
- }
-
- void format(const ImportExpression importExpression)
- {
- debug(verbose) writeln("ImportExpression");
-
- put("import (");
- format(importExpression.assignExpression);
- put(");");
- }
-
- void format(const IndexExpression indexExpression)
- {
- debug(verbose) writeln("IndexExpression");
-
- /**
- UnaryExpression unaryExpression;
- ArgumentList argumentList;
- **/
-
- with(indexExpression)
- {
- format(indexExpression.unaryExpression);
- put("[");
- format(argumentList);
- put("]");
- }
- }
-
- void format(const InExpression inExpression)
- {
- debug(verbose) writeln("InExpression");
-
- with(inExpression)
- {
- if (left) format(left);
- put(negated ? " !in " : " in ");
- if (right) format(right);
- }
- }
-
- void format(const InStatement inStatement)
- {
- debug(verbose) writeln("InStatement");
-
- onNewline();
- put("in");
- format(inStatement.blockStatement);
- }
-
- void format(const Initialize initialize)
- {
- debug(verbose) writeln("Initialize");
- assert(false);
- }
-
- void format(const Initializer initializer)
- {
- debug(verbose) writeln("Initializer");
-
- initializer.nonVoidInitializer ? format(initializer.nonVoidInitializer) : put("void");
- }
-
- void format(const InterfaceDeclaration interfaceDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("InterfaceDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- Constraint constraint;
- BaseClassList baseClassList;
- StructBody structBody;
- string comment;
- **/
-
- with(interfaceDeclaration)
- {
- newThing(What.aggregateDecl);
- putComment(comment);
- putAttrs(attrs);
-
- put("interface ");
- format(name);
- if (templateParameters) format(templateParameters);
- if (constraint)
- {
- space();
- format(constraint);
- }
- if (baseClassList)
- {
- put(": ");
- format(baseClassList);
- }
-
- if (structBody)
- format(structBody);
- else
- put(";");
- }
- }
-
- void format(const Invariant invariant_, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("Invariant");
-
- /**
- BlockStatement blockStatement;
- string comment;
- **/
-
- putComment(invariant_.comment);
- putAttrs(attrs);
- put("invariant()");
- format(invariant_.blockStatement);
- }
-
- void format(const IsExpression isExpression)
- {
- debug(verbose) writeln("IsExpression");
-
- /**
- Type type;
- Token identifier;
- TypeSpecialization typeSpecialization;
- TemplateParameterList templateParameterList;
- IdType equalsOrColon;
- **/
-
- with(isExpression)
- {
- put("is(");
- if (type) format(type);
- if (identifier != tok!"")
- {
- space();
- format(identifier);
- }
-
- if (equalsOrColon)
- {
- space();
- put(tokenRep(equalsOrColon));
- space();
- }
-
- if (typeSpecialization) format(typeSpecialization);
- if (templateParameterList)
- {
- put(", ");
- format(templateParameterList);
- }
- put(")");
- }
- }
-
- void format(const KeyValuePair keyValuePair)
- {
- debug(verbose) writeln("KeyValuePair");
-
- /**
- AssignExpression key;
- AssignExpression value;
- **/
-
- format(keyValuePair.key);
- put(":");
- format(keyValuePair.value);
- }
-
- void format(const KeyValuePairs keyValuePairs)
- {
- debug(verbose) writeln("KeyValuePairs");
-
- /**
- KeyValuePair[] keyValuePairs;
- **/
-
- foreach(count, pair; keyValuePairs.keyValuePairs)
- {
- format(pair);
- if (count < keyValuePairs.keyValuePairs.length - 1)
- put(", ");
- }
- }
-
- void format(const LabeledStatement stmt)
- {
- debug(verbose) writeln("LabeledStatement");
-
- /**
- Token identifier;
- DeclarationOrStatement declarationOrStatement;
- **/
-
- format(stmt.identifier);
- put(":");
- if (stmt.declarationOrStatement)
- format(stmt.declarationOrStatement);
- }
-
- void format(const LambdaExpression lambdaExpression)
- {
- debug(verbose) writeln("LambdaExpression");
-
- /**
- IdType functionType;
- Token identifier;
- Parameters parameters;
- FunctionAttribute[] functionAttributes;
- AssignExpression assignExpression;
- **/
-
- with(lambdaExpression)
- {
- if (identifier != tok!"")
- format(identifier);
- else
- {
- if (functionType) put(tokenRep(functionType));
- format(parameters);
- foreach(count, attr; functionAttributes)
- {
- space();
- format(attr);
- }
- }
- put(" => ");
- format(assignExpression);
- }
- }
-
- void format(const LastCatch lastCatch)
- {
- debug(verbose) writeln("LastCatch");
-
- put("catch");
- format(lastCatch.statementNoCaseNoDefault);
- }
-
- void format(const LinkageAttribute linkageAttribute)
- {
- debug(verbose) writeln("LinkageAttribute");
-
- /**
- Token identifier;
- bool hasPlusPlus;
- **/
-
- put("extern(");
- format(linkageAttribute.identifier);
- if (linkageAttribute.hasPlusPlus)
- put("++");
- put(")");
- }
-
- void format(const MemberFunctionAttribute memberFunctionAttribute)
- {
- debug(verbose) writeln("MemberFunctionAttribute");
-
- /**
- IdType tokenType;
- AtAttribute atAttribute;
- **/
-
- with(memberFunctionAttribute)
- {
- if (tokenType) put(tokenRep(tokenType));
- else format(atAttribute);
- }
- }
-
- void format(const MixinDeclaration mixinDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("MixinDeclaration");
-
- /**
- MixinExpression mixinExpression;
- TemplateMixinExpression templateMixinExpression;
- **/
-
- with(mixinDeclaration)
- {
- putAttrs(attrs);
- if (mixinExpression) format(mixinExpression);
- else format(templateMixinExpression);
- put(";");
- }
- }
-
- void format(const MixinExpression mixinExpression)
- {
- debug(verbose) writeln("MixinExpression");
-
- put("mixin(");
- format(mixinExpression.assignExpression);
- put(")");
- }
-
- void format(const MixinTemplateDeclaration mixinTemplateDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("MixinTemplateDeclaration");
-
- putAttrs(attrs);
- put("mixin ");
- format(mixinTemplateDeclaration.templateDeclaration);
- }
-
- void format(const MixinTemplateName mixinTemplateName)
- {
- debug(verbose) writeln("MixinTemplateName");
-
- /**
- Symbol symbol;
- IdentifierOrTemplateChain identifierOrTemplateChain;
- TypeofExpression typeofExpression;
- **/
-
- with(mixinTemplateName)
- {
- if (symbol) format(symbol);
- else
- {
- format(typeofExpression);
- put(".");
- format(identifierOrTemplateChain);
- }
- }
- }
-
- void format(const Module module_)
- {
- debug(verbose) writeln("Module");
-
- /**
- ModuleDeclaration moduleDeclaration;
- Declaration[] declarations;
- **/
-
- format(module_.moduleDeclaration);
- foreach(decl; module_.declarations)
- format(decl);
- }
-
- void format(const ModuleDeclaration moduleDeclaration)
- {
- debug(verbose) writeln("ModuleDeclaration");
-
- /**
- IdentifierChain moduleName;
- **/
-
- put("module ");
- format(moduleDeclaration.moduleName);
- put(";");
- newline();
- newline();
- }
-
- void format(const MulExpression mulExpression)
- {
- debug(verbose) writeln("MulExpression");
- mixin(binary("mulExpression"));
- }
-
- void format(const NewAnonClassExpression newAnonClassExpression)
- {
- debug(verbose) writeln("NewAnonClassExpression");
-
- /**
- Arguments allocatorArguments;
- Arguments constructorArguments;
- BaseClassList baseClassList;
- StructBody structBody;
- **/
-
- with(newAnonClassExpression)
- {
- if (allocatorArguments)
- {
- format(allocatorArguments);
- space();
- }
- put("class");
- if (constructorArguments)
- format(constructorArguments);
-
- if (baseClassList)
- {
- space();
- format(baseClassList);
- }
-
- format(structBody);
- }
- }
-
- void format(const NewExpression newExpression)
- {
- debug(verbose) writeln("NewExpression");
-
- /**
- Type type;
- NewAnonClassExpression newAnonClassExpression;
- Arguments arguments;
- AssignExpression assignExpression;
- **/
-
- with(newExpression)
- {
- put("new ");
- if (newAnonClassExpression) format(newAnonClassExpression);
- else
- {
- if (type) format(type);
- if (arguments) format(arguments);
- if (assignExpression)
- {
- put("[");
- format(assignExpression);
- put("]");
- }
- }
- }
- }
-
- void format(const NonVoidInitializer nonVoidInitializer)
- {
- debug(verbose) writeln("NonVoidInitializer");
-
- /**
- AssignExpression assignExpression;
- ArrayInitializer arrayInitializer;
- StructInitializer structInitializer;
- **/
-
- with(nonVoidInitializer)
- {
- if (assignExpression) format(assignExpression);
- else if (arrayInitializer) format(arrayInitializer);
- else if (structInitializer) format(structInitializer);
- }
- }
-
- void format(const Operand operand)
- {
- debug(verbose) writeln("Operand");
- assert(false);
- }
-
- void format(const Operands operands)
- {
- debug(verbose) writeln("Operands");
- assert(false);
- }
-
- void format(const OrExpression orExpression)
- {
- debug(verbose) writeln("OrExpression");
- mixin(binary("orExpression", "|"));
- }
-
- void format(const OrOrExpression orOrExpression)
- {
- debug(verbose) writeln("OrOrExpression");
- mixin(binary("orOrExpression", "||"));
- }
-
- void format(const OutStatement stmnt)
- {
- debug(verbose) writeln("OutStatement");
-
- /**
- Token parameter;
- BlockStatement blockStatement;
- **/
-
- onNewline();
- put("out");
- if (stmnt.parameter != tok!"")
- {
- put("(");
- format(stmnt.parameter);
- put(")");
- }
- format(stmnt.blockStatement);
- }
-
- void format(const Parameter parameter)
- {
- debug(verbose) writeln("Parameter");
-
- /**
- IdType[] parameterAttributes;
- Type type;
- Token name;
- bool vararg;
- AssignExpression default_;
- TypeSuffix[] cstyle;
- **/
-
- foreach (count, attribute; parameter.parameterAttributes)
- {
- if (count) space();
- put(tokenRep(attribute));
- }
-
- if (parameter.parameterAttributes.length > 0)
- space();
-
- if (parameter.type !is null)
- format(parameter.type);
-
- if (parameter.name.type != tok!"")
- {
- space();
- put(parameter.name.text);
- }
-
- foreach(suffix; parameter.cstyle)
- format(suffix);
-
- if (parameter.default_)
- {
- put(" = ");
- format(parameter.default_);
- }
-
- if (parameter.vararg)
- put("...");
- }
-
- void format(const Parameters parameters)
- {
- debug(verbose) writeln("Parameters");
-
- /**
- Parameter[] parameters;
- bool hasVarargs;
- **/
-
- put("(");
- foreach (count, param; parameters.parameters)
- {
- if (count) put(", ");
- format(param);
- }
- if (parameters.hasVarargs)
- {
- if (parameters.parameters.length)
- put(", ");
- put("...");
- }
- put(")");
- }
-
- void format(const Postblit postblit, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("Postblit");
-
- /**
- FunctionBody functionBody;
- **/
-
- newThing(What.functionDecl);
- putAttrs(attrs);
- put("this(this)");
-
- foreach(attr; postblit.memberFunctionAttributes)
- {
- space();
- format(attr);
- }
-
- if (postblit.functionBody)
- format(postblit.functionBody);
- else
- put(";");
- }
-
- void format(const PostIncDecExpression postIncDecExpression)
- {
- debug(verbose) writeln("PostIncDecExpression");
- assert(false); // parsePostIncDecExpression never gets called??
- }
-
- void format(const PowExpression powExpression)
- {
- debug(verbose) writeln("PowExpression");
- mixin(binary("powExpression", "^^", true));
- }
-
- void format(const PragmaDeclaration pragmaDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("PragmaDeclaration");
-
- /**
- PragmaExpression pragmaExpression;
- **/
-
- putAttrs(attrs);
- format(pragmaDeclaration.pragmaExpression);
- put(";");
- }
-
- void format(const PragmaExpression pragmaExpression)
- {
- debug(verbose) writeln("PragmaExpression");
-
- /**
- Token identifier;
- ArgumentList argumentList;
- **/
-
- put("pragma(");
- format(pragmaExpression.identifier);
- if (pragmaExpression.argumentList)
- {
- put(", ");
- format(pragmaExpression.argumentList);
- }
- put(")");
- }
-
- void format(const PreIncDecExpression preIncDecExpression)
- {
- debug(verbose) writeln("PreIncDecExpression");
- assert(false); // parsePreIncDecExpression never called ??
- }
-
- void format(const PrimaryExpression primaryExpression)
- {
- debug(verbose) writeln("PrimaryExpression");
-
- /**
- Token dot;
- Token primary;
- IdentifierOrTemplateInstance identifierOrTemplateInstance;
- Token basicType;
- TypeofExpression typeofExpression;
- TypeidExpression typeidExpression;
- ArrayLiteral arrayLiteral;
- AssocArrayLiteral assocArrayLiteral;
- Expression expression;
- IsExpression isExpression;
- LambdaExpression lambdaExpression;
- FunctionLiteralExpression functionLiteralExpression;
- TraitsExpression traitsExpression;
- MixinExpression mixinExpression;
- ImportExpression importExpression;
- Vector vector;
- **/
-
- with(primaryExpression)
- {
- if (dot != tok!"") put(".");
- if (basicType != tok!"") format(basicType);
- if (primary != tok!"")
- {
- if (basicType != tok!"") put("."); // i.e. : uint.max
- format(primary);
- }
-
- if (expression)
- {
- put("(");
- format(expression);
- put(")");
- }
- else if (identifierOrTemplateInstance)
- {
- format(identifierOrTemplateInstance);
- }
- else if (typeofExpression) format(typeofExpression);
- else if (typeidExpression) format(typeidExpression);
- else if (arrayLiteral) format(arrayLiteral);
- else if (assocArrayLiteral) format(assocArrayLiteral);
- else if (isExpression) format(isExpression);
- else if (lambdaExpression) format(lambdaExpression);
- else if (functionLiteralExpression) format(functionLiteralExpression);
- else if (traitsExpression) format(traitsExpression);
- else if (mixinExpression) format(mixinExpression);
- else if (importExpression) format(importExpression);
- else if (vector) format(vector);
- }
- }
-
- void format(const Register register)
- {
- debug(verbose) writeln("Register");
- assert(false);
- }
-
- void format(const RelExpression relExpression)
- {
- debug(verbose) writeln("RelExpression");
- mixin(binary("relExpression"));
- }
-
- void format(const ReturnStatement returnStatement)
- {
- debug(verbose) writeln("ReturnStatement");
-
- put("return");
- if (returnStatement.expression)
- {
- space();
- format(returnStatement.expression);
- }
- put(";");
- }
-
- void format(const ScopeGuardStatement scopeGuardStatement)
- {
- debug(verbose) writeln("ScopeGuardStatement");
-
- /**
- Token identifier;
- StatementNoCaseNoDefault statementNoCaseNoDefault;
- **/
-
- with(scopeGuardStatement)
- {
- put("scope(");
- format(identifier);
- put(")");
- indent();
- format(statementNoCaseNoDefault);
- outdent();
- }
- }
-
- void format(const SharedStaticConstructor sharedStaticConstructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("SharedStaticConstructor");
-
- with(sharedStaticConstructor)
- {
- newThing(What.functionDecl);
- putComment(comment);
- putAttrs(attrs);
- put("shared static this()");
- format(functionBody);
- }
- }
-
- void format(const SharedStaticDestructor sharedStaticDestructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("SharedStaticDestructor");
-
- with(sharedStaticDestructor)
- {
- newThing(What.functionDecl);
- putComment(comment);
- putAttrs(attrs);
- put("shared static ~this()");
- format(functionBody);
- }
- }
-
- void format(const ShiftExpression shiftExpression)
- {
- debug(verbose) writeln("ShiftExpression");
- mixin(binary("shiftExpression"));
- }
-
- void format(const SingleImport singleImport)
- {
- debug(verbose) writeln("SingleImport");
-
- /**
- Token rename;
- IdentifierChain identifierChain;
- **/
-
- if (singleImport.rename != tok!"")
- {
- format(singleImport.rename);
- put(" = ");
- }
- format(singleImport.identifierChain);
- }
-
- void format(const SliceExpression sliceExpression)
- {
- debug(verbose) writeln("SliceExpression");
-
- /**
- UnaryExpression unaryExpression;
- AssignExpression lower;
- AssignExpression upper;
- **/
-
- with(sliceExpression)
- {
- format(unaryExpression);
- put("[");
- if (lower && upper)
- {
- format(lower);
- put("..");
- format(upper);
- }
- put("]");
- }
- }
-
- void format(const Statement statement)
- {
- debug(verbose) writeln("Statement");
-
- /**
- StatementNoCaseNoDefault statementNoCaseNoDefault;
- CaseStatement caseStatement;
- CaseRangeStatement caseRangeStatement;
- DefaultStatement defaultStatement;
- **/
-
- with(statement)
- {
- if (statementNoCaseNoDefault)
- {
- format(statementNoCaseNoDefault);
- return;
- }
-
- onNewline();
- if (caseStatement) format(caseStatement);
- else if (caseRangeStatement) format(caseRangeStatement);
- else if (defaultStatement) format(defaultStatement);
- }
- }
-
- void format(const StatementNoCaseNoDefault statementNoCaseNoDefault)
- {
- debug(verbose) writeln("StatementNoCaseNoDefault");
-
- string mix(string s) { return "if (" ~ s ~ ") format(" ~ s ~ ");"; }
-
- with(statementNoCaseNoDefault)
- {
- if (!blockStatement) onNewline();
-
- enum stmnts = TypeTuple!(
- "labeledStatement",
- "blockStatement",
- "ifStatement",
- "whileStatement",
- "doStatement",
- "forStatement",
- "foreachStatement",
- "switchStatement",
- "finalSwitchStatement",
- "continueStatement",
- "breakStatement",
- "returnStatement",
- "gotoStatement",
- "withStatement",
- "synchronizedStatement",
- "tryStatement",
- "throwStatement",
- "scopeGuardStatement",
- "asmStatement",
- "conditionalStatement",
- "staticAssertStatement",
- "versionSpecification",
- "debugSpecification",
- "functionCallStatement",
- "expressionStatement"
- );
-
- foreach(s; stmnts)
- mixin(mix(s));
- }
- }
-
- void format(const StaticAssertDeclaration staticAssertDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("StaticAssertDeclaration");
-
- newThing(What.other);
- putAttrs(attrs);
- format(staticAssertDeclaration.staticAssertStatement);
- put(";");
- }
-
- void format(const StaticAssertStatement staticAssertStatement)
- {
- debug(verbose) writeln("StaticAssertStatement");
-
- put("static ");
- format(staticAssertStatement.assertExpression);
- }
-
- void format(const StaticConstructor staticConstructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("StaticConstructor");
-
- putAttrs(attrs);
- put("static this()");
- format(staticConstructor.functionBody);
- }
-
- void format(const StaticDestructor staticDestructor, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("StaticDestructor");
-
- putAttrs(attrs);
- put("static ~this()");
- format(staticDestructor.functionBody);
- }
-
- void format(const StaticIfCondition staticIfCondition)
- {
- debug(verbose) writeln("StaticIfCondition");
-
- put("static if (");
- format(staticIfCondition.assignExpression);
- put(")");
- }
-
- void format(const StorageClass storageClass)
- {
- debug(verbose) writeln("StorageClass");
-
- /**
- AtAttribute atAttribute;
- Deprecated deprecated_;
- Token token;
- **/
-
- with(storageClass)
- {
- if (atAttribute) format(atAttribute);
- else if (deprecated_) format(deprecated_);
- else format(token);
- }
- }
-
- void format(const StructBody structBody)
- {
- debug(verbose) writeln("StructBody");
-
- if (structBody.declarations.length > 0)
- {
- startBlock();
- foreach(count, decl; structBody.declarations)
- format(decl);
- endBlock();
- }
- else
- {
- space();
- put("{}");
- }
- }
-
- void format(const StructDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("StructDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- Constraint constraint;
- StructBody structBody;
- string comment;
- **/
-
- newThing(What.aggregateDecl);
- putComment(decl.comment);
- putAttrs(attrs);
- put("struct ");
- format(decl.name);
-
- if (decl.templateParameters)
- format(decl.templateParameters);
-
- if (decl.constraint)
- {
- space();
- format(decl.constraint);
- }
-
- if (decl.structBody)
- format(decl.structBody);
- else
- put(";");
- }
-
- void format(const StructInitializer structInitializer)
- {
- debug(verbose) writeln("StructInitializer");
-
- put("{");
- format(structInitializer.structMemberInitializers);
- put("}");
- }
-
- void format(const StructMemberInitializer structMemberInitializer)
- {
- debug(verbose) writeln("StructMemberInitializer");
-
- /**
- Token identifier;
- NonVoidInitializer nonVoidInitializer;
- **/
-
- with(structMemberInitializer)
- {
- if (identifier != tok!"")
- {
- format(identifier);
- put(":");
- }
- format(nonVoidInitializer);
- }
- }
-
- void format(const StructMemberInitializers structMemberInitializers)
- {
- debug(verbose) writeln("StructMemberInitializers");
-
- foreach(count, mem; structMemberInitializers.structMemberInitializers)
- {
- if (count) put(", ");
- format(mem);
- }
- }
-
- void format(const SwitchStatement switchStatement, bool isFinal = false)
- {
- debug(verbose) writeln("SwitchStatement");
-
- /**
- Expression expression;
- Statement statement;
- **/
-
- with(switchStatement)
- {
- newThing(What.other);
- isFinal ? put(" final switch(") : put("switch(");
- format(expression);
- put(")");
-
- bool needBlock = statement.statementNoCaseNoDefault &&
- !(statement.statementNoCaseNoDefault.withStatement ||
- statement.statementNoCaseNoDefault.blockStatement );
-
- if (needBlock)
- startBlock();
- format(statement);
- if (needBlock)
- endBlock();
- }
- }
-
- void format(const Symbol symbol)
- {
- debug(verbose) writeln("Symbol");
-
- if (symbol.dot != tok!"")
- put(".");
- format(symbol.identifierOrTemplateChain);
- }
-
- void format(const SynchronizedStatement synchronizedStatement)
- {
- debug(verbose) writeln("SynchronizedStatement");
-
- /**
- Expression expression;
- StatementNoCaseNoDefault statementNoCaseNoDefault;
- **/
-
- with(synchronizedStatement)
- {
- put("synchronized");
- if (expression)
- {
- put("(");
- format(expression);
- put(")");
- }
- format(statementNoCaseNoDefault);
- }
- }
-
- void format(const TemplateAliasParameter templateAliasParameter)
- {
- debug(verbose) writeln("TemplateAliasParameter");
-
- /**
- Type type;
- Token identifier;
- Type colonType;
- AssignExpression colonExpression;
- Type assignType;
- AssignExpression assignExpression;
- **/
-
- with(templateAliasParameter)
- {
- put("alias ");
- if (type)
- {
- format(type);
- space();
- }
- format(identifier);
- if (colonType)
- {
- put(" : ");
- format(colonType);
- }
- else if (colonExpression)
- {
- put(" : ");
- format(colonExpression);
- }
- if (assignType)
- {
- put(" = ");
- format(assignType);
- }
- else if (assignExpression)
- {
- put(" = ");
- format(assignExpression);
- }
- }
- }
-
- void format(const TemplateArgument templateArgument)
- {
- debug(verbose) writeln("TemplateArgument");
-
- /**
- Type type;
- AssignExpression assignExpression;
- **/
-
- with(templateArgument)
- {
- if (type) format(type);
- if (assignExpression) format(assignExpression);
- }
- }
-
- void format(const TemplateArgumentList templateArgumentList, bool parens = true)
- {
- debug(verbose) writeln("TemplateArgumentList");
-
- if (parens) put("!(");
- foreach(count, arg; templateArgumentList.items)
- {
- if (count) put(", ");
- format(arg);
- }
- if (parens) put(")");
- }
-
- void format(const TemplateArguments templateArguments)
- {
- debug(verbose) writeln("TemplateArguments");
-
- /**
- TemplateArgumentList templateArgumentList;
- TemplateSingleArgument templateSingleArgument;
- **/
-
- with(templateArguments)
- {
- if (templateArgumentList) format(templateArgumentList);
- else if (templateSingleArgument) format(templateSingleArgument);
- else put("!()");
- }
- }
-
- void format(const TemplateDeclaration templateDeclaration, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("TemplateDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- Constraint constraint;
- Declaration[] declarations;
- EponymousTemplateDeclaration eponymousTemplateDeclaration;
- string comment;
- **/
-
- with(templateDeclaration)
- {
- newThing(What.other);
- putComment(comment);
- putAttrs(attrs);
-
- if (eponymousTemplateDeclaration)
- {
- format(eponymousTemplateDeclaration);
- }
- else
- {
- put("template ");
- format(name);
-
- if (templateParameters)
- format(templateParameters);
-
- if (constraint)
- {
- space();
- format(constraint);
- }
-
- startBlock();
- foreach(d; declarations)
- format(d);
- endBlock();
- }
- }
- }
-
- void format(const TemplateInstance templateInstance)
- {
- debug(verbose) writeln("TemplateInstance");
-
- /**
- Token identifier;
- TemplateArguments templateArguments;
- **/
-
- with(templateInstance)
- {
- format(identifier);
- if (templateArguments) format(templateArguments);
- }
- }
-
- void format(const TemplateMixinExpression templateMixinExpression)
- {
- debug(verbose) writeln("TemplateMixinExpression");
-
- /**
- Token identifier;
- TemplateArguments templateArguments;
- MixinTemplateName mixinTemplateName;
- **/
-
- with(templateMixinExpression)
- {
- put("mixin ");
- format(mixinTemplateName);
- if (templateArguments) format(templateArguments);
- space();
- format(identifier);
- }
- }
-
- void format(const TemplateParameter templateParameter)
- {
- debug(verbose) writeln("TemplateParameter");
-
- with(templateParameter)
- {
- if (templateTypeParameter)
- format(templateTypeParameter);
- else if (templateValueParameter)
- format(templateValueParameter);
- else if (templateAliasParameter)
- format(templateAliasParameter);
- else if (templateTupleParameter)
- format(templateTupleParameter);
- else if (templateThisParameter)
- format(templateThisParameter);
- }
- }
-
- void format(const TemplateParameterList templateParameterList)
- {
- debug(verbose) writeln("TemplateParameterList");
-
- foreach(i, param; templateParameterList.items)
- {
- if (i) put(", ");
- format(param);
- }
- }
-
- void format(const TemplateParameters templateParameters)
- {
- debug(verbose) writeln("TemplateParameters");
-
- with(templateParameters)
- {
- put("(");
- if (templateParameterList)
- format(templateParameterList);
- put(")");
- }
- }
-
- void format(const TemplateSingleArgument templateSingleArgument)
- {
- debug(verbose) writeln("TemplateSingleArgument");
-
- /**
- Token token;
- **/
-
- put("!");
- format(templateSingleArgument.token);
- }
-
- void format(const TemplateThisParameter templateThisParameter)
- {
- debug(verbose) writeln("TemplateThisParameter");
-
- with(templateThisParameter)
- {
- put("this ");
- if (templateTypeParameter)
- format(templateTypeParameter);
- }
- }
-
- void format(const TemplateTupleParameter templateTupleParameter)
- {
- debug(verbose) writeln("TemplateTupleParameter");
-
- format(templateTupleParameter.identifier);
- put("...");
- }
-
- void format(const TemplateTypeParameter templateTypeParameter)
- {
- debug(verbose) writeln("TemplateTypeParameter");
-
- /**
- Token identifier;
- Type colonType;
- Type assignType;
- **/
-
- with(templateTypeParameter)
- {
- format(identifier);
- if (colonType)
- {
- put(" : ");
- format(colonType);
- }
- if (assignType)
- {
- put(" = ");
- format(assignType);
- }
- }
- }
-
- void format(const TemplateValueParameter templateValueParameter)
- {
- debug(verbose) writeln("TemplateValueParameter");
-
- /**
- Type type;
- Token identifier;
- Expression expression;
- TemplateValueParameterDefault templateValueParameterDefault;
- **/
-
- with(templateValueParameter)
- {
- if (type) format(type);
- space();
- format(identifier);
-
- if (expression)
- {
- put(" : ");
- format(expression);
- }
-
- if (templateValueParameterDefault)
- {
- put(" = ");
- format(templateValueParameterDefault);
- }
- }
- }
-
- void format(const TemplateValueParameterDefault templateValueParameterDefault)
- {
- debug(verbose) writeln("TemplateValueParameterDefault");
-
- with(templateValueParameterDefault)
- assignExpression ? format(assignExpression) : format(token);
- }
-
- void format(const TernaryExpression expr)
- {
- debug(verbose) writeln("TernaryExpression");
-
- /**
- ExpressionNode orOrExpression;
- ExpressionNode expression;
- ExpressionNode ternaryExpression;
- **/
-
- format(expr.orOrExpression);
-
- if (expr.expression && expr.ternaryExpression)
- {
- put(" ? ");
- format(expr.expression);
- put(" : ");
- format(expr.ternaryExpression);
- }
- }
-
- void format(const ThrowStatement throwStatement)
- {
- debug(verbose) writeln("ThrowStatement");
-
- put("throw ");
- assert(throwStatement.expression);
- format(throwStatement.expression);
- put(";");
- }
-
- void format(const Token token)
- {
- debug(verbose) writeln("Token ", tokenRep(token));
- put(tokenRep(token));
- }
-
- void format(const TraitsExpression traitExpr)
- {
- debug(verbose) writeln("TraitsExpression");
-
- /**
- Token identifier;
- TemplateArgumentList templateArgumentList;
- **/
-
- put("__traits(");
- format(traitExpr.identifier);
- put(", ");
- format(traitExpr.templateArgumentList, false);
- put(")");
- }
-
- void format(const TryStatement tryStatement)
- {
- debug(verbose) writeln("TryStatement");
-
- /**
- DeclarationOrStatement declarationOrStatement;
- Catches catches;
- Finally finally_;
- **/
-
- with(tryStatement)
- {
- newThing(What.other);
- put("try");
- maybeIndent(declarationOrStatement);
- if (catches) format(catches);
- if (finally_) format(finally_);
- }
- }
-
- void format(const Type type)
- {
- debug(verbose) writeln("Type(");
-
- /**
- IdType[] typeConstructors;
- TypeSuffix[] typeSuffixes;
- Type2 type2;
- **/
-
- foreach (count, constructor; type.typeConstructors)
- {
- if (count) space();
- put(tokenRep(constructor));
- }
-
- if (type.typeConstructors.length) space();
- format(type.type2);
-
- foreach (suffix; type.typeSuffixes)
- format(suffix);
-
- debug(verbose) writeln(")");
- }
-
- void format(const Type2 type2)
- {
- debug(verbose) writeln("Type2");
-
- /**
- IdType builtinType;
- Symbol symbol;
- TypeofExpression typeofExpression;
- IdentifierOrTemplateChain identifierOrTemplateChain;
- IdType typeConstructor;
- Type type;
- **/
-
- if (type2.symbol !is null)
- {
- format(type2.symbol);
- }
- else if (type2.typeofExpression !is null)
- {
- format(type2.typeofExpression);
- return;
- }
- else if (type2.typeConstructor != tok!"")
- {
- put(tokenRep(type2.typeConstructor));
- put("(");
- format(type2.type);
- put(")");
- }
- else
- {
- put(tokenRep(type2.builtinType));
- }
-
- if (type2.identifierOrTemplateChain)
- {
- put(".");
- format(type2.identifierOrTemplateChain);
- }
- }
-
- void format(const TypeSpecialization typeSpecialization)
- {
- debug(verbose) writeln("TypeSpecialization");
-
- /**
- Token token;
- Type type;
- **/
-
- with(typeSpecialization)
- {
- format(token);
- if (type) format(type);
- }
- }
-
- void format(const TypeSuffix typeSuffix)
- {
- debug(verbose) writeln("TypeSuffix");
-
- /**
- Token delegateOrFunction;
- bool star;
- bool array;
- Type type;
- AssignExpression low;
- AssignExpression high;
- Parameters parameters;
- MemberFunctionAttribute[] memberFunctionAttributes;
- **/
-
- if (typeSuffix.star)
- {
- put("*");
- return;
- }
- else if (typeSuffix.array)
- {
- if (typeSuffix.type is null)
- {
- if (typeSuffix.low is null)
- {
- put("[]");
- return;
- }
- else
- {
- if (typeSuffix.high is null)
- {
- put("[");
- format(typeSuffix.low);
- put("]");
- return;
- }
- else
- {
- put("[");
- format(typeSuffix.low);
- put("..");
- format(typeSuffix.high);
- put("]");
- return;
- }
- }
- }
- else
- {
- put("[");
- format(typeSuffix.type);
- put("]");
- return;
- }
- }
- else
- {
- space();
- format(typeSuffix.delegateOrFunction);
- if (typeSuffix.parameters) format(typeSuffix.parameters);
- foreach(attr; typeSuffix.memberFunctionAttributes)
- {
- space();
- format(attr);
- }
- return;
- }
- }
-
- void format(const TypeidExpression idExpr)
- {
- debug(verbose) writeln("TypeidExpression");
-
- /**
- Type type;
- Expression expression;
- **/
-
- put("typeid(");
- idExpr.type ? format(idExpr.type) : format(idExpr.expression);
- put(")");
- }
-
- void format(const TypeofExpression typeofExpr)
- {
- debug(verbose) writeln("TypeofExpression");
-
- /**
- Expression expression;
- Token return_;
- **/
-
- put("typeof(");
- typeofExpr.expression ? format(typeofExpr.expression) : format(typeofExpr.return_);
- put(")");
- }
-
- void format(const UnaryExpression unary)
- {
- debug(verbose) writeln("UnaryExpression(");
-
- /**
- Type type;
- PrimaryExpression primaryExpression;
- Token prefix;
- Token suffix;
- UnaryExpression unaryExpression;
- NewExpression newExpression;
- DeleteExpression deleteExpression;
- CastExpression castExpression;
- FunctionCallExpression functionCallExpression;
- ArgumentList argumentList;
- IdentifierOrTemplateInstance identifierOrTemplateInstance;
- AssertExpression assertExpression;
- SliceExpression sliceExpression;
- IndexExpression indexExpression;
- **/
-
- with(unary)
- {
- if (prefix != tok!"") format(prefix);
-
- if (type)
- {
- // handle things like (void*).sizeof
- if (identifierOrTemplateInstance)
- {
- put("(");
- format(type);
- put(")");
- }
- else
- {
- format(type);
- put("(");
- if (argumentList)
- format(argumentList);
- put(")");
- }
- }
-
- if (primaryExpression) format(primaryExpression);
- if (newExpression) format(newExpression);
- if (deleteExpression) format(deleteExpression);
- if (castExpression) format(castExpression);
- if (functionCallExpression) format(functionCallExpression);
- if (assertExpression) format(assertExpression);
- if (sliceExpression) format(sliceExpression);
- if (indexExpression) format(indexExpression);
-
- if (unaryExpression) format(unaryExpression);
- if (suffix != tok!"") format(suffix);
-
- if (identifierOrTemplateInstance)
- {
- put(".");
- format(identifierOrTemplateInstance);
- }
- }
-
- debug(verbose) writeln(")");
- }
-
- void format(const UnionDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("UnionDeclaration");
-
- /**
- Token name;
- TemplateParameters templateParameters;
- Constraint constraint;
- StructBody structBody;
- string comment;
- **/
-
- newThing(What.aggregateDecl);
- putComment(decl.comment);
- putAttrs(attrs);
- put("union ");
- format(decl.name);
- if (decl.templateParameters)
- format(decl.templateParameters);
- if (decl.constraint)
- {
- space();
- format(decl.constraint);
- }
- format(decl.structBody);
- }
-
- void format(const Unittest unittest_, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("Unittest");
-
- /**
- BlockStatement blockStatement;
- string comment;
- **/
-
- newThing(What.functionDecl);
- putComment(unittest_.comment);
- putAttrs(attrs);
- put("unittest");
- format(unittest_.blockStatement);
- }
-
- void format(const VariableDeclaration decl, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("VariableDeclaration");
-
- /**
- Type type;
- Declarator[] declarators;
- StorageClass storageClass;
- AutoDeclaration autoDeclaration;
- string comment;
- **/
-
- newThing(What.variableDecl);
- putComment(decl.comment);
- putAttrs(attrs);
-
- if (decl.autoDeclaration)
- format(decl.autoDeclaration);
- else
- {
- if (decl.storageClass)
- {
- format(decl.storageClass);
- space();
- }
- if (decl.type) format(decl.type);
- if (decl.declarators.length) space();
- foreach(count, d; decl.declarators)
- {
- if (count) put(", ");
- format(d);
- }
- }
- put(";");
- }
-
- void format(const Vector vector)
- {
- debug(verbose) writeln("Vector");
-
- put("__vector(");
- format(vector.type);
- put(")");
- }
-
- void format(const VersionCondition versionCondition)
- {
- debug(verbose) writeln("VersionCondition");
-
- put("version(");
- format(versionCondition.token);
- put(")");
- }
-
- void format(const VersionSpecification ver, const Attribute[] attrs = null)
- {
- debug(verbose) writeln("VersionSpecification");
-
- newThing(What.other);
- putAttrs(attrs);
- put("version = ");
- format(ver.token);
- put(";");
- }
-
- void format(const WhileStatement stmt)
- {
- debug(verbose) writeln("WhileStatement");
-
- /**
- Expression expression;
- DeclarationOrStatement declarationOrStatement;
- **/
-
- newThing(What.other);
- put("while(");
- format(stmt.expression);
- put(")");
- maybeIndent(stmt.declarationOrStatement);
- }
-
- void format(const WithStatement stmt)
- {
- debug(verbose) writeln("WithStatement");
-
- /**
- Expression expression;
- StatementNoCaseNoDefault statementNoCaseNoDefault;
- **/
-
- space();
- put("with(");
- format(stmt.expression);
- put(")");
- format(stmt.statementNoCaseNoDefault);
- }
-
- void format(const XorExpression xorExpression)
- {
- debug(verbose) writeln("XorExpression");
- mixin(binary("xorExpression", "^"));
- }
-
- Sink sink;
-
-private:
-
- import std.uni : isWhite;
-
- void indent()
- {
- indentLevel++;
- }
-
- void outdent()
- {
- if (indentLevel == 0)
- return;
- indentLevel--;
- }
-
- void putIndent()
- {
- if (!indentLevel) return;
- auto i = getIndent();
- sink.put(i);
- lineLength += i.length;
- }
-
- string getIndent()
- {
- return useTabs ? iota(indentLevel).map!(a => "\t").join : iota(indentLevel*indentWidth).map!(a => " ").join;
- }
-
- enum What
- {
- functionDecl,
- aggregateDecl,
- attributeDecl,
- conditionalDecl,
- variableDecl,
- importDecl,
- expr,
- loop,
- else_,
- catch_,
- other
- }
-
- void newThing(What thing)
- {
- lastThing = currentThing;
- currentThing = thing;
-
- with(What) {
-
- if (lastThing == importDecl && thing != importDecl)
- lineGap(1);
-
- if (lastThing == loop)
- lineGap(1);
-
- switch(thing)
- {
- case other:
- onNewline();
- break;
- case aggregateDecl: goto case;
- case attributeDecl: goto case;
- case functionDecl:
- lineGap(1);
- break;
- case conditionalDecl:
- lineGap(1);
- break;
- case variableDecl:
- lineGap(1);
- onNewline();
- break;
- case importDecl:
- onNewline();
- break;
- case expr: break;
- case catch_: goto case;
- case else_:
- final switch(style) with(IndentStyle)
- {
- case allman: onNewline(); break;
- case otbs: space(); break;
- }
- break;
- default: break;
- }
- }
- }
-
- void lineGap(int gap)
- {
- }
-
- void newline()
- {
- if (ignoreNewlines)
- {
- space(); // don't do this when splitting lines
- }
- else
- {
- sink.put("\n");
- lineLength = 0;
- putIndent();
- }
- }
-
- void onNewline()
- {
- }
-
- void space()
- {
- put(" ");
- }
-
- static string binary(string symbol, string operator = null, bool nospace = false)
- {
- return "with(" ~ symbol ~ "){"
- ~ "format(left); if (right is null) return;"
- ~ (nospace ? "" : "put(` `);")
- ~ (operator ? "put(`" ~ operator ~ "`);" : "put(tokenRep(operator));")
- ~ (nospace ? "" : "put(` `);")
- ~ "format(right);}";
- }
-
- void startBlock()
- {
- final switch(style) with(IndentStyle)
- {
- case allman: onNewline(); break;
- case otbs: space(); break;
- }
- put("{");
- indent();
- }
-
- void endBlock()
- {
- outdent();
- onNewline();
- put("}");
- }
-
- string tokenRep(Token t)
- {
- return t.text.length ? t.text : tokenRep(t.type);
- }
-
- string tokenRep(IdType t)
- {
- return t ? str(t) : "";
- }
-
- void putComment(string c)
- {
- import std.string : splitLines;
- if (!c.length) return;
- lineGap(1);
- put(c.splitLines().map!(l => getIndent() ~ l).join("\n"));
- newline();
- }
-
- void putAttrs(const Attribute[] attrs)
- {
- if (attrs !is null)
- {
- foreach(count, attr; attrs)
- {
- space();
- format(attr);
- space();
- }
- }
- }
-
- void put(string s)
- {
- sink.put(s);
- lineLength += s.length; // TODO: tabs / spaces?
- }
-
- void formatCaseDecls(const DeclarationsAndStatements declsAndStmnts)
- {
- bool seenBlock = false;
- auto items = declsAndStmnts.declarationsAndStatements;
- foreach(item; items)
- {
- bool _indent = false;
- if (item.declaration) _indent = true;
- if (item.statement && item.statement.statementNoCaseNoDefault)
- {
- if (item.statement.statementNoCaseNoDefault.blockStatement)
- seenBlock = true;
- else if (!item.statement.statementNoCaseNoDefault.labeledStatement)
- _indent = true;
- }
- if (seenBlock) _indent = false;
- if (_indent) indent();
- format(item);
- if (_indent) outdent();
- }
- }
-
- bool needIndent(const Statement s)
- {
- return s.statementNoCaseNoDefault &&
- !s.statementNoCaseNoDefault.blockStatement;
- }
-
- bool needIndent(const Declaration d)
- {
- return !d.declarations.length;
- }
-
- bool needIndent(const DeclarationOrStatement dors)
- {
- return (dors.declaration && needIndent(dors.declaration)) ||
- (dors.statement && needIndent(dors.statement));
- }
-
- void maybeIndent(T)(const T t)
- {
- auto _indent = needIndent(t);
- if (_indent) indent();
- format(t);
- if (_indent) outdent();
- }
-
- bool isEmptyDeclaration(const Declaration decl)
- {
- with(decl)
- {
- string mix(string[] s) {
- string r;
- foreach(c, d; s)
- r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") return false;";
- return r;
- }
- mixin(mix(possibleDeclarations));
- return attributes.length == 0 &&
- declarations.length == 0;
- }
- }
-
- bool ignoreNewlines = false;
- bool useTabs;
- uint caseDepth;
- uint indentWidth;
- uint indentLevel;
- IndentStyle style;
-
-
- What lastThing, currentThing;
- uint lineLength;
- uint maxLineLength = 80;
-
- enum possibleDeclarations = [
- "attributeDeclaration",
- "importDeclaration",
- "functionDeclaration",
- "variableDeclaration",
- "aliasThisDeclaration",
- "structDeclaration",
- "classDeclaration",
- "interfaceDeclaration",
- "unionDeclaration",
- "enumDeclaration",
- "aliasDeclaration",
- "mixinDeclaration",
- "mixinTemplateDeclaration",
- "unittest_",
- "staticAssertDeclaration",
- "templateDeclaration",
- "constructor",
- "destructor",
- "staticConstructor",
- "staticDestructor",
- "sharedStaticDestructor",
- "sharedStaticConstructor",
- "conditionalDeclaration",
- "pragmaDeclaration",
- "versionSpecification",
- "invariant_",
- "postblit"
- ];
-}
diff --git a/libdparse b/libdparse
new file mode 160000
index 0000000..d9387eb
--- /dev/null
+++ b/libdparse
@@ -0,0 +1 @@
+Subproject commit d9387eb3b275295cd0263bdc273c4b0b63f29f98
diff --git a/main.d b/main.d
index e6c852d..8c94bb8 100644
--- a/main.d
+++ b/main.d
@@ -102,18 +102,15 @@ int run(string[] args)
return 1;
}
- StringCache* cache = new StringCache(StringCache.defaultBucketCount);
+ StringCache cache = StringCache(StringCache.defaultBucketCount);
if (tokenDump || highlight)
{
bool usingStdin = args.length == 1;
ubyte[] bytes = usingStdin ? readStdin() : readFile(args[1]);
LexerConfig config;
- config.whitespaceBehavior = WhitespaceBehavior.include;
config.stringBehavior = StringBehavior.source;
- config.commentBehavior = CommentBehavior.include;
- config.specialTokenBehavior = SpecialTokenBehavior.include;
- auto tokens = byToken(bytes, config, cache);
+ auto tokens = byToken(bytes, config, &cache);
if (highlight)
{
highlighter.highlight(tokens, args.length == 1 ? "stdin" : args[1]);
@@ -121,11 +118,11 @@ int run(string[] args)
}
else if (tokenDump)
{
- writeln("text blank\tindex\tline\tcolumn\ttype");
+ writeln("text blank\tindex\tline\tcolumn\ttype\tcomment");
foreach (token; tokens)
{
- writefln("<<%20s>>%b\t%d\t%d\t%d\t%d", token.text is null ? str(token.type) : token.text,
- token.text !is null, token.index, token.line, token.column, token.type);
+ writefln("<<%20s>>%b\t%d\t%d\t%d\t%d\t%s", token.text is null ? str(token.type) : token.text,
+ token.text !is null, token.index, token.line, token.column, token.type, token.comment);
}
return 0;
}
@@ -150,10 +147,8 @@ int run(string[] args)
if (usingStdin)
{
LexerConfig config;
- config.whitespaceBehavior = WhitespaceBehavior.skip;
config.stringBehavior = StringBehavior.source;
- config.commentBehavior = CommentBehavior.attach;
- auto tokens = byToken(readStdin(), config, cache);
+ auto tokens = byToken(readStdin(), config, &cache);
if (tokenCount)
printTokenCount(stdout, "stdin", tokens);
else
@@ -166,10 +161,8 @@ int run(string[] args)
{
LexerConfig config;
- config.whitespaceBehavior = WhitespaceBehavior.skip;
config.stringBehavior = StringBehavior.source;
- config.commentBehavior = CommentBehavior.attach;
- auto tokens = byToken(readFile(f), config, cache);
+ auto tokens = byToken(readFile(f), config, &cache);
if (tokenCount)
count += printTokenCount(stdout, f, tokens);
else
@@ -180,9 +173,20 @@ int run(string[] args)
}
else if (imports || ast || outline)
{
- auto tokens = byToken(usingStdin ? readStdin() : readFile(args[1]));
- auto mod = parseModule(tokens.array(), usingStdin ? "stdin" : args[1],
- null, &doNothing);
+ string fileName = usingStdin ? "stdin" : args[1];
+ LexerConfig config;
+ config.fileName = fileName;
+ config.stringBehavior = StringBehavior.source;
+ auto tokens = getTokensForParser(
+ usingStdin ? readStdin() : readFile(args[1]),
+ config, &cache);
+// writeln("text blank\tindex\tline\tcolumn\ttype\tcomment");
+// foreach (token; tokens)
+// {
+// writefln("<<%20s>>%b\t%d\t%d\t%d\t%d\t%s", token.text is null ? str(token.type) : token.text,
+// token.text !is null, token.index, token.line, token.column, token.type, token.comment);
+// }
+ auto mod = parseModule(tokens, fileName, null, &doNothing);
if (imports)
{
auto visitor = new ImportPrinter;
diff --git a/makefile b/makefile
index ee6888b..2bc716b 100644
--- a/makefile
+++ b/makefile
@@ -1,9 +1,35 @@
-
.PHONY: all test
-all:
- @./build.sh
+DMD = /home/brian/src/dmd/src/dmd
+GDC = gdc
+LDC = ldc
+SRC = main.d\
+ stats.d\
+ imports.d\
+ highlighter.d\
+ ctags.d\
+ astprinter.d\
+ outliner.d\
+ libdparse/src/std/*.d\
+ libdparse/src/std/d/*.d\
+ analysis/*.d
+INCLUDE_PATHS = -Ilibdparse/src
+VERSIONS = -version=DIP61
+
+all: dmdbuild
+
+dmdbuild:
+ ${DMD} -O -release -inline -ofdscanner ${VERSIONS} ${INCLUDE_PATHS} ${SRC}
+
+gdcbuild:
+ ${GDC} -O3 -frelease -odscanner ${VERSIONS} ${INCLUDE_PATHS} ${SRC}
+
+ldcbuild:
+ ${LDC} -O5 -release -oq -of=dscanner ${VERSIONS} ${INCLUDE_PATHS} ${SRC}
test:
@./test.sh
+clean:
+ rm -f dscanner *.o
+
diff --git a/outliner.d b/outliner.d
index 919d8fc..86fa693 100644
--- a/outliner.d
+++ b/outliner.d
@@ -5,11 +5,11 @@
import std.d.lexer;
import std.d.ast;
+import std.d.formatter;
import std.stdio;
import std.string;
import std.array;
import std.conv;
-import formatter;
class Outliner : ASTVisitor
{
diff --git a/std/allocator.d b/std/allocator.d
deleted file mode 100644
index 499262e..0000000
--- a/std/allocator.d
+++ /dev/null
@@ -1,4617 +0,0 @@
-// Written in the D programming language.
-
-/**
-Macros:
-WIKI = Phobos/StdAllocator
-MYREF = $1
-TDC =
$(D $1)$(BR)$(SMALL $(I Post:) $(BLUE $(D $+))) |
-TDC2 = $(D $(LREF $0)) |
-RES = $(I result)
-
-Copyright: Andrei Alexandrescu 2013-.
-
-License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
-
-Authors: $(WEB erdani.com, Andrei Alexandrescu)
-
-Source: $(PHOBOSSRC std/_allocator.d)
-
-This module implements untyped composable memory allocators. They are $(I
-untyped) because they deal exclusively in $(D void[]) and have no notion of what
-type the memory allocated would be destined for. They are $(I composable)
-because the included allocators are building blocks that can be assembled in
-complex nontrivial allocators.
-
-$(P Unlike the allocators for the C and C++ programming languages, which manage
-the allocated size internally, these allocators require that the client
-maintains (or knows $(I a priori)) the allocation size for each piece of memory
-allocated. Put simply, the client must pass the allocated size upon
-deallocation. Storing the size in the _allocator has significant negative
-performance implications, and is virtually always redundant because client code
-needs knowledge of the allocated size in order to avoid buffer overruns. (See
-more discussion in a $(WEB open-
-std.org/JTC1/SC22/WG21/docs/papers/2013/n3536.html, proposal) for sized
-deallocation in C++.) For this reason, allocators herein traffic in $(D void[])
-as opposed to $(D void*).)
-
-$(P In order to be usable as an _allocator, a type should implement the
-following methods with their respective semantics. Only $(D alignment) and $(D
-allocate) are required. If any of the other methods is missing, the _allocator
-is assumed to not have that capability (for example some allocators do not offer
-manual deallocation of memory).)
-
-$(BOOKTABLE ,
-$(TR $(TH Method name) $(TH Semantics))
-
-$(TR $(TDC uint alignment;, $(RES) > 0) $(TD Returns the minimum alignment of
-all data returned by the allocator. An allocator may implement $(D alignment) as
-a statically-known $(D enum) value only. Applications that need
-dynamically-chosen alignment values should use the $(D alignedAllocate) and $(D
-alignedReallocate) APIs.))
-
-$(TR $(TDC size_t goodAllocSize(size_t n);, $(RES) >= n) $(TD Allocators
-customarily allocate memory in discretely-sized chunks. Therefore, a request for
-$(D n) bytes may result in a larger allocation. The extra memory allocated goes
-unused and adds to the so-called $(WEB goo.gl/YoKffF,internal fragmentation).
-The function $(D goodAllocSize(n)) returns the actual number of bytes that would
-be allocated upon a request for $(D n) bytes. This module defines a default
-implementation that returns $(D n) rounded up to a multiple of the allocator's
-alignment.))
-
-$(TR $(TDC void[] allocate(size_t s);, $(RES) is null || $(RES).length == s)
-$(TD If $(D s == 0), the call may return any empty slice (including $(D
-null)). Otherwise, the call allocates $(D s) bytes of memory and returns the
-allocated block, or $(D null) if the request could not be satisfied.))
-
-$(TR $(TDC void[] alignedAllocate(size_t s, uint a);, $(RES) is null ||
-$(RES).length == s) $(TD Similar to $(D allocate), with the additional guarantee
-that the memory returned is aligned to at least $(D a) bytes. $(D a) must be a
-power of 2 greater than $(D (void*).sizeof).))
-
-$(TR $(TDC void[] allocateAll();, n/a) $(TD This is a special function
-indicating to wrapping allocators that $(D this) is a simple,
-limited-capabilities allocator that invites customization. Fixed-size regions
-fit this characterization. If called, the function allocates all memory
-available to the allocator and returns it.))
-
-$(TR $(TDC bool expand(ref void[] b, size_t delta);, !$(RES) || b.length == $(I
-old)(b).length + delta) $(TD Expands $(D b) by $(D delta) bytes. If $(D b is
-null), the call evaluates $(D b = allocate(delta)) and returns $(D b !is null).
-Otherwise, $(D b) must be a buffer previously allocated with the same allocator.
-If expansion was successful, $(D expand) changes $(D b)'s length to $(D b.length
-+ delta) and returns $(D true). Upon failure, the call effects no change upon
-the allocator object, leaves $(D b) unchanged, and returns $(D false).))
-
-$(TR $(TDC bool reallocate(ref void[] b, size_t s);, !$(RES) || b.length == s)
-$(TD Reallocates $(D b) to size $(D s), possibly moving memory around. $(D b)
-must be $(D null) or a buffer allocated with the same allocator. If reallocation
-was successful, $(D reallocate) changes $(D b) appropriately and returns $(D
-true). Upon failure, the call effects no change upon the allocator object,
-leaves $(D b) unchanged, and returns $(D false). An allocator should implement
-$(D reallocate) if it can derive some advantage from doing so; otherwise, this
-module defines a $(D reallocate) free function implemented in terms of $(D
-expand), $(D allocate), and $(D deallocate).))
-
-$(TR $(TDC bool alignedReallocate(ref void[] b, size_t s, uint a);, !$(RES) ||
-b.length == s) $(TD Similar to $(D reallocate), but guarantees the reallocated
-memory is aligned at $(D a) bytes. The buffer must have been originated with a
-call to $(D alignedAllocate). $(D a) must be a power of 2 greater than $(D
-(void*).sizeof).))
-
-$(TR $(TDC bool owns(void[] b);, n/a) $(TD Returns $(D true) if $(D b) has been
-allocated with this allocator. An allocator should define this
-method only if it can decide on ownership precisely and fast (in constant time,
-logarithmic time, or linear time with a low multiplication factor). Traditional
-allocators such as the C heap do not define such functionality. If $(D b is
-null), the allocator should return $(D true) if it may return $(D null) as result of an allocation with $(D size == 0).))
-
-$(TR $(TDC void deallocate(void[] b);, n/a) $(TD If $(D b is null), does
-nothing. Otherwise, deallocates memory previously allocated with this
-allocator.))
-
-$(TR $(TDC void deallocateAll();, n/a) $(TD Deallocates all memory allocated
-with this allocator. If an allocator implements this method, it must specify
-whether its destructor calls it, too.))
-
-$(TR $(TDC static Allocator it;, it $(I is a valid) Allocator $(I object)) $(TD
-Some allocators are $(I monostate), i.e. have only an instance and hold only
-global state. (Notable examples are C's own $(D malloc)-based allocator and D's
-garbage-collected heap.) Such allocators must define a static $(D it) instance
-that serves as the symbolic placeholder for the global instance of the
-allocator. An allocator should not hold state and define $(D it) simultaneously.
-Depending on whether the allocator is thread-safe or not, this instance may be
-$(D shared).))
-
-)
-
-The example below features an allocator modeled after $(WEB goo.gl/m7329l,
-jemalloc), which uses a battery of free-list allocators spaced so as to keep
-internal fragmentation to a minimum. The $(D FList) definitions specify no
-bounds for the freelist because the $(D Segregator) does all size selection in
-advance.
-
-Sizes through 3584 bytes are handled via freelists of staggered sizes. Sizes
-from 3585 bytes through 4072 KB are handled by a $(D HeapBlock) with a
-block size of 4 KB. Sizes above that are passed direct to the $(D Mallocator).
-
-----
- alias FList = Freelist!(GCAllocator, 0, unbounded);
- alias A = Segregator!(
- 8, Freelist!(GCAllocator, 0, 8),
- 128, Bucketizer!(FList, 1, 128, 16),
- 256, Bucketizer!(FList, 129, 256, 32),
- 512, Bucketizer!(FList, 257, 512, 64),
- 1024, Bucketizer!(FList, 513, 1024, 128),
- 2048, Bucketizer!(FList, 1025, 2048, 256),
- 3584, Bucketizer!(FList, 2049, 3584, 512),
- 4072 * 1024, CascadingAllocator!(
- () => HeapBlock!(GCAllocator, 4096)(4072 * 1024)),
- GCAllocator
- );
- A tuMalloc;
- auto b = tuMalloc.allocate(500);
- assert(b.length == 500);
- auto c = tuMalloc.allocate(113);
- assert(c.length == 113);
- assert(tuMalloc.expand(c, 14));
- tuMalloc.deallocate(b);
- tuMalloc.deallocate(c);
-----
-
-$(H2 Allocating memory for sharing across threads)
-
-One allocation pattern used in multithreaded applications is to share memory
-across threads, and to deallocate blocks in a different thread than the one that
-allocated it.
-
-All allocators in this module accept and return $(D void[]) (as opposed to
-$(D shared void[])). This is because at the time of allocation, deallocation, or
-reallocation, the memory is effectively not $(D shared) (if it were, it would
-reveal a bug at the application level).
-
-The issue remains of calling $(D a.deallocate(b)) from a different thread than
-the one that allocated $(D b). It follows that both threads must have access to
-the same instance $(D a) of the respective allocator type. By definition of D,
-this is possible only if $(D a) has the $(D shared) qualifier. It follows that
-the allocator type must implement $(D allocate) and $(D deallocate) as $(D
-shared) methods. That way, the allocator commits to allowing usable $(D shared)
-instances.
-
-Conversely, allocating memory with one non-$(D shared) allocator, passing it
-across threads (by casting the obtained buffer to $(D shared)), and later
-deallocating it in a different thread (either with a different allocator object
-or with the same allocator object after casting it to $(D shared)) is illegal.
-
-$(BOOKTABLE $(BIG Synopsis of predefined _allocator building blocks),
-$(TR $(TH Allocator) $(TH Description))
-
-$(TR $(TDC2 NullAllocator) $(TD Very good at doing absolutely nothing. A good
-starting point for defining other allocators or for studying the API.))
-
-$(TR $(TDC2 GCAllocator) $(TD The system-provided garbage-collector allocator.
-This should be the default fallback allocator tapping into system memory. It
-offers manual $(D free) and dutifully collects litter.))
-
-$(TR $(TDC2 Mallocator) $(TD The C heap _allocator, a.k.a. $(D
-malloc)/$(D realloc)/$(D free). Use sparingly and only for code that is unlikely
-to leak.))
-
-$(TR $(TDC2 AlignedMallocator) $(TD Interface to OS-specific _allocators that
-support specifying alignment:
-$(WEB man7.org/linux/man-pages/man3/posix_memalign.3.html, $(D posix_memalign))
-on Posix and $(WEB msdn.microsoft.com/en-us/library/fs9stz4e(v=vs.80).aspx,
-$(D __aligned_xxx)) on Windows.))
-
-$(TR $(TDC2 AffixAllocator) $(TD Allocator that allows and manages allocating
-extra prefix and/or a suffix bytes for each block allocated.))
-
-$(TR $(TDC2 HeapBlock) $(TD Organizes one contiguous chunk of memory in
-equal-size blocks and tracks allocation status at the cost of one bit per
-block.))
-
-$(TR $(TDC2 FallbackAllocator) $(TD Allocator that combines two other allocators
- - primary and fallback. Allocation requests are first tried with primary, and
- upon failure are passed to the fallback. Useful for small and fast allocators
- fronting general-purpose ones.))
-
-$(TR $(TDC2 Freelist) $(TD Allocator that implements a $(WEB
-wikipedia.org/wiki/Free_list, free list) on top of any other allocator. The
-preferred size, tolerance, and maximum elements are configurable at compile- and
-run time.))
-
-$(TR $(TDC2 SharedFreelist) $(TD Same features as $(D Freelist), but packaged as
-a $(D shared) structure that is accessible to several threads.))
-
-$(TR $(TDC2 Region) $(TD Region allocator organizes a chunk of memory as a
-simple bump-the-pointer allocator.))
-
-$(TR $(TDC2 InSituRegion) $(TD Region holding its own allocation, most often on
-the stack. Has statically-determined size.))
-
-$(TR $(TDC2 AllocatorWithStats) $(TD Collect statistics about any other
-allocator.))
-
-$(TR $(TDC2 CascadingAllocator) $(TD Given an allocator factory, lazily creates as
-many allocators as needed to satisfy allocation requests. The allocators are
-stored in a linked list. Requests for allocation are satisfied by searching the
-list in a linear manner.))
-
-$(TR $(TDC2 Segregator) $(TD Segregates allocation requests by size and
-dispatches them to distinct allocators.))
-
-$(TR $(TDC2 Bucketizer) $(TD Divides allocation sizes in discrete buckets and
-uses an array of allocators, one per bucket, to satisfy requests.))
-
-)
- */
-
-module std.allocator;
-
-// Example in the synopsis above
-unittest
-{
- alias FList = Freelist!(GCAllocator, 0, unbounded);
- alias A = Segregator!(
- 8, Freelist!(GCAllocator, 0, 8),
- 128, Bucketizer!(FList, 1, 128, 16),
- 256, Bucketizer!(FList, 129, 256, 32),
- 512, Bucketizer!(FList, 257, 512, 64),
- 1024, Bucketizer!(FList, 513, 1024, 128),
- 2048, Bucketizer!(FList, 1025, 2048, 256),
- 3584, Bucketizer!(FList, 2049, 3584, 512),
- 4072 * 1024, CascadingAllocator!(
- () => HeapBlock!(GCAllocator, 4096)(4072 * 1024)),
- GCAllocator
- );
- A tuMalloc;
- auto b = tuMalloc.allocate(500);
- assert(b.length == 500);
- auto c = tuMalloc.allocate(113);
- assert(c.length == 113);
- assert(tuMalloc.expand(c, 14));
- tuMalloc.deallocate(b);
- tuMalloc.deallocate(c);
-}
-
-import std.algorithm, std.conv, std.exception, std.range, std.traits,
- std.typecons, std.typetuple;
-version(unittest) import std.stdio;
-
-/*
-Ternary by Timon Gehr and Andrei Alexandrescu.
-*/
-private struct Ternary
-{
- private ubyte value = 6;
- private static Ternary make(ubyte b)
- {
- Ternary r = void;
- r.value = b;
- return r;
- }
-
- enum no = make(0), yes = make(2), unknown = make(6);
-
- this(bool b) { value = b << 1; }
-
- void opAssign(bool b) { value = b << 1; }
-
- Ternary opUnary(string s)() if (s == "~")
- {
- return make(386 >> value & 6);
- }
-
- Ternary opBinary(string s)(Ternary rhs) if (s == "|")
- {
- return make(25512 >> value + rhs.value & 6);
- }
-
- Ternary opBinary(string s)(Ternary rhs) if (s == "&")
- {
- return make(26144 >> value + rhs.value & 6);
- }
-
- Ternary opBinary(string s)(Ternary rhs) if (s == "^")
- {
- return make(26504 >> value + rhs.value & 6);
- }
-}
-
-unittest
-{
- alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown;
- auto truthTableAnd =
- [
- t, t, t,
- t, u, u,
- t, f, f,
- u, t, u,
- u, u, u,
- u, f, f,
- f, t, f,
- f, u, f,
- f, f, f,
- ];
-
- auto truthTableOr =
- [
- t, t, t,
- t, u, t,
- t, f, t,
- u, t, t,
- u, u, u,
- u, f, u,
- f, t, t,
- f, u, u,
- f, f, f,
- ];
-
- auto truthTableXor =
- [
- t, t, f,
- t, u, u,
- t, f, t,
- u, t, u,
- u, u, u,
- u, f, u,
- f, t, t,
- f, u, u,
- f, f, f,
- ];
-
- for (auto i = 0; i != truthTableAnd.length; i += 3)
- {
- assert((truthTableAnd[i] & truthTableAnd[i + 1])
- == truthTableAnd[i + 2]);
- assert((truthTableOr[i] | truthTableOr[i + 1])
- == truthTableOr[i + 2]);
- assert((truthTableXor[i] ^ truthTableXor[i + 1])
- == truthTableXor[i + 2]);
- }
-
- Ternary a;
- assert(a == Ternary.unknown);
- static assert(!is(typeof({ if (a) {} })));
- assert(!is(typeof({ auto b = Ternary(3); })));
- a = true;
- assert(a == Ternary.yes);
- a = false;
- assert(a == Ternary.no);
- a = Ternary.unknown;
- assert(a == Ternary.unknown);
- Ternary b;
- b = a;
- assert(b == a);
- assert(~Ternary.yes == Ternary.no);
- assert(~Ternary.no == Ternary.yes);
- assert(~Ternary.unknown == Ternary.unknown);
-}
-
-/**
-Returns the size in bytes of the state that needs to be allocated to hold an
-object of type $(D T). $(D stateSize!T) is zero for $(D struct)s that are not
-nested and have no nonstatic member variables.
- */
-private template stateSize(T)
-{
- static if (is(T == class) || is(T == interface))
- enum stateSize = __traits(classInstanceSize, T);
- else static if (is(T == struct) || is(T == union))
- enum stateSize = FieldTypeTuple!T.length || isNested!T ? T.sizeof : 0;
- else static if (is(T == void))
- enum size_t stateSize = 0;
- else
- enum stateSize = T.sizeof;
-}
-
-unittest
-{
- static assert(stateSize!void == 0);
- struct A {}
- static assert(stateSize!A == 0);
- struct B { int x; }
- static assert(stateSize!B == 4);
- interface I1 {}
- static assert(stateSize!I1 == 2 * size_t.sizeof);
- class C1 {}
- static assert(stateSize!C1 == 3 * size_t.sizeof);
- class C2 { char c; }
- static assert(stateSize!C2 == 4 * size_t.sizeof);
- static class C3 { char c; }
- 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
-the exact value. For example, $(D HeapBlock!(Allocator, 4096)) (described in
-detail below) defines a block allocator with block size of 4096 bytes, whereas
-$(D HeapBlock!(Allocator, chooseAtRuntime)) defines a block allocator that has a
-field storing the block size, initialized by the user.
-*/
-enum chooseAtRuntime = size_t.max - 1;
-
-/**
-$(D unbounded) is a compile-time constant of type $(D size_t) that several
-parameterized structures in this module recognize to mean "infinite" bounds for
-the parameter. For example, $(D Freelist) (described in detail below) accepts a
-$(D maxNodes) parameter limiting the number of freelist items. If $(D unbounded)
-is passed for $(D maxNodes), then there is no limit and no checking for the
-number of nodes.
-*/
-enum unbounded = size_t.max;
-
-/**
-The alignment that is guaranteed to accommodate any D object allocation on the
-current platform.
-*/
-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) pure nothrow
-{
- return n.roundUpToMultipleOf(a.alignment);
-}
-
-/**
-The default $(D reallocate) function first attempts to use $(D expand). If $(D
-Allocator.expand) is not defined or returns $(D false), $(D reallocate)
-allocates a new block of memory of appropriate size and copies data from the old
-block to the new block. Finally, if $(D Allocator) defines $(D deallocate), $(D
-reallocate) uses it to free the old memory block.
-
-$(D reallocate) does not attempt to use $(D Allocator.reallocate) even if
-defined. This is deliberate so allocators may use it internally within their own
-implementation of $(D reallocate).
-
-*/
-bool reallocate(Allocator)(ref Allocator a, ref void[] b, size_t s)
-{
- if (b.length == s) return true;
- static if (hasMember!(Allocator, "expand"))
- {
- if (b.length <= s && a.expand(b, s - b.length)) return true;
- }
- auto newB = a.allocate(s);
- if (newB.length <= b.length) newB[] = b[0 .. newB.length];
- else newB[0 .. b.length] = b[];
- static if (hasMember!(Allocator, "deallocate"))
- a.deallocate(b);
- b = newB;
- return true;
-}
-
-/*
- _ _ _ _ _ _ _
- | \ | | | | | /\ | | | | |
- | \| |_ _| | | / \ | | | ___ ___ __ _| |_ ___ _ __
- | . ` | | | | | | / /\ \ | | |/ _ \ / __/ _` | __/ _ \| '__|
- | |\ | |_| | | |/ ____ \| | | (_) | (_| (_| | || (_) | |
- |_| \_|\__,_|_|_/_/ \_\_|_|\___/ \___\__,_|\__\___/|_|
-*/
-/**
-$(D NullAllocator) is an emphatically empty implementation of the allocator interface. Although it has no direct use, it is useful as a "terminator" in composite allocators.
-*/
-struct NullAllocator
-{
- /**
- $(D NullAllocator) advertises a relatively large _alignment equal to 64 KB.
- This is because $(D NullAllocator) never actually needs to honor this
- alignment and because composite allocators using $(D NullAllocator)
- shouldn't be unnecessarily constrained.
- */
- enum uint alignment = 64 * 1024;
- /// Always returns $(D null).
- void[] allocate(size_t) shared { return null; }
- /// Returns $(D b is null).
- bool owns(void[] b) shared { return b is null; }
- /**
- These methods return $(D false).
- Precondition: $(D b is null). This is because there is no other possible
- legitimate input.
- */
- bool expand(ref void[] b, size_t) shared
- { assert(b is null); return false; }
- /// Ditto
- bool reallocate(ref void[] b, size_t) shared
- { assert(b is null); return false; }
- /**
- No-op.
- Precondition: $(D b is null)
- */
- void deallocate(void[] b) shared { assert(b is null); }
- /**
- 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).
- */
- private static shared const NullAllocator _it;
-}
-
-unittest
-{
- auto b = NullAllocator.it.allocate(100);
- assert(b is null);
- NullAllocator.it.deallocate(b);
- NullAllocator.it.deallocateAll();
- assert(NullAllocator.it.owns(null));
-}
-
-/**
-D's built-in garbage-collected allocator.
- */
-struct GCAllocator
-{
- private import core.memory;
-
- /**
- The alignment is a static constant equal to $(D platformAlignment), which
- ensures proper alignment for any D data type.
- */
- 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.
- */
- @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 nothrow pure
- {
- auto newSize = GC.extend(b.ptr, b.length + delta,
- b.length + delta);
- if (newSize == 0)
- {
- // expansion unsuccessful
- return false;
- }
- assert(newSize >= b.length + delta);
- b = b.ptr[0 .. newSize];
- return true;
- }
-
- /// Ditto
- @system bool reallocate(ref void[] b, size_t newSize) shared nothrow pure
- {
- import core.exception : OutOfMemoryError;
- try
- {
- auto p = cast(ubyte*) GC.realloc(b.ptr, newSize);
- b = p[0 .. newSize];
- }
- catch (OutOfMemoryError)
- {
- // leave the block in place, tell caller
- return false;
- }
- return true;
- }
-
- /// Ditto
- @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).
- */
- private static shared const GCAllocator _it;
-
- // Leave it undocummented for now.
- @trusted void collect() shared
- {
- GC.collect();
- }
-}
-
-///
-unittest
-{
- auto buffer = GCAllocator.it.allocate(1024 * 1024 * 4);
- scope(exit) GCAllocator.it.deallocate(buffer); // or leave it to collection
- //...
-}
-
-unittest
-{
- auto b = GCAllocator.it.allocate(10000);
- 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;
-
- /**
- The alignment is a static constant equal to $(D platformAlignment), which ensures proper alignment for any D data type.
- */
- 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.
- */
- void[] allocate(size_t bytes) shared pure nothrow @trusted
- {
- auto p = malloc(bytes);
- return p ? p[0 .. bytes] : null;
- }
-
- /// Ditto
- void deallocate(void[] b) shared pure nothrow @system
- {
- free(b.ptr);
- }
-
- /// Ditto
- bool reallocate(ref void[] b, size_t s) shared pure nothrow @system
- {
- if (!s)
- {
- // fuzzy area in the C standard, see http://goo.gl/ZpWeSE
- // so just deallocate and nullify the pointer
- deallocate(b);
- b = null;
- return true;
- }
- auto p = cast(ubyte*) realloc(b.ptr, s);
- if (!p) return false;
- b = p[0 .. s];
- 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).
- */
- private static shared const Mallocator _it;
-}
-
-///
-unittest
-{
- auto buffer = Mallocator.it.allocate(1024 * 1024 * 4);
- scope(exit) Mallocator.it.deallocate(buffer);
- //...
-}
-
-unittest
-{
- static void test(A)()
- {
- int* p = null;
- p = new int;
- *p = 42;
- assert(*p == 42);
- }
-
- test!GCAllocator();
- test!Mallocator();
-}
-
-unittest
-{
- static void test(A)()
- {
- Object p = null;
- p = new Object;
- assert(p !is null);
- }
-
- test!GCAllocator();
- test!Mallocator();
-}
-
-/**
-Returns s rounded up to a multiple of base.
-*/
-private size_t roundUpToMultipleOf(size_t s, uint base) pure nothrow @safe
-{
- assert(base);
- auto rem = s % base;
- return rem ? s + base - rem : s;
-}
-
-unittest
-{
- assert(10.roundUpToMultipleOf(11) == 11);
- assert(11.roundUpToMultipleOf(11) == 11);
- assert(12.roundUpToMultipleOf(11) == 22);
- assert(118.roundUpToMultipleOf(11) == 121);
-}
-
-/**
-Returns s rounded up to a multiple of base.
-*/
-private void[] roundStartToMultipleOf(void[] s, uint base) pure nothrow @trusted
-{
- assert(base);
- auto p = cast(void*) roundUpToMultipleOf(
- cast(size_t) s.ptr, base);
- auto end = s.ptr + s.length;
- return p[0 .. end - p];
-}
-
-unittest
-{
- void[] p;
- assert(roundStartToMultipleOf(p, 16) is null);
- p = new ulong[10];
- assert(roundStartToMultipleOf(p, 16) is p);
-}
-
-/**
-Returns $(D s) rounded up to the nearest power of 2.
-*/
-private size_t roundUpToPowerOf2(size_t s) pure nothrow @safe
-{
- assert(s <= (size_t.max >> 1) + 1);
- --s;
- static if (size_t.sizeof == 4)
- alias Shifts = TypeTuple!(1, 2, 4, 8, 16);
- else
- alias Shifts = TypeTuple!(1, 2, 4, 8, 16, 32);
- foreach (i; Shifts)
- {
- s |= s >> i;
- }
- return s + 1;
-}
-
-unittest
-{
- assert(0.roundUpToPowerOf2 == 0);
- assert(1.roundUpToPowerOf2 == 1);
- assert(2.roundUpToPowerOf2 == 2);
- assert(3.roundUpToPowerOf2 == 4);
- assert(7.roundUpToPowerOf2 == 8);
- assert(8.roundUpToPowerOf2 == 8);
- assert(10.roundUpToPowerOf2 == 16);
- assert(11.roundUpToPowerOf2 == 16);
- assert(12.roundUpToPowerOf2 == 16);
- assert(118.roundUpToPowerOf2 == 128);
- assert((size_t.max >> 1).roundUpToPowerOf2 == (size_t.max >> 1) + 1);
- assert(((size_t.max >> 1) + 1).roundUpToPowerOf2 == (size_t.max >> 1) + 1);
-}
-
-/**
-
-Allocator that adds some extra data before (of type $(D Prefix)) and/or after
-(of type $(D Suffix)) any allocation made with its parent allocator. This is
-useful for uses where additional allocation-related information is needed, such
-as mutexes, reference counts, or walls for debugging memory corruption errors.
-
-If $(D Prefix) is not $(D void), $(D Allocator) must guarantee an alignment at
-least as large as $(D Prefix.alignof).
-
-Suffixes are slower to get at because of alignment rounding, so prefixes should
-be preferred. However, small prefixes blunt the alignment so if a large
-alignment with a small affix is needed, suffixes should be chosen.
-
- */
-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.");
- static assert(alignment % Suffix.alignof == 0,
- "This restriction could be relaxed in the future.");
-
- /**
- If $(D Prefix) is $(D void), the alignment is that of the parent. Otherwise, the alignment is the same as the $(D Prefix)'s alignment.
- */
- enum uint alignment =
- stateSize!Prefix ? Allocator.alignment : Prefix.alignof;
-
- /**
- If the parent allocator $(D Allocator) is stateful, an instance of it is
- stored as a member. Otherwise, $(D AffixAllocator) uses $(D Allocator.it).
- In either case, the name $(D _parent) is uniformly used for accessing the
- parent allocator.
- */
- static if (stateSize!Allocator) Allocator parent;
- else alias parent = Allocator.it;
-
- template Impl()
- {
- size_t goodAllocSize(size_t s) pure nothrow const
- {
- return parent.goodAllocSize(actualAllocationSize(s));
- }
-
- private size_t actualAllocationSize(size_t s) const
- {
- static if (!stateSize!Suffix)
- {
- return s + stateSize!Prefix;
- }
- else
- {
- return roundUpToMultipleOf(
- s + stateSize!Prefix,
- Suffix.alignof) + stateSize!Suffix;
- }
- }
-
- private void[] actualAllocation(void[] b) const
- {
- assert(b !is null);
- return (b.ptr - stateSize!Prefix)
- [0 .. actualAllocationSize(b.length)];
- }
-
- void[] allocate(size_t bytes)
- {
- auto result = parent.allocate(actualAllocationSize(bytes));
- if (result is null) return null;
- static if (stateSize!Prefix)
- emplace!Prefix(cast(Prefix*)result.ptr);
- static if (stateSize!Suffix)
- emplace!Suffix(
- cast(Suffix*)(result.ptr + result.length - Suffix.sizeof));
- return result[stateSize!Prefix .. stateSize!Prefix + bytes];
- }
-
- static if (hasMember!(Allocator, "owns"))
- bool owns(void[] b)
- {
- return b is null ? true : parent.owns(actualAllocation(b));
- }
-
- static if (!stateSize!Suffix && hasMember!(Allocator, "expand"))
- bool expand(ref void[] b, size_t delta)
- {
- auto t = actualAllocation(b);
- auto result = parent.expand(t, delta);
- if (!result) return false;
- b = b.ptr[0 .. b.length + delta];
- return true;
- }
-
- static if (hasMember!(Allocator, "reallocate"))
- bool reallocate(ref void[] b, size_t s)
- {
- auto t = actualAllocation(b);
- auto result = parent.reallocate(t, actualAllocationSize(s));
- if (!result) return false; // no harm done
- b = t.ptr[stateSize!Prefix .. stateSize!Prefix + s];
- return true;
- }
-
- static if (hasMember!(Allocator, "deallocate"))
- void deallocate(void[] b)
- {
- auto p = b.ptr - stateSize!Prefix;
- parent.deallocate(p[0 .. actualAllocationSize(b.length)]);
- }
-
- static if (hasMember!(Allocator, "deallocateAll"))
- void deallocateAll()
- {
- parent.deallocateAll();
- }
-
- // Extra functions
- static if (stateSize!Prefix)
- static ref Prefix prefix(void[] b)
- {
- return (cast(Prefix*)b.ptr)[-1];
- }
- static if (stateSize!Suffix)
- ref Suffix suffix(void[] b)
- {
- auto p = b.ptr - stateSize!Prefix
- + actualAllocationSize(b.length);
- return (cast(Prefix*) p)[-1];
- }
- }
-
- version (StdDdoc)
- {
- /**
- Standard allocator methods. Each is defined if and only if the parent
- allocator defines the homonym method (except for $(D goodAllocSize),
- 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) pure nothrow const;
- /// Ditto
- void[] allocate(size_t) pure nothrow;
- /// Ditto
- bool owns(void[]) pure nothrow;
- /// Ditto
- bool expand(ref void[] b, size_t delta) pure nothrow;
- /// Ditto
- bool reallocate(ref void[] b, size_t s)pure nothrow;
- /// Ditto
- void deallocate(void[] b) pure nothrow;
- /// Ditto
- 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.
- */
- 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).
-
- Precondition: $(D b !is null)
- */
- static ref Prefix prefix(void[] b);
- /// Ditto
- static ref Suffix suffix(void[] b);
- }
- else static if (is(typeof(Allocator.it) == shared))
- {
- static shared AffixAllocator it;
- shared { mixin Impl!(); }
- }
- else
- {
- mixin Impl!();
- static if (stateSize!Allocator == 0)
- static __gshared AffixAllocator it;
- }
-}
-
-///
-unittest
-{
- // One word before and after each allocation.
- alias A = AffixAllocator!(Mallocator, size_t, size_t);
- auto b = A.it.allocate(11);
- A.it.prefix(b) = 0xCAFE_BABE;
- A.it.suffix(b) = 0xDEAD_BEEF;
- assert(A.it.prefix(b) == 0xCAFE_BABE && A.it.suffix(b) == 0xDEAD_BEEF);
-}
-
-unittest
-{
- alias A = AffixAllocator!(Mallocator, size_t);
- auto b = A.it.allocate(10);
- A.it.prefix(b) = 10;
- assert(A.it.prefix(b) == 10);
-
- alias B = AffixAllocator!(NullAllocator, size_t);
- b = B.it.allocate(100);
- assert(b is null);
-}
-
-/**
-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) pure nothrow @safe
-{
- uint result = 0;
- while (cast(long) x < 0)
- {
- ++result;
- x <<= 1;
- }
- return result;
-}
-
-unittest
-{
- assert(leadingOnes(0) == 0);
- assert(leadingOnes(~0UL) == 64);
- assert(leadingOnes(0xF000_0000_0000_0000) == 4);
- assert(leadingOnes(0xE400_0000_0000_0000) == 3);
- assert(leadingOnes(0xC700_0200_0000_0000) == 2);
- assert(leadingOnes(0x8000_0030_0000_0000) == 1);
- assert(leadingOnes(0x2000_0000_0000_0000) == 0);
-}
-
-/**
-Finds a run of contiguous ones in $(D x) of length at least $(D n).
-*/
-private uint findContigOnes(ulong x, uint n) pure nothrow @safe
-{
- while (n > 1)
- {
- immutable s = n >> 1;
- x &= x << s;
- n -= s;
- }
- return leadingOnes(~x);
-}
-
-unittest
-{
- assert(findContigOnes(0x0000_0000_0000_0300, 2) == 54);
-
- assert(findContigOnes(~0UL, 1) == 0);
- assert(findContigOnes(~0UL, 2) == 0);
- assert(findContigOnes(~0UL, 32) == 0);
- assert(findContigOnes(~0UL, 64) == 0);
- assert(findContigOnes(0UL, 1) == 64);
-
- assert(findContigOnes(0x4000_0000_0000_0000, 1) == 1);
- assert(findContigOnes(0x0000_0F00_0000_0000, 4) == 20);
-}
-
-/**
-Returns the number of trailing zeros of $(D x).
-*/
-private uint trailingZeros(ulong x) pure nothrow @safe
-{
- uint result;
- while (result < 64 && !(x & (1UL << result)))
- {
- ++result;
- }
- return result;
-}
-
-unittest
-{
- assert(trailingZeros(0) == 64);
- assert(trailingZeros(1) == 0);
- assert(trailingZeros(2) == 1);
- assert(trailingZeros(3) == 0);
- assert(trailingZeros(4) == 2);
-}
-
-/*
-Unconditionally sets the bits from lsb through msb in w to zero.
-*/
-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));
- w |= mask;
-}
-
-unittest
-{
- ulong w;
- w = 0; setBits(w, 0, 63); assert(w == ulong.max);
- w = 0; setBits(w, 1, 63); assert(w == ulong.max - 1);
- w = 6; setBits(w, 0, 1); assert(w == 7);
- w = 6; setBits(w, 3, 3); assert(w == 14);
-}
-
-/* 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) pure nothrow @safe
-{
- assert(lsb <= msb && msb < 64);
- const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb));
- if (w & mask) return false;
- w |= mask;
- return true;
-}
-
-unittest
-{
- // TODO
-}
-
-// Assigns bits in w from lsb through msb to zero.
-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
-of memory organized in blocks, each of size $(D theBlockSize). A block is a unit
-of allocation. A bitmap serves as bookkeeping data, more precisely one bit per
-block indicating whether that block is currently allocated or not.
-
-There are advantages to storing bookkeeping data separated from the payload
-(as opposed to e.g. $(D AffixAllocator)). The layout is more compact, searching
-for a free block during allocation enjoys better cache locality, and
-deallocation does not touch memory around the payload being deallocated (which
-is often cold).
-
-Allocation requests are handled on a first-fit basis. Although linear in
-complexity, allocation is in practice fast because of the compact bookkeeping
-representation, use of simple and fast bitwise routines, and memoization of the
-first available block position. A known issue with this general approach is
-fragmentation, partially mitigated by coalescing. Since $(D HeapBlock) does
-not maintain the allocated size, freeing memory implicitly coalesces free blocks
-together. Also, tuning $(D blockSize) has a considerable impact on both internal
-and external fragmentation.
-
-The size of each block can be selected either during compilation or at run
-time. Statically-known block sizes are frequent in practice and yield slightly
-better performance. To choose a block size statically, pass it as the $(D
-blockSize) parameter as in $(D HeapBlock!(Allocator, 4096)). To choose a block
-size parameter, use $(D HeapBlock!(Allocator, chooseAtRuntime)) and pass the
-block size to the constructor.
-
-TODO: implement $(D alignedAllocate) and $(D alignedReallocate).
-
-*/
-struct HeapBlock(Allocator, size_t theBlockSize,
- size_t theAlignment = platformAlignment)
-{
- static assert(theBlockSize > 0 && theAlignment.isGoodStaticAlignment);
-
- /**
- Parent allocator. If it has no state, $(D parent) is an alias for $(D
- Allocator.it).
- */
- static if (stateSize!Allocator) Allocator parent;
- else alias parent = Allocator.it;
-
- /**
- If $(D blockSize == chooseAtRuntime), $(D HeapBlock) offers a read/write
- property $(D blockSize). It must be set to a power of two before any use
- of the allocator. Otherwise, $(D blockSize) is an alias for $(D
- theBlockSize).
- */
- static if (theBlockSize != chooseAtRuntime)
- {
- alias blockSize = theBlockSize;
- }
- else
- {
- @property uint blockSize() { return _blockSize; }
- @property void blockSize(uint s)
- {
- assert(!_control && s % alignment == 0);
- _blockSize = s;
- }
- private uint _blockSize;
- }
-
- /**
- The alignment offered is user-configurable statically through parameter
- $(D theAlignment), defaulted to $(D platformAlignment).
- */
- alias alignment = theAlignment;
-
- private uint _blocks;
- private ulong[] _control;
- private void[] _payload;
- private size_t _startIdx;
-
- /**
- Constructs a block allocator given the total number of blocks. Only one $(D
- parent.allocate) call will be made, and the layout puts the bitmap at the
- front followed immediately by the payload. The constructor does not perform the allocation, however; allocation is done lazily upon the first call to
- $(D allocate).
- */
- this(uint blocks)
- {
- _blocks = blocks;
- }
-
- private void initialize() pure nothrow @trusted
- {
- assert(_blocks);
- const controlBytes = ((_blocks + 63) / 64) * 8;
- const controlBytesRounded = controlBytes.roundUpToMultipleOf(
- alignment);
- const payloadBytes = _blocks * blockSize;
- auto allocatedByUs = parent.allocate(
- controlBytesRounded // control bits
- + payloadBytes // payload
- );
- auto m = cast(ulong[]) allocatedByUs;
- _control = m[0 .. controlBytes / 8];
- _control[] = 0;
- _payload = m[controlBytesRounded / 8 .. $];
- assert(_payload.length == _blocks * blockSize/+,
- text(_payload.length, " != ", _blocks * blockSize)+/);
- }
-
- private void initialize(void[] store) pure nothrow @trusted
- {
- assert(store.length);
- // Round store to be ulong-aligned
- store = store.roundStartToMultipleOf(ulong.alignof);
- assert(store.length);
- /* Divide data between control and payload. The equation is (in real
- numbers, not integers): bs * x + x / 8 = store.length, where x is
- the number of blocks.
- */
- double approxBlocks = (8.0 * store.length) / (8 * blockSize + 1);
- import std.math;
- auto blocks = cast(size_t) (approxBlocks + nextDown(1.0));
- assert(blocks > 0);
- assert(blockSize);
- assert(blocks * blockSize + ((blocks + 63) / 64) * 8 >= store.length/+,
- text(approxBlocks, " ", blocks, " ", blockSize, " ",
- store.length)+/);
- while (blocks * blockSize + ((blocks + 63) / 64) * 8 > store.length)
- {
- --blocks;
- assert(blocks > 0);
- }
- auto control = cast(ulong[]) store[0 .. ((blocks + 63) / 64) * 8];
- store = store[control.length * 8 .. $];
- // Take into account data alignment necessities
- store = store.roundStartToMultipleOf(alignment);
- assert(store.length);
- while (blocks * blockSize > store.length)
- {
- --blocks;
- }
- auto payload = store[0 .. blocks * blockSize];
- initialize(control, payload, blockSize);
- }
-
- private void initialize(ulong[] control, void[] payload, size_t blockSize)
- pure nothrow @trusted
- {
- assert(payload.length % blockSize == 0);
- assert(payload.length / blockSize <= uint.max);
- _blocks = cast(uint) (payload.length / blockSize);
- const controlWords = (_blocks + 63) / 64;
- assert(controlWords == control.length);
- _control = control;
- assert(control.equal(repeat(0, control.length)));
- _payload = payload;
- }
-
- /*
- Adjusts the memoized _startIdx to the leftmost control word that has at
- least one zero bit. Assumes all control words to the left of $(D
- _control[_startIdx]) are already occupied.
- */
- private void adjustStartIdx()
- {
- while (_startIdx < _control.length && _control[_startIdx] == ulong.max)
- {
- ++_startIdx;
- }
- }
-
- /*
- Returns the blocks corresponding to the control bits starting at word index
- wordIdx and bit index msbIdx (MSB=0) for a total of howManyBlocks.
- */
- private void[] blocksFor(size_t wordIdx, uint msbIdx, size_t howManyBlocks)
- {
- assert(msbIdx <= 63);
- const start = (wordIdx * 64 + msbIdx) * blockSize;
- const end = start + blockSize * howManyBlocks;
- if (end <= _payload.length) return _payload[start .. end];
- // This could happen if we have more control bits than available memory.
- // That's possible because the control bits are rounded up to fit in
- // 64-bit words.
- return null;
- }
-
- /**
- 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.
-
- BUGS: Neither $(D deallocateAll) nor the destructor free the original memory
- block. Either user code or the parent allocator should carry that.
- */
- void[] allocate(const size_t s) pure nothrow @trusted
- {
- if (!_control)
- {
- // Lazy initialize
- if (!_blocks)
- static if (hasMember!(Allocator, "allocateAll"))
- initialize(parent.allocateAll);
- else
- return null;
- else
- initialize();
- }
- assert(_blocks && _control && _payload);
- const blocks = (s + blockSize - 1) / blockSize;
- void[] result = void;
-
- switcharoo:
- switch (blocks)
- {
- case 1:
- // inline code here for speed
- // find the next available block
- foreach (i; _startIdx .. _control.length)
- {
- const w = _control[i];
- if (w == ulong.max) continue;
- uint j = leadingOnes(w);
- assert(j < 64);
- assert((_control[i] & ((1UL << 63) >> j)) == 0);
- _control[i] |= (1UL << 63) >> j;
- if (i == _startIdx)
- {
- adjustStartIdx();
- }
- result = blocksFor(i, j, 1);
- break switcharoo;
- }
- goto case 0; // fall through
- case 0:
- return null;
- case 2: .. case 63:
- result = smallAlloc(cast(uint) blocks);
- break;
- default:
- result = hugeAlloc(blocks);
- break;
- }
- return result ? result.ptr[0 .. s] : null;
- }
-
- /// Ditto
- bool owns(void[] b) const pure nothrow @trusted
- {
- return b.ptr >= _payload.ptr
- && b.ptr + b.length <= _payload.ptr + _payload.length
- || b is null;
- }
-
- /*
- Tries to allocate "blocks" blocks at the exact position indicated by the
- position wordIdx/msbIdx (msbIdx counts from MSB, i.e. MSB has index 0). If
- it succeeds, fills "result" with the result and returns tuple(size_t.max,
- 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) pure nothrow @trusted
- {
- assert(blocks > 0);
- assert(wordIdx < _control.length);
- assert(msbIdx <= 63);
- if (msbIdx + blocks <= 64)
- {
- // Allocation should fit this control word
- if (setBitsIfZero(_control[wordIdx],
- cast(uint) (64 - msbIdx - blocks), 63 - msbIdx))
- {
- // Success
- result = blocksFor(wordIdx, msbIdx, blocks);
- return tuple(size_t.max, 0u);
- }
- // Can't allocate, make a suggestion
- return msbIdx + blocks == 64
- ? tuple(wordIdx + 1, 0u)
- : tuple(wordIdx, cast(uint) (msbIdx + blocks));
- }
- // Allocation spans two control words or more
- auto mask = ulong.max >> msbIdx;
- if (_control[wordIdx] & mask)
- {
- // We can't allocate the rest of this control word,
- // return a suggestion.
- return tuple(wordIdx + 1, 0u);
- }
- // We can allocate the rest of this control word, but we first need to
- // make sure we can allocate the tail.
- if (wordIdx + 1 == _control.length)
- {
- // No more memory
- return tuple(_control.length, 0u);
- }
- auto hint = allocateAt(wordIdx + 1, 0, blocks - 64 + msbIdx, result);
- if (hint[0] == size_t.max)
- {
- // We did it!
- _control[wordIdx] |= mask;
- result = blocksFor(wordIdx, msbIdx, blocks);
- return tuple(size_t.max, 0u);
- }
- // Failed, return a suggestion that skips this whole run.
- return hint;
- }
-
- /* Allocates as many blocks as possible at the end of the blocks indicated
- by wordIdx. Returns the number of blocks allocated. */
- private uint allocateAtTail(size_t wordIdx)
- {
- assert(wordIdx < _control.length);
- const available = trailingZeros(_control[wordIdx]);
- _control[wordIdx] |= ulong.max >> available;
- return available;
- }
-
- private void[] smallAlloc(uint blocks) pure nothrow @trusted
- {
- assert(blocks >= 2 && blocks <= 64/+, text(blocks)+/);
- foreach (i; _startIdx .. _control.length)
- {
- // Test within the current 64-bit word
- const v = _control[i];
- if (v == ulong.max) continue;
- auto j = findContigOnes(~v, blocks);
- if (j < 64)
- {
- // yay, found stuff
- setBits(_control[i], 64 - j - blocks, 63 - j);
- return blocksFor(i, j, blocks);
- }
- // Next, try allocations that cross a word
- auto available = trailingZeros(v);
- if (available == 0) continue;
- if (i + 1 >= _control.length) break;
- assert(available < blocks); // otherwise we should have found it
- auto needed = blocks - available;
- assert(needed > 0 && needed < 64);
- if (allocateAtFront(i + 1, needed))
- {
- // yay, found a block crossing two words
- _control[i] |= (1UL << available) - 1;
- return blocksFor(i, 64 - available, blocks);
- }
- }
- return null;
- }
-
- private void[] hugeAlloc(size_t blocks) pure nothrow @trusted
- {
- assert(blocks > 64);
- void[] result;
- auto pos = tuple(_startIdx, 0);
- for (;;)
- {
- if (pos[0] >= _control.length)
- {
- // No more memory
- return null;
- }
- pos = allocateAt(pos[0], pos[1], blocks, result);
- if (pos[0] == size_t.max)
- {
- // Found and allocated
- return result;
- }
- }
- }
-
- // Rounds sizeInBytes to a multiple of blockSize.
- private size_t bytes2blocks(size_t sizeInBytes)
- {
- return (sizeInBytes + blockSize - 1) / blockSize;
- }
-
- /* Allocates given blocks at the beginning blocks indicated by wordIdx.
- Returns true if allocation was possible, false otherwise. */
- private bool allocateAtFront(size_t wordIdx, uint blocks)
- {
- assert(wordIdx < _control.length && blocks >= 1 && blocks <= 64);
- const mask = (1UL << (64 - blocks)) - 1;
- if (_control[wordIdx] > mask) return false;
- // yay, works
- _control[wordIdx] |= ~mask;
- return true;
- }
-
- /// Ditto
- bool expand(ref void[] b, size_t delta) pure nothrow @trusted
- {
- //debug writefln("expand(%s, %s, %s)", b, minDelta, desiredDelta);
- if (b is null)
- {
- b = allocate(delta);
- return b !is null;
- }
-
- const blocksOld = bytes2blocks(b.length);
- const blocksNew = bytes2blocks(b.length + delta);
- assert(blocksOld <= blocksNew);
-
- // Possibly we have enough slack at the end of the block!
- if (blocksOld == blocksNew)
- {
- b = b.ptr[0 .. b.length + delta];
- return true;
- }
-
- assert((b.ptr - _payload.ptr) % blockSize == 0);
- const blockIdx = (b.ptr - _payload.ptr) / blockSize;
- const blockIdxAfter = blockIdx + blocksOld;
- //writefln("blockIdx: %s, blockIdxAfter: %s", blockIdx, blockIdxAfter);
-
- // Try the maximum
- const wordIdx = blockIdxAfter / 64,
- msbIdx = cast(uint) (blockIdxAfter % 64);
- void[] p;
- auto hint = allocateAt(wordIdx, msbIdx, blocksNew - blocksOld, p);
- if (hint[0] != size_t.max)
- {
- return false;
- }
- // Expansion successful
- assert(p.ptr == b.ptr + blocksOld * blockSize/+,
- text(p.ptr, " != ", b.ptr + blocksOld * blockSize)+/);
- b = b.ptr[0 .. b.length + delta];
- return true;
- }
-
- /// Ditto
- bool reallocate(ref void[] b, size_t newSize) pure nothrow @system
- {
- if (newSize == 0)
- {
- deallocate(b);
- b = null;
- return true;
- }
- if (newSize < b.length)
- {
- // Shrink. Will shrink in place by deallocating the trailing part.
- auto newCapacity = bytes2blocks(newSize) * blockSize;
- deallocate(b[newCapacity .. $]);
- b = b[0 .. newSize];
- return true;
- }
- // Attempt an in-place expansion first
- const delta = newSize - b.length;
- if (expand(b, delta)) return true;
- // Go the slow route
- return .reallocate(this, b, newSize);
- }
-
- /// Ditto
- void deallocate(void[] b)
- {
- // Round up size to multiple of block size
- auto blocks = (b.length + blockSize - 1) / blockSize;
- // Locate position
- auto pos = b.ptr - _payload.ptr;
- assert(pos % blockSize == 0);
- auto blockIdx = pos / blockSize;
- auto wordIdx = blockIdx / 64, msbIdx = cast(uint) (blockIdx % 64);
- if (_startIdx > wordIdx) _startIdx = wordIdx;
-
- // Three stages: heading bits, full words, leftover bits
- if (msbIdx)
- {
- if (blocks + msbIdx <= 64)
- {
- resetBits(_control[wordIdx], cast(uint) (64 - msbIdx - blocks),
- 63 - msbIdx);
- return;
- }
- else
- {
- _control[wordIdx] &= ulong.max << 64 - msbIdx;
- blocks -= 64 - msbIdx;
- ++wordIdx;
- msbIdx = 0;
- }
- }
-
- // Stage 2: reset one word at a time
- for (; blocks >= 64; blocks -= 64)
- {
- _control[wordIdx++] = 0;
- }
-
- // Stage 3: deal with leftover bits, if any
- assert(wordIdx <= _control.length);
- if (blocks)
- {
- _control[wordIdx] &= ulong.max >> blocks;
- }
- }
-
- /// Ditto
- void deallocateAll()
- {
- static if (false && hasMember!(Allocator, "deallocate"))
- {
- parent.deallocate(_allocatedByUs);
- this = this.init;
- }
- else
- {
- _control[] = 0;
- _startIdx = 0;
- }
- }
-}
-
-///
-unittest
-{
- // Create a block allocator on top of a 10KB stack region.
- HeapBlock!(InSituRegion!(10240, 64), 64, 64) a;
- static assert(hasMember!(InSituRegion!(10240, 64), "allocateAll"));
- auto b = a.allocate(100);
- assert(b.length == 100);
-}
-
-unittest
-{
- static void testAllocateAll(size_t bs)(uint blocks, uint blocksAtATime)
- {
- assert(bs);
- auto a = HeapBlock!(GCAllocator, bs)(blocks);
- assert(a._blocks || !blocks);
-
- // test allocation of 0 bytes
- auto x = a.allocate(0);
- assert(x is null);
- // test allocation of 1 byte
- x = a.allocate(1);
- assert(x.length == 1 || blocks == 0, text(x.ptr, " ", x.length, " ", a));
- a.deallocateAll();
-
- //writeln("Control words: ", a._control.length);
- //writeln("Payload bytes: ", a._payload.length);
- bool twice = true;
-
- begin:
- foreach (i; 0 .. blocks / blocksAtATime)
- {
- auto b = a.allocate(bs * blocksAtATime);
- assert(b.length == bs * blocksAtATime, text(i, ": ", b.length));
- }
- assert(a.allocate(bs * blocksAtATime) is null);
- assert(a.allocate(1) is null);
-
- // Now deallocate all and do it again!
- a.deallocateAll();
-
- // Test deallocation
-
- auto v = new void[][blocks / blocksAtATime];
- foreach (i; 0 .. blocks / blocksAtATime)
- {
- auto b = a.allocate(bs * blocksAtATime);
- assert(b.length == bs * blocksAtATime, text(i, ": ", b.length));
- v[i] = b;
- }
- assert(a.allocate(bs * blocksAtATime) is null);
- assert(a.allocate(1) is null);
-
- foreach (i; 0 .. blocks / blocksAtATime)
- {
- a.deallocate(v[i]);
- }
-
- foreach (i; 0 .. blocks / blocksAtATime)
- {
- auto b = a.allocate(bs * blocksAtATime);
- assert(b.length == bs * blocksAtATime, text(i, ": ", b.length));
- v[i] = b;
- }
-
- foreach (i; 0 .. v.length)
- {
- a.deallocate(v[i]);
- }
-
- if (twice)
- {
- twice = false;
- goto begin;
- }
-
- a.deallocateAll;
-
- // test expansion
- if (blocks >= blocksAtATime)
- {
- foreach (i; 0 .. blocks / blocksAtATime - 1)
- {
- auto b = a.allocate(bs * blocksAtATime);
- assert(b.length == bs * blocksAtATime, text(i, ": ", b.length));
- (cast(ubyte[]) b)[] = 0xff;
- a.expand(b, blocksAtATime * bs)
- || assert(0, text(i));
- (cast(ubyte[]) b)[] = 0xfe;
- assert(b.length == bs * blocksAtATime * 2, text(i, ": ", b.length));
- a.reallocate(b, blocksAtATime * bs) || assert(0);
- assert(b.length == bs * blocksAtATime, text(i, ": ", b.length));
- }
- }
- }
-
- testAllocateAll!(1)(0, 1);
- testAllocateAll!(1)(8, 1);
- testAllocateAll!(4096)(128, 1);
-
- testAllocateAll!(1)(0, 2);
- testAllocateAll!(1)(128, 2);
- testAllocateAll!(4096)(128, 2);
-
- testAllocateAll!(1)(0, 4);
- testAllocateAll!(1)(128, 4);
- testAllocateAll!(4096)(128, 4);
-
- testAllocateAll!(1)(0, 3);
- testAllocateAll!(1)(24, 3);
- testAllocateAll!(3000)(100, 1);
- testAllocateAll!(3000)(100, 3);
-
- testAllocateAll!(1)(0, 128);
- testAllocateAll!(1)(128 * 1, 128);
- testAllocateAll!(128 * 20)(13 * 128, 128);
-}
-
-/**
-$(D FallbackAllocator) is the allocator equivalent of an "or" operator in
-algebra. An allocation request is first attempted with the $(D Primary)
-allocator. If that returns $(D null), the request is forwarded to the $(D
-Fallback) allocator. All other requests are dispatched appropriately to one of
-the two allocators.
-
-In order to work, $(D FallbackAllocator) requires that $(D Primary) defines the
-$(D owns) method. This is needed in order to decide which allocator was
-responsible for a given allocation.
-
-$(D FallbackAllocator) is useful for fast, special-purpose allocators backed up
-by general-purpose allocators. The example below features a stack region backed
-up by the $(D GCAllocator).
-*/
-struct FallbackAllocator(Primary, Fallback)
-{
- /// The primary allocator.
- static if (stateSize!Primary) Primary primary;
- else alias primary = Primary.it;
-
- /// The fallback allocator.
- static if (stateSize!Fallback) Fallback fallback;
- else alias fallback = Fallback.it;
-
- /**
- If both $(D Primary) and $(D Fallback) are stateless, $(D FallbackAllocator)
- defines a static instance $(D it).
- */
- /+static if (!stateSize!Primary && !stateSize!Fallback)
- {
- static FallbackAllocator it;
- }+/
-
- /**
- The alignment offered is the minimum of the two allocators' alignment.
- */
- enum uint alignment = min(Primary.alignment, Fallback.alignment);
-
- /**
- Allocates memory trying the primary allocator first. If it returns $(D
- null), the fallback allocator is tried.
- */
- void[] allocate(size_t s) pure nothrow @safe
- {
- auto result = primary.allocate(s);
- return result ? result : fallback.allocate(s);
- }
-
- /**
-
- $(D expand) is defined if and only if at least one of the allocators
- defines $(D expand). It works as follows. If $(D primary.owns(b)), then the
- request is forwarded to $(D primary.expand) if it is defined, or fails
- (returning $(D false)) otherwise. If $(D primary) does not own $(D b), then
- the request is forwarded to $(D fallback.expand) if it is defined, or fails
- (returning $(D false)) otherwise.
-
- */
- static if (hasMember!(Primary, "expand") || hasMember!(Fallback, "expand"))
- bool expand(ref void[] b, size_t delta)
- {
- if (primary.owns(b))
- {
- static if (hasMember!(Primary, "expand"))
- return primary.expand(b, delta);
- else
- return false;
- }
- static if (hasMember!(Fallback, "expand"))
- return fallback.expand(b, delta);
- else
- return false;
- }
-
- /**
-
- $(D reallocate) works as follows. If $(D primary.owns(b)), then $(D
- primary.reallocate(b, newSize)) is attempted. If it fails, an attempt is
- made to move the allocation from $(D primary) to $(D fallback).
-
- If $(D primary) does not own $(D b), then $(D fallback.reallocate(b,
- newSize)) is attempted. If that fails, an attempt is made to move the
- allocation from $(D fallback) to $(D primary).
-
- */
- bool reallocate(ref void[] b, size_t newSize) pure nothrow @trusted
- {
- bool crossAllocatorMove(From, To)(auto ref From from, auto ref To to)
- {
- auto b1 = to.allocate(newSize);
- 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"))
- from.deallocate(b);
- b = b1;
- return true;
- }
-
- if (primary.owns(b))
- {
- if (primary.reallocate(b, newSize)) return true;
- // Move from primary to fallback
- return crossAllocatorMove(primary, fallback);
- }
- if (fallback.reallocate(b, newSize)) return true;
- // Interesting. Move from fallback to primary.
- return crossAllocatorMove(fallback, primary);
- }
-
- /**
- $(D owns) is defined if and only if both allocators define $(D owns).
- Returns $(D primary.owns(b) || fallback.owns(b)).
- */
- static if (hasMember!(Primary, "owns") && hasMember!(Fallback, "owns"))
- bool owns(void[] p)
- {
- return primary.owns(b) || fallback.owns(p);
- }
-
- /**
- $(D deallocate) is defined if and only if at least one of the allocators
- define $(D deallocate). It works as follows. If $(D primary.owns(b)),
- then the request is forwarded to $(D primary.deallocate) if it is defined,
- or is a no-op otherwise. If $(D primary) does not own $(D b), then the
- request is forwarded to $(D fallback.deallocate) if it is defined, or is a
- no-op otherwise.
- */
- static if (hasMember!(Primary, "deallocate")
- || hasMember!(Fallback, "deallocate"))
- void deallocate(void[] b) pure nothrow @trusted
- {
- if (primary.owns(b))
- {
- static if (hasMember!(Primary, "deallocate"))
- primary.deallocate(b);
- }
- else
- {
- static if (hasMember!(Fallback, "deallocate"))
- fallback.deallocate(b);
- }
- }
-}
-
-///
-unittest
-{
- FallbackAllocator!(InSituRegion!16_384, GCAllocator) a;
- // This allocation uses the stack
- auto b1 = a.allocate(1024);
- assert(b1.length == 1024, text(b1.length));
- assert(a.primary.owns(b1));
- // This large allocation will go to the Mallocator
- auto b2 = a.allocate(1024 * 1024);
- assert(!a.primary.owns(b2));
- a.deallocate(b1);
- a.deallocate(b2);
-}
-
-/**
-
-$(WEB en.wikipedia.org/wiki/Free_list, Free list allocator), stackable on top of
-another allocator. Allocation requests between $(D min) and $(D max) bytes are
-rounded up to $(D max) and served from a singly-linked list of buffers
-deallocated in the past. All other allocations are directed to $(D
-ParentAllocator). Due to the simplicity of free list management, allocations
-from the free list are fast.
-
-If a program makes many allocations in the interval $(D [minSize, maxSize]) and
-then frees most of them, the freelist may grow large, thus making memory
-inaccessible to requests of other sizes. To prevent that, the $(D maxNodes)
-parameter allows limiting the size of the free list. Alternatively, $(D
-deallocateAll) cleans the free list.
-
-$(D Freelist) attempts to reduce internal fragmentation and improve cache
-locality by allocating multiple nodes at once, under the control of the $(D
-batchCount) parameter. This makes $(D Freelist) an efficient front for small
-object allocation on top of a large-block allocator. The default value of $(D
-batchCount) is 8, which should amortize freelist management costs to negligible
-in most cases.
-
-One instantiation is of particular interest: $(D Freelist!(0,unbounded)) puts
-every deallocation in the freelist, and subsequently serves any allocation from
-the freelist (if not empty). There is no checking of size matching, which would
-be incorrect for a freestanding allocator but is both correct and fast when an
-owning allocator on top of the free list allocator (such as $(D Segregator)) is
-already in charge of handling size checking.
-
-*/
-struct Freelist(ParentAllocator,
- size_t minSize, size_t maxSize = minSize,
- uint batchCount = 8, size_t maxNodes = unbounded)
-{
- static assert(minSize != unbounded, "Use minSize = 0 for no low bound.");
- static assert(maxSize >= (void*).sizeof,
- "Maximum size must accommodate a pointer.");
-
- static if (minSize != chooseAtRuntime)
- {
- alias min = minSize;
- }
- else
- {
- size_t _min = chooseAtRuntime;
- @property size_t min() const nothrow pure @safe
- {
- assert(_min != chooseAtRuntime);
- return _min;
- }
- @property void min(size_t x)
- {
- enforce(x <= _max);
- _min = x;
- }
- static if (maxSize == chooseAtRuntime)
- {
- // Both bounds can be set, provide one function for setting both in
- // one shot.
- void setBounds(size_t low, size_t high)
- {
- enforce(low <= high && high >= (void*).sizeof);
- _min = low;
- _max = high;
- }
- }
- }
-
- private bool tooSmall(size_t n) const nothrow pure @safe
- {
- static if (minSize == 0) return false;
- else return n < min;
- }
-
- static if (maxSize != chooseAtRuntime)
- {
- alias max = maxSize;
- }
- else
- {
- size_t _max;
- @property size_t max() const { return _max; }
- @property void max(size_t x)
- {
- enforce(x >= _min && x >= (void*).sizeof);
- _max = x;
- }
- }
-
- 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 nothrow pure @safe
- {
- static if (minSize == maxSize && minSize != chooseAtRuntime)
- return n == maxSize;
- else return !tooSmall(n) && !tooLarge(n);
- }
-
- version (StdDdoc)
- {
- /**
- Properties for getting and setting bounds. Setting a bound is only
- possible if the respective compile-time parameter has been set to $(D
- chooseAtRuntime). $(D setBounds) is defined only if both $(D minSize)
- and $(D maxSize) are set to $(D chooseAtRuntime).
- */
- @property size_t min();
- /// Ditto
- @property void min(size_t newMinSize);
- /// Ditto
- @property size_t max();
- /// Ditto
- @property void max(size_t newMaxSize);
- /// Ditto
- void setBounds(size_t newMin, size_t newMax);
- ///
- unittest
- {
- Freelist!(Mallocator, chooseAtRuntime, chooseAtRuntime) a;
- // Set the maxSize first so setting the minSize doesn't throw
- a.max = 128;
- a.min = 64;
- a.setBounds(64, 128); // equivalent
- assert(a.max == 128);
- assert(a.min == 64);
- }
- }
-
- /**
- The parent allocator. Depending on whether $(D ParentAllocator) holds state
- or not, this is a member variable or an alias for $(D ParentAllocator.it).
- */
- static if (stateSize!ParentAllocator) ParentAllocator parent;
- else alias parent = ParentAllocator.it;
-
- private struct Node { Node* next; }
- static assert(ParentAllocator.alignment >= Node.alignof);
- private Node* _root;
- private uint nodesAtATime = batchCount;
-
- static if (maxNodes != unbounded)
- {
- private size_t nodes;
- private void incNodes() { ++nodes; }
- private void decNodes() { assert(nodes); --nodes; }
- private bool nodesFull() { return nodes >= maxNodes; }
- }
- else
- {
- private static void incNodes() { }
- private static void decNodes() { }
- private enum bool nodesFull = false;
- }
-
- /**
- Alignment is defined as $(D parent.alignment). However, if $(D
- parent.alignment > maxSize), objects returned from the freelist will have a
- smaller _alignment, namely $(D maxSize) rounded up to the nearest multiple
- of 2. This allows $(D Freelist) to minimize internal fragmentation by
- allocating several small objects within an allocated block. Also, there is
- no disruption because no object has smaller size than its _alignment.
- */
- enum uint alignment = ParentAllocator.alignment;
-
- /**
- Returns $(D max) for sizes in the interval $(D [min, max]), and $(D
- parent.goodAllocSize(bytes)) otherwise.
- */
- size_t goodAllocSize(size_t bytes) const nothrow pure @safe
- {
- if (inRange(bytes)) return maxSize == unbounded ? bytes : max;
- return parent.goodAllocSize(bytes);
- }
-
- /**
- Allocates memory either off of the free list or from the parent allocator.
- */
- void[] allocate(size_t bytes) pure nothrow @trusted
- {
- assert(bytes < size_t.max / 2);
- if (!inRange(bytes)) return parent.allocate(bytes);
- // Round up allocation to max
- if (maxSize != unbounded) bytes = max;
- if (!_root) return allocateFresh(bytes);
- // Pop off the freelist
- auto result = (cast(ubyte*) _root)[0 .. bytes];
- _root = _root.next;
- decNodes();
- return result;
- }
-
- private void[] allocateFresh(const size_t bytes) pure nothrow @trusted
- {
- assert(!_root);
- assert(bytes == max || max == unbounded);
- if (nodesAtATime == 1)
- {
- // Easy case, just get it over with
- return parent.allocate(bytes);
- }
- static if (maxSize != unbounded && maxSize != chooseAtRuntime)
- {
- static assert((parent.alignment + max) % Node.alignof == 0,
- text("(", parent.alignment, " + ", max, ") % ",
- Node.alignof));
- }
- else
- {
- assert((parent.alignment + bytes) % Node.alignof == 0/+,
- text("(", parent.alignment, " + ", bytes, ") % ",
- Node.alignof)+/);
- }
-
- auto data = parent.allocate(nodesAtATime * bytes);
- if (!data) return null;
- auto result = data[0 .. bytes];
- auto n = data[bytes .. $];
- _root = cast(Node*) n.ptr;
- for (;;)
- {
- if (n.length < bytes)
- {
- (cast(Node*) data.ptr).next = null;
- break;
- }
- (cast(Node*) data.ptr).next = cast(Node*) n.ptr;
- data = n;
- n = data[bytes .. $];
- }
- return result;
- }
-
- /**
- If $(D b.length) is in the interval $(D [min, max]), returns $(D true).
- Otherwise, if $(D Parent.owns) is defined, forwards to it. Otherwise,
- returns $(D false). This semantics is intended to have $(D
- 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) const pure nothrow @safe
- {
- if (inRange(b.length)) return true;
- static if (hasMember!(ParentAllocator, "owns"))
- return parent.owns(b);
- else
- return false;
- }
-
- /**
- Forwards to $(D parent).
- */
- static if (hasMember!(ParentAllocator, "expand"))
- bool expand(void[] b, size_t s)
- {
- return parent.expand(b, s);
- }
-
- /// Ditto
- static if (hasMember!(ParentAllocator, "reallocate"))
- bool reallocate(void[] b, size_t s)
- {
- return parent.reallocate(b, s);
- }
-
- /**
- Intercepts deallocations and caches those of the appropriate size in the
- freelist. For all others, forwards to $(D parent.deallocate) or does nothing
- if $(D Parent) does not define $(D deallocate).
- */
- void deallocate(void[] block)
- {
- if (!nodesFull && inRange(block.length))
- {
- auto t = _root;
- _root = cast(Node*) block.ptr;
- _root.next = t;
- incNodes();
- }
- else
- {
- static if (is(typeof(parent.deallocate(block))))
- parent.deallocate(block);
- }
- }
-
- /**
- If $(D ParentAllocator) defines $(D deallocateAll), just forwards to it and
- reset the freelist. Otherwise, walks the list and frees each object in turn.
- */
- void deallocateAll()
- {
- static if (hasMember!(ParentAllocator, "deallocateAll"))
- {
- parent.deallocateAll();
- }
- else static if (hasMember!(ParentAllocator, "deallocate"))
- {
- for (auto n = _root; n; n = n.next)
- {
- parent.deallocate((cast(ubyte*)n)[0 .. max]);
- }
- }
- _root = null;
- }
-}
-
-unittest
-{
- Freelist!(GCAllocator, 0, 8, 1) fl;
- assert(fl._root is null);
- auto b1 = fl.allocate(7);
- //assert(fl._root !is null);
- auto b2 = fl.allocate(8);
- assert(fl._root is null);
- fl.deallocate(b1);
- assert(fl._root !is null);
- auto b3 = fl.allocate(8);
- assert(fl._root is null);
-}
-
-/**
-Freelist shared across threads. Allocation and deallocation are lock-free. The
-parameters have the same semantics as for $(D Freelist).
-*/
-struct SharedFreelist(ParentAllocator,
- size_t minSize, size_t maxSize = minSize,
- uint batchCount = 8, size_t maxNodes = unbounded)
-{
- static assert(minSize != unbounded, "Use minSize = 0 for no low bound.");
- static assert(maxSize >= (void*).sizeof,
- "Maximum size must accommodate a pointer.");
-
- private import core.atomic;
-
- static if (minSize != chooseAtRuntime)
- {
- alias min = minSize;
- }
- else
- {
- shared size_t _min = chooseAtRuntime;
- @property size_t min() const shared
- {
- assert(_min != chooseAtRuntime);
- return _min;
- }
- @property void min(size_t x) shared
- {
- enforce(x <= max);
- enforce(cas(&_min, chooseAtRuntime, x),
- "SharedFreelist.min must be initialized exactly once.");
- }
- static if (maxSize == chooseAtRuntime)
- {
- // Both bounds can be set, provide one function for setting both in
- // one shot.
- void setBounds(size_t low, size_t high) shared
- {
- enforce(low <= high && high >= (void*).sizeof);
- enforce(cas(&_min, chooseAtRuntime, low),
- "SharedFreelist.min must be initialized exactly once.");
- enforce(cas(&_max, chooseAtRuntime, high),
- "SharedFreelist.max must be initialized exactly once.");
- }
- }
- }
-
- private bool tooSmall(size_t n) const shared
- {
- static if (minSize == 0) return false;
- else static if (minSize == chooseAtRuntime) return n < _min;
- else return n < minSize;
- }
-
- static if (maxSize != chooseAtRuntime)
- {
- alias max = maxSize;
- }
- else
- {
- shared size_t _max = chooseAtRuntime;
- @property size_t max() const shared { return _max; }
- @property void max(size_t x) shared
- {
- enforce(x >= _min && x >= (void*).sizeof);
- enforce(cas(&_max, chooseAtRuntime, x),
- "SharedFreelist.max must be initialized exactly once.");
- }
- }
-
- private bool tooLarge(size_t n) const shared
- {
- static if (maxSize == unbounded) return false;
- else static if (maxSize == chooseAtRuntime) return n > _max;
- else return n > maxSize;
- }
-
- private bool inRange(size_t n) const shared
- {
- static if (minSize == maxSize && minSize != chooseAtRuntime)
- return n == maxSize;
- else return !tooSmall(n) && !tooLarge(n);
- }
-
- static if (maxNodes != unbounded)
- {
- private shared size_t nodes;
- private void incNodes() shared
- {
- atomicOp!("+=")(nodes, 1);
- }
- private void decNodes() shared
- {
- assert(nodes);
- atomicOp!("-=")(nodes, 1);
- }
- private bool nodesFull() shared
- {
- return nodes >= maxNodes;
- }
- }
- else
- {
- private static void incNodes() { }
- private static void decNodes() { }
- private enum bool nodesFull = false;
- }
-
- version (StdDdoc)
- {
- /**
- Properties for getting (and possibly setting) the bounds. Setting bounds
- is allowed only once , and before any allocation takes place. Otherwise,
- the primitives have the same semantics as those of $(D Freelist).
- */
- @property size_t min();
- /// Ditto
- @property void min(size_t newMinSize);
- /// Ditto
- @property size_t max();
- /// Ditto
- @property void max(size_t newMaxSize);
- /// Ditto
- void setBounds(size_t newMin, size_t newMax);
- ///
- unittest
- {
- Freelist!(Mallocator, chooseAtRuntime, chooseAtRuntime) a;
- // Set the maxSize first so setting the minSize doesn't throw
- a.max = 128;
- a.min = 64;
- a.setBounds(64, 128); // equivalent
- assert(a.max == 128);
- assert(a.min == 64);
- }
- }
-
- /**
- The parent allocator. Depending on whether $(D ParentAllocator) holds state
- or not, this is a member variable or an alias for $(D ParentAllocator.it).
- */
- static if (stateSize!ParentAllocator) shared ParentAllocator parent;
- else alias parent = ParentAllocator.it;
-
- private struct Node { Node* next; }
- static assert(ParentAllocator.alignment >= Node.alignof);
- private Node* _root;
- private uint nodesAtATime = batchCount;
-
- /// Standard primitives.
- enum uint alignment = ParentAllocator.alignment;
-
- /// Ditto
- size_t goodAllocSize(size_t bytes) shared
- {
- if (inRange(bytes)) return maxSize == unbounded ? bytes : max;
- return parent.goodAllocSize(bytes);
- }
-
- /// Ditto
- bool owns(void[] b) shared const
- {
- if (inRange(b.length)) return true;
- static if (hasMember!(ParentAllocator, "owns"))
- return parent.owns(b);
- else
- return false;
- }
-
- /**
- Forwards to $(D parent), which must also support $(D shared) primitives.
- */
- static if (hasMember!(ParentAllocator, "expand"))
- bool expand(void[] b, size_t s)
- {
- return parent.expand(b, s);
- }
-
- /// Ditto
- static if (hasMember!(ParentAllocator, "reallocate"))
- bool reallocate(void[] b, size_t s)
- {
- return parent.reallocate(b, s);
- }
-
- /// Ditto
- void[] allocate(size_t bytes) shared
- {
- assert(bytes < size_t.max / 2);
- if (!inRange(bytes)) return parent.allocate(bytes);
- if (maxSize != unbounded) bytes = max;
- if (!_root) return allocateFresh(bytes);
- // Pop off the freelist
- shared Node* oldRoot = void, next = void;
- do
- {
- oldRoot = _root; // atomic load
- next = oldRoot is null ? null : oldRoot.next; // atomic load
- }
- while (!cas(&_root, oldRoot, next));
- // great, snatched the root
- decNodes();
- return (cast(ubyte*) oldRoot)[0 .. bytes];
- }
-
- private void[] allocateFresh(const size_t bytes) shared
- {
- assert(bytes == max || max == unbounded);
- if (nodesAtATime == 1)
- {
- // Easy case, just get it over with
- return parent.allocate(bytes);
- }
- static if (maxSize != unbounded && maxSize != chooseAtRuntime)
- {
- static assert(
- (parent.alignment + max) % Node.alignof == 0,
- text("(", parent.alignment, " + ", max, ") % ",
- Node.alignof));
- }
- else
- {
- assert((parent.alignment + bytes) % Node.alignof == 0,
- text("(", parent.alignment, " + ", bytes, ") % ",
- Node.alignof));
- }
-
- auto data = parent.allocate(nodesAtATime * bytes);
- if (!data) return null;
- auto result = data[0 .. bytes];
- auto n = data[bytes .. $];
- auto newRoot = cast(shared Node*) n.ptr;
- shared Node* lastNode;
- for (;;)
- {
- if (n.length < bytes)
- {
- lastNode = cast(shared Node*) data.ptr;
- break;
- }
- (cast(Node*) data.ptr).next = cast(Node*) n.ptr;
- data = n;
- n = data[bytes .. $];
- }
- // Created the list, now wire the new nodes in considering another
- // thread might have also created some nodes.
- do
- {
- lastNode.next = _root;
- }
- while (!cas(&_root, lastNode.next, newRoot));
- return result;
- }
-
- /// Ditto
- void deallocate(void[] b) shared
- {
- if (!nodesFull && inRange(b.length))
- {
- auto newRoot = cast(shared Node*) b.ptr;
- shared Node* oldRoot;
- do
- {
- oldRoot = _root;
- newRoot.next = oldRoot;
- }
- while (!cas(&_root, oldRoot, newRoot));
- incNodes();
- }
- else
- {
- static if (is(typeof(parent.deallocate(block))))
- parent.deallocate(block);
- }
- }
-
- /// Ditto
- void deallocateAll() shared
- {
- static if (hasMember!(ParentAllocator, "deallocateAll"))
- {
- parent.deallocateAll();
- }
- else static if (hasMember!(ParentAllocator, "deallocate"))
- {
- for (auto n = _root; n; n = n.next)
- {
- parent.deallocate((cast(ubyte*)n)[0 .. max]);
- }
- }
- _root = null;
- }
-}
-
-// FIXME: This test breaks on weaker machines that can't do 1000 concurrent threads.
-// If you change the number of threads from 1000 to 100 it works on 32bit x86 Atom under Linux
-version(none) unittest
-{
- import core.thread, std.concurrency;
-
- static shared SharedFreelist!(Mallocator, 64, 128, 8, 100) a;
-
- assert(a.goodAllocSize(1) == platformAlignment);
-
- auto b = a.allocate(100);
- a.deallocate(b);
-
- static void fun(Tid tid, int i)
- {
- scope(exit) tid.send(true);
- auto b = cast(ubyte[]) a.allocate(100);
- b[] = cast(ubyte) i;
-
- assert(b.equal(repeat(cast(ubyte) i, b.length)));
- a.deallocate(b);
- }
-
- Tid[] tids;
- foreach (i; 0 .. 1000) // FIXME: Works with 100
- {
- tids ~= spawn(&fun, thisTid, i);
- }
-
- foreach (i; 0 .. 1000) // FIXME: Works with 100
- {
- assert(receiveOnly!bool);
- }
-}
-
-unittest
-{
- shared SharedFreelist!(Mallocator, chooseAtRuntime, chooseAtRuntime,
- 8, 100) a;
- auto b = a.allocate(64);
-}
-
-/*
-(This type is not public.)
-
-A $(D BasicRegion) allocator allocates memory straight from an externally-
-provided storage as backend. There is no deallocation, and once the region is
-full, allocation requests return $(D null). Therefore, $(D Region)s are often
-used in conjunction with freelists and a fallback general-purpose allocator.
-
-The region only stores two words, corresponding to the current position in the
-store and the available length. One allocation entails rounding up the
-allocation size for alignment purposes, bumping the current pointer, and
-comparing it against the limit.
-
-The $(D minAlign) parameter establishes alignment. If $(D minAlign > 1), the
-sizes of all allocation requests are rounded up to a multiple of $(D minAlign).
-Applications aiming at maximum speed may want to choose $(D minAlign = 1) and
-control alignment externally.
-*/
-private struct BasicRegion(uint minAlign = platformAlignment)
-{
- static assert(minAlign.isGoodStaticAlignment);
- private void* _current, _end;
-
- /**
- Constructs a region backed by a user-provided store.
- */
- this(void[] store) pure nothrow @trusted
- {
- static if (minAlign > 1)
- {
- auto newStore = cast(void*) roundUpToMultipleOf(
- cast(size_t) store.ptr,
- alignment);
- assert(newStore <= store.ptr + store.length);
- _current = newStore;
- }
- else
- {
- _current = store;
- }
- _end = store.ptr + store.length;
- }
-
- /**
- The postblit of $(D BasicRegion) is disabled because such objects should not
- be copied around naively.
- */
- //@disable this(this);
-
- /**
- Standard allocator primitives.
- */
- enum uint alignment = minAlign;
-
- /// Ditto
- void[] allocate(size_t bytes) pure nothrow @trusted
- {
- static if (minAlign > 1)
- const rounded = bytes.roundUpToMultipleOf(alignment);
- else
- alias rounded = bytes;
- auto newCurrent = _current + rounded;
- if (newCurrent > _end) return null;
- auto result = _current[0 .. bytes];
- _current = newCurrent;
- assert(cast(ulong) result.ptr % alignment == 0);
- return result;
- }
-
- /// Ditto
- void[] alignedAllocate(size_t bytes, uint a)
- {
- // Just bump the pointer to the next good allocation
- auto save = _current;
- _current = cast(void*) roundUpToMultipleOf(
- cast(size_t) _current, a);
- if (auto b = allocate(bytes)) return b;
- // Failed, rollback
- _current = save;
- return null;
- }
-
- /// Allocates and returns all memory available to this region.
- void[] allocateAll()
- {
- auto result = _current[0 .. available];
- _current = _end;
- return result;
- }
- /// Nonstandard property that returns bytes available for allocation.
- size_t available() const
- {
- return _end - _current;
- }
-}
-
-/*
-For implementers' eyes: Region adds more capabilities on top of $(BasicRegion)
-at the cost of one extra word of storage. $(D Region) "remembers" the beginning
-of the region and therefore is able to provide implementations of $(D owns) and
-$(D deallocateAll). For most applications the performance distinction between
-$(D BasicRegion) and $(D Region) is unimportant, so the latter should be the
-default choice.
-*/
-
-/**
-A $(D Region) allocator manages one block of memory provided at construction.
-There is no deallocation, and once the region is full, allocation requests
-return $(D null). Therefore, $(D Region)s are often used in conjunction
-with freelists, a fallback general-purpose allocator, or both.
-
-The region stores three words corresponding to the start of the store, the
-current position in the store, and the end of the store. One allocation entails
-rounding up the allocation size for alignment purposes, bumping the current
-pointer, and comparing it against the limit.
-
-The $(D minAlign) parameter establishes alignment. If $(D minAlign > 1), the
-sizes of all allocation requests are rounded up to a multiple of $(D minAlign).
-Applications aiming at maximum speed may want to choose $(D minAlign = 1) and
-control alignment externally.
-*/
-struct Region(uint minAlign = platformAlignment)
-{
- static assert(minAlign.isGoodStaticAlignment);
-
- private BasicRegion!(minAlign) base;
- private void* _begin;
-
- /**
- Constructs a $(D Region) object backed by $(D buffer), which must be aligned
- to $(D minAlign).
- */
- this(void[] buffer) pure nothrow @safe
- {
- base = BasicRegion!minAlign(buffer);
- assert(buffer.ptr !is &this);
- _begin = base._current;
- }
-
- /**
- Standard primitives.
- */
- enum uint alignment = minAlign;
-
- /// Ditto
- void[] allocate(size_t bytes)
- {
- return base.allocate(bytes);
- }
-
- /// Ditto
- void[] alignedAllocate(size_t bytes, uint a)
- {
- return base.alignedAllocate(bytes, a);
- }
-
- /// Ditto
- bool owns(void[] b) const
- {
- return b.ptr >= _begin && b.ptr + b.length <= base._end
- || b is null;
- }
-
- /// Ditto
- void deallocateAll()
- {
- base._current = _begin;
- }
-
- /**
- Nonstandard function that gives away the initial buffer used by the range,
- and makes the range unavailable for further allocations. This is useful for
- deallocating the memory assigned to the region.
- */
- void[] relinquish()
- {
- auto result = _begin[0 .. base._end - _begin];
- base._current = base._end;
- return result;
- }
-}
-
-///
-unittest
-{
- auto reg = Region!()(Mallocator.it.allocate(1024 * 64));
- scope(exit) Mallocator.it.deallocate(reg.relinquish);
- auto b = reg.allocate(101);
- assert(b.length == 101);
-}
-
-/**
-
-$(D InSituRegion) is a convenient region that carries its storage within itself
-(in the form of a statically-sized array).
-
-The first template argument is the size of the region and the second is the
-needed alignment. Depending on the alignment requested and platform details,
-the actual available storage may be smaller than the compile-time parameter. To
-make sure that at least $(D n) bytes are available in the region, use
-$(D InSituRegion!(n + a - 1, a)).
-
-*/
-struct InSituRegion(size_t size, size_t minAlign = platformAlignment)
-{
- static assert(minAlign.isGoodStaticAlignment);
- static assert(size >= minAlign);
-
- // The store will be aligned to double.alignof, regardless of the requested
- // alignment.
- union
- {
- private ubyte[size] _store = void;
- private double _forAlignmentOnly = void;
- }
- private void* _crt, _end;
-
- /**
- An alias for $(D minAlign), which must be a valid alignment (nonzero power
- of 2). The start of the region and all allocation requests will be rounded
- up to a multiple of the alignment.
-
- ----
- InSituRegion!(4096) a1;
- assert(a1.alignment == platformAlignment);
- InSituRegion!(4096, 64) a2;
- assert(a2.alignment == 64);
- ----
- */
- enum uint alignment = minAlign;
-
- private void lazyInit()
- {
- assert(!_crt);
- _crt = cast(void*) roundUpToMultipleOf(
- cast(size_t) _store.ptr, alignment);
- _end = _store.ptr + _store.length;
- }
-
- /**
- Allocates $(D bytes) and returns them, or $(D null) if the region cannot
- accommodate the request. For efficiency reasons, if $(D bytes == 0) the
- function returns an empty non-null slice.
- */
- 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.
- const rounded = bytes.roundUpToMultipleOf(alignment);
- auto newCrt = _crt + rounded;
- assert(newCrt >= _crt); // big overflow
- again:
- if (newCrt <= _end)
- {
- assert(_crt); // this relies on null + size > null
- auto result = _crt[0 .. bytes];
- _crt = newCrt;
- return result;
- }
- // slow path
- if (_crt) return null;
- // Lazy initialize _crt
- lazyInit();
- newCrt = _crt + rounded;
- goto again;
- }
-
- /**
- As above, but the memory allocated is aligned at $(D a) bytes.
- */
- void[] alignedAllocate(size_t bytes, uint a)
- {
- // Just bump the pointer to the next good allocation
- auto save = _crt;
- _crt = cast(void*) roundUpToMultipleOf(
- cast(size_t) _crt, a);
- if (auto b = allocate(bytes)) return b;
- // Failed, rollback
- _crt = save;
- return null;
- }
-
- /**
- Returns $(D true) if and only if $(D b) is the result of a successful
- allocation. For efficiency reasons, if $(D b is null) the function returns
- $(D false).
- */
- bool owns(const void[] b) const nothrow pure @trusted
- {
- // No nullptr
- return b.ptr >= _store.ptr
- && b.ptr + b.length <= _store.ptr + _store.length;
- }
-
- /**
- Deallocates all memory allocated with this allocator.
- */
- void deallocateAll() pure nothrow @safe
- {
- _crt = _store.ptr;
- }
-
- /**
- Allocates all memory available with this allocator.
- */
- void[] allocateAll()
- {
- auto s = available;
- auto result = _crt[0 .. s];
- _crt = _end;
- return result;
- }
-
- /**
- Nonstandard function that returns the bytes available for allocation.
- */
- size_t available()
- {
- if (!_crt) lazyInit();
- return _end - _crt;
- }
-}
-
-///
-unittest
-{
- // 128KB region, allocated to x86's cache line
- InSituRegion!(128 * 1024, 64) r1;
- auto a1 = r1.allocate(101);
- assert(a1.length == 101);
-
- // 128KB region, with fallback to the garbage collector.
- FallbackAllocator!(InSituRegion!(128 * 1024), GCAllocator) r2;
- auto a2 = r1.allocate(102);
- assert(a2.length == 102);
-
- // Reap with GC fallback.
- InSituRegion!(128 * 1024) tmp3;
- FallbackAllocator!(HeapBlock!(InSituRegion!(128 * 1024), 64, 64),
- GCAllocator) r3;
- auto a3 = r3.allocate(103);
- assert(a3.length == 103);
-
- // Reap/GC with a freelist for small objects up to 16 bytes.
- InSituRegion!(128 * 1024) tmp4;
- Freelist!(FallbackAllocator!(
- HeapBlock!(InSituRegion!(128 * 1024), 64, 64), GCAllocator), 0, 16) r4;
- auto a4 = r4.allocate(104);
- assert(a4.length == 104);
-
- // Same as above, except the freelist only applies to the reap.
- InSituRegion!(128 * 1024) tmp5;
- FallbackAllocator!(Freelist!(HeapBlock!(InSituRegion!(128 * 1024), 64, 64), 0, 16), GCAllocator) r5;
- auto a5 = r5.allocate(105);
- assert(a5.length == 105);
-}
-
-// FIXME: Disabling this test because it is machine dependent
-version (none) unittest
-{
- InSituRegion!(4096) r1;
- auto a = r1.allocate(2001);
- assert(a.length == 2001);
- assert(r1.available == 2080, text(r1.available)); // FIXME: Is 2092 on my machine TM
-
- InSituRegion!(65536, 1024*4) r2;
- assert(r2.available <= 65536);
- a = r2.allocate(2001);
- assert(a.length == 2001);
-}
-
-/**
-_Options for $(D AllocatorWithStats) defined below. Each enables during
-compilation one specific counter, statistic, or other piece of information.
-*/
-enum Options : uint
-{
- /**
- Counts the number of calls to $(D owns).
- */
- numOwns = 1u << 0,
- /**
- Counts the number of calls to $(D allocate). All calls are counted,
- including requests for zero bytes or failed requests.
- */
- numAllocate = 1u << 1,
- /**
- Counts the number of calls to $(D allocate) that succeeded, i.e. they were
- for more than zero bytes and returned a non-null block.
- */
- numAllocateOK = 1u << 2,
- /**
- Counts the number of calls to $(D expand), regardless of arguments or
- result.
- */
- numExpand = 1u << 3,
- /**
- Counts the number of calls to $(D expand) that resulted in a successful
- expansion.
- */
- numExpandOK = 1u << 4,
- /**
- Counts the number of calls to $(D reallocate), regardless of arguments or
- result.
- */
- numReallocate = 1u << 5,
- /**
- Counts the number of calls to $(D reallocate) that succeeded. (Reallocations
- to zero bytes count as successful.)
- */
- numReallocateOK = 1u << 6,
- /**
- Counts the number of calls to $(D reallocate) that resulted in an in-place
- reallocation (no memory moved). If this number is close to the total number
- of reallocations, that indicates the allocator finds room at the current
- block's end in a large fraction of the cases, but also that internal
- fragmentation may be high (the size of the unit of allocation is large
- compared to the typical allocation size of the application).
- */
- numReallocateInPlace = 1u << 7,
- /**
- Counts the number of calls to $(D deallocate).
- */
- numDeallocate = 1u << 8,
- /**
- Counts the number of calls to $(D deallocateAll).
- */
- numDeallocateAll = 1u << 9,
- /**
- Chooses all $(D numXxx) flags.
- */
- numAll = (1u << 10) - 1,
- /**
- Tracks total cumulative bytes allocated by means of $(D allocate),
- $(D expand), and $(D reallocate) (when resulting in an expansion). This
- number always grows and indicates allocation traffic. To compute bytes
- currently allocated, subtract $(D bytesDeallocated) (below) from
- $(D bytesAllocated).
- */
- bytesAllocated = 1u << 10,
- /**
- Tracks total cumulative bytes deallocated by means of $(D deallocate) and
- $(D reallocate) (when resulting in a contraction). This number always grows
- and indicates deallocation traffic.
- */
- bytesDeallocated = 1u << 11,
- /**
- Tracks the sum of all $(D delta) values in calls of the form
- $(D expand(b, delta)) that succeed (return $(D true)).
- */
- bytesExpanded = 1u << 12,
- /**
- Tracks the sum of all $(D b.length - s) with $(D b.length > s) in calls of
- the form $(D realloc(b, s)) that succeed (return $(D true)).
- */
- bytesContracted = 1u << 13,
- /**
- Tracks the sum of all bytes moved as a result of calls to $(D realloc) that
- were unable to reallocate in place. A large number (relative to $(D
- bytesAllocated)) indicates that the application should use larger
- preallocations.
- */
- bytesMoved = 1u << 14,
- /**
- Measures the sum of extra bytes allocated beyond the bytes requested, i.e.
- the $(WEB goo.gl/YoKffF, internal fragmentation). This is the current
- effective number of slack bytes, and it goes up and down with time.
- */
- bytesSlack = 1u << 15,
- /**
- Measures the maximum bytes allocated over the time. This is useful for
- dimensioning allocators.
- */
- bytesHighTide = 1u << 16,
- /**
- Chooses all $(D byteXxx) flags.
- */
- bytesAll = ((1u << 17) - 1) & ~numAll,
- /**
- Instructs $(D AllocatorWithStats) to store the size asked by the caller for
- each allocation. All per-allocation data is stored just before the actually
- allocation (see $(D AffixAllocator)).
- */
- callerSize = 1u << 17,
- /**
- Instructs $(D AllocatorWithStats) to store the caller module for each
- allocation.
- */
- callerModule = 1u << 18,
- /**
- Instructs $(D AllocatorWithStats) to store the caller's file for each
- allocation.
- */
- callerFile = 1u << 19,
- /**
- Instructs $(D AllocatorWithStats) to store the caller $(D __FUNCTION__) for
- each allocation.
- */
- callerFunction = 1u << 20,
- /**
- Instructs $(D AllocatorWithStats) to store the caller's line for each
- allocation.
- */
- callerLine = 1u << 21,
- /**
- Instructs $(D AllocatorWithStats) to store the time of each allocation.
- */
- callerTime = 1u << 22,
- /**
- Chooses all $(D callerXxx) flags.
- */
- callerAll = ((1u << 23) - 1) & ~numAll & ~bytesAll,
- /**
- Combines all flags above.
- */
- all = (1u << 23) - 1
-}
-
-/**
-
-Allocator that collects extra data about allocations. Since each piece of
-information adds size and time overhead, statistics can be individually enabled
-or disabled through compile-time $(D flags).
-
-All stats of the form $(D numXxx) record counts of events occurring, such as
-calls to functions and specific results. The stats of the form $(D bytesXxx)
-collect cumulative sizes.
-
-In addition, the data $(D callerSize), $(D callerModule), $(D callerFile), $(D
-callerLine), and $(D callerTime) is associated with each specific allocation.
-This data prefixes each allocation.
-
-*/
-struct AllocatorWithStats(Allocator, uint flags = Options.all)
-{
-private:
- // Per-allocator state
- mixin(define("ulong",
- "numOwns",
- "numAllocate",
- "numAllocateOK",
- "numExpand",
- "numExpandOK",
- "numReallocate",
- "numReallocateOK",
- "numReallocateInPlace",
- "numDeallocate",
- "numDeallocateAll",
- "bytesAllocated",
- "bytesDeallocated",
- "bytesExpanded",
- "bytesContracted",
- "bytesMoved",
- "bytesSlack",
- "bytesHighTide",
- ));
-
- static string define(string type, string[] names...)
- {
- string result;
- foreach (v; names)
- result ~= "static if (flags & Options."~v~") {"
- "private "~type~" _"~v~";"
- "public const("~type~") "~v~"() const { return _"~v~"; }"
- "}";
- return result;
- }
-
- void add(string counter)(Signed!size_t n)
- {
- mixin("static if (flags & Options." ~ counter
- ~ ") _" ~ counter ~ " += n;");
- }
-
- void up(string counter)() { add!counter(1); }
- void down(string counter)() { add!counter(-1); }
-
- version (StdDdoc)
- {
- /**
- Read-only properties enabled by the homonym $(D flags) chosen by the
- user.
-
- Example:
- ----
- AllocatorWithStats!(Mallocator,
- Options.bytesAllocated | Options.bytesDeallocated) a;
- auto d1 = a.allocate(10);
- auto d2 = a.allocate(11);
- a.deallocate(d1);
- assert(a.bytesAllocated == 21);
- assert(a.bytesDeallocated == 10);
- ----
- */
- @property ulong numOwns() const;
- /// Ditto
- @property ulong numAllocate() const;
- /// Ditto
- @property ulong numAllocateOK() const;
- /// Ditto
- @property ulong numExpand() const;
- /// Ditto
- @property ulong numExpandOK() const;
- /// Ditto
- @property ulong numReallocate() const;
- /// Ditto
- @property ulong numReallocateOK() const;
- /// Ditto
- @property ulong numReallocateInPlace() const;
- /// Ditto
- @property ulong numDeallocate() const;
- /// Ditto
- @property ulong numDeallocateAll() const;
- /// Ditto
- @property ulong bytesAllocated() const;
- /// Ditto
- @property ulong bytesDeallocated() const;
- /// Ditto
- @property ulong bytesExpanded() const;
- /// Ditto
- @property ulong bytesContracted() const;
- /// Ditto
- @property ulong bytesMoved() const;
- /// Ditto
- @property ulong bytesSlack() const;
- /// Ditto
- @property ulong bytesHighTide() const;
- }
-
- // Do flags require any per allocation state?
- enum hasPerAllocationState = flags & (Options.callerTime
- | Options.callerModule | Options.callerFile | Options.callerLine);
-
- version (StdDdoc)
- {
- /**
- Per-allocation information that can be iterated upon by using
- $(D byAllocation). This only tracks live allocations and is useful for
- e.g. tracking memory leaks.
-
- Example:
- ----
- AllocatorWithStats!(Mallocator, Options.all) a;
- auto d1 = a.allocate(10);
- auto d2 = a.allocate(11);
- a.deallocate(d1);
- foreach (ref e; a.byAllocation)
- {
- writeln("Allocation module: ", e.callerModule);
- }
- ----
- */
- public struct AllocationInfo
- {
- /**
- Read-only property defined by the corresponding flag chosen in
- $(D options).
- */
- @property size_t callerSize() const;
- /// Ditto
- @property string callerModule() const;
- /// Ditto
- @property string callerFile() const;
- /// Ditto
- @property uint callerLine() const;
- /// Ditto
- @property uint callerFunction() const;
- /// Ditto
- @property const(SysTime) callerTime() const;
- }
- }
- else static if (hasPerAllocationState)
- {
- public struct AllocationInfo
- {
- import std.datetime;
- mixin(define("string", "callerModule", "callerFile",
- "callerFunction"));
- mixin(define("uint", "callerLine"));
- mixin(define("size_t", "callerSize"));
- mixin(define("SysTime", "callerTime"));
- private AllocationInfo* _prev, _next;
- }
- AllocationInfo* _root;
- alias MyAllocator = AffixAllocator!(Allocator, AllocationInfo);
-
- public auto byAllocation()
- {
- struct Voldemort
- {
- private AllocationInfo* _root;
- bool empty() { return _root is null; }
- ref AllocationInfo front() { return *_root; }
- void popFront() { _root = _root._next; }
- Voldemort save() { return this; }
- }
- return Voldemort(_root);
- }
- }
- else
- {
- alias MyAllocator = Allocator;
- }
-
-public:
- // Parent allocator (publicly accessible)
- static if (stateSize!MyAllocator) MyAllocator parent;
- else alias parent = MyAllocator.it;
-
- enum uint alignment = Allocator.alignment;
-
- static if (hasMember!(Allocator, "owns"))
- bool owns(void[] b)
- {
- up!"numOwns";
- return parent.owns(b);
- }
-
- void[] allocate
- (string m = __MODULE__, string f = __FILE__, ulong n = __LINE__,
- string fun = __FUNCTION__)
- (size_t bytes)
- {
- up!"numAllocate";
- auto result = parent.allocate(bytes);
- add!"bytesAllocated"(result.length);
- add!"bytesSlack"(this.goodAllocSize(result.length) - result.length);
- add!"numAllocateOK"(result || !bytes); // allocating 0 bytes is OK
- static if (flags & Options.bytesHighTide)
- {
- const bytesNow = bytesAllocated - bytesDeallocated;
- if (_bytesHighTide < bytesNow) _bytesHighTide = bytesNow;
- }
- static if (hasPerAllocationState)
- {
- auto p = &parent.prefix(result);
- static if (flags & Options.callerSize)
- p._callerSize = bytes;
- static if (flags & Options.callerModule)
- p._callerModule = m;
- static if (flags & Options.callerFile)
- p._callerFile = f;
- static if (flags & Options.callerFunction)
- p._callerFunction = fun;
- static if (flags & Options.callerLine)
- p._callerLine = n;
- static if (flags & Options.callerTime)
- {
- import std.datetime;
- p._callerTime = Clock.currTime;
- }
- // Wire the new info into the list
- assert(p._prev is null);
- p._next = _root;
- if (_root) _root._prev = p;
- _root = p;
- }
- return result;
- }
-
- static if (hasMember!(Allocator, "expand"))
- bool expand(ref void[] b, size_t s)
- {
- up!"numExpand";
- static if (flags & Options.bytesSlack)
- const bytesSlackB4 = goodAllocSize(b.length) - b.length;
- auto result = parent.expand(b, s);
- if (result)
- {
- up!"numExpandOK";
- add!"bytesExpanded"(s);
- add!"bytesSlack"(goodAllocSize(b.length) - b.length - bytesSlackB4);
- }
- return result;
- }
-
- bool reallocate(ref void[] b, size_t s)
- {
- up!"numReallocate";
- static if (flags & Options.bytesSlack)
- const bytesSlackB4 = this.goodAllocSize(b.length) - b.length;
- static if (flags & Options.numReallocateInPlace)
- const oldB = b.ptr;
- static if (flags & Options.bytesMoved)
- const oldLength = b.length;
- static if (hasPerAllocationState)
- const reallocatingRoot = b && _root is &parent.prefix(b);
- if (!parent.reallocate(b, s)) return false;
- up!"numReallocateOK";
- add!"bytesSlack"(this.goodAllocSize(b.length) - b.length
- - bytesSlackB4);
- if (oldB == b.ptr)
- {
- // This was an in-place reallocation, yay
- up!"numReallocateInPlace";
- const Signed!size_t delta = b.length - oldLength;
- if (delta >= 0)
- {
- // Expansion
- add!"bytesAllocated"(delta);
- add!"bytesExpanded"(delta);
- }
- else
- {
- // Contraction
- add!"bytesDeallocated"(-delta);
- add!"bytesContracted"(-delta);
- }
- }
- else
- {
- // This was a allocate-move-deallocate cycle
- add!"bytesAllocated"(b.length);
- add!"bytesMoved"(oldLength);
- add!"bytesDeallocated"(oldLength);
- static if (hasPerAllocationState)
- {
- // Stitch the pointers again, ho-hum
- auto p = &parent.prefix(b);
- if (p._next) p._next._prev = p;
- if (p._prev) p._prev._next = p;
- if (reallocatingRoot) _root = p;
- }
- }
- return true;
- }
-
- void deallocate(void[] b)
- {
- up!"numDeallocate";
- add!"bytesDeallocated"(b.length);
- add!"bytesSlack"(-(this.goodAllocSize(b.length) - b.length));
- // Remove the node from the list
- static if (hasPerAllocationState)
- {
- auto p = &parent.prefix(b);
- if (p._next) p._next._prev = p._prev;
- if (p._prev) p._prev._next = p._next;
- if (_root is p) _root = p._next;
- }
- parent.deallocate(b);
- }
-
- static if (hasMember!(Allocator, "deallocateAll"))
- void deallocateAll()
- {
- up!"numDeallocateAll";
- // Must force bytesDeallocated to match bytesAllocated
- static if ((flags & Options.bytesDeallocated)
- && (flags & Options.bytesDeallocated))
- _bytesDeallocated = _bytesAllocated;
- parent.deallocateAll();
- static if (hasPerAllocationState) _root = null;
- }
-}
-
-unittest
-{
- void test(Allocator)()
- {
- Allocator a;
- auto b1 = a.allocate(100);
- assert(a.numAllocate == 1);
- auto b2 = a.allocate(101);
- assert(a.numAllocate == 2);
- assert(a.bytesAllocated == 201);
- auto b3 = a.allocate(202);
- assert(a.numAllocate == 3);
- assert(a.bytesAllocated == 403);
-
- assert(walkLength(a.byAllocation) == 3);
-
- foreach (ref e; a.byAllocation)
- {
- if (false) writeln(e);
- }
-
- a.deallocate(b2);
- assert(a.numDeallocate == 1);
- a.deallocate(b1);
- assert(a.numDeallocate == 2);
- a.deallocate(b3);
- assert(a.numDeallocate == 3);
- assert(a.numAllocate == a.numDeallocate);
- assert(a.bytesDeallocated == 403);
- }
-
- test!(AllocatorWithStats!Mallocator)();
- test!(AllocatorWithStats!(Freelist!(Mallocator, 128)))();
-}
-
-//struct ArrayOfAllocators(alias make)
-//{
-// alias Allocator = typeof(make());
-// private Allocator[] allox;
-
-// void[] allocate(size_t bytes)
-// {
-// void[] result = allocateNoGrow(bytes);
-// if (result) return result;
-// // Everything's full to the brim, create a new allocator.
-// auto newAlloc = make();
-// assert(&newAlloc !is newAlloc.initial);
-// // Move the array to the new allocator
-// assert(Allocator.alignment % Allocator.alignof == 0);
-// const arrayBytes = (allox.length + 1) * Allocator.sizeof;
-// Allocator[] newArray = void;
-// do
-// {
-// if (arrayBytes < bytes)
-// {
-// // There is a chance we can find room in the existing allocator.
-// newArray = cast(Allocator[]) allocateNoGrow(arrayBytes);
-// if (newArray) break;
-// }
-// newArray = cast(Allocator[]) newAlloc.allocate(arrayBytes);
-// writeln(newArray.length);
-// assert(newAlloc.initial !is &newArray[$ - 1]);
-// if (!newArray) return null;
-// } while (false);
-
-// assert(newAlloc.initial !is &newArray[$ - 1]);
-
-// // Move data over to the new position
-// foreach (i, ref e; allox)
-// {
-// writeln(&e, " ", e.base.store_.ptr, " ", e.initial);
-// e.move(newArray[i]);
-// }
-// auto recoveredBytes = allox.length * Allocator.sizeof;
-// static if (hasMember!(Allocator, "deallocate"))
-// deallocate(allox);
-// allox = newArray;
-// assert(&allox[$ - 1] !is newAlloc.initial);
-// newAlloc.move(allox[$ - 1]);
-// assert(&allox[$ - 1] !is allox[$ - 1].initial);
-// if (recoveredBytes >= bytes)
-// {
-// // The new request may be served from the just-freed memory. Recurse
-// // and be bold.
-// return allocateNoGrow(bytes);
-// }
-// // Otherwise, we can't possibly fetch memory from anywhere else but the
-// // fresh new allocator.
-// return allox.back.allocate(bytes);
-// }
-
-// private void[] allocateNoGrow(size_t bytes)
-// {
-// void[] result;
-// foreach (ref a; allox)
-// {
-// result = a.allocate(bytes);
-// if (result) break;
-// }
-// return result;
-// }
-
-// bool owns(void[] b)
-// {
-// foreach (i, ref a; allox)
-// {
-// if (a.owns(b)) return true;
-// }
-// return false;
-// }
-
-// static if (hasMember!(Allocator, "deallocate"))
-// void deallocate(void[] b)
-// {
-// foreach (i, ref a; allox)
-// {
-// if (!a.owns(b)) continue;
-// a.deallocate(b);
-// break;
-// }
-// }
-//}
-//
-//version(none) unittest
-//{
-// ArrayOfAllocators!({ return Region!()(new void[1024 * 4096]); }) a;
-// assert(a.allox.length == 0);
-// auto b1 = a.allocate(1024 * 8192);
-// assert(b1 is null);
-// b1 = a.allocate(1024 * 10);
-// assert(b1.length == 1024 * 10);
-// assert(a.allox.length == 1);
-// auto b2 = a.allocate(1024 * 4095);
-// assert(a.allox.length == 2);
-//}
-
-
-/**
-Given $(D make) as a function that returns fresh allocators, $(D
-CascadingAllocator) creates an allocator that lazily creates as many allocators
-are needed for satisfying client allocation requests.
-
-The management data of the allocators is stored in memory obtained from the
-allocators themselves, in a private linked list.
-*/
-struct CascadingAllocator(alias make)
-{
- /// Alias for $(D typeof(make)).
- alias typeof(make()) Allocator;
- private struct Node
- {
- Allocator a;
- Node* next;
- bool nextIsInitialized;
- }
- private Node* _root;
-
- /**
- Standard primitives.
- */
- enum uint alignment = Allocator.alignment;
-
- /// Ditto
- 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;
- // Must create a new allocator object
- if (!_root)
- {
- // I mean _brand_ new allocator object
- auto newNodeStack = Node(make());
- // Weird: store the new node inside its own allocated storage!
- _root = cast(Node*) newNodeStack.a.allocate(Node.sizeof).ptr;
- if (!_root)
- {
- // Are you serious? Not even the first allocation?
- return null;
- }
- newNodeStack.move(*_root);
- // Make sure we reserve room for the next next node
- _root.next = cast(Node*) _root.a.allocate(Node.sizeof).ptr;
- assert(_root.next);
- // root is set up, serve from it
- return allocateNoGrow(s);
- }
- // No room left, must append a new allocator
- auto n = _root;
- while (n.nextIsInitialized) n = n.next;
- if (!n.next)
- {
- // Resources truly exhausted, not much to do
- return null;
- }
- emplace(n.next, Node(make()));
- n.nextIsInitialized = true;
- // Reserve room for the next next allocator
- n.next.next = cast(Node*) allocateNoGrow(Node.sizeof).ptr;
- // Rare failure cases leave nextIsInitialized to false
- if (!n.next.next) n.nextIsInitialized = false;
- // TODO: would be nice to bring the new allocator to the front.
- // All done!
- return allocateNoGrow(s);
- }
-
- private void[] allocateNoGrow(size_t bytes)
- {
- void[] result;
- if (!_root) return result;
- for (auto n = _root; ; n = n.next)
- {
- result = n.a.allocate(bytes);
- if (result) break;
- if (!n.nextIsInitialized) break;
- }
- return result;
- }
-
- /// Defined only if $(D Allocator.owns) is defined.
- static if (hasMember!(Allocator, "owns"))
- bool owns(void[] b)
- {
- if (!_root) return b is null;
- for (auto n = _root; ; n = n.next)
- {
- if (n.a.owns(b)) return true;
- if (!n.nextIsInitialized) break;
- }
- return false;
- }
-
- /// Defined only if $(D Allocator.expand) is defined.
- static if (hasMember!(Allocator, "expand"))
- bool expand(ref void[] b, size_t delta)
- {
- if (!b) return (b = allocate(delta)) !is null;
- if (!_root) return false;
- for (auto n = _root; ; n = n.next)
- {
- if (n.a.owns(b)) return n.a.expand(b, delta);
- if (!n.nextIsInitialized) break;
- }
- return false;
- }
-
- /// Allows moving data from one $(D Allocator) to another.
- bool reallocate(ref void[] b, size_t s)
- {
- if (!b) return (b = allocate(s)) !is null;
- // First attempt to reallocate within the existing node
- if (!_root) return false;
- for (auto n = _root; ; n = n.next)
- {
- 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.
- auto newB = allocate(s);
- if (!newB) return false;
- newB[] = b[];
- static if (hasMember!(Allocator, "deallocate"))
- deallocate(b);
- b = newB;
- return true;
- }
-
- /// Defined only if $(D Allocator.deallocate) is defined.
- static if (hasMember!(Allocator, "deallocate"))
- void deallocate(void[] b)
- {
- if (!_root)
- {
- assert(b is null);
- return;
- }
- for (auto n = _root; ; n = n.next)
- {
- if (n.a.owns(b)) return n.a.deallocate(b);
- if (!n.nextIsInitialized) break;
- }
- assert(false);
- }
-
- /// Defined only if $(D Allocator.deallocateAll) is defined.
- static if (hasMember!(Allocator, "deallocateAll"))
- void deallocateAll()
- {
- if (!_root) return;
- // This is tricky because the list of allocators is threaded through the
- // allocators themselves. Malloc to the rescue!
- // First compute the number of allocators
- uint k = 0;
- for (auto n = _root; ; n = n.next)
- {
- ++k;
- if (!n.nextIsInitialized) break;
- }
- auto nodes =
- cast(Node*[]) Mallocator.it.allocate(k * (Allocator*).sizeof);
- scope(exit) Mallocator.it.deallocate(nodes);
- foreach (ref n; nodes)
- {
- n = _root;
- _root = _root.next;
- }
- _root = null;
- // Now we can deallocate in peace
- foreach (n; nodes)
- {
- n.a.deallocateAll();
- }
- }
-}
-
-///
-unittest
-{
- // Create an allocator based upon 4MB regions, fetched from the GC heap.
- 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);
- assert(b1.length == 1024 * 10);
- a.deallocateAll();
-}
-
-unittest
-{
- CascadingAllocator!({ return Region!()(new void[1024 * 4096]); }) a;
- auto b1 = a.allocate(1024 * 8192);
- assert(b1 is null);
- assert(!a._root.nextIsInitialized);
- b1 = a.allocate(1024 * 10);
- assert(b1.length == 1024 * 10);
- auto b2 = a.allocate(1024 * 4095);
- assert(a._root.nextIsInitialized);
- a.deallocateAll();
- assert(!a._root);
-}
-
-/**
-Dispatches allocations (and deallocations) between two allocators ($(D
-SmallAllocator) and $(D LargeAllocator)) depending on the size allocated, as
-follows. All allocations smaller than or equal to $(D threshold) will be
-dispatched to $(D SmallAllocator). The others will go to $(D LargeAllocator).
-
-If both allocators are $(D shared), the $(D Segregator) will also offer $(D
-shared) methods.
-*/
-struct Segregator(size_t threshold, SmallAllocator, LargeAllocator)
-{
- static if (stateSize!SmallAllocator) SmallAllocator _small;
- else static alias SmallAllocator.it _small;
- static if (stateSize!LargeAllocator) LargeAllocator _large;
- else alias LargeAllocator.it _large;
-
- version (StdDdoc)
- {
- /**
- The alignment offered is the minimum of the two allocators' alignment.
- */
- enum uint alignment;
- /**
- This method is defined only if at least one of the allocators defines
- it. The good allocation size is obtained from $(D SmallAllocator) if $(D
- s <= threshold), or $(D LargeAllocator) otherwise. (If one of the
- allocators does not define $(D goodAllocSize), the default
- implementation in this module applies.)
- */
- static size_t goodAllocSize(size_t s);
- /**
- The memory is obtained from $(D SmallAllocator) if $(D s <= threshold),
- or $(D LargeAllocator) otherwise.
- */
- void[] allocate(size_t);
- /**
- This method is defined only if both allocators define it. The call is
- forwarded to $(D SmallAllocator) if $(D b.length <= threshold), or $(D
- LargeAllocator) otherwise.
- */
- bool owns(void[] b);
- /**
- This method is defined only if at least one of the allocators defines
- it. If $(D SmallAllocator) defines $(D expand) and $(D b.length +
- delta <= threshold), the call is forwarded to $(D SmallAllocator). If $(
- LargeAllocator) defines $(D expand) and $(D b.length > threshold), the
- call is forwarded to $(D LargeAllocator). Otherwise, the call returns
- $(D false).
- */
- bool expand(ref void[] b, size_t delta);
- /**
- This method is defined only if at least one of the allocators defines
- it. If $(D SmallAllocator) defines $(D reallocate) and $(D b.length <=
- threshold && s <= threshold), the call is forwarded to $(D
- SmallAllocator). If $(D LargeAllocator) defines $(D expand) and $(D
- b.length > threshold && s > threshold), the call is forwarded to $(D
- LargeAllocator). Otherwise, the call returns $(D false).
- */
- bool reallocate(ref void[] b, size_t s);
- /**
- This function is defined only if both allocators define it, and forwards
- appropriately depending on $(D b.length).
- */
- void deallocate(void[] b);
- /**
- This function is defined only if both allocators define it, and calls
- $(D deallocateAll) for them in turn.
- */
- void deallocateAll();
- }
-
- /**
- Composite allocators involving nested instantiations of $(D Segregator) make
- it difficult to access individual sub-allocators stored within. $(D
- allocatorForSize) simplifies the task by supplying the allocator nested
- inside a $(D Segregator) that is responsible for a specific size $(D s).
-
- Example:
- ----
- alias A = Segregator!(300,
- Segregator!(200, A1, A2),
- A3);
- A a;
- static assert(typeof(a.allocatorForSize!10) == A1);
- static assert(typeof(a.allocatorForSize!250) == A2);
- static assert(typeof(a.allocatorForSize!301) == A3);
- ----
- */
- ref auto allocatorForSize(size_t s)()
- {
- static if (s <= threshold)
- static if (is(SmallAllocator == Segregator!(Args), Args...))
- return _small.allocatorForSize!s;
- else return _small;
- else
- static if (is(LargeAllocator == Segregator!(Args), Args...))
- return _large.allocatorForSize!s;
- else return _large;
- }
-
- enum uint alignment = min(SmallAllocator.alignment,
- LargeAllocator.alignment);
-
- template Impl()
- {
- 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) nothrow pure @trusted
- {
- data.length <= threshold
- ? _small.deallocate(data)
- : _large.deallocate(data);
- }
-
- size_t goodAllocSize(size_t s) const nothrow pure @safe
- {
- return s <= threshold
- ? _small.goodAllocSize(s)
- : _large.goodAllocSize(s);
- }
-
- static if (hasMember!(SmallAllocator, "owns")
- && hasMember!(LargeAllocator, "owns"))
- bool owns(void[] b) const nothrow pure @safe
- {
- return b.length <= threshold ? _small.owns(b) : _large.owns(b);
- }
-
- static if (hasMember!(SmallAllocator, "expand")
- || hasMember!(LargeAllocator, "expand"))
- bool expand(ref void[] b, size_t delta)
- {
- if (b.length + delta <= threshold)
- {
- // Old and new allocations handled by _small
- static if (hasMember!(SmallAllocator, "expand"))
- return _small.expand(b, delta);
- else
- return false;
- }
- if (b.length > threshold)
- {
- // Old and new allocations handled by _large
- static if (hasMember!(LargeAllocator, "expand"))
- return _large.expand(b, delta);
- else
- return false;
- }
- // Oops, cross-allocator transgression
- return false;
- }
-
- static if (hasMember!(SmallAllocator, "reallocate")
- || hasMember!(LargeAllocator, "reallocate"))
- bool reallocate(ref void[] b, size_t s)
- {
- static if (hasMember!(SmallAllocator, "reallocate"))
- if (b.length <= threshold && s <= threshold)
- {
- // Old and new allocations handled by _small
- return _small.reallocate(b, s);
- }
- static if (hasMember!(LargeAllocator, "reallocate"))
- if (b.length > threshold && s > threshold)
- {
- // Old and new allocations handled by _large
- return _large.reallocate(b, s);
- }
- // Cross-allocator transgression
- return .reallocate(this, b, s);
- }
-
- static if (hasMember!(SmallAllocator, "deallocateAll")
- && hasMember!(LargeAllocator, "deallocateAll"))
- void deallocateAll()
- {
- _small.deallocateAll();
- _large.deallocateAll();
- }
- }
-
- enum sharedMethods =
- !stateSize!SmallAllocator
- && !stateSize!LargeAllocator
- && is(typeof(SmallAllocator.it) == shared)
- && is(typeof(LargeAllocator.it) == shared);
- //pragma(msg, sharedMethods);
-
- static if (sharedMethods)
- {
- static shared(typeof(this)) it() pure nothrow @property @trusted
- {
- return cast(typeof(return)) _it;
- }
- private static const shared Segregator _it;
- shared { mixin Impl!(); }
- }
- else
- {
- static if (!stateSize!SmallAllocator && !stateSize!LargeAllocator)
- static __gshared Segregator it;
- mixin Impl!();
- }
-}
-
-///
-unittest
-{
- alias A =
- Segregator!(
- 1024 * 4,
- Segregator!(
- 128, Freelist!(Mallocator, 0, 128),
- GCAllocator),
- Segregator!(
- 1024 * 1024, Mallocator,
- GCAllocator)
- );
- A a;
- auto b = a.allocate(200);
- assert(b.length == 200);
- a.deallocate(b);
-}
-
-/**
-A $(D Segregator) with more than three arguments expands to a composition of
-elemental $(D Segregator)s, as illustrated by the following example:
-
-----
-alias A =
- Segregator!(
- n1, A1,
- n2, A2,
- n3, A3,
- A4
- );
-----
-
-With this definition, allocation requests for $(D n1) bytes or less are directed
-to $(D A1); requests between $(D n1 + 1) and $(D n2) bytes (inclusive) are
-directed to $(D A2); requests between $(D n2 + 1) and $(D n3) bytes (inclusive)
-are directed to $(D A3); and requests for more than $(D n3) bytes are directed
-to $(D A4). If some particular range should not be handled, $(D NullAllocator)
-may be used appropriately.
-
-*/
-template Segregator(Args...) if (Args.length > 3)
-{
- // Binary search
- private enum cutPoint = ((Args.length - 2) / 4) * 2;
- static if (cutPoint >= 2)
- {
- alias Segregator = .Segregator!(
- Args[cutPoint],
- .Segregator!(Args[0 .. cutPoint], Args[cutPoint + 1]),
- .Segregator!(Args[cutPoint + 2 .. $])
- );
- }
- else
- {
- // Favor small sizes
- alias Segregator = .Segregator!(
- Args[0],
- Args[1],
- .Segregator!(Args[2 .. $])
- );
- }
-
- // Linear search
- //alias Segregator = .Segregator!(
- // Args[0], Args[1],
- // .Segregator!(Args[2 .. $])
- //);
-}
-
-///
-unittest
-{
- alias A =
- Segregator!(
- 128, Freelist!(Mallocator, 0, 128),
- 1024 * 4, GCAllocator,
- 1024 * 1024, Mallocator,
- GCAllocator
- );
- A a;
- auto b = a.allocate(201);
- assert(b.length == 201);
- a.deallocate(b);
-}
-
-/**
-
-A $(D Bucketizer) uses distinct allocators for handling allocations of sizes in
-the intervals $(D [min, min + step - 1]), $(D [min + step, min + 2 * step - 1]),
-$(D [min + 2 * step, min + 3 * step - 1]), $(D ...), $(D [max - step + 1, max]).
-
-$(D Bucketizer) holds a fixed-size array of allocators and dispatches calls to
-them appropriately. The size of the array is $(D (max + 1 - min) / step), which
-must be an exact division.
-
-Allocations for sizes smaller than $(D min) or larger than $(D max) are illegal
-for $(D Bucketizer). To handle them separately, $(D Segregator) may be of use.
-
-*/
-struct Bucketizer(Allocator, size_t min, size_t max, size_t step)
-{
- static assert((max - (min - 1)) % step == 0,
- "Invalid limits when instantiating " ~ Bucketizer.stringof);
-
- //static if (min == chooseAtRuntime) size_t _min;
- //else alias _min = min;
- //static if (max == chooseAtRuntime) size_t _max;
- //else alias _max = max;
- //static if (step == chooseAtRuntime) size_t _step;
- //else alias _step = step;
-
- /// The array of allocators is publicly available for e.g. initialization
- /// and inspection.
- Allocator buckets[(max - (min - 1)) / step];
-
- /**
- The alignment offered is the same as $(D Allocator.alignment).
- */
- enum uint alignment = Allocator.alignment;
-
- /**
- Rounds up to the maximum size of the bucket in which $(D bytes) falls.
- */
- size_t goodAllocSize(size_t bytes) const
- {
- // round up bytes such that bytes - min + 1 is a multiple of step
- assert(bytes >= min);
- const min_1 = min - 1;
- return min_1 + roundUpToMultipleOf(bytes - min_1, step);
- }
-
- /**
- Returns $(D b.length >= min && b.length <= max).
- */
- bool owns(void[] b) const
- {
- return b.length >= min && b.length <= max;
- }
-
- /**
- Directs the call to either one of the $(D buckets) allocators.
- */
- void[] allocate(size_t bytes)
- {
- // Choose the appropriate allocator
- const i = (bytes - min) / step;
- assert(i < buckets.length);
- const actual = goodAllocSize(bytes);
- auto result = buckets[i].allocate(actual);
- return result.ptr[0 .. bytes];
- }
-
- /**
- This method allows expansion within the respective bucket range. It succeeds
- if both $(D b.length) and $(D b.length + delta) fall in a range of the form
- $(D [min + k * step, min + (k + 1) * step - 1]).
- */
- bool expand(ref void[] b, size_t delta)
- {
- assert(b.length >= min && b.length <= max);
- const available = goodAllocSize(b.length);
- const desired = b.length + delta;
- if (available < desired) return false;
- b = b.ptr[0 .. desired];
- return true;
- }
-
- /**
- This method is only defined if $(D Allocator) defines $(D deallocate).
- */
- static if (hasMember!(Allocator, "deallocate"))
- void deallocate(void[] b)
- {
- const i = (b.length - min) / step;
- assert(i < buckets.length);
- const actual = goodAllocSize(b.length);
- buckets.ptr[i].deallocate(b.ptr[0 .. actual]);
- }
-
- /**
- This method is only defined if all allocators involved define $(D
- deallocateAll), and calls it for each bucket in turn.
- */
- static if (hasMember!(Allocator, "deallocateAll"))
- void deallocateAll()
- {
- foreach (ref a; buckets)
- {
- a.deallocateAll();
- }
- }
-}
-
-///
-unittest
-{
- Bucketizer!(Freelist!(Mallocator, 0, unbounded),
- 65, 512, 64) a;
- auto b = a.allocate(400);
- assert(b.length == 400, text(b.length));
- a.deallocate(b);
-}
-
-/**
-Dynamic version of an allocator. This should be used wherever a uniform type is
-required for encapsulating various allocator implementations.
-
-TODO: add support for $(D shared).
-*/
-class CAllocator
-{
- /// Returns the alignment offered. By default this method returns $(D
- /// platformAlignment).
- uint alignment() pure nothrow const @property
- {
- return platformAlignment;
- }
-
- /**
- Sets the alignment and returns $(D true) on success, $(D false) if not
- supported. By default returns $(D false). An allocator implementation could
- throw an exception if it does allow setting the alignment but an invalid
- value is passed.
- */
- @property bool alignment(uint) pure nothrow
- {
- return false;
- }
-
- /**
- Returns the good allocation size that guarantees zero internal
- fragmentation. By default returns $(D s) rounded up to the nearest multiple
- of $(D alignment).
- */
- size_t goodAllocSize(size_t s) pure nothrow const @property
- {
- return s.roundUpToMultipleOf(alignment);
- }
-
- /**
- Allocates memory.
- */
- abstract void[] allocate(size_t) pure nothrow @safe;
-
- /**
- Returns $(D true) if the allocator supports $(D owns). By default returns
- $(D false).
- */
- bool supportsOwns()
- {
- return false;
- }
-
- /**
- Returns $(D true) if the allocator owns $(D b). By default issues $(D
- assert(false)).
- */
- bool owns(void[] b)
- {
- assert(false);
- }
-
- /// Expands a memory block in place.
- abstract bool expand(ref void[], size_t) pure nothrow;
-
- /// Reallocates a memory block.
- 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[]) pure nothrow;
-
- /// Deallocates all memory. Returns $(D false) if not supported.
- abstract bool deallocateAll() pure nothrow;
-
- /// Returns $(D true) if allocator supports $(D allocateAll). By default
- /// returns $(D false).
- bool supportsAllocateAll()
- {
- return false;
- }
-
- /**
- Allocates and returns all memory available to this allocator. By default
- issues $(D assert(false)).
- */
- void[] allocateAll()
- {
- assert(false);
- }
-}
-
-/**
-Implementation of $(D CAllocator) using $(D Allocator). This adapts a
-statically-built allocator type to a uniform dynamic interface that is directly
-usable by non-templated code.
-*/
-class CAllocatorImpl(Allocator) : CAllocator
-{
- /**
- The implementation is available as a public member.
- */
- static if (stateSize!Allocator) Allocator impl;
- else alias impl = Allocator.it;
-
- /// Returns $(D impl.alignment).
- override uint alignment() pure nothrow const @property
- {
- return impl.alignment;
- }
-
- /**
- If $(D Allocator) supports alignment setting, performs it and returns $(D
- true). Otherwise, returns $(D false).
- */
- override bool alignment(uint a) pure nothrow const @property
- {
- static if (is(typeof(impl.alignment = a)))
- {
- impl.alignment = a;
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- Returns $(D impl.goodAllocSize(s)).
- */
- override size_t goodAllocSize(size_t s) pure nothrow const @property
- {
- return impl.goodAllocSize(s);
- }
-
- /**
- Returns $(D impl.allocate(s)).
- */
- override void[] allocate(size_t s) pure nothrow @safe
- {
- return impl.allocate(s);
- }
-
- /**
- Returns $(D true) if $(D Allocator) supports $(D owns).
- */
- override bool supportsOwns() pure nothrow const @safe
- {
- return hasMember!(Allocator, "owns");
- }
-
- /**
- Overridden only if $(D Allocator) implements $(D owns). In that case,
- returns $(D impl.owns(b)).
- */
- static if (hasMember!(Allocator, "owns"))
- override bool owns(void[] b)
- {
- return impl.owns(b);
- }
-
- /// Returns $(D impl.expand(b, s)) if defined, $(D false) otherwise.
- override bool expand(ref void[] b, size_t s) pure nothrow
- {
- static if (hasMember!(Allocator, "expand"))
- return impl.expand(b, s);
- else
- return false;
- }
-
- /// Returns $(D impl.reallocate(b, s)).
- override bool reallocate(ref void[] b, size_t s)
- {
- return impl.reallocate(b, s);
- }
-
- /// Calls $(D impl.deallocate(b)) and returns $(D true) if defined,
- /// otherwise returns $(D false).
- override bool deallocate(void[] b) pure nothrow
- {
- static if (hasMember!(Allocator, "deallocate"))
- {
- impl.deallocate(b);
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /// Calls $(D impl.deallocateAll()) and returns $(D true) if defined,
- /// otherwise returns $(D false).
- override bool deallocateAll() pure nothrow
- {
- static if (hasMember!(Allocator, "deallocateAll"))
- {
- impl.deallocateAll();
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /// Returns $(D true) if allocator supports $(D allocateAll). By default
- /// returns $(D false).
- override bool supportsAllocateAll() pure nothrow const
- {
- return hasMember!(Allocator, "allocateAll");
- }
-
- /**
- Overridden only if $(D Allocator) implements $(D allocateAll). In that case,
- returns $(D impl.allocateAll()).
- */
- static if (hasMember!(Allocator, "allocateAll"))
- override void[] allocateAll() pure nothrow
- {
- return impl.allocateAll();
- }
-}
-
-///
-unittest
-{
- /// Define an allocator bound to the built-in GC.
- CAllocator alloc = new CAllocatorImpl!GCAllocator;
- auto b = alloc.allocate(42);
- assert(b.length == 42);
- assert(alloc.deallocate(b));
-
- // Define an elaborate allocator and bind it to the class API.
- // Note that the same variable "alloc" is used.
- alias FList = Freelist!(GCAllocator, 0, unbounded);
- alias A = Segregator!(
- 8, Freelist!(GCAllocator, 0, 8),
- 128, Bucketizer!(FList, 1, 128, 16),
- 256, Bucketizer!(FList, 129, 256, 32),
- 512, Bucketizer!(FList, 257, 512, 64),
- 1024, Bucketizer!(FList, 513, 1024, 128),
- 2048, Bucketizer!(FList, 1025, 2048, 256),
- 3584, Bucketizer!(FList, 2049, 3584, 512),
- 4072 * 1024, CascadingAllocator!(
- () => HeapBlock!(GCAllocator, 4096)(4072 * 1024)),
- GCAllocator
- );
-
- alloc = new CAllocatorImpl!A;
- b = alloc.allocate(101);
- assert(alloc.deallocate(b));
-}
-
-private bool isPowerOf2(uint x)
-{
- return (x & (x - 1)) == 0;
-}
-
-private bool isGoodStaticAlignment(uint x)
-{
- return x.isPowerOf2 && x > 0;
-}
-
-private bool isGoodDynamicAlignment(uint x)
-{
- return x.isPowerOf2 && x >= (void*).sizeof;
-}
-
-__EOF__
-
-version(none) struct TemplateAllocator
-{
- enum alignment = platformAlignment;
- static size_t goodAllocSize(size_t s)
- {
- }
- void[] allocate(size_t)
- {
- }
- bool owns(void[])
- {
- }
- bool expand(ref void[] b, size_t)
- {
- }
- bool reallocate(ref void[] b, size_t)
- {
- }
- void deallocate(void[] b)
- {
- }
- void deallocateAll()
- {
- }
- void[] allocateAll()
- {
- }
- static shared TemplateAllocator it;
-}
-
diff --git a/std/d/ast.d b/std/d/ast.d
deleted file mode 100644
index c03db06..0000000
--- a/std/d/ast.d
+++ /dev/null
@@ -1,3151 +0,0 @@
-// Written in the D programming language.
-
-/**
- * This module defines an Abstract Syntax Tree for the D language
- *
- * Examples:
- * ---
- * // TODO
- * ---
- *
- * Copyright: Brian Schott 2013
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt Boost, License 1.0)
- * Authors: Brian Schott
- * Source: $(PHOBOSSRC std/d/_ast.d)
- */
-
-module std.d.ast;
-
-import std.d.lexer;
-import std.traits;
-import std.algorithm;
-import std.array;
-import std.string;
-
-// TODO: Many of these classes can be simplified by using std.variant.Algebraic
-
-/**
- * Implements the $(LINK2 http://en.wikipedia.org/wiki/Visitor_pattern, Visitor Pattern)
- * for the various AST classes
- */
-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 AddExpression addExpression) { addExpression.accept(this); }
- /** */ void visit(const AliasDeclaration aliasDeclaration) { aliasDeclaration.accept(this); }
- /** */ void visit(const AliasInitializer aliasInitializer) { aliasInitializer.accept(this); }
- /** */ void visit(const AliasThisDeclaration aliasThisDeclaration) { aliasThisDeclaration.accept(this); }
- /** */ void visit(const AlignAttribute alignAttribute) { alignAttribute.accept(this); }
- /** */ void visit(const AndAndExpression andAndExpression) { andAndExpression.accept(this); }
- /** */ void visit(const AndExpression andExpression) { andExpression.accept(this); }
- /** */ void visit(const ArgumentList argumentList) { argumentList.accept(this); }
- /** */ void visit(const Arguments arguments) { arguments.accept(this); }
- /** */ void visit(const ArrayInitializer arrayInitializer) { arrayInitializer.accept(this); }
- /** */ void visit(const ArrayLiteral arrayLiteral) { arrayLiteral.accept(this); }
- /** */ void visit(const ArrayMemberInitialization arrayMemberInitialization) { arrayMemberInitialization.accept(this); }
- /** */ void visit(const AsmAddExp asmAddExp) { asmAddExp.accept(this); }
- /** */ void visit(const AsmAndExp asmAndExp) { asmAndExp.accept(this); }
- /** */ void visit(const AsmBrExp asmBrExp) { asmBrExp.accept(this); }
- /** */ void visit(const AsmEqualExp asmEqualExp) { asmEqualExp.accept(this); }
- /** */ void visit(const AsmExp asmExp) { asmExp.accept(this); }
- /** */ void visit(const AsmInstruction asmInstruction) { asmInstruction.accept(this); }
- /** */ void visit(const AsmLogAndExp asmLogAndExp) { asmLogAndExp.accept(this); }
- /** */ void visit(const AsmLogOrExp asmLogOrExp) { asmLogOrExp.accept(this); }
- /** */ void visit(const AsmMulExp asmMulExp) { asmMulExp.accept(this); }
- /** */ void visit(const AsmOrExp asmOrExp) { asmOrExp.accept(this); }
- /** */ void visit(const AsmPrimaryExp asmPrimaryExp) { asmPrimaryExp.accept(this); }
- /** */ void visit(const AsmRelExp asmRelExp) { asmRelExp.accept(this); }
- /** */ void visit(const AsmShiftExp asmShiftExp) { asmShiftExp.accept(this); }
- /** */ void visit(const AsmStatement asmStatement) { asmStatement.accept(this); }
- /** */ void visit(const AsmTypePrefix asmTypePrefix) { asmTypePrefix.accept(this); }
- /** */ void visit(const AsmUnaExp asmUnaExp) { asmUnaExp.accept(this); }
- /** */ void visit(const AsmXorExp asmXorExp) { asmXorExp.accept(this); }
- /** */ void visit(const AssertExpression assertExpression) { assertExpression.accept(this); }
- /** */ void visit(const AssignExpression assignExpression) { assignExpression.accept(this); }
- /** */ void visit(const AssocArrayLiteral assocArrayLiteral) { assocArrayLiteral.accept(this); }
- /** */ void visit(const AtAttribute atAttribute) { atAttribute.accept(this); }
- /** */ void visit(const Attribute attribute) { attribute.accept(this); }
- /** */ void visit(const AttributeDeclaration attributeDeclaration) { attributeDeclaration.accept(this); }
- /** */ void visit(const AutoDeclaration autoDeclaration) { autoDeclaration.accept(this); }
- /** */ void visit(const BlockStatement blockStatement) { blockStatement.accept(this); }
- /** */ void visit(const BodyStatement bodyStatement) { bodyStatement.accept(this); }
- /** */ void visit(const BreakStatement breakStatement) { breakStatement.accept(this); }
- /** */ void visit(const BaseClass baseClass) { baseClass.accept(this); }
- /** */ void visit(const BaseClassList baseClassList) { baseClassList.accept(this); }
- /** */ void visit(const CaseRangeStatement caseRangeStatement) { caseRangeStatement.accept(this); }
- /** */ void visit(const CaseStatement caseStatement) { caseStatement.accept(this); }
- /** */ void visit(const CastExpression castExpression) { castExpression.accept(this); }
- /** */ void visit(const CastQualifier castQualifier) { castQualifier.accept(this); }
- /** */ void visit(const Catch catch_) { catch_.accept(this); }
- /** */ void visit(const Catches catches) { catches.accept(this); }
- /** */ void visit(const ClassDeclaration classDeclaration) { classDeclaration.accept(this); }
- /** */ void visit(const CmpExpression cmpExpression) { cmpExpression.accept(this); }
- /** */ void visit(const CompileCondition compileCondition) { compileCondition.accept(this); }
- /** */ void visit(const ConditionalDeclaration conditionalDeclaration) { conditionalDeclaration.accept(this); }
- /** */ void visit(const ConditionalStatement conditionalStatement) { conditionalStatement.accept(this); }
- /** */ void visit(const Constraint constraint) { constraint.accept(this); }
- /** */ void visit(const Constructor constructor) { constructor.accept(this); }
- /** */ void visit(const ContinueStatement continueStatement) { continueStatement.accept(this); }
- /** */ void visit(const DebugCondition debugCondition) { debugCondition.accept(this); }
- /** */ void visit(const DebugSpecification debugSpecification) { debugSpecification.accept(this); }
- /** */ void visit(const Declaration declaration) { declaration.accept(this); }
- /** */ void visit(const DeclarationOrStatement declarationsOrStatement) { declarationsOrStatement.accept(this); }
- /** */ void visit(const DeclarationsAndStatements declarationsAndStatements) { declarationsAndStatements.accept(this); }
- /** */ void visit(const Declarator declarator) { declarator.accept(this); }
- /** */ void visit(const DefaultStatement defaultStatement) { defaultStatement.accept(this); }
- /** */ void visit(const DeleteExpression deleteExpression) { deleteExpression.accept(this); }
- /** */ void visit(const DeleteStatement deleteStatement) { deleteStatement.accept(this); }
- /** */ void visit(const Deprecated deprecated_) { deprecated_.accept(this); }
- /** */ void visit(const Destructor destructor) { destructor.accept(this); }
- /** */ void visit(const DoStatement doStatement) { doStatement.accept(this); }
- /** */ void visit(const EnumBody enumBody) { enumBody.accept(this); }
- /** */ void visit(const EnumDeclaration enumDeclaration) { enumDeclaration.accept(this); }
- /** */ void visit(const EnumMember enumMember) { enumMember.accept(this); }
- /** */ void visit(const EponymousTemplateDeclaration eponymousTemplateDeclaration) { eponymousTemplateDeclaration.accept(this); }
- /** */ void visit(const EqualExpression equalExpression) { equalExpression.accept(this); }
- /** */ void visit(const Expression expression) { expression.accept(this); }
- /** */ void visit(const ExpressionStatement expressionStatement) { expressionStatement.accept(this); }
- /** */ void visit(const FinalSwitchStatement finalSwitchStatement) { finalSwitchStatement.accept(this); }
- /** */ void visit(const Finally finally_) { finally_.accept(this); }
- /** */ void visit(const ForStatement forStatement) { forStatement.accept(this); }
- /** */ void visit(const ForeachStatement foreachStatement) { foreachStatement.accept(this); }
- /** */ void visit(const ForeachType foreachType) { foreachType.accept(this); }
- /** */ void visit(const ForeachTypeList foreachTypeList) { foreachTypeList.accept(this); }
- /** */ void visit(const FunctionAttribute functionAttribute) { functionAttribute.accept(this); }
- /** */ void visit(const FunctionBody functionBody) { functionBody.accept(this); }
- /** */ void visit(const FunctionCallExpression functionCallExpression) { functionCallExpression.accept(this); }
- /** */ void visit(const FunctionCallStatement functionCallStatement) { functionCallStatement.accept(this); }
- /** */ void visit(const FunctionDeclaration functionDeclaration) { functionDeclaration.accept(this); }
- /** */ void visit(const FunctionLiteralExpression functionLiteralExpression) { functionLiteralExpression.accept(this); }
- /** */ void visit(const GotoStatement gotoStatement) { gotoStatement.accept(this); }
- /** */ void visit(const IdentifierChain identifierChain) { identifierChain.accept(this); }
- /** */ void visit(const IdentifierList identifierList) { identifierList.accept(this); }
- /** */ void visit(const IdentifierOrTemplateChain identifierOrTemplateChain) { identifierOrTemplateChain.accept(this); }
- /** */ void visit(const IdentifierOrTemplateInstance identifierOrTemplateInstance) { identifierOrTemplateInstance.accept(this); }
- /** */ void visit(const IdentityExpression identityExpression) { identityExpression.accept(this); }
- /** */ void visit(const IfStatement ifStatement) { ifStatement.accept(this); }
- /** */ void visit(const ImportBind importBind) { importBind.accept(this); }
- /** */ void visit(const ImportBindings importBindings) { importBindings.accept(this); }
- /** */ void visit(const ImportDeclaration importDeclaration) { importDeclaration.accept(this); }
- /** */ void visit(const ImportExpression importExpression) { importExpression.accept(this); }
- /** */ void visit(const IndexExpression indexExpression) { indexExpression.accept(this); }
- /** */ void visit(const InExpression inExpression) { inExpression.accept(this); }
- /** */ void visit(const InStatement inStatement) { inStatement.accept(this); }
- /** */ void visit(const Initialize initialize) { initialize.accept(this); }
- /** */ void visit(const Initializer initializer) { initializer.accept(this); }
- /** */ void visit(const InterfaceDeclaration interfaceDeclaration) { interfaceDeclaration.accept(this); }
- /** */ void visit(const Invariant invariant_) { invariant_.accept(this); }
- /** */ void visit(const IsExpression isExpression) { isExpression.accept(this); }
- /** */ void visit(const KeyValuePair keyValuePair) { keyValuePair.accept(this); }
- /** */ void visit(const KeyValuePairs keyValuePairs) { keyValuePairs.accept(this); }
- /** */ void visit(const LabeledStatement labeledStatement) { labeledStatement.accept(this); }
- /** */ void visit(const LambdaExpression lambdaExpression) { lambdaExpression.accept(this); }
- /** */ void visit(const LastCatch lastCatch) { lastCatch.accept(this); }
- /** */ void visit(const LinkageAttribute linkageAttribute) { linkageAttribute.accept(this); }
- /** */ void visit(const MemberFunctionAttribute memberFunctionAttribute) { memberFunctionAttribute.accept(this); }
- /** */ void visit(const MixinDeclaration mixinDeclaration) { mixinDeclaration.accept(this); }
- /** */ void visit(const MixinExpression mixinExpression) { mixinExpression.accept(this); }
- /** */ void visit(const MixinTemplateDeclaration mixinTemplateDeclaration) { mixinTemplateDeclaration.accept(this); }
- /** */ void visit(const MixinTemplateName mixinTemplateName) { mixinTemplateName.accept(this); }
- /** */ void visit(const Module module_) { module_.accept(this); }
- /** */ void visit(const ModuleDeclaration moduleDeclaration) { moduleDeclaration.accept(this); }
- /** */ void visit(const MulExpression mulExpression) { mulExpression.accept(this); }
- /** */ void visit(const NewAnonClassExpression newAnonClassExpression) { newAnonClassExpression.accept(this); }
- /** */ void visit(const NewExpression newExpression) { newExpression.accept(this); }
- /** */ void visit(const NonVoidInitializer nonVoidInitializer) { nonVoidInitializer.accept(this); }
- /** */ void visit(const Operand operand) { operand.accept(this); }
- /** */ void visit(const Operands operands) { operands.accept(this); }
- /** */ void visit(const OrExpression orExpression) { orExpression.accept(this); }
- /** */ void visit(const OrOrExpression orOrExpression) { orOrExpression.accept(this); }
- /** */ void visit(const OutStatement outStatement) { outStatement.accept(this); }
- /** */ void visit(const Parameter parameter) { parameter.accept(this); }
- /** */ void visit(const Parameters parameters) { parameters.accept(this); }
- /** */ void visit(const Postblit postblit) { postblit.accept(this); }
- /** */ void visit(const PostIncDecExpression postIncDecExpression) { postIncDecExpression.accept(this); }
- /** */ void visit(const PowExpression powExpression) { powExpression.accept(this); }
- /** */ void visit(const PragmaDeclaration pragmaDeclaration) { pragmaDeclaration.accept(this); }
- /** */ void visit(const PragmaExpression pragmaExpression) { pragmaExpression.accept(this); }
- /** */ void visit(const PreIncDecExpression preIncDecExpression) { preIncDecExpression.accept(this); }
- /** */ void visit(const PrimaryExpression primaryExpression) { primaryExpression.accept(this); }
- /** */ void visit(const Register register) { register.accept(this); }
- /** */ void visit(const RelExpression relExpression) { relExpression.accept(this); }
- /** */ void visit(const ReturnStatement returnStatement) { returnStatement.accept(this); }
- /** */ void visit(const ScopeGuardStatement scopeGuardStatement) { scopeGuardStatement.accept(this); }
- /** */ void visit(const SharedStaticConstructor sharedStaticConstructor) { sharedStaticConstructor.accept(this); }
- /** */ void visit(const SharedStaticDestructor sharedStaticDestructor) { sharedStaticDestructor.accept(this); }
- /** */ void visit(const ShiftExpression shiftExpression) { shiftExpression.accept(this); }
- /** */ void visit(const SingleImport singleImport) { singleImport.accept(this); }
- /** */ void visit(const SliceExpression sliceExpression) { sliceExpression.accept(this); }
- /** */ void visit(const Statement statement) { statement.accept(this); }
- /** */ void visit(const StatementNoCaseNoDefault statementNoCaseNoDefault) { statementNoCaseNoDefault.accept(this); }
- /** */ void visit(const StaticAssertDeclaration staticAssertDeclaration) { staticAssertDeclaration.accept(this); }
- /** */ void visit(const StaticAssertStatement staticAssertStatement) { staticAssertStatement.accept(this); }
- /** */ void visit(const StaticConstructor staticConstructor) { staticConstructor.accept(this); }
- /** */ void visit(const StaticDestructor staticDestructor) { staticDestructor.accept(this); }
- /** */ void visit(const StaticIfCondition staticIfCondition) { staticIfCondition.accept(this); }
- /** */ void visit(const StorageClass storageClass) { storageClass.accept(this); }
- /** */ void visit(const StructBody structBody) { structBody.accept(this); }
- /** */ void visit(const StructDeclaration structDeclaration) { structDeclaration.accept(this); }
- /** */ void visit(const StructInitializer structInitializer) { structInitializer.accept(this); }
- /** */ void visit(const StructMemberInitializer structMemberInitializer) { structMemberInitializer.accept(this); }
- /** */ void visit(const StructMemberInitializers structMemberInitializers) { structMemberInitializers.accept(this); }
- /** */ void visit(const SwitchStatement switchStatement) { switchStatement.accept(this); }
- /** */ void visit(const Symbol symbol) { symbol.accept(this); }
- /** */ void visit(const SynchronizedStatement synchronizedStatement) { synchronizedStatement.accept(this); }
- /** */ void visit(const TemplateAliasParameter templateAliasParameter) { templateAliasParameter.accept(this); }
- /** */ void visit(const TemplateArgument templateArgument) { templateArgument.accept(this); }
- /** */ void visit(const TemplateArgumentList templateArgumentList) { templateArgumentList.accept(this); }
- /** */ void visit(const TemplateArguments templateArguments) { templateArguments.accept(this); }
- /** */ void visit(const TemplateDeclaration templateDeclaration) { templateDeclaration.accept(this); }
- /** */ void visit(const TemplateInstance templateInstance) { templateInstance.accept(this); }
- /** */ void visit(const TemplateMixinExpression templateMixinExpression) { templateMixinExpression.accept(this); }
- /** */ void visit(const TemplateParameter templateParameter) { templateParameter.accept(this); }
- /** */ void visit(const TemplateParameterList templateParameterList) { templateParameterList.accept(this); }
- /** */ void visit(const TemplateParameters templateParameters) { templateParameters.accept(this); }
- /** */ void visit(const TemplateSingleArgument templateSingleArgument) { templateSingleArgument.accept(this); }
- /** */ void visit(const TemplateThisParameter templateThisParameter) { templateThisParameter.accept(this); }
- /** */ void visit(const TemplateTupleParameter templateTupleParameter) { templateTupleParameter.accept(this); }
- /** */ void visit(const TemplateTypeParameter templateTypeParameter) { templateTypeParameter.accept(this); }
- /** */ void visit(const TemplateValueParameter templateValueParameter) { templateValueParameter.accept(this); }
- /** */ void visit(const TemplateValueParameterDefault templateValueParameterDefault) { templateValueParameterDefault.accept(this); }
- /** */ void visit(const TernaryExpression ternaryExpression) { ternaryExpression.accept(this); }
- /** */ void visit(const ThrowStatement throwStatement) { throwStatement.accept(this); }
- /** */ void visit(const Token token) { }
- /** */ void visit(const TraitsExpression traitsExpression) { traitsExpression.accept(this); }
- /** */ void visit(const TryStatement tryStatement) { tryStatement.accept(this); }
- /** */ void visit(const Type type) { type.accept(this); }
- /** */ void visit(const Type2 type2) { type2.accept(this); }
- /** */ void visit(const TypeSpecialization typeSpecialization) { typeSpecialization.accept(this); }
- /** */ void visit(const TypeSuffix typeSuffix) { typeSuffix.accept(this); }
- /** */ void visit(const TypeidExpression typeidExpression) { typeidExpression.accept(this); }
- /** */ void visit(const TypeofExpression typeofExpression) { typeofExpression.accept(this); }
- /** */ void visit(const UnaryExpression unaryExpression) { unaryExpression.accept(this); }
- /** */ void visit(const UnionDeclaration unionDeclaration) { unionDeclaration.accept(this); }
- /** */ void visit(const Unittest unittest_) { unittest_.accept(this); }
- /** */ void visit(const VariableDeclaration variableDeclaration) { variableDeclaration.accept(this); }
- /** */ void visit(const Vector vector) { vector.accept(this); }
- /** */ void visit(const VersionCondition versionCondition) { versionCondition.accept(this); }
- /** */ void visit(const VersionSpecification versionSpecification) { versionSpecification.accept(this); }
- /** */ void visit(const WhileStatement whileStatement) { whileStatement.accept(this); }
- /** */ void visit(const WithStatement withStatement) { withStatement.accept(this); }
- /** */ void visit(const XorExpression xorExpression) { xorExpression.accept(this); }
-}
-
-interface ASTNode
-{
-public:
- /** */ void accept(ASTVisitor visitor) const;
-}
-
-immutable string DEFAULT_ACCEPT = q{override void accept(ASTVisitor visitor) const {}};
-
-template visitIfNotNull(fields ...)
-{
- static if (fields.length > 1)
- immutable visitIfNotNull = visitIfNotNull!(fields[0]) ~ visitIfNotNull!(fields[1..$]);
- else
- {
- static if (typeof(fields[0]).stringof[$ - 2 .. $] == "[]")
- {
- static if (__traits(hasMember, typeof(fields[0][0]), "classinfo"))
- immutable visitIfNotNull = "foreach (i; " ~ fields[0].stringof ~ ") if (i !is null) visitor.visit(i);\n";
- else
- immutable visitIfNotNull = "foreach (i; " ~ fields[0].stringof ~ ") visitor.visit(i);\n";
- }
- else static if (__traits(hasMember, typeof(fields[0]), "classinfo"))
- immutable visitIfNotNull = "if (" ~ fields[0].stringof ~ " !is null) visitor.visit(" ~ fields[0].stringof ~ ");\n";
- else
- immutable visitIfNotNull = "visitor.visit(" ~ fields[0].stringof ~ ");\n";
- }
-}
-
-mixin template OpEquals(bool print = false)
-{
- override bool opEquals(Object other) const
- {
- static if (print)
- pragma(msg, generateOpEquals!(typeof(this)));
- 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;" ~ opEqualsPart!(p[1 .. $]);
- }
- 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);
- }
-}
-
-mixin template BinaryExpressionBody()
-{
- ExpressionNode left;
- ExpressionNode right;
- size_t line;
- size_t column;
-}
-
-///
-final class AddExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin OpEquals;
- /** */ IdType operator;
- mixin BinaryExpressionBody;
-}
-
-///
-final class AliasDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(storageClasses, type, name, initializers));
- }
- mixin OpEquals;
- /** */ StorageClass[] storageClasses;
- /** */ Type type;
- /** */ Token name;
- /** */ AliasInitializer[] initializers;
- /** */ string comment;
-}
-
-///
-final class AliasInitializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(name, templateParameters, storageClasses, type));
- }
- mixin OpEquals;
- /** */ Token name;
- /** */ StorageClass[] storageClasses;
- /** */ TemplateParameters templateParameters;
- /** */ Type type;
-}
-
-///
-final class AliasThisDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier));
- }
- mixin OpEquals;
- /** */ Token identifier;
-}
-
-///
-final class AlignAttribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(intLiteral));
- }
- mixin OpEquals;
- /** */ Token intLiteral;
-}
-
-///
-final class AndAndExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin OpEquals;
- mixin BinaryExpressionBody;
-}
-
-///
-final class AndExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin OpEquals;
- mixin BinaryExpressionBody;
-}
-
-///
-final class ArgumentList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- mixin OpEquals;
- /** */ AssignExpression[] items;
- /** */ size_t startLocation;
- /** */ size_t endLocation;
-}
-
-///
-final class Arguments : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(argumentList));
- }
- mixin OpEquals;
- /** */ ArgumentList argumentList;
-}
-
-///
-final class ArrayInitializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(arrayMemberInitializations));
- }
- mixin OpEquals;
- /** */ ArrayMemberInitialization[] arrayMemberInitializations;
-}
-
-///
-final class ArrayLiteral : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(argumentList));
- }
- mixin OpEquals;
- /** */ ArgumentList argumentList;
-}
-
-///
-final class ArrayMemberInitialization : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression, nonVoidInitializer));
- }
- mixin OpEquals;
- /** */ AssignExpression assignExpression;
- /** */ NonVoidInitializer nonVoidInitializer;
-}
-
-///
-final class AsmAddExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin OpEquals;
- /** */ IdType operator;
- mixin BinaryExpressionBody;
-}
-
-///
-final class AsmAndExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin OpEquals;
- mixin BinaryExpressionBody;
-}
-
-///
-final class AsmBrExp : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin OpEquals;
- /** */ AsmBrExp asmBrExp;
- /** */ AsmEqualExp asmEqualExp;
- /** */ AsmUnaExp asmUnaExp;
-}
-
-///
-final class AsmEqualExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- mixin OpEquals;
- /** */ Token operator;
-}
-
-///
-final class AsmExp : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin OpEquals;
- /** */ AsmLogOrExp left;
- /** */ AsmExp middle;
- /** */ AsmExp right;
-}
-
-///
-final class AsmInstruction : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin OpEquals;
- /** */ Token identifierOrIntegerOrOpcode;
- /** */ bool hasAlign;
- /** */ AsmExp asmExp;
- /** */ Operands operands;
-}
-
-///
-final class AsmLogAndExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class AsmLogOrExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class AsmMulExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ IdType operator;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-
-}
-
-///
-final class AsmOrExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class AsmPrimaryExp : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ IdentifierChain identifierChain;
- /** */ Register register;
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class AsmRelExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- /** */ Token operator;
- mixin OpEquals;
-}
-
-///
-final class AsmShiftExp : ExpressionNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- /** */ Token operator;
- mixin OpEquals;
-}
-
-///
-final class AsmStatement : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ AsmInstruction[] asmInstructions;
- mixin OpEquals;
-}
-
-///
-final class AsmTypePrefix : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ Token left;
- /** */ Token right;
- mixin OpEquals;
-}
-
-///
-final class AsmUnaExp : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ AsmTypePrefix asmTypePrefix;
- /** */ AsmExp asmExp;
- /** */ Token prefix;
- /** */ AsmPrimaryExp asmPrimaryExp;
- /** */ AsmUnaExp asmUnaExp;
- mixin OpEquals;
-}
-
-///
-final class AsmXorExp : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class AssertExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assertion, message));
- }
- /** */ AssignExpression assertion;
- /** */ AssignExpression message;
- mixin OpEquals;
-}
-
-///
-final class AssignExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(ternaryExpression, assignExpression));
- }
- /** */ ExpressionNode ternaryExpression;
- /** */ ExpressionNode assignExpression;
- /** */ IdType operator;
- size_t line;
- size_t column;
- mixin OpEquals;
-}
-
-///
-final class AssocArrayLiteral : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(keyValuePairs));
- }
- /** */ KeyValuePairs keyValuePairs;
- mixin OpEquals;
-}
-
-///
-final class AtAttribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionCallExpression, argumentList));
- }
- /** */ FunctionCallExpression functionCallExpression;
- /** */ ArgumentList argumentList;
- /** */ Token identifier;
- /** */ size_t startLocation;
- /** */ size_t endLocation;
- mixin OpEquals;
-}
-
-///
-final class Attribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(pragmaExpression, storageClass));
- }
- /** */ PragmaExpression pragmaExpression;
- /** */ StorageClass storageClass;
- /** */ IdType attribute;
- mixin OpEquals;
-}
-
-///
-final class AttributeDeclaration : ASTNode
-{
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(attribute));
- }
- /** */ Attribute attribute;
- mixin OpEquals;
-}
-
-///
-final class AutoDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- foreach (i; 0 .. initializers.length)
- {
- visitor.visit(initializers[i]);
- }
- }
- /** */ Token[] identifiers;
- /** */ Initializer[] initializers;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class BlockStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarationsAndStatements));
- }
-
- /**
- * Byte position of the opening brace
- */
- size_t startLocation;
-
- /**
- * Byte position of the closing brace
- */
- size_t endLocation;
-
- /** */ DeclarationsAndStatements declarationsAndStatements;
- mixin OpEquals;
-}
-
-///
-final class BodyStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(blockStatement));
- }
- /** */ BlockStatement blockStatement;
- mixin OpEquals;
-}
-
-///
-final class BreakStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(label));
- }
- /** */ Token label;
- mixin OpEquals;
-}
-
-///
-final class BaseClass : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifierOrTemplateChain, typeofExpression));
- }
- /** */ IdentifierOrTemplateChain identifierOrTemplateChain;
- /** */ TypeofExpression typeofExpression;
- mixin OpEquals;
-}
-
-///
-final class BaseClassList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- /** */ BaseClass[] items;
- mixin OpEquals;
-}
-
-///
-final class CaseRangeStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(low, high, declarationsAndStatements));
- }
- /** */ AssignExpression low;
- /** */ AssignExpression high;
- /** */ DeclarationsAndStatements declarationsAndStatements;
- mixin OpEquals;
-}
-
-///
-final class CaseStatement: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(argumentList, declarationsAndStatements));
- }
- /** */ ArgumentList argumentList;
- /** */ DeclarationsAndStatements declarationsAndStatements;
- mixin OpEquals;
-}
-
-///
-final class CastExpression: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, castQualifier, unaryExpression));
- }
- /** */ Type type;
- /** */ CastQualifier castQualifier;
- /** */ UnaryExpression unaryExpression;
- mixin OpEquals;
-}
-
-///
-final class CastQualifier: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(first, second));
- }
- /** */ Token first;
- /** */ Token second;
- mixin OpEquals;
-}
-
-///
-final class Catches: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(catches, lastCatch));
- }
- /** */ Catch[] catches;
- /** */ LastCatch lastCatch;
- mixin OpEquals;
-}
-
-///
-final class Catch: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, identifier, declarationOrStatement));
- }
- /** */ Type type;
- /** */ Token identifier;
- /** */ DeclarationOrStatement declarationOrStatement;
- mixin OpEquals;
-}
-
-///
-final class ClassDeclaration: ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateParameters, constraint, baseClassList,
- structBody));
- }
-
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Constraint constraint;
- /** */ BaseClassList baseClassList;
- /** */ StructBody structBody;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class CmpExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(shiftExpression, equalExpression,
- identityExpression, relExpression, inExpression));
- }
- /** */ ExpressionNode shiftExpression;
- /** */ ExpressionNode equalExpression;
- /** */ ExpressionNode identityExpression;
- /** */ ExpressionNode relExpression;
- /** */ ExpressionNode inExpression;
- mixin OpEquals;
-}
-
-///
-final class CompileCondition : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(versionCondition, debugCondition, staticIfCondition));
- }
- /** */ VersionCondition versionCondition;
- /** */ DebugCondition debugCondition;
- /** */ StaticIfCondition staticIfCondition;
- mixin OpEquals;
-}
-
-///
-final class ConditionalDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(compileCondition, trueDeclarations, falseDeclaration));
- }
- /** */ CompileCondition compileCondition;
- /** */ Declaration[] trueDeclarations;
- /** */ Declaration falseDeclaration;
- mixin OpEquals;
-}
-
-///
-final class ConditionalStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(compileCondition, trueStatement, falseStatement));
- }
- /** */ CompileCondition compileCondition;
- /** */ DeclarationOrStatement trueStatement;
- /** */ DeclarationOrStatement falseStatement;
- mixin OpEquals;
-}
-
-///
-final class Constraint : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression));
- }
- /** */ Expression expression;
- mixin OpEquals;
-}
-
-///
-final class Constructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(parameters, templateParameters, constraint,
- memberFunctionAttributes, functionBody));
- }
- /** */ Parameters parameters;
- /** */ FunctionBody functionBody;
- /** */ Constraint constraint;
- /** */ MemberFunctionAttribute[] memberFunctionAttributes;
- /** */ TemplateParameters templateParameters;
- /** */ size_t location;
- /** */ size_t line;
- /** */ size_t column;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class ContinueStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(label));
- }
- /** */ Token label;
- mixin OpEquals;
-}
-
-///
-final class DebugCondition : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifierOrInteger));
- }
- /** */ Token identifierOrInteger;
- mixin OpEquals;
-}
-
-///
-final class DebugSpecification : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifierOrInteger));
- }
- /** */ Token identifierOrInteger;
- mixin OpEquals;
-}
-
-///
-final class Declaration : ASTNode
-{
-public:
-
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(attributes, attributeDeclaration,
- importDeclaration, functionDeclaration,
- variableDeclaration, aliasThisDeclaration, structDeclaration,
- classDeclaration, interfaceDeclaration, unionDeclaration,
- enumDeclaration, aliasDeclaration, mixinDeclaration,
- mixinTemplateDeclaration, unittest_, staticAssertDeclaration,
- templateDeclaration, constructor,
- destructor, staticConstructor, staticDestructor,
- sharedStaticDestructor, sharedStaticConstructor,
- conditionalDeclaration, pragmaDeclaration, versionSpecification,
- invariant_, postblit, declarations));
- }
-
- /** */ Attribute[] attributes;
- /** */ AttributeDeclaration attributeDeclaration;
- /** */ ImportDeclaration importDeclaration;
- /** */ FunctionDeclaration functionDeclaration;
- /** */ VariableDeclaration variableDeclaration;
- /** */ AliasThisDeclaration aliasThisDeclaration;
- /** */ StructDeclaration structDeclaration;
- /** */ ClassDeclaration classDeclaration;
- /** */ InterfaceDeclaration interfaceDeclaration;
- /** */ UnionDeclaration unionDeclaration;
- /** */ EnumDeclaration enumDeclaration;
- /** */ AliasDeclaration aliasDeclaration;
- /** */ MixinDeclaration mixinDeclaration;
- /** */ MixinTemplateDeclaration mixinTemplateDeclaration;
- /** */ Unittest unittest_;
- /** */ StaticAssertDeclaration staticAssertDeclaration;
- /** */ TemplateDeclaration templateDeclaration;
- /** */ Constructor constructor;
- /** */ Destructor destructor;
- /** */ StaticConstructor staticConstructor;
- /** */ StaticDestructor staticDestructor;
- /** */ SharedStaticDestructor sharedStaticDestructor;
- /** */ SharedStaticConstructor sharedStaticConstructor;
- /** */ ConditionalDeclaration conditionalDeclaration;
- /** */ PragmaDeclaration pragmaDeclaration;
- /** */ VersionSpecification versionSpecification;
- /** */ Invariant invariant_;
- /** */ Postblit postblit;
- /** */ Declaration[] declarations;
- mixin OpEquals;
-}
-
-///
-final class DeclarationsAndStatements : ASTNode
-{
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarationsAndStatements));
- }
-
- /** */ DeclarationOrStatement[] declarationsAndStatements;
- mixin OpEquals;
-}
-
-///
-final class DeclarationOrStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declaration, statement));
- }
-
- /** */ Declaration declaration;
- /** */ Statement statement;
- mixin OpEquals;
-}
-
-///
-final class Declarator : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(initializer));
- }
- /** */ Token name;
- /** */ Initializer initializer;
- /** */ TypeSuffix[] cstyle;
-
- mixin OpEquals;
-}
-
-///
-final class DefaultStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarationsAndStatements));
- }
- /** */ DeclarationsAndStatements declarationsAndStatements;
- mixin OpEquals;
-}
-
-///
-final class DeleteExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(unaryExpression));
- }
- /** */ UnaryExpression unaryExpression;
- /** */ size_t line;
- /** */ size_t column;
- mixin OpEquals;
-}
-
-///
-final class DeleteStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(deleteExpression));
- }
- /** */ DeleteExpression deleteExpression;
- mixin OpEquals;
-}
-
-///
-final class Deprecated : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression));
- }
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class Destructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(memberFunctionAttributes, functionBody));
- }
- /** */ MemberFunctionAttribute[] memberFunctionAttributes;
- /** */ FunctionBody functionBody;
- /** */ size_t line;
- /** */ size_t column;
- /** */ size_t index;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class DoStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, statementNoCaseNoDefault));
- }
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- /** */ Expression expression;
- mixin OpEquals;
-}
-
-///
-final class EnumBody : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(enumMembers));
- }
- /** */ EnumMember[] enumMembers;
-
- /**
- * Byte position of the opening brace
- */
- size_t startLocation;
-
- /**
- * Byte position of the closing brace
- */
- size_t endLocation;
- mixin OpEquals;
-}
-
-///
-final class EnumDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, enumBody));
- }
- /** */ Token name;
- /** */ Type type;
- /** */ EnumBody enumBody;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class EnumMember : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(name, type, assignExpression));
- }
- /** */ Token name;
- /** */ Type type;
- /** */ AssignExpression assignExpression;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class EponymousTemplateDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(name, templateParameters, assignExpression));
- }
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ AssignExpression assignExpression;
- /** */ Type type;
- mixin OpEquals;
-}
-
-///
-final class EqualExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ IdType operator;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class Expression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- /** */ AssignExpression[] items;
- mixin OpEquals;
-}
-
-///
-final class ExpressionStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression));
- }
- /** */ Expression expression;
- mixin OpEquals;
-}
-
-///
-final class FinalSwitchStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(switchStatement));
- }
- /** */ SwitchStatement switchStatement;
- mixin OpEquals;
-}
-
-///
-final class Finally : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarationOrStatement));
- }
- /** */ DeclarationOrStatement declarationOrStatement;
- mixin OpEquals;
-}
-
-///
-final class ForStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(initialization, test, increment,
- declarationOrStatement));
- }
- /** */ DeclarationOrStatement initialization;
- /** */ ExpressionStatement test;
- /** */ Expression increment;
- /** */ DeclarationOrStatement declarationOrStatement;
- /** */ size_t startIndex;
- mixin OpEquals;
-}
-
-///
-final class ForeachStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(foreachType, foreachTypeList, low, high,
- declarationOrStatement));
- }
- /** */ IdType type;
- /** */ ForeachTypeList foreachTypeList;
- /** */ ForeachType foreachType;
- /** */ Expression low;
- /** */ Expression high;
- /** */ DeclarationOrStatement declarationOrStatement;
- /** */ size_t startIndex;
- mixin OpEquals;
-}
-
-///
-final class ForeachType : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, identifier));
- }
- /** */ IdType[] typeConstructors;
- /** */ Type type;
- /** */ Token identifier;
- mixin OpEquals;
-}
-
-///
-final class ForeachTypeList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- /** */ ForeachType[] items;
- mixin OpEquals;
-}
-
-///
-final class FunctionAttribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token, atAttribute));
- }
- /** */ Token token;
- /** */ AtAttribute atAttribute;
- mixin OpEquals;
-}
-
-///
-final class FunctionBody : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(inStatement, outStatement, bodyStatement,
- blockStatement));
- }
-
- /** */ BlockStatement blockStatement;
- /** */ BodyStatement bodyStatement;
- /** */ OutStatement outStatement;
- /** */ InStatement inStatement;
- mixin OpEquals;
-}
-
-///
-final class FunctionCallExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, unaryExpression, templateArguments, arguments));
- }
- /** */ Type type;
- /** */ UnaryExpression unaryExpression;
- /** */ TemplateArguments templateArguments;
- /** */ Arguments arguments;
- mixin OpEquals;
-}
-
-///
-final class FunctionCallStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionCallExpression));
- }
- /** */ FunctionCallExpression functionCallExpression;
- mixin OpEquals;
-}
-
-///
-final class FunctionDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(returnType, parameters, templateParameters,
- constraint, memberFunctionAttributes, functionBody));
- }
- /** */ bool hasAuto;
- /** */ bool hasRef;
- /** */ Type returnType;
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Parameters parameters;
- /** */ Constraint constraint;
- /** */ FunctionBody functionBody;
- /** */ MemberFunctionAttribute[] memberFunctionAttributes;
- /** */ string comment;
- /** */ Attribute[] attributes;
- mixin OpEquals;
-}
-
-///
-final class FunctionLiteralExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, parameters, functionAttributes,
- functionBody));
- }
- /** */ IdType functionOrDelegate;
- /** */ Type type;
- /** */ Parameters parameters;
- /** */ FunctionAttribute[] functionAttributes;
- /** */ FunctionBody functionBody;
- mixin OpEquals;
-}
-
-///
-final class GotoStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(label, expression));
- }
- /** */ Expression expression;
- /** */ Token label;
- mixin OpEquals;
-}
-
-///
-final class IdentifierChain : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifiers));
- }
- /** */ Token[] identifiers;
- mixin OpEquals;
-}
-
-///
-final class IdentifierList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifiers));
- }
- /** */ Token[] identifiers;
- mixin OpEquals;
-}
-
-///
-final class IdentifierOrTemplateChain : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifiersOrTemplateInstances));
- }
-
- /** */ IdentifierOrTemplateInstance[] identifiersOrTemplateInstances;
- mixin OpEquals;
-}
-
-///
-final class IdentifierOrTemplateInstance : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, templateInstance));
- }
-
- /** */ Token identifier;
- /** */ TemplateInstance templateInstance;
- mixin OpEquals;
-}
-
-///
-final class IdentityExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ bool negated;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class IfStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, type, expression, thenStatement,
- elseStatement));
- }
- /** */ Token identifier;
- /** */ Type type;
- /** */ Expression expression;
- /** */ DeclarationOrStatement thenStatement;
- /** */ DeclarationOrStatement elseStatement;
- /** */ size_t startIndex;
- /** */ size_t line;
- /** */ size_t column;
- mixin OpEquals;
-}
-
-///
-final class ImportBind : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ Token left;
- /** */ Token right;
- mixin OpEquals;
-}
-
-///
-final class ImportBindings : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(singleImport, importBinds));
- }
- /** */ SingleImport singleImport;
- /** */ ImportBind[] importBinds;
- mixin OpEquals;
-}
-
-///
-final class ImportDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(singleImports, importBindings));
- }
- /** */ SingleImport[] singleImports;
- /** */ ImportBindings importBindings;
- mixin OpEquals;
-}
-
-///
-final class ImportExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression));
- }
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class IndexExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(unaryExpression, argumentList));
- }
- /** */ UnaryExpression unaryExpression;
- /** */ ArgumentList argumentList;
- mixin OpEquals;
-}
-
-///
-final class InExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin BinaryExpressionBody;
- bool negated;
- mixin OpEquals;
-}
-
-///
-final class InStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(blockStatement));
- }
- /** */ BlockStatement blockStatement;
- mixin OpEquals;
-}
-
-///
-final class Initialize : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(statementNoCaseNoDefault));
- }
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- mixin OpEquals;
-}
-
-///
-final class Initializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(nonVoidInitializer));
- }
- /** */ NonVoidInitializer nonVoidInitializer;
- mixin OpEquals;
-}
-
-///
-final class InterfaceDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateParameters, constraint, baseClassList,
- structBody));
- }
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Constraint constraint;
- /** */ BaseClassList baseClassList;
- /** */ StructBody structBody;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class Invariant : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(blockStatement));
- }
- /** */ BlockStatement blockStatement;
- /** */ string comment;
- size_t line;
- size_t index;
- mixin OpEquals;
-}
-
-///
-final class IsExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, identifier, typeSpecialization,
- templateParameterList));
- }
- /** */ Type type;
- /** */ Token identifier;
- /** */ TypeSpecialization typeSpecialization;
- /** */ TemplateParameterList templateParameterList;
- /** */ IdType equalsOrColon;
- mixin OpEquals;
-}
-
-///
-final class KeyValuePair : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(key, value));
- }
- /** */ AssignExpression key;
- /** */ AssignExpression value;
- mixin OpEquals;
-}
-
-///
-final class KeyValuePairs : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(keyValuePairs));
- }
- /** */ KeyValuePair[] keyValuePairs;
- mixin OpEquals;
-}
-
-///
-final class LabeledStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, declarationOrStatement));
- }
- Token identifier;
- /** */ DeclarationOrStatement declarationOrStatement;
- mixin OpEquals;
-}
-
-///
-final class LambdaExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, parameters, functionAttributes,
- assignExpression));
- }
- /** */ IdType functionType;
- /** */ Token identifier;
- /** */ Parameters parameters;
- /** */ FunctionAttribute[] functionAttributes;
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class LastCatch : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(statementNoCaseNoDefault));
- }
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- size_t line;
- size_t column;
- mixin OpEquals;
-}
-
-///
-final class LinkageAttribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- version (DIP61) mixin (visitIfNotNull!(identifier, identifierChain));
- else mixin (visitIfNotNull!(identifier));
- }
- /** */ Token identifier;
- /** */ bool hasPlusPlus;
- version (DIP61) /** */ IdentifierChain identifierChain;
- mixin OpEquals;
-}
-
-///
-final class MemberFunctionAttribute : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(atAttribute));
- }
- /** */ IdType tokenType;
- /** */ AtAttribute atAttribute;
- mixin OpEquals;
-}
-
-///
-final class MixinDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(mixinExpression, templateMixinExpression));
- }
- /** */ MixinExpression mixinExpression;
- /** */ TemplateMixinExpression templateMixinExpression;
- mixin OpEquals;
-}
-
-///
-final class MixinExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression));
- }
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class MixinTemplateDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateDeclaration));
- }
- /** */ TemplateDeclaration templateDeclaration;
- mixin OpEquals;
-}
-
-///
-final class MixinTemplateName : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(symbol, typeofExpression, identifierOrTemplateChain));
- }
- /** */ Symbol symbol;
- /** */ IdentifierOrTemplateChain identifierOrTemplateChain;
- /** */ TypeofExpression typeofExpression;
- mixin OpEquals;
-}
-
-///
-final class Module : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(scriptLine, moduleDeclaration, declarations));
- }
- /** */ Token scriptLine;
- /** */ ModuleDeclaration moduleDeclaration;
- /** */ Declaration[] declarations;
- mixin OpEquals;
-}
-
-///
-final class ModuleDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(moduleName));
- }
- /** */ IdentifierChain moduleName;
- /** */ size_t startLocation;
- /** */ size_t endLocation;
- /** */ string comment;
- mixin OpEquals;
-}
-
-
-///
-final class MulExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ IdType operator;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class NewAnonClassExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(allocatorArguments, constructorArguments,
- baseClassList, structBody));
- }
- /** */ Arguments allocatorArguments;
- /** */ Arguments constructorArguments;
- /** */ BaseClassList baseClassList;
- /** */ StructBody structBody;
- mixin OpEquals;
-}
-
-///
-final class NewExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(newAnonClassExpression, type, arguments,
- assignExpression));
- }
- /** */ Type type;
- /** */ NewAnonClassExpression newAnonClassExpression;
- /** */ Arguments arguments;
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-
-///
-final class StatementNoCaseNoDefault : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(labeledStatement, blockStatement, ifStatement,
- whileStatement, doStatement, forStatement, foreachStatement,
- switchStatement, finalSwitchStatement, continueStatement,
- breakStatement, returnStatement, gotoStatement, withStatement,
- synchronizedStatement, tryStatement, throwStatement,
- scopeGuardStatement, asmStatement, conditionalStatement,
- staticAssertStatement, versionSpecification, debugSpecification,
- functionCallStatement, expressionStatement));
- }
- /** */ LabeledStatement labeledStatement;
- /** */ BlockStatement blockStatement;
- /** */ IfStatement ifStatement;
- /** */ WhileStatement whileStatement;
- /** */ DoStatement doStatement;
- /** */ ForStatement forStatement;
- /** */ ForeachStatement foreachStatement;
- /** */ SwitchStatement switchStatement;
- /** */ FinalSwitchStatement finalSwitchStatement;
- /** */ ContinueStatement continueStatement;
- /** */ BreakStatement breakStatement;
- /** */ ReturnStatement returnStatement;
- /** */ GotoStatement gotoStatement;
- /** */ WithStatement withStatement;
- /** */ SynchronizedStatement synchronizedStatement;
- /** */ TryStatement tryStatement;
- /** */ ThrowStatement throwStatement;
- /** */ ScopeGuardStatement scopeGuardStatement;
- /** */ AsmStatement asmStatement;
- /** */ ConditionalStatement conditionalStatement;
- /** */ StaticAssertStatement staticAssertStatement;
- /** */ VersionSpecification versionSpecification;
- /** */ DebugSpecification debugSpecification;
- /** */ FunctionCallStatement functionCallStatement;
- /** */ ExpressionStatement expressionStatement;
- mixin OpEquals;
-}
-
-///
-final class NonVoidInitializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression, arrayInitializer,
- structInitializer, functionBody));
- }
- /** */ AssignExpression assignExpression;
- /** */ ArrayInitializer arrayInitializer;
- /** */ StructInitializer structInitializer;
- /** */ FunctionBody functionBody;
-
- mixin OpEquals;
-}
-
-///
-final class Operand : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ AsmExp asmExp;
- mixin OpEquals;
-}
-
-///
-final class Operands : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ Operand[] operands;
- mixin OpEquals;
-}
-
-///
-final class OrExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class OrOrExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class OutStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(parameter, blockStatement));
- }
- /** */ Token parameter;
- /** */ BlockStatement blockStatement;
- mixin OpEquals;
-}
-
-///
-final class Parameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, name, default_));
- }
-
- /** */ IdType[] parameterAttributes;
- /** */ Type type;
- /** */ Token name;
- /** */ bool vararg;
- /** */ AssignExpression default_;
- /** */ TypeSuffix[] cstyle;
-
- mixin OpEquals;
-}
-
-///
-final class Parameters : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(parameters));
- }
-
- /** */ Parameter[] parameters;
- /** */ bool hasVarargs;
- mixin OpEquals;
-}
-
-///
-final class Postblit : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionBody));
- }
- /** */ FunctionBody functionBody;
- /** */ MemberFunctionAttribute[] memberFunctionAttributes;
- mixin OpEquals;
-}
-
-///
-final class PostIncDecExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(unaryExpression));
- }
- /** */ IdType operator;
- /** */ UnaryExpression unaryExpression;
- mixin OpEquals;
-}
-
-///
-final class PowExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class PragmaDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(pragmaExpression));
- }
- /** */ PragmaExpression pragmaExpression;
- mixin OpEquals;
-}
-
-///
-final class PragmaExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, argumentList));
- }
- /** */ Token identifier;
- /** */ ArgumentList argumentList;
- mixin OpEquals;
-}
-
-///
-final class PreIncDecExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(unaryExpression));
- }
- /** */ IdType operator;
- /** */ UnaryExpression unaryExpression;
- mixin OpEquals;
-}
-
-///
-final class PrimaryExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(basicType, typeConstructor, type, primary,
- typeofExpression, typeidExpression, arrayLiteral, assocArrayLiteral,
- expression, dot, identifierOrTemplateInstance, isExpression,
- lambdaExpression, functionLiteralExpression,
- mixinExpression, importExpression, vector));
- }
- /** */ Token dot;
- /** */ Token primary;
- /** */ IdentifierOrTemplateInstance identifierOrTemplateInstance;
- /** */ Token basicType;
- /** */ TypeofExpression typeofExpression;
- /** */ TypeidExpression typeidExpression;
- /** */ ArrayLiteral arrayLiteral;
- /** */ AssocArrayLiteral assocArrayLiteral;
- /** */ Expression expression;
- /** */ IsExpression isExpression;
- /** */ LambdaExpression lambdaExpression;
- /** */ FunctionLiteralExpression functionLiteralExpression;
- /** */ TraitsExpression traitsExpression;
- /** */ MixinExpression mixinExpression;
- /** */ ImportExpression importExpression;
- /** */ Vector vector;
- /** */ Type type;
- /** */ Token typeConstructor;
- /** */ Arguments arguments;
- mixin OpEquals;
-}
-
-///
-final class Register : ASTNode
-{
-public:
- mixin (DEFAULT_ACCEPT);
- /** */ Token identifier;
- /** */ Token intLiteral;
- /** */ bool hasIntegerLiteral;
- mixin OpEquals;
-}
-
-///
-final class RelExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ IdType operator;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class ReturnStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression));
- }
- /** */ Expression expression;
- /** */ size_t startLocation;
- /** */ size_t endLocation;
- mixin OpEquals;
-}
-
-///
-final class ScopeGuardStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, statementNoCaseNoDefault));
- }
- /** */ Token identifier;
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- mixin OpEquals;
-}
-
-///
-final class SharedStaticConstructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionBody));
- }
- /** */ FunctionBody functionBody;
- /** */ size_t location;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class SharedStaticDestructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionBody));
- }
- /** */ FunctionBody functionBody;
- /** */ size_t location;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class ShiftExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- /** */ IdType operator;
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
-
-///
-final class SingleImport : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(rename, identifierChain));
- }
- /** */ Token rename;
- /** */ IdentifierChain identifierChain;
- mixin OpEquals;
-}
-
-///
-final class SliceExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(unaryExpression, lower, upper));
- }
- /** */ UnaryExpression unaryExpression;
- /** */ AssignExpression lower;
- /** */ AssignExpression upper;
- mixin OpEquals;
-}
-
-///
-final class Statement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(statementNoCaseNoDefault, caseStatement,
- caseRangeStatement, defaultStatement));
- }
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- /** */ CaseStatement caseStatement;
- /** */ CaseRangeStatement caseRangeStatement;
- /** */ DefaultStatement defaultStatement;
- mixin OpEquals;
-}
-
-///
-final class StaticAssertDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(staticAssertStatement));
- }
- /** */ StaticAssertStatement staticAssertStatement;
- mixin OpEquals;
-}
-
-///
-final class StaticAssertStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assertExpression));
- }
- /** */ AssertExpression assertExpression;
- mixin OpEquals;
-}
-
-///
-final class StaticConstructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionBody));
- }
- /** */ FunctionBody functionBody;
- /** */ size_t location;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class StaticDestructor : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(functionBody));
- }
- /** */ FunctionBody functionBody;
- /** */ size_t location;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class StaticIfCondition : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(assignExpression));
- }
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class StorageClass : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token, alignAttribute, linkageAttribute,
- atAttribute, deprecated_));
- }
- /** */ AlignAttribute alignAttribute;
- /** */ LinkageAttribute linkageAttribute;
- /** */ AtAttribute atAttribute;
- /** */ Deprecated deprecated_;
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class StructBody : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarations));
- }
-
- /**
- * Byte position of the opening brace
- */
- size_t startLocation;
-
- /**
- * Byte position of the closing brace
- */
- size_t endLocation;
- /** */ Declaration[] declarations;
- mixin OpEquals;
-}
-
-///
-final class StructDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateParameters, constraint, structBody));
- }
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Constraint constraint;
- /** */ StructBody structBody;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class StructInitializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(structMemberInitializers));
- }
- /** */ StructMemberInitializers structMemberInitializers;
-
- mixin OpEquals;
-}
-
-///
-final class StructMemberInitializer : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, nonVoidInitializer));
- }
- /** */ Token identifier;
- /** */ NonVoidInitializer nonVoidInitializer;
- mixin OpEquals;
-}
-
-///
-final class StructMemberInitializers : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(structMemberInitializers));
- }
- /** */ StructMemberInitializer[] structMemberInitializers;
- mixin OpEquals;
-}
-
-///
-final class SwitchStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, statement));
- }
- /** */ Expression expression;
- /** */ Statement statement;
- mixin OpEquals;
-}
-
-///
-final class Symbol : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifierOrTemplateChain));
- }
-
- /** */ IdentifierOrTemplateChain identifierOrTemplateChain;
- /** */ bool dot;
- mixin OpEquals;
-}
-
-///
-final class SynchronizedStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, statementNoCaseNoDefault));
- }
- /** */ Expression expression;
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- mixin OpEquals;
-}
-
-///
-final class TemplateAliasParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, identifier, colonType, colonExpression,
- assignType, assignExpression));
- }
- /** */ Type type;
- /** */ Token identifier;
- /** */ Type colonType;
- /** */ AssignExpression colonExpression;
- /** */ Type assignType;
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class TemplateArgument : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, assignExpression));
- }
- /** */ Type type;
- /** */ AssignExpression assignExpression;
- mixin OpEquals;
-}
-
-///
-final class TemplateArgumentList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- /** */ TemplateArgument[] items;
- mixin OpEquals;
-}
-
-///
-final class TemplateArguments : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateArgumentList, templateSingleArgument));
- }
- /** */ TemplateArgumentList templateArgumentList;
- /** */ TemplateSingleArgument templateSingleArgument;
- mixin OpEquals;
-}
-
-///
-final class TemplateDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(name, templateParameters, constraint,
- declarations, eponymousTemplateDeclaration));
- }
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Constraint constraint;
- /** */ Declaration[] declarations;
- /** */ EponymousTemplateDeclaration eponymousTemplateDeclaration;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class TemplateInstance : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, templateArguments));
- }
- /** */ Token identifier;
- /** */ TemplateArguments templateArguments;
- mixin OpEquals;
-}
-
-///
-final class TemplateMixinExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, templateArguments, mixinTemplateName));
- }
- /** */ Token identifier;
- /** */ TemplateArguments templateArguments;
- /** */ MixinTemplateName mixinTemplateName;
- mixin OpEquals;
-}
-
-///
-final class TemplateParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateTypeParameter, templateValueParameter,
- templateAliasParameter, templateTupleParameter,
- templateThisParameter));
- }
- /** */ TemplateTypeParameter templateTypeParameter;
- /** */ TemplateValueParameter templateValueParameter;
- /** */ TemplateAliasParameter templateAliasParameter;
- /** */ TemplateTupleParameter templateTupleParameter;
- /** */ TemplateThisParameter templateThisParameter;
- mixin OpEquals;
-}
-
-///
-final class TemplateParameterList : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(items));
- }
- /** */ TemplateParameter[] items;
- mixin OpEquals;
-}
-
-///
-final class TemplateParameters : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateParameterList));
- }
- /** */ TemplateParameterList templateParameterList;
- mixin OpEquals;
-}
-
-///
-final class TemplateSingleArgument : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token));
- }
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class TemplateThisParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(templateTypeParameter));
- }
- /** */ TemplateTypeParameter templateTypeParameter;
- mixin OpEquals;
-}
-
-///
-final class TemplateTupleParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier));
- }
- /** */ Token identifier;
- mixin OpEquals;
-}
-
-///
-final class TemplateTypeParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, colonType, assignType));
- }
- /** */ Token identifier;
- /** */ Type colonType;
- /** */ Type assignType;
- mixin OpEquals;
-}
-
-///
-final class TemplateValueParameter : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, identifier, expression,
- templateValueParameterDefault));
- }
- /** */ Type type;
- /** */ Token identifier;
- /** */ Expression expression;
- /** */ TemplateValueParameterDefault templateValueParameterDefault;
- mixin OpEquals;
-}
-
-///
-final class TemplateValueParameterDefault : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token, assignExpression));
- }
- /** */ AssignExpression assignExpression;
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class TernaryExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(orOrExpression, expression, ternaryExpression));
- }
- /** */ ExpressionNode orOrExpression;
- /** */ ExpressionNode expression;
- /** */ ExpressionNode ternaryExpression;
- mixin OpEquals;
-}
-
-///
-final class ThrowStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression));
- }
- /** */ Expression expression;
- mixin OpEquals;
-}
-
-///
-final class TraitsExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(identifier, templateArgumentList));
- }
- /** */ Token identifier;
- /** */ TemplateArgumentList templateArgumentList;
- mixin OpEquals;
-}
-
-///
-final class TryStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(declarationOrStatement, catches, finally_));
- }
- /** */ DeclarationOrStatement declarationOrStatement;
- /** */ Catches catches;
- /** */ Finally finally_;
- mixin OpEquals;
-}
-
-///
-final class Type : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type2, typeSuffixes));
- }
-
- /** */ IdType[] typeConstructors;
- /** */ TypeSuffix[] typeSuffixes;
- /** */ Type2 type2;
- mixin OpEquals;
-}
-
-///
-final class Type2 : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(symbol, typeofExpression,
- identifierOrTemplateChain, type));
- }
-
- /** */ IdType builtinType;
- /** */ Symbol symbol;
- /** */ TypeofExpression typeofExpression;
- /** */ IdentifierOrTemplateChain identifierOrTemplateChain;
- /** */ IdType typeConstructor;
- /** */ Type type;
- mixin OpEquals;
-}
-
-///
-final class TypeSpecialization : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token, type));
- }
- /** */ Token token;
- /** */ Type type;
- mixin OpEquals;
-}
-
-///
-final class TypeSuffix : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, low, high, delegateOrFunction, parameters,
- memberFunctionAttributes));
- }
-
- /** */ Token delegateOrFunction;
- /** */ bool star;
- /** */ bool array;
- /** */ Type type;
- /** */ AssignExpression low;
- /** */ AssignExpression high;
- /** */ Parameters parameters;
- /** */ MemberFunctionAttribute[] memberFunctionAttributes;
- mixin OpEquals;
-}
-
-///
-final class TypeidExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type, expression));
- }
- /** */ Type type;
- /** */ Expression expression;
- mixin OpEquals;
-}
-
-///
-final class TypeofExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, return_));
- }
- /** */ Expression expression;
- /** */ Token return_;
- mixin OpEquals;
-}
-
-///
-final class UnaryExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- // TODO prefix, postfix, unary
- mixin (visitIfNotNull!(primaryExpression, newExpression,
- deleteExpression, castExpression, functionCallExpression, argumentList,
- unaryExpression, type, identifierOrTemplateInstance, assertExpression,
- sliceExpression, indexExpression));
- }
-
- /** */ Type type;
- /** */ PrimaryExpression primaryExpression;
- /** */ Token prefix;
- /** */ Token suffix;
- /** */ UnaryExpression unaryExpression;
- /** */ NewExpression newExpression;
- /** */ DeleteExpression deleteExpression;
- /** */ CastExpression castExpression;
- /** */ FunctionCallExpression functionCallExpression;
- /** */ ArgumentList argumentList;
- /** */ IdentifierOrTemplateInstance identifierOrTemplateInstance;
- /** */ AssertExpression assertExpression;
- /** */ SliceExpression sliceExpression;
- /** */ IndexExpression indexExpression;
- mixin OpEquals;
-}
-
-///
-final class UnionDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(name, templateParameters, constraint, structBody));
- }
-
- /** */ Token name;
- /** */ TemplateParameters templateParameters;
- /** */ Constraint constraint;
- /** */ StructBody structBody;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class Unittest : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(blockStatement));
- }
- /** */ BlockStatement blockStatement;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class VariableDeclaration : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(storageClass, type, declarators, autoDeclaration));
- }
- /** */ Type type;
- /** */ Declarator[] declarators;
- /** */ StorageClass storageClass;
- /** */ AutoDeclaration autoDeclaration;
- /** */ string comment;
- mixin OpEquals;
-}
-
-///
-final class Vector : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(type));
- }
- /** */ Type type;
- mixin OpEquals;
-}
-
-///
-final class VersionCondition : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token));
- }
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class VersionSpecification : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(token));
- }
- /** */ Token token;
- mixin OpEquals;
-}
-
-///
-final class WhileStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, declarationOrStatement));
- }
-
- /** */ Expression expression;
- /** */ DeclarationOrStatement declarationOrStatement;
- /** */ size_t startIndex;
- mixin OpEquals;
-}
-
-///
-final class WithStatement : ASTNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(expression, statementNoCaseNoDefault));
- }
-
- /** */ Expression expression;
- /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
- mixin OpEquals;
-}
-
-///
-final class XorExpression : ExpressionNode
-{
-public:
- override void accept(ASTVisitor visitor) const
- {
- mixin (visitIfNotNull!(left, right));
- }
- mixin BinaryExpressionBody;
- mixin OpEquals;
-}
diff --git a/std/d/entities.d b/std/d/entities.d
deleted file mode 100644
index f9df641..0000000
--- a/std/d/entities.d
+++ /dev/null
@@ -1,2150 +0,0 @@
-// Written in the D programming language
-
-/**
- * Contains listing of named entities for the D lexer.
- *
- * Copyright: Brian Schott 2013
- * License: Boost License 1.0.
- * Authors: Brian Schott
- * Source: $(PHOBOSSRC std/d/_entities.d)
- */
-
-module std.d.entities;
-
-/**
- * Generated from $(LINK http://www.w3.org/TR/html5/entities.json)
- * Standards: $(LINK http://www.w3.org/TR/html5/syntax.html#named-character-references)
- */
-struct HtmlEntity
-{
- string name, value;
-}
-
-immutable HtmlEntity[] characterEntities = [
- HtmlEntity("AElig", "\u00C6"),
- HtmlEntity("AMP", "\u0026"),
- HtmlEntity("Aacute", "\u00C1"),
- HtmlEntity("Abreve", "\u0102"),
- HtmlEntity("Acirc", "\u00C2"),
- HtmlEntity("Acy", "\u0410"),
- HtmlEntity("Afr", x"D835DD04"),
- HtmlEntity("Agrave", "\u00C0"),
- HtmlEntity("Alpha", "\u0391"),
- HtmlEntity("Amacr", "\u0100"),
- HtmlEntity("And", "\u2A53"),
- HtmlEntity("Aogon", "\u0104"),
- HtmlEntity("Aopf", x"D835DD38"),
- HtmlEntity("ApplyFunction", "\u2061"),
- HtmlEntity("Aring", "\u00C5"),
- HtmlEntity("Ascr", x"D835DC9C"),
- HtmlEntity("Assign", "\u2254"),
- HtmlEntity("Atilde", "\u00C3"),
- HtmlEntity("Auml", "\u00C4"),
- HtmlEntity("Backslash", "\u2216"),
- HtmlEntity("Barv", "\u2AE7"),
- HtmlEntity("Barwed", "\u2306"),
- HtmlEntity("Bcy", "\u0411"),
- HtmlEntity("Because", "\u2235"),
- HtmlEntity("Bernoullis", "\u212C"),
- HtmlEntity("Beta", "\u0392"),
- HtmlEntity("Bfr", x"D835DD05"),
- HtmlEntity("Bopf", x"D835DD39"),
- HtmlEntity("Breve", "\u02D8"),
- HtmlEntity("Bscr", "\u212C"),
- HtmlEntity("Bumpeq", "\u224E"),
- HtmlEntity("CHcy", "\u0427"),
- HtmlEntity("COPY", "\u00A9"),
- HtmlEntity("Cacute", "\u0106"),
- HtmlEntity("Cap", "\u22D2"),
- HtmlEntity("CapitalDifferentialD", "\u2145"),
- HtmlEntity("Cayleys", "\u212D"),
- HtmlEntity("Ccaron", "\u010C"),
- HtmlEntity("Ccedil", "\u00C7"),
- HtmlEntity("Ccirc", "\u0108"),
- HtmlEntity("Cconint", "\u2230"),
- HtmlEntity("Cdot", "\u010A"),
- HtmlEntity("Cedilla", "\u00B8"),
- HtmlEntity("CenterDot", "\u00B7"),
- HtmlEntity("Cfr", "\u212D"),
- HtmlEntity("Chi", "\u03A7"),
- HtmlEntity("CircleDot", "\u2299"),
- HtmlEntity("CircleMinus", "\u2296"),
- HtmlEntity("CirclePlus", "\u2295"),
- HtmlEntity("CircleTimes", "\u2297"),
- HtmlEntity("ClockwiseContourIntegral", "\u2232"),
- HtmlEntity("CloseCurlyDoubleQuote", "\u201D"),
- HtmlEntity("CloseCurlyQuote", "\u2019"),
- HtmlEntity("Colon", "\u2237"),
- HtmlEntity("Colone", "\u2A74"),
- HtmlEntity("Congruent", "\u2261"),
- HtmlEntity("Conint", "\u222F"),
- HtmlEntity("ContourIntegral", "\u222E"),
- HtmlEntity("Copf", "\u2102"),
- HtmlEntity("Coproduct", "\u2210"),
- HtmlEntity("CounterClockwiseContourIntegral", "\u2233"),
- HtmlEntity("Cross", "\u2A2F"),
- HtmlEntity("Cscr", x"D835DC9E"),
- HtmlEntity("Cup", "\u22D3"),
- HtmlEntity("CupCap", "\u224D"),
- HtmlEntity("DD", "\u2145"),
- HtmlEntity("DDotrahd", "\u2911"),
- HtmlEntity("DJcy", "\u0402"),
- HtmlEntity("DScy", "\u0405"),
- HtmlEntity("DZcy", "\u040F"),
- HtmlEntity("Dagger", "\u2021"),
- HtmlEntity("Darr", "\u21A1"),
- HtmlEntity("Dashv", "\u2AE4"),
- HtmlEntity("Dcaron", "\u010E"),
- HtmlEntity("Dcy", "\u0414"),
- HtmlEntity("Del", "\u2207"),
- HtmlEntity("Delta", "\u0394"),
- HtmlEntity("Dfr", x"D835DD07"),
- HtmlEntity("DiacriticalAcute", "\u00B4"),
- HtmlEntity("DiacriticalDot", "\u02D9"),
- HtmlEntity("DiacriticalDoubleAcute", "\u02DD"),
- HtmlEntity("DiacriticalGrave", "\u0060"),
- HtmlEntity("DiacriticalTilde", "\u02DC"),
- HtmlEntity("Diamond", "\u22C4"),
- HtmlEntity("DifferentialD", "\u2146"),
- HtmlEntity("Dopf", x"D835DD3B"),
- HtmlEntity("Dot", "\u00A8"),
- HtmlEntity("DotDot", "\u20DC"),
- HtmlEntity("DotEqual", "\u2250"),
- HtmlEntity("DoubleContourIntegral", "\u222F"),
- HtmlEntity("DoubleDot", "\u00A8"),
- HtmlEntity("DoubleDownArrow", "\u21D3"),
- HtmlEntity("DoubleLeftArrow", "\u21D0"),
- HtmlEntity("DoubleLeftRightArrow", "\u21D4"),
- HtmlEntity("DoubleLeftTee", "\u2AE4"),
- HtmlEntity("DoubleLongLeftArrow", "\u27F8"),
- HtmlEntity("DoubleLongLeftRightArrow", "\u27FA"),
- HtmlEntity("DoubleLongRightArrow", "\u27F9"),
- HtmlEntity("DoubleRightArrow", "\u21D2"),
- HtmlEntity("DoubleRightTee", "\u22A8"),
- HtmlEntity("DoubleUpArrow", "\u21D1"),
- HtmlEntity("DoubleUpDownArrow", "\u21D5"),
- HtmlEntity("DoubleVerticalBar", "\u2225"),
- HtmlEntity("DownArrow", "\u2193"),
- HtmlEntity("DownArrowBar", "\u2913"),
- HtmlEntity("DownArrowUpArrow", "\u21F5"),
- HtmlEntity("DownBreve", "\u0311"),
- HtmlEntity("DownLeftRightVector", "\u2950"),
- HtmlEntity("DownLeftTeeVector", "\u295E"),
- HtmlEntity("DownLeftVector", "\u21BD"),
- HtmlEntity("DownLeftVectorBar", "\u2956"),
- HtmlEntity("DownRightTeeVector", "\u295F"),
- HtmlEntity("DownRightVector", "\u21C1"),
- HtmlEntity("DownRightVectorBar", "\u2957"),
- HtmlEntity("DownTee", "\u22A4"),
- HtmlEntity("DownTeeArrow", "\u21A7"),
- HtmlEntity("Downarrow", "\u21D3"),
- HtmlEntity("Dscr", x"D835DC9F"),
- HtmlEntity("Dstrok", "\u0110"),
- HtmlEntity("ENG", "\u014A"),
- HtmlEntity("ETH", "\u00D0"),
- HtmlEntity("Eacute", "\u00C9"),
- HtmlEntity("Ecaron", "\u011A"),
- HtmlEntity("Ecirc", "\u00CA"),
- HtmlEntity("Ecy", "\u042D"),
- HtmlEntity("Edot", "\u0116"),
- HtmlEntity("Efr", x"D835DD08"),
- HtmlEntity("Egrave", "\u00C8"),
- HtmlEntity("Element", "\u2208"),
- HtmlEntity("Emacr", "\u0112"),
- HtmlEntity("EmptySmallSquare", "\u25FB"),
- HtmlEntity("EmptyVerySmallSquare", "\u25AB"),
- HtmlEntity("Eogon", "\u0118"),
- HtmlEntity("Eopf", x"D835DD3C"),
- HtmlEntity("Epsilon", "\u0395"),
- HtmlEntity("Equal", "\u2A75"),
- HtmlEntity("EqualTilde", "\u2242"),
- HtmlEntity("Equilibrium", "\u21CC"),
- HtmlEntity("Escr", "\u2130"),
- HtmlEntity("Esim", "\u2A73"),
- HtmlEntity("Eta", "\u0397"),
- HtmlEntity("Euml", "\u00CB"),
- HtmlEntity("Exists", "\u2203"),
- HtmlEntity("ExponentialE", "\u2147"),
- HtmlEntity("Fcy", "\u0424"),
- HtmlEntity("Ffr", x"D835DD09"),
- HtmlEntity("FilledSmallSquare", "\u25FC"),
- HtmlEntity("FilledVerySmallSquare", "\u25AA"),
- HtmlEntity("Fopf", x"D835DD3D"),
- HtmlEntity("ForAll", "\u2200"),
- HtmlEntity("Fouriertrf", "\u2131"),
- HtmlEntity("Fscr", "\u2131"),
- HtmlEntity("GJcy", "\u0403"),
- HtmlEntity("GT", "\u003E"),
- HtmlEntity("Gamma", "\u0393"),
- HtmlEntity("Gammad", "\u03DC"),
- HtmlEntity("Gbreve", "\u011E"),
- HtmlEntity("Gcedil", "\u0122"),
- HtmlEntity("Gcirc", "\u011C"),
- HtmlEntity("Gcy", "\u0413"),
- HtmlEntity("Gdot", "\u0120"),
- HtmlEntity("Gfr", x"D835DD0A"),
- HtmlEntity("Gg", "\u22D9"),
- HtmlEntity("Gopf", x"D835DD3E"),
- HtmlEntity("GreaterEqual", "\u2265"),
- HtmlEntity("GreaterEqualLess", "\u22DB"),
- HtmlEntity("GreaterFullEqual", "\u2267"),
- HtmlEntity("GreaterGreater", "\u2AA2"),
- HtmlEntity("GreaterLess", "\u2277"),
- HtmlEntity("GreaterSlantEqual", "\u2A7E"),
- HtmlEntity("GreaterTilde", "\u2273"),
- HtmlEntity("Gscr", x"D835DCA2"),
- HtmlEntity("Gt", "\u226B"),
- HtmlEntity("HARDcy", "\u042A"),
- HtmlEntity("Hacek", "\u02C7"),
- HtmlEntity("Hat", "\u005E"),
- HtmlEntity("Hcirc", "\u0124"),
- HtmlEntity("Hfr", "\u210C"),
- HtmlEntity("HilbertSpace", "\u210B"),
- HtmlEntity("Hopf", "\u210D"),
- HtmlEntity("HorizontalLine", "\u2500"),
- HtmlEntity("Hscr", "\u210B"),
- HtmlEntity("Hstrok", "\u0126"),
- HtmlEntity("HumpDownHump", "\u224E"),
- HtmlEntity("HumpEqual", "\u224F"),
- HtmlEntity("IEcy", "\u0415"),
- HtmlEntity("IJlig", "\u0132"),
- HtmlEntity("IOcy", "\u0401"),
- HtmlEntity("Iacute", "\u00CD"),
- HtmlEntity("Icirc", "\u00CE"),
- HtmlEntity("Icy", "\u0418"),
- HtmlEntity("Idot", "\u0130"),
- HtmlEntity("Ifr", "\u2111"),
- HtmlEntity("Igrave", "\u00CC"),
- HtmlEntity("Im", "\u2111"),
- HtmlEntity("Imacr", "\u012A"),
- HtmlEntity("ImaginaryI", "\u2148"),
- HtmlEntity("Implies", "\u21D2"),
- HtmlEntity("Int", "\u222C"),
- HtmlEntity("Integral", "\u222B"),
- HtmlEntity("Intersection", "\u22C2"),
- HtmlEntity("InvisibleComma", "\u2063"),
- HtmlEntity("InvisibleTimes", "\u2062"),
- HtmlEntity("Iogon", "\u012E"),
- HtmlEntity("Iopf", x"D835DD40"),
- HtmlEntity("Iota", "\u0399"),
- HtmlEntity("Iscr", "\u2110"),
- HtmlEntity("Itilde", "\u0128"),
- HtmlEntity("Iukcy", "\u0406"),
- HtmlEntity("Iuml", "\u00CF"),
- HtmlEntity("Jcirc", "\u0134"),
- HtmlEntity("Jcy", "\u0419"),
- HtmlEntity("Jfr", x"D835DD0D"),
- HtmlEntity("Jopf", x"D835DD41"),
- HtmlEntity("Jscr", x"D835DCA5"),
- HtmlEntity("Jsercy", "\u0408"),
- HtmlEntity("Jukcy", "\u0404"),
- HtmlEntity("KHcy", "\u0425"),
- HtmlEntity("KJcy", "\u040C"),
- HtmlEntity("Kappa", "\u039A"),
- HtmlEntity("Kcedil", "\u0136"),
- HtmlEntity("Kcy", "\u041A"),
- HtmlEntity("Kfr", x"D835DD0E"),
- HtmlEntity("Kopf", x"D835DD42"),
- HtmlEntity("Kscr", x"D835DCA6"),
- HtmlEntity("LJcy", "\u0409"),
- HtmlEntity("LT", "\u003C"),
- HtmlEntity("Lacute", "\u0139"),
- HtmlEntity("Lambda", "\u039B"),
- HtmlEntity("Lang", "\u27EA"),
- HtmlEntity("Laplacetrf", "\u2112"),
- HtmlEntity("Larr", "\u219E"),
- HtmlEntity("Lcaron", "\u013D"),
- HtmlEntity("Lcedil", "\u013B"),
- HtmlEntity("Lcy", "\u041B"),
- HtmlEntity("LeftAngleBracket", "\u27E8"),
- HtmlEntity("LeftArrow", "\u2190"),
- HtmlEntity("LeftArrowBar", "\u21E4"),
- HtmlEntity("LeftArrowRightArrow", "\u21C6"),
- HtmlEntity("LeftCeiling", "\u2308"),
- HtmlEntity("LeftDoubleBracket", "\u27E6"),
- HtmlEntity("LeftDownTeeVector", "\u2961"),
- HtmlEntity("LeftDownVector", "\u21C3"),
- HtmlEntity("LeftDownVectorBar", "\u2959"),
- HtmlEntity("LeftFloor", "\u230A"),
- HtmlEntity("LeftRightArrow", "\u2194"),
- HtmlEntity("LeftRightVector", "\u294E"),
- HtmlEntity("LeftTee", "\u22A3"),
- HtmlEntity("LeftTeeArrow", "\u21A4"),
- HtmlEntity("LeftTeeVector", "\u295A"),
- HtmlEntity("LeftTriangle", "\u22B2"),
- HtmlEntity("LeftTriangleBar", "\u29CF"),
- HtmlEntity("LeftTriangleEqual", "\u22B4"),
- HtmlEntity("LeftUpDownVector", "\u2951"),
- HtmlEntity("LeftUpTeeVector", "\u2960"),
- HtmlEntity("LeftUpVector", "\u21BF"),
- HtmlEntity("LeftUpVectorBar", "\u2958"),
- HtmlEntity("LeftVector", "\u21BC"),
- HtmlEntity("LeftVectorBar", "\u2952"),
- HtmlEntity("Leftarrow", "\u21D0"),
- HtmlEntity("Leftrightarrow", "\u21D4"),
- HtmlEntity("LessEqualGreater", "\u22DA"),
- HtmlEntity("LessFullEqual", "\u2266"),
- HtmlEntity("LessGreater", "\u2276"),
- HtmlEntity("LessLess", "\u2AA1"),
- HtmlEntity("LessSlantEqual", "\u2A7D"),
- HtmlEntity("LessTilde", "\u2272"),
- HtmlEntity("Lfr", x"D835DD0F"),
- HtmlEntity("Ll", "\u22D8"),
- HtmlEntity("Lleftarrow", "\u21DA"),
- HtmlEntity("Lmidot", "\u013F"),
- HtmlEntity("LongLeftArrow", "\u27F5"),
- HtmlEntity("LongLeftRightArrow", "\u27F7"),
- HtmlEntity("LongRightArrow", "\u27F6"),
- HtmlEntity("Longleftarrow", "\u27F8"),
- HtmlEntity("Longleftrightarrow", "\u27FA"),
- HtmlEntity("Longrightarrow", "\u27F9"),
- HtmlEntity("Lopf", x"D835DD43"),
- HtmlEntity("LowerLeftArrow", "\u2199"),
- HtmlEntity("LowerRightArrow", "\u2198"),
- HtmlEntity("Lscr", "\u2112"),
- HtmlEntity("Lsh", "\u21B0"),
- HtmlEntity("Lstrok", "\u0141"),
- HtmlEntity("Lt", "\u226A"),
- HtmlEntity("Map", "\u2905"),
- HtmlEntity("Mcy", "\u041C"),
- HtmlEntity("MediumSpace", "\u205F"),
- HtmlEntity("Mellintrf", "\u2133"),
- HtmlEntity("Mfr", x"D835DD10"),
- HtmlEntity("MinusPlus", "\u2213"),
- HtmlEntity("Mopf", x"D835DD44"),
- HtmlEntity("Mscr", "\u2133"),
- HtmlEntity("Mu", "\u039C"),
- HtmlEntity("NJcy", "\u040A"),
- HtmlEntity("Nacute", "\u0143"),
- HtmlEntity("Ncaron", "\u0147"),
- HtmlEntity("Ncedil", "\u0145"),
- HtmlEntity("Ncy", "\u041D"),
- HtmlEntity("NegativeMediumSpace", "\u200B"),
- HtmlEntity("NegativeThickSpace", "\u200B"),
- HtmlEntity("NegativeThinSpace", "\u200B"),
- HtmlEntity("NegativeVeryThinSpace", "\u200B"),
- HtmlEntity("NestedGreaterGreater", "\u226B"),
- HtmlEntity("NestedLessLess", "\u226A"),
- HtmlEntity("NewLine", "\u000A"),
- HtmlEntity("Nfr", x"D835DD11"),
- HtmlEntity("NoBreak", "\u2060"),
- HtmlEntity("NonBreakingSpace", "\u00A0"),
- HtmlEntity("Nopf", "\u2115"),
- HtmlEntity("Not", "\u2AEC"),
- HtmlEntity("NotCongruent", "\u2262"),
- HtmlEntity("NotCupCap", "\u226D"),
- HtmlEntity("NotDoubleVerticalBar", "\u2226"),
- HtmlEntity("NotElement", "\u2209"),
- HtmlEntity("NotEqual", "\u2260"),
- HtmlEntity("NotEqualTilde", x"22420338"),
- HtmlEntity("NotExists", "\u2204"),
- HtmlEntity("NotGreater", "\u226F"),
- HtmlEntity("NotGreaterEqual", "\u2271"),
- HtmlEntity("NotGreaterFullEqual", x"22670338"),
- HtmlEntity("NotGreaterGreater", x"226B0338"),
- HtmlEntity("NotGreaterLess", "\u2279"),
- HtmlEntity("NotGreaterSlantEqual", x"2A7E0338"),
- HtmlEntity("NotGreaterTilde", "\u2275"),
- HtmlEntity("NotHumpDownHump", x"224E0338"),
- HtmlEntity("NotHumpEqual", x"224F0338"),
- HtmlEntity("NotLeftTriangle", "\u22EA"),
- HtmlEntity("NotLeftTriangleBar", x"29CF0338"),
- HtmlEntity("NotLeftTriangleEqual", "\u22EC"),
- HtmlEntity("NotLess", "\u226E"),
- HtmlEntity("NotLessEqual", "\u2270"),
- HtmlEntity("NotLessGreater", "\u2278"),
- HtmlEntity("NotLessLess", x"226A0338"),
- HtmlEntity("NotLessSlantEqual", x"2A7D0338"),
- HtmlEntity("NotLessTilde", "\u2274"),
- HtmlEntity("NotNestedGreaterGreater", x"2AA20338"),
- HtmlEntity("NotNestedLessLess", x"2AA10338"),
- HtmlEntity("NotPrecedes", "\u2280"),
- HtmlEntity("NotPrecedesEqual", x"2AAF0338"),
- HtmlEntity("NotPrecedesSlantEqual", "\u22E0"),
- HtmlEntity("NotReverseElement", "\u220C"),
- HtmlEntity("NotRightTriangle", "\u22EB"),
- HtmlEntity("NotRightTriangleBar", x"29D00338"),
- HtmlEntity("NotRightTriangleEqual", "\u22ED"),
- HtmlEntity("NotSquareSubset", x"228F0338"),
- HtmlEntity("NotSquareSubsetEqual", "\u22E2"),
- HtmlEntity("NotSquareSuperset", x"22900338"),
- HtmlEntity("NotSquareSupersetEqual", "\u22E3"),
- HtmlEntity("NotSubset", x"228220D2"),
- HtmlEntity("NotSubsetEqual", "\u2288"),
- HtmlEntity("NotSucceeds", "\u2281"),
- HtmlEntity("NotSucceedsEqual", x"2AB00338"),
- HtmlEntity("NotSucceedsSlantEqual", "\u22E1"),
- HtmlEntity("NotSucceedsTilde", x"227F0338"),
- HtmlEntity("NotSuperset", x"228320D2"),
- HtmlEntity("NotSupersetEqual", "\u2289"),
- HtmlEntity("NotTilde", "\u2241"),
- HtmlEntity("NotTildeEqual", "\u2244"),
- HtmlEntity("NotTildeFullEqual", "\u2247"),
- HtmlEntity("NotTildeTilde", "\u2249"),
- HtmlEntity("NotVerticalBar", "\u2224"),
- HtmlEntity("Nscr", x"D835DCA9"),
- HtmlEntity("Ntilde", "\u00D1"),
- HtmlEntity("Nu", "\u039D"),
- HtmlEntity("OElig", "\u0152"),
- HtmlEntity("Oacute", "\u00D3"),
- HtmlEntity("Ocirc", "\u00D4"),
- HtmlEntity("Ocy", "\u041E"),
- HtmlEntity("Odblac", "\u0150"),
- HtmlEntity("Ofr", x"D835DD12"),
- HtmlEntity("Ograve", "\u00D2"),
- HtmlEntity("Omacr", "\u014C"),
- HtmlEntity("Omega", "\u03A9"),
- HtmlEntity("Omicron", "\u039F"),
- HtmlEntity("Oopf", x"D835DD46"),
- HtmlEntity("OpenCurlyDoubleQuote", "\u201C"),
- HtmlEntity("OpenCurlyQuote", "\u2018"),
- HtmlEntity("Or", "\u2A54"),
- HtmlEntity("Oscr", x"D835DCAA"),
- HtmlEntity("Oslash", "\u00D8"),
- HtmlEntity("Otilde", "\u00D5"),
- HtmlEntity("Otimes", "\u2A37"),
- HtmlEntity("Ouml", "\u00D6"),
- HtmlEntity("OverBar", "\u203E"),
- HtmlEntity("OverBrace", "\u23DE"),
- HtmlEntity("OverBracket", "\u23B4"),
- HtmlEntity("OverParenthesis", "\u23DC"),
- HtmlEntity("PartialD", "\u2202"),
- HtmlEntity("Pcy", "\u041F"),
- HtmlEntity("Pfr", x"D835DD13"),
- HtmlEntity("Phi", "\u03A6"),
- HtmlEntity("Pi", "\u03A0"),
- HtmlEntity("PlusMinus", "\u00B1"),
- HtmlEntity("Poincareplane", "\u210C"),
- HtmlEntity("Popf", "\u2119"),
- HtmlEntity("Pr", "\u2ABB"),
- HtmlEntity("Precedes", "\u227A"),
- HtmlEntity("PrecedesEqual", "\u2AAF"),
- HtmlEntity("PrecedesSlantEqual", "\u227C"),
- HtmlEntity("PrecedesTilde", "\u227E"),
- HtmlEntity("Prime", "\u2033"),
- HtmlEntity("Product", "\u220F"),
- HtmlEntity("Proportion", "\u2237"),
- HtmlEntity("Proportional", "\u221D"),
- HtmlEntity("Pscr", x"D835DCAB"),
- HtmlEntity("Psi", "\u03A8"),
- HtmlEntity("QUOT", "\u0022"),
- HtmlEntity("Qfr", x"D835DD14"),
- HtmlEntity("Qopf", "\u211A"),
- HtmlEntity("Qscr", x"D835DCAC"),
- HtmlEntity("RBarr", "\u2910"),
- HtmlEntity("REG", "\u00AE"),
- HtmlEntity("Racute", "\u0154"),
- HtmlEntity("Rang", "\u27EB"),
- HtmlEntity("Rarr", "\u21A0"),
- HtmlEntity("Rarrtl", "\u2916"),
- HtmlEntity("Rcaron", "\u0158"),
- HtmlEntity("Rcedil", "\u0156"),
- HtmlEntity("Rcy", "\u0420"),
- HtmlEntity("Re", "\u211C"),
- HtmlEntity("ReverseElement", "\u220B"),
- HtmlEntity("ReverseEquilibrium", "\u21CB"),
- HtmlEntity("ReverseUpEquilibrium", "\u296F"),
- HtmlEntity("Rfr", "\u211C"),
- HtmlEntity("Rho", "\u03A1"),
- HtmlEntity("RightAngleBracket", "\u27E9"),
- HtmlEntity("RightArrow", "\u2192"),
- HtmlEntity("RightArrowBar", "\u21E5"),
- HtmlEntity("RightArrowLeftArrow", "\u21C4"),
- HtmlEntity("RightCeiling", "\u2309"),
- HtmlEntity("RightDoubleBracket", "\u27E7"),
- HtmlEntity("RightDownTeeVector", "\u295D"),
- HtmlEntity("RightDownVector", "\u21C2"),
- HtmlEntity("RightDownVectorBar", "\u2955"),
- HtmlEntity("RightFloor", "\u230B"),
- HtmlEntity("RightTee", "\u22A2"),
- HtmlEntity("RightTeeArrow", "\u21A6"),
- HtmlEntity("RightTeeVector", "\u295B"),
- HtmlEntity("RightTriangle", "\u22B3"),
- HtmlEntity("RightTriangleBar", "\u29D0"),
- HtmlEntity("RightTriangleEqual", "\u22B5"),
- HtmlEntity("RightUpDownVector", "\u294F"),
- HtmlEntity("RightUpTeeVector", "\u295C"),
- HtmlEntity("RightUpVector", "\u21BE"),
- HtmlEntity("RightUpVectorBar", "\u2954"),
- HtmlEntity("RightVector", "\u21C0"),
- HtmlEntity("RightVectorBar", "\u2953"),
- HtmlEntity("Rightarrow", "\u21D2"),
- HtmlEntity("Ropf", "\u211D"),
- HtmlEntity("RoundImplies", "\u2970"),
- HtmlEntity("Rrightarrow", "\u21DB"),
- HtmlEntity("Rscr", "\u211B"),
- HtmlEntity("Rsh", "\u21B1"),
- HtmlEntity("RuleDelayed", "\u29F4"),
- HtmlEntity("SHCHcy", "\u0429"),
- HtmlEntity("SHcy", "\u0428"),
- HtmlEntity("SOFTcy", "\u042C"),
- HtmlEntity("Sacute", "\u015A"),
- HtmlEntity("Sc", "\u2ABC"),
- HtmlEntity("Scaron", "\u0160"),
- HtmlEntity("Scedil", "\u015E"),
- HtmlEntity("Scirc", "\u015C"),
- HtmlEntity("Scy", "\u0421"),
- HtmlEntity("Sfr", x"D835DD16"),
- HtmlEntity("ShortDownArrow", "\u2193"),
- HtmlEntity("ShortLeftArrow", "\u2190"),
- HtmlEntity("ShortRightArrow", "\u2192"),
- HtmlEntity("ShortUpArrow", "\u2191"),
- HtmlEntity("Sigma", "\u03A3"),
- HtmlEntity("SmallCircle", "\u2218"),
- HtmlEntity("Sopf", x"D835DD4A"),
- HtmlEntity("Sqrt", "\u221A"),
- HtmlEntity("Square", "\u25A1"),
- HtmlEntity("SquareIntersection", "\u2293"),
- HtmlEntity("SquareSubset", "\u228F"),
- HtmlEntity("SquareSubsetEqual", "\u2291"),
- HtmlEntity("SquareSuperset", "\u2290"),
- HtmlEntity("SquareSupersetEqual", "\u2292"),
- HtmlEntity("SquareUnion", "\u2294"),
- HtmlEntity("Sscr", x"D835DCAE"),
- HtmlEntity("Star", "\u22C6"),
- HtmlEntity("Sub", "\u22D0"),
- HtmlEntity("Subset", "\u22D0"),
- HtmlEntity("SubsetEqual", "\u2286"),
- HtmlEntity("Succeeds", "\u227B"),
- HtmlEntity("SucceedsEqual", "\u2AB0"),
- HtmlEntity("SucceedsSlantEqual", "\u227D"),
- HtmlEntity("SucceedsTilde", "\u227F"),
- HtmlEntity("SuchThat", "\u220B"),
- HtmlEntity("Sum", "\u2211"),
- HtmlEntity("Sup", "\u22D1"),
- HtmlEntity("Superset", "\u2283"),
- HtmlEntity("SupersetEqual", "\u2287"),
- HtmlEntity("Supset", "\u22D1"),
- HtmlEntity("THORN", "\u00DE"),
- HtmlEntity("TRADE", "\u2122"),
- HtmlEntity("TSHcy", "\u040B"),
- HtmlEntity("TScy", "\u0426"),
- HtmlEntity("Tab", "\u0009"),
- HtmlEntity("Tau", "\u03A4"),
- HtmlEntity("Tcaron", "\u0164"),
- HtmlEntity("Tcedil", "\u0162"),
- HtmlEntity("Tcy", "\u0422"),
- HtmlEntity("Tfr", x"D835DD17"),
- HtmlEntity("Therefore", "\u2234"),
- HtmlEntity("Theta", "\u0398"),
- HtmlEntity("ThickSpace", x"205F200A"),
- HtmlEntity("ThinSpace", "\u2009"),
- HtmlEntity("Tilde", "\u223C"),
- HtmlEntity("TildeEqual", "\u2243"),
- HtmlEntity("TildeFullEqual", "\u2245"),
- HtmlEntity("TildeTilde", "\u2248"),
- HtmlEntity("Topf", x"D835DD4B"),
- HtmlEntity("TripleDot", "\u20DB"),
- HtmlEntity("Tscr", x"D835DCAF"),
- HtmlEntity("Tstrok", "\u0166"),
- HtmlEntity("Uacute", "\u00DA"),
- HtmlEntity("Uarr", "\u219F"),
- HtmlEntity("Uarrocir", "\u2949"),
- HtmlEntity("Ubrcy", "\u040E"),
- HtmlEntity("Ubreve", "\u016C"),
- HtmlEntity("Ucirc", "\u00DB"),
- HtmlEntity("Ucy", "\u0423"),
- HtmlEntity("Udblac", "\u0170"),
- HtmlEntity("Ufr", x"D835DD18"),
- HtmlEntity("Ugrave", "\u00D9"),
- HtmlEntity("Umacr", "\u016A"),
- HtmlEntity("UnderBar", "\u005F"),
- HtmlEntity("UnderBrace", "\u23DF"),
- HtmlEntity("UnderBracket", "\u23B5"),
- HtmlEntity("UnderParenthesis", "\u23DD"),
- HtmlEntity("Union", "\u22C3"),
- HtmlEntity("UnionPlus", "\u228E"),
- HtmlEntity("Uogon", "\u0172"),
- HtmlEntity("Uopf", x"D835DD4C"),
- HtmlEntity("UpArrow", "\u2191"),
- HtmlEntity("UpArrowBar", "\u2912"),
- HtmlEntity("UpArrowDownArrow", "\u21C5"),
- HtmlEntity("UpDownArrow", "\u2195"),
- HtmlEntity("UpEquilibrium", "\u296E"),
- HtmlEntity("UpTee", "\u22A5"),
- HtmlEntity("UpTeeArrow", "\u21A5"),
- HtmlEntity("Uparrow", "\u21D1"),
- HtmlEntity("Updownarrow", "\u21D5"),
- HtmlEntity("UpperLeftArrow", "\u2196"),
- HtmlEntity("UpperRightArrow", "\u2197"),
- HtmlEntity("Upsi", "\u03D2"),
- HtmlEntity("Upsilon", "\u03A5"),
- HtmlEntity("Uring", "\u016E"),
- HtmlEntity("Uscr", x"D835DCB0"),
- HtmlEntity("Utilde", "\u0168"),
- HtmlEntity("Uuml", "\u00DC"),
- HtmlEntity("VDash", "\u22AB"),
- HtmlEntity("Vbar", "\u2AEB"),
- HtmlEntity("Vcy", "\u0412"),
- HtmlEntity("Vdash", "\u22A9"),
- HtmlEntity("Vdashl", "\u2AE6"),
- HtmlEntity("Vee", "\u22C1"),
- HtmlEntity("Verbar", "\u2016"),
- HtmlEntity("Vert", "\u2016"),
- HtmlEntity("VerticalBar", "\u2223"),
- HtmlEntity("VerticalLine", "\u007C"),
- HtmlEntity("VerticalSeparator", "\u2758"),
- HtmlEntity("VerticalTilde", "\u2240"),
- HtmlEntity("VeryThinSpace", "\u200A"),
- HtmlEntity("Vfr", x"D835DD19"),
- HtmlEntity("Vopf", x"D835DD4D"),
- HtmlEntity("Vscr", x"D835DCB1"),
- HtmlEntity("Vvdash", "\u22AA"),
- HtmlEntity("Wcirc", "\u0174"),
- HtmlEntity("Wedge", "\u22C0"),
- HtmlEntity("Wfr", x"D835DD1A"),
- HtmlEntity("Wopf", x"D835DD4E"),
- HtmlEntity("Wscr", x"D835DCB2"),
- HtmlEntity("Xfr", x"D835DD1B"),
- HtmlEntity("Xi", "\u039E"),
- HtmlEntity("Xopf", x"D835DD4F"),
- HtmlEntity("Xscr", x"D835DCB3"),
- HtmlEntity("YAcy", "\u042F"),
- HtmlEntity("YIcy", "\u0407"),
- HtmlEntity("YUcy", "\u042E"),
- HtmlEntity("Yacute", "\u00DD"),
- HtmlEntity("Ycirc", "\u0176"),
- HtmlEntity("Ycy", "\u042B"),
- HtmlEntity("Yfr", x"D835DD1C"),
- HtmlEntity("Yopf", x"D835DD50"),
- HtmlEntity("Yscr", x"D835DCB4"),
- HtmlEntity("Yuml", "\u0178"),
- HtmlEntity("ZHcy", "\u0416"),
- HtmlEntity("Zacute", "\u0179"),
- HtmlEntity("Zcaron", "\u017D"),
- HtmlEntity("Zcy", "\u0417"),
- HtmlEntity("Zdot", "\u017B"),
- HtmlEntity("ZeroWidthSpace", "\u200B"),
- HtmlEntity("Zeta", "\u0396"),
- HtmlEntity("Zfr", "\u2128"),
- HtmlEntity("Zopf", "\u2124"),
- HtmlEntity("Zscr", x"D835DCB5"),
- HtmlEntity("aacute", "\u00E1"),
- HtmlEntity("abreve", "\u0103"),
- HtmlEntity("ac", "\u223E"),
- HtmlEntity("acE", x"223E0333"),
- HtmlEntity("acd", "\u223F"),
- HtmlEntity("acirc", "\u00E2"),
- HtmlEntity("acute", "\u00B4"),
- HtmlEntity("acy", "\u0430"),
- HtmlEntity("aelig", "\u00E6"),
- HtmlEntity("af", "\u2061"),
- HtmlEntity("afr", x"D835DD1E"),
- HtmlEntity("agrave", "\u00E0"),
- HtmlEntity("alefsym", "\u2135"),
- HtmlEntity("aleph", "\u2135"),
- HtmlEntity("alpha", "\u03B1"),
- HtmlEntity("amacr", "\u0101"),
- HtmlEntity("amalg", "\u2A3F"),
- HtmlEntity("amp", "\u0026"),
- HtmlEntity("and", "\u2227"),
- HtmlEntity("andand", "\u2A55"),
- HtmlEntity("andd", "\u2A5C"),
- HtmlEntity("andslope", "\u2A58"),
- HtmlEntity("andv", "\u2A5A"),
- HtmlEntity("ang", "\u2220"),
- HtmlEntity("ange", "\u29A4"),
- HtmlEntity("angle", "\u2220"),
- HtmlEntity("angmsd", "\u2221"),
- HtmlEntity("angmsdaa", "\u29A8"),
- HtmlEntity("angmsdab", "\u29A9"),
- HtmlEntity("angmsdac", "\u29AA"),
- HtmlEntity("angmsdad", "\u29AB"),
- HtmlEntity("angmsdae", "\u29AC"),
- HtmlEntity("angmsdaf", "\u29AD"),
- HtmlEntity("angmsdag", "\u29AE"),
- HtmlEntity("angmsdah", "\u29AF"),
- HtmlEntity("angrt", "\u221F"),
- HtmlEntity("angrtvb", "\u22BE"),
- HtmlEntity("angrtvbd", "\u299D"),
- HtmlEntity("angsph", "\u2222"),
- HtmlEntity("angst", "\u00C5"),
- HtmlEntity("angzarr", "\u237C"),
- HtmlEntity("aogon", "\u0105"),
- HtmlEntity("aopf", x"D835DD52"),
- HtmlEntity("ap", "\u2248"),
- HtmlEntity("apE", "\u2A70"),
- HtmlEntity("apacir", "\u2A6F"),
- HtmlEntity("ape", "\u224A"),
- HtmlEntity("apid", "\u224B"),
- HtmlEntity("apos", "\u0027"),
- HtmlEntity("approx", "\u2248"),
- HtmlEntity("approxeq", "\u224A"),
- HtmlEntity("aring", "\u00E5"),
- HtmlEntity("ascr", x"D835DCB6"),
- HtmlEntity("ast", "\u002A"),
- HtmlEntity("asymp", "\u2248"),
- HtmlEntity("asympeq", "\u224D"),
- HtmlEntity("atilde", "\u00E3"),
- HtmlEntity("auml", "\u00E4"),
- HtmlEntity("awconint", "\u2233"),
- HtmlEntity("awint", "\u2A11"),
- HtmlEntity("bNot", "\u2AED"),
- HtmlEntity("backcong", "\u224C"),
- HtmlEntity("backepsilon", "\u03F6"),
- HtmlEntity("backprime", "\u2035"),
- HtmlEntity("backsim", "\u223D"),
- HtmlEntity("backsimeq", "\u22CD"),
- HtmlEntity("barvee", "\u22BD"),
- HtmlEntity("barwed", "\u2305"),
- HtmlEntity("barwedge", "\u2305"),
- HtmlEntity("bbrk", "\u23B5"),
- HtmlEntity("bbrktbrk", "\u23B6"),
- HtmlEntity("bcong", "\u224C"),
- HtmlEntity("bcy", "\u0431"),
- HtmlEntity("bdquo", "\u201E"),
- HtmlEntity("becaus", "\u2235"),
- HtmlEntity("because", "\u2235"),
- HtmlEntity("bemptyv", "\u29B0"),
- HtmlEntity("bepsi", "\u03F6"),
- HtmlEntity("bernou", "\u212C"),
- HtmlEntity("beta", "\u03B2"),
- HtmlEntity("beth", "\u2136"),
- HtmlEntity("between", "\u226C"),
- HtmlEntity("bfr", x"D835DD1F"),
- HtmlEntity("bigcap", "\u22C2"),
- HtmlEntity("bigcirc", "\u25EF"),
- HtmlEntity("bigcup", "\u22C3"),
- HtmlEntity("bigodot", "\u2A00"),
- HtmlEntity("bigoplus", "\u2A01"),
- HtmlEntity("bigotimes", "\u2A02"),
- HtmlEntity("bigsqcup", "\u2A06"),
- HtmlEntity("bigstar", "\u2605"),
- HtmlEntity("bigtriangledown", "\u25BD"),
- HtmlEntity("bigtriangleup", "\u25B3"),
- HtmlEntity("biguplus", "\u2A04"),
- HtmlEntity("bigvee", "\u22C1"),
- HtmlEntity("bigwedge", "\u22C0"),
- HtmlEntity("bkarow", "\u290D"),
- HtmlEntity("blacklozenge", "\u29EB"),
- HtmlEntity("blacksquare", "\u25AA"),
- HtmlEntity("blacktriangle", "\u25B4"),
- HtmlEntity("blacktriangledown", "\u25BE"),
- HtmlEntity("blacktriangleleft", "\u25C2"),
- HtmlEntity("blacktriangleright", "\u25B8"),
- HtmlEntity("blank", "\u2423"),
- HtmlEntity("blk12", "\u2592"),
- HtmlEntity("blk14", "\u2591"),
- HtmlEntity("blk34", "\u2593"),
- HtmlEntity("block", "\u2588"),
- HtmlEntity("bne", x"003D20E5"),
- HtmlEntity("bnequiv", x"226120E5"),
- HtmlEntity("bnot", "\u2310"),
- HtmlEntity("bopf", x"D835DD53"),
- HtmlEntity("bot", "\u22A5"),
- HtmlEntity("bottom", "\u22A5"),
- HtmlEntity("bowtie", "\u22C8"),
- HtmlEntity("boxDL", "\u2557"),
- HtmlEntity("boxDR", "\u2554"),
- HtmlEntity("boxDl", "\u2556"),
- HtmlEntity("boxDr", "\u2553"),
- HtmlEntity("boxH", "\u2550"),
- HtmlEntity("boxHD", "\u2566"),
- HtmlEntity("boxHU", "\u2569"),
- HtmlEntity("boxHd", "\u2564"),
- HtmlEntity("boxHu", "\u2567"),
- HtmlEntity("boxUL", "\u255D"),
- HtmlEntity("boxUR", "\u255A"),
- HtmlEntity("boxUl", "\u255C"),
- HtmlEntity("boxUr", "\u2559"),
- HtmlEntity("boxV", "\u2551"),
- HtmlEntity("boxVH", "\u256C"),
- HtmlEntity("boxVL", "\u2563"),
- HtmlEntity("boxVR", "\u2560"),
- HtmlEntity("boxVh", "\u256B"),
- HtmlEntity("boxVl", "\u2562"),
- HtmlEntity("boxVr", "\u255F"),
- HtmlEntity("boxbox", "\u29C9"),
- HtmlEntity("boxdL", "\u2555"),
- HtmlEntity("boxdR", "\u2552"),
- HtmlEntity("boxdl", "\u2510"),
- HtmlEntity("boxdr", "\u250C"),
- HtmlEntity("boxh", "\u2500"),
- HtmlEntity("boxhD", "\u2565"),
- HtmlEntity("boxhU", "\u2568"),
- HtmlEntity("boxhd", "\u252C"),
- HtmlEntity("boxhu", "\u2534"),
- HtmlEntity("boxminus", "\u229F"),
- HtmlEntity("boxplus", "\u229E"),
- HtmlEntity("boxtimes", "\u22A0"),
- HtmlEntity("boxuL", "\u255B"),
- HtmlEntity("boxuR", "\u2558"),
- HtmlEntity("boxul", "\u2518"),
- HtmlEntity("boxur", "\u2514"),
- HtmlEntity("boxv", "\u2502"),
- HtmlEntity("boxvH", "\u256A"),
- HtmlEntity("boxvL", "\u2561"),
- HtmlEntity("boxvR", "\u255E"),
- HtmlEntity("boxvh", "\u253C"),
- HtmlEntity("boxvl", "\u2524"),
- HtmlEntity("boxvr", "\u251C"),
- HtmlEntity("bprime", "\u2035"),
- HtmlEntity("breve", "\u02D8"),
- HtmlEntity("brvbar", "\u00A6"),
- HtmlEntity("bscr", x"D835DCB7"),
- HtmlEntity("bsemi", "\u204F"),
- HtmlEntity("bsim", "\u223D"),
- HtmlEntity("bsime", "\u22CD"),
- HtmlEntity("bsol", "\u005C"),
- HtmlEntity("bsolb", "\u29C5"),
- HtmlEntity("bsolhsub", "\u27C8"),
- HtmlEntity("bull", "\u2022"),
- HtmlEntity("bullet", "\u2022"),
- HtmlEntity("bump", "\u224E"),
- HtmlEntity("bumpE", "\u2AAE"),
- HtmlEntity("bumpe", "\u224F"),
- HtmlEntity("bumpeq", "\u224F"),
- HtmlEntity("cacute", "\u0107"),
- HtmlEntity("cap", "\u2229"),
- HtmlEntity("capand", "\u2A44"),
- HtmlEntity("capbrcup", "\u2A49"),
- HtmlEntity("capcap", "\u2A4B"),
- HtmlEntity("capcup", "\u2A47"),
- HtmlEntity("capdot", "\u2A40"),
- HtmlEntity("caps", x"2229FE00"),
- HtmlEntity("caret", "\u2041"),
- HtmlEntity("caron", "\u02C7"),
- HtmlEntity("ccaps", "\u2A4D"),
- HtmlEntity("ccaron", "\u010D"),
- HtmlEntity("ccedil", "\u00E7"),
- HtmlEntity("ccirc", "\u0109"),
- HtmlEntity("ccups", "\u2A4C"),
- HtmlEntity("ccupssm", "\u2A50"),
- HtmlEntity("cdot", "\u010B"),
- HtmlEntity("cedil", "\u00B8"),
- HtmlEntity("cemptyv", "\u29B2"),
- HtmlEntity("cent", "\u00A2"),
- HtmlEntity("centerdot", "\u00B7"),
- HtmlEntity("cfr", x"D835DD20"),
- HtmlEntity("chcy", "\u0447"),
- HtmlEntity("check", "\u2713"),
- HtmlEntity("checkmark", "\u2713"),
- HtmlEntity("chi", "\u03C7"),
- HtmlEntity("cir", "\u25CB"),
- HtmlEntity("cirE", "\u29C3"),
- HtmlEntity("circ", "\u02C6"),
- HtmlEntity("circeq", "\u2257"),
- HtmlEntity("circlearrowleft", "\u21BA"),
- HtmlEntity("circlearrowright", "\u21BB"),
- HtmlEntity("circledR", "\u00AE"),
- HtmlEntity("circledS", "\u24C8"),
- HtmlEntity("circledast", "\u229B"),
- HtmlEntity("circledcirc", "\u229A"),
- HtmlEntity("circleddash", "\u229D"),
- HtmlEntity("cire", "\u2257"),
- HtmlEntity("cirfnint", "\u2A10"),
- HtmlEntity("cirmid", "\u2AEF"),
- HtmlEntity("cirscir", "\u29C2"),
- HtmlEntity("clubs", "\u2663"),
- HtmlEntity("clubsuit", "\u2663"),
- HtmlEntity("colon", "\u003A"),
- HtmlEntity("colone", "\u2254"),
- HtmlEntity("coloneq", "\u2254"),
- HtmlEntity("comma", "\u002C"),
- HtmlEntity("commat", "\u0040"),
- HtmlEntity("comp", "\u2201"),
- HtmlEntity("compfn", "\u2218"),
- HtmlEntity("complement", "\u2201"),
- HtmlEntity("complexes", "\u2102"),
- HtmlEntity("cong", "\u2245"),
- HtmlEntity("congdot", "\u2A6D"),
- HtmlEntity("conint", "\u222E"),
- HtmlEntity("copf", x"D835DD54"),
- HtmlEntity("coprod", "\u2210"),
- HtmlEntity("copy", "\u00A9"),
- HtmlEntity("copysr", "\u2117"),
- HtmlEntity("crarr", "\u21B5"),
- HtmlEntity("cross", "\u2717"),
- HtmlEntity("cscr", x"D835DCB8"),
- HtmlEntity("csub", "\u2ACF"),
- HtmlEntity("csube", "\u2AD1"),
- HtmlEntity("csup", "\u2AD0"),
- HtmlEntity("csupe", "\u2AD2"),
- HtmlEntity("ctdot", "\u22EF"),
- HtmlEntity("cudarrl", "\u2938"),
- HtmlEntity("cudarrr", "\u2935"),
- HtmlEntity("cuepr", "\u22DE"),
- HtmlEntity("cuesc", "\u22DF"),
- HtmlEntity("cularr", "\u21B6"),
- HtmlEntity("cularrp", "\u293D"),
- HtmlEntity("cup", "\u222A"),
- HtmlEntity("cupbrcap", "\u2A48"),
- HtmlEntity("cupcap", "\u2A46"),
- HtmlEntity("cupcup", "\u2A4A"),
- HtmlEntity("cupdot", "\u228D"),
- HtmlEntity("cupor", "\u2A45"),
- HtmlEntity("cups", x"222AFE00"),
- HtmlEntity("curarr", "\u21B7"),
- HtmlEntity("curarrm", "\u293C"),
- HtmlEntity("curlyeqprec", "\u22DE"),
- HtmlEntity("curlyeqsucc", "\u22DF"),
- HtmlEntity("curlyvee", "\u22CE"),
- HtmlEntity("curlywedge", "\u22CF"),
- HtmlEntity("curren", "\u00A4"),
- HtmlEntity("curvearrowleft", "\u21B6"),
- HtmlEntity("curvearrowright", "\u21B7"),
- HtmlEntity("cuvee", "\u22CE"),
- HtmlEntity("cuwed", "\u22CF"),
- HtmlEntity("cwconint", "\u2232"),
- HtmlEntity("cwint", "\u2231"),
- HtmlEntity("cylcty", "\u232D"),
- HtmlEntity("dArr", "\u21D3"),
- HtmlEntity("dHar", "\u2965"),
- HtmlEntity("dagger", "\u2020"),
- HtmlEntity("daleth", "\u2138"),
- HtmlEntity("darr", "\u2193"),
- HtmlEntity("dash", "\u2010"),
- HtmlEntity("dashv", "\u22A3"),
- HtmlEntity("dbkarow", "\u290F"),
- HtmlEntity("dblac", "\u02DD"),
- HtmlEntity("dcaron", "\u010F"),
- HtmlEntity("dcy", "\u0434"),
- HtmlEntity("dd", "\u2146"),
- HtmlEntity("ddagger", "\u2021"),
- HtmlEntity("ddarr", "\u21CA"),
- HtmlEntity("ddotseq", "\u2A77"),
- HtmlEntity("deg", "\u00B0"),
- HtmlEntity("delta", "\u03B4"),
- HtmlEntity("demptyv", "\u29B1"),
- HtmlEntity("dfisht", "\u297F"),
- HtmlEntity("dfr", x"D835DD21"),
- HtmlEntity("dharl", "\u21C3"),
- HtmlEntity("dharr", "\u21C2"),
- HtmlEntity("diam", "\u22C4"),
- HtmlEntity("diamond", "\u22C4"),
- HtmlEntity("diamondsuit", "\u2666"),
- HtmlEntity("diams", "\u2666"),
- HtmlEntity("die", "\u00A8"),
- HtmlEntity("digamma", "\u03DD"),
- HtmlEntity("disin", "\u22F2"),
- HtmlEntity("div", "\u00F7"),
- HtmlEntity("divide", "\u00F7"),
- HtmlEntity("divideontimes", "\u22C7"),
- HtmlEntity("divonx", "\u22C7"),
- HtmlEntity("djcy", "\u0452"),
- HtmlEntity("dlcorn", "\u231E"),
- HtmlEntity("dlcrop", "\u230D"),
- HtmlEntity("dollar", "\u0024"),
- HtmlEntity("dopf", x"D835DD55"),
- HtmlEntity("dot", "\u02D9"),
- HtmlEntity("doteq", "\u2250"),
- HtmlEntity("doteqdot", "\u2251"),
- HtmlEntity("dotminus", "\u2238"),
- HtmlEntity("dotplus", "\u2214"),
- HtmlEntity("dotsquare", "\u22A1"),
- HtmlEntity("doublebarwedge", "\u2306"),
- HtmlEntity("downarrow", "\u2193"),
- HtmlEntity("downdownarrows", "\u21CA"),
- HtmlEntity("downharpoonleft", "\u21C3"),
- HtmlEntity("downharpoonright", "\u21C2"),
- HtmlEntity("drbkarow", "\u2910"),
- HtmlEntity("drcorn", "\u231F"),
- HtmlEntity("drcrop", "\u230C"),
- HtmlEntity("dscr", x"D835DCB9"),
- HtmlEntity("dscy", "\u0455"),
- HtmlEntity("dsol", "\u29F6"),
- HtmlEntity("dstrok", "\u0111"),
- HtmlEntity("dtdot", "\u22F1"),
- HtmlEntity("dtri", "\u25BF"),
- HtmlEntity("dtrif", "\u25BE"),
- HtmlEntity("duarr", "\u21F5"),
- HtmlEntity("duhar", "\u296F"),
- HtmlEntity("dwangle", "\u29A6"),
- HtmlEntity("dzcy", "\u045F"),
- HtmlEntity("dzigrarr", "\u27FF"),
- HtmlEntity("eDDot", "\u2A77"),
- HtmlEntity("eDot", "\u2251"),
- HtmlEntity("eacute", "\u00E9"),
- HtmlEntity("easter", "\u2A6E"),
- HtmlEntity("ecaron", "\u011B"),
- HtmlEntity("ecir", "\u2256"),
- HtmlEntity("ecirc", "\u00EA"),
- HtmlEntity("ecolon", "\u2255"),
- HtmlEntity("ecy", "\u044D"),
- HtmlEntity("edot", "\u0117"),
- HtmlEntity("ee", "\u2147"),
- HtmlEntity("efDot", "\u2252"),
- HtmlEntity("efr", x"D835DD22"),
- HtmlEntity("eg", "\u2A9A"),
- HtmlEntity("egrave", "\u00E8"),
- HtmlEntity("egs", "\u2A96"),
- HtmlEntity("egsdot", "\u2A98"),
- HtmlEntity("el", "\u2A99"),
- HtmlEntity("elinters", "\u23E7"),
- HtmlEntity("ell", "\u2113"),
- HtmlEntity("els", "\u2A95"),
- HtmlEntity("elsdot", "\u2A97"),
- HtmlEntity("emacr", "\u0113"),
- HtmlEntity("empty", "\u2205"),
- HtmlEntity("emptyset", "\u2205"),
- HtmlEntity("emptyv", "\u2205"),
- HtmlEntity("emsp", "\u2003"),
- HtmlEntity("emsp13", "\u2004"),
- HtmlEntity("emsp14", "\u2005"),
- HtmlEntity("eng", "\u014B"),
- HtmlEntity("ensp", "\u2002"),
- HtmlEntity("eogon", "\u0119"),
- HtmlEntity("eopf", x"D835DD56"),
- HtmlEntity("epar", "\u22D5"),
- HtmlEntity("eparsl", "\u29E3"),
- HtmlEntity("eplus", "\u2A71"),
- HtmlEntity("epsi", "\u03B5"),
- HtmlEntity("epsilon", "\u03B5"),
- HtmlEntity("epsiv", "\u03F5"),
- HtmlEntity("eqcirc", "\u2256"),
- HtmlEntity("eqcolon", "\u2255"),
- HtmlEntity("eqsim", "\u2242"),
- HtmlEntity("eqslantgtr", "\u2A96"),
- HtmlEntity("eqslantless", "\u2A95"),
- HtmlEntity("equals", "\u003D"),
- HtmlEntity("equest", "\u225F"),
- HtmlEntity("equiv", "\u2261"),
- HtmlEntity("equivDD", "\u2A78"),
- HtmlEntity("eqvparsl", "\u29E5"),
- HtmlEntity("erDot", "\u2253"),
- HtmlEntity("erarr", "\u2971"),
- HtmlEntity("escr", "\u212F"),
- HtmlEntity("esdot", "\u2250"),
- HtmlEntity("esim", "\u2242"),
- HtmlEntity("eta", "\u03B7"),
- HtmlEntity("eth", "\u00F0"),
- HtmlEntity("euml", "\u00EB"),
- HtmlEntity("euro", "\u20AC"),
- HtmlEntity("excl", "\u0021"),
- HtmlEntity("exist", "\u2203"),
- HtmlEntity("expectation", "\u2130"),
- HtmlEntity("exponentiale", "\u2147"),
- HtmlEntity("fallingdotseq", "\u2252"),
- HtmlEntity("fcy", "\u0444"),
- HtmlEntity("female", "\u2640"),
- HtmlEntity("ffilig", "\uFB03"),
- HtmlEntity("fflig", "\uFB00"),
- HtmlEntity("ffllig", "\uFB04"),
- HtmlEntity("ffr", x"D835DD23"),
- HtmlEntity("filig", "\uFB01"),
- HtmlEntity("fjlig", x"0066006A"),
- HtmlEntity("flat", "\u266D"),
- HtmlEntity("fllig", "\uFB02"),
- HtmlEntity("fltns", "\u25B1"),
- HtmlEntity("fnof", "\u0192"),
- HtmlEntity("fopf", x"D835DD57"),
- HtmlEntity("forall", "\u2200"),
- HtmlEntity("fork", "\u22D4"),
- HtmlEntity("forkv", "\u2AD9"),
- HtmlEntity("fpartint", "\u2A0D"),
- HtmlEntity("frac12", "\u00BD"),
- HtmlEntity("frac13", "\u2153"),
- HtmlEntity("frac14", "\u00BC"),
- HtmlEntity("frac15", "\u2155"),
- HtmlEntity("frac16", "\u2159"),
- HtmlEntity("frac18", "\u215B"),
- HtmlEntity("frac23", "\u2154"),
- HtmlEntity("frac25", "\u2156"),
- HtmlEntity("frac34", "\u00BE"),
- HtmlEntity("frac35", "\u2157"),
- HtmlEntity("frac38", "\u215C"),
- HtmlEntity("frac45", "\u2158"),
- HtmlEntity("frac56", "\u215A"),
- HtmlEntity("frac58", "\u215D"),
- HtmlEntity("frac78", "\u215E"),
- HtmlEntity("frasl", "\u2044"),
- HtmlEntity("frown", "\u2322"),
- HtmlEntity("fscr", x"D835DCBB"),
- HtmlEntity("gE", "\u2267"),
- HtmlEntity("gEl", "\u2A8C"),
- HtmlEntity("gacute", "\u01F5"),
- HtmlEntity("gamma", "\u03B3"),
- HtmlEntity("gammad", "\u03DD"),
- HtmlEntity("gap", "\u2A86"),
- HtmlEntity("gbreve", "\u011F"),
- HtmlEntity("gcirc", "\u011D"),
- HtmlEntity("gcy", "\u0433"),
- HtmlEntity("gdot", "\u0121"),
- HtmlEntity("ge", "\u2265"),
- HtmlEntity("gel", "\u22DB"),
- HtmlEntity("geq", "\u2265"),
- HtmlEntity("geqq", "\u2267"),
- HtmlEntity("geqslant", "\u2A7E"),
- HtmlEntity("ges", "\u2A7E"),
- HtmlEntity("gescc", "\u2AA9"),
- HtmlEntity("gesdot", "\u2A80"),
- HtmlEntity("gesdoto", "\u2A82"),
- HtmlEntity("gesdotol", "\u2A84"),
- HtmlEntity("gesl", x"22DBFE00"),
- HtmlEntity("gesles", "\u2A94"),
- HtmlEntity("gfr", x"D835DD24"),
- HtmlEntity("gg", "\u226B"),
- HtmlEntity("ggg", "\u22D9"),
- HtmlEntity("gimel", "\u2137"),
- HtmlEntity("gjcy", "\u0453"),
- HtmlEntity("gl", "\u2277"),
- HtmlEntity("glE", "\u2A92"),
- HtmlEntity("gla", "\u2AA5"),
- HtmlEntity("glj", "\u2AA4"),
- HtmlEntity("gnE", "\u2269"),
- HtmlEntity("gnap", "\u2A8A"),
- HtmlEntity("gnapprox", "\u2A8A"),
- HtmlEntity("gne", "\u2A88"),
- HtmlEntity("gneq", "\u2A88"),
- HtmlEntity("gneqq", "\u2269"),
- HtmlEntity("gnsim", "\u22E7"),
- HtmlEntity("gopf", x"D835DD58"),
- HtmlEntity("grave", "\u0060"),
- HtmlEntity("gscr", "\u210A"),
- HtmlEntity("gsim", "\u2273"),
- HtmlEntity("gsime", "\u2A8E"),
- HtmlEntity("gsiml", "\u2A90"),
- HtmlEntity("gt", "\u003E"),
- HtmlEntity("gtcc", "\u2AA7"),
- HtmlEntity("gtcir", "\u2A7A"),
- HtmlEntity("gtdot", "\u22D7"),
- HtmlEntity("gtlPar", "\u2995"),
- HtmlEntity("gtquest", "\u2A7C"),
- HtmlEntity("gtrapprox", "\u2A86"),
- HtmlEntity("gtrarr", "\u2978"),
- HtmlEntity("gtrdot", "\u22D7"),
- HtmlEntity("gtreqless", "\u22DB"),
- HtmlEntity("gtreqqless", "\u2A8C"),
- HtmlEntity("gtrless", "\u2277"),
- HtmlEntity("gtrsim", "\u2273"),
- HtmlEntity("gvertneqq", x"2269FE00"),
- HtmlEntity("gvnE", x"2269FE00"),
- HtmlEntity("hArr", "\u21D4"),
- HtmlEntity("hairsp", "\u200A"),
- HtmlEntity("half", "\u00BD"),
- HtmlEntity("hamilt", "\u210B"),
- HtmlEntity("hardcy", "\u044A"),
- HtmlEntity("harr", "\u2194"),
- HtmlEntity("harrcir", "\u2948"),
- HtmlEntity("harrw", "\u21AD"),
- HtmlEntity("hbar", "\u210F"),
- HtmlEntity("hcirc", "\u0125"),
- HtmlEntity("hearts", "\u2665"),
- HtmlEntity("heartsuit", "\u2665"),
- HtmlEntity("hellip", "\u2026"),
- HtmlEntity("hercon", "\u22B9"),
- HtmlEntity("hfr", x"D835DD25"),
- HtmlEntity("hksearow", "\u2925"),
- HtmlEntity("hkswarow", "\u2926"),
- HtmlEntity("hoarr", "\u21FF"),
- HtmlEntity("homtht", "\u223B"),
- HtmlEntity("hookleftarrow", "\u21A9"),
- HtmlEntity("hookrightarrow", "\u21AA"),
- HtmlEntity("hopf", x"D835DD59"),
- HtmlEntity("horbar", "\u2015"),
- HtmlEntity("hscr", x"D835DCBD"),
- HtmlEntity("hslash", "\u210F"),
- HtmlEntity("hstrok", "\u0127"),
- HtmlEntity("hybull", "\u2043"),
- HtmlEntity("hyphen", "\u2010"),
- HtmlEntity("iacute", "\u00ED"),
- HtmlEntity("ic", "\u2063"),
- HtmlEntity("icirc", "\u00EE"),
- HtmlEntity("icy", "\u0438"),
- HtmlEntity("iecy", "\u0435"),
- HtmlEntity("iexcl", "\u00A1"),
- HtmlEntity("iff", "\u21D4"),
- HtmlEntity("ifr", x"D835DD26"),
- HtmlEntity("igrave", "\u00EC"),
- HtmlEntity("ii", "\u2148"),
- HtmlEntity("iiiint", "\u2A0C"),
- HtmlEntity("iiint", "\u222D"),
- HtmlEntity("iinfin", "\u29DC"),
- HtmlEntity("iiota", "\u2129"),
- HtmlEntity("ijlig", "\u0133"),
- HtmlEntity("imacr", "\u012B"),
- HtmlEntity("image", "\u2111"),
- HtmlEntity("imagline", "\u2110"),
- HtmlEntity("imagpart", "\u2111"),
- HtmlEntity("imath", "\u0131"),
- HtmlEntity("imof", "\u22B7"),
- HtmlEntity("imped", "\u01B5"),
- HtmlEntity("in", "\u2208"),
- HtmlEntity("incare", "\u2105"),
- HtmlEntity("infin", "\u221E"),
- HtmlEntity("infintie", "\u29DD"),
- HtmlEntity("inodot", "\u0131"),
- HtmlEntity("int", "\u222B"),
- HtmlEntity("intcal", "\u22BA"),
- HtmlEntity("integers", "\u2124"),
- HtmlEntity("intercal", "\u22BA"),
- HtmlEntity("intlarhk", "\u2A17"),
- HtmlEntity("intprod", "\u2A3C"),
- HtmlEntity("iocy", "\u0451"),
- HtmlEntity("iogon", "\u012F"),
- HtmlEntity("iopf", x"D835DD5A"),
- HtmlEntity("iota", "\u03B9"),
- HtmlEntity("iprod", "\u2A3C"),
- HtmlEntity("iquest", "\u00BF"),
- HtmlEntity("iscr", x"D835DCBE"),
- HtmlEntity("isin", "\u2208"),
- HtmlEntity("isinE", "\u22F9"),
- HtmlEntity("isindot", "\u22F5"),
- HtmlEntity("isins", "\u22F4"),
- HtmlEntity("isinsv", "\u22F3"),
- HtmlEntity("isinv", "\u2208"),
- HtmlEntity("it", "\u2062"),
- HtmlEntity("itilde", "\u0129"),
- HtmlEntity("iukcy", "\u0456"),
- HtmlEntity("iuml", "\u00EF"),
- HtmlEntity("jcirc", "\u0135"),
- HtmlEntity("jcy", "\u0439"),
- HtmlEntity("jfr", x"D835DD27"),
- HtmlEntity("jmath", "\u0237"),
- HtmlEntity("jopf", x"D835DD5B"),
- HtmlEntity("jscr", x"D835DCBF"),
- HtmlEntity("jsercy", "\u0458"),
- HtmlEntity("jukcy", "\u0454"),
- HtmlEntity("kappa", "\u03BA"),
- HtmlEntity("kappav", "\u03F0"),
- HtmlEntity("kcedil", "\u0137"),
- HtmlEntity("kcy", "\u043A"),
- HtmlEntity("kfr", x"D835DD28"),
- HtmlEntity("kgreen", "\u0138"),
- HtmlEntity("khcy", "\u0445"),
- HtmlEntity("kjcy", "\u045C"),
- HtmlEntity("kopf", x"D835DD5C"),
- HtmlEntity("kscr", x"D835DCC0"),
- HtmlEntity("lAarr", "\u21DA"),
- HtmlEntity("lArr", "\u21D0"),
- HtmlEntity("lAtail", "\u291B"),
- HtmlEntity("lBarr", "\u290E"),
- HtmlEntity("lE", "\u2266"),
- HtmlEntity("lEg", "\u2A8B"),
- HtmlEntity("lHar", "\u2962"),
- HtmlEntity("lacute", "\u013A"),
- HtmlEntity("laemptyv", "\u29B4"),
- HtmlEntity("lagran", "\u2112"),
- HtmlEntity("lambda", "\u03BB"),
- HtmlEntity("lang", "\u27E8"),
- HtmlEntity("langd", "\u2991"),
- HtmlEntity("langle", "\u27E8"),
- HtmlEntity("lap", "\u2A85"),
- HtmlEntity("laquo", "\u00AB"),
- HtmlEntity("larr", "\u2190"),
- HtmlEntity("larrb", "\u21E4"),
- HtmlEntity("larrbfs", "\u291F"),
- HtmlEntity("larrfs", "\u291D"),
- HtmlEntity("larrhk", "\u21A9"),
- HtmlEntity("larrlp", "\u21AB"),
- HtmlEntity("larrpl", "\u2939"),
- HtmlEntity("larrsim", "\u2973"),
- HtmlEntity("larrtl", "\u21A2"),
- HtmlEntity("lat", "\u2AAB"),
- HtmlEntity("latail", "\u2919"),
- HtmlEntity("late", "\u2AAD"),
- HtmlEntity("lates", x"2AADFE00"),
- HtmlEntity("lbarr", "\u290C"),
- HtmlEntity("lbbrk", "\u2772"),
- HtmlEntity("lbrace", "\u007B"),
- HtmlEntity("lbrack", "\u005B"),
- HtmlEntity("lbrke", "\u298B"),
- HtmlEntity("lbrksld", "\u298F"),
- HtmlEntity("lbrkslu", "\u298D"),
- HtmlEntity("lcaron", "\u013E"),
- HtmlEntity("lcedil", "\u013C"),
- HtmlEntity("lceil", "\u2308"),
- HtmlEntity("lcub", "\u007B"),
- HtmlEntity("lcy", "\u043B"),
- HtmlEntity("ldca", "\u2936"),
- HtmlEntity("ldquo", "\u201C"),
- HtmlEntity("ldquor", "\u201E"),
- HtmlEntity("ldrdhar", "\u2967"),
- HtmlEntity("ldrushar", "\u294B"),
- HtmlEntity("ldsh", "\u21B2"),
- HtmlEntity("le", "\u2264"),
- HtmlEntity("leftarrow", "\u2190"),
- HtmlEntity("leftarrowtail", "\u21A2"),
- HtmlEntity("leftharpoondown", "\u21BD"),
- HtmlEntity("leftharpoonup", "\u21BC"),
- HtmlEntity("leftleftarrows", "\u21C7"),
- HtmlEntity("leftrightarrow", "\u2194"),
- HtmlEntity("leftrightarrows", "\u21C6"),
- HtmlEntity("leftrightharpoons", "\u21CB"),
- HtmlEntity("leftrightsquigarrow", "\u21AD"),
- HtmlEntity("leftthreetimes", "\u22CB"),
- HtmlEntity("leg", "\u22DA"),
- HtmlEntity("leq", "\u2264"),
- HtmlEntity("leqq", "\u2266"),
- HtmlEntity("leqslant", "\u2A7D"),
- HtmlEntity("les", "\u2A7D"),
- HtmlEntity("lescc", "\u2AA8"),
- HtmlEntity("lesdot", "\u2A7F"),
- HtmlEntity("lesdoto", "\u2A81"),
- HtmlEntity("lesdotor", "\u2A83"),
- HtmlEntity("lesg", x"22DAFE00"),
- HtmlEntity("lesges", "\u2A93"),
- HtmlEntity("lessapprox", "\u2A85"),
- HtmlEntity("lessdot", "\u22D6"),
- HtmlEntity("lesseqgtr", "\u22DA"),
- HtmlEntity("lesseqqgtr", "\u2A8B"),
- HtmlEntity("lessgtr", "\u2276"),
- HtmlEntity("lesssim", "\u2272"),
- HtmlEntity("lfisht", "\u297C"),
- HtmlEntity("lfloor", "\u230A"),
- HtmlEntity("lfr", x"D835DD29"),
- HtmlEntity("lg", "\u2276"),
- HtmlEntity("lgE", "\u2A91"),
- HtmlEntity("lhard", "\u21BD"),
- HtmlEntity("lharu", "\u21BC"),
- HtmlEntity("lharul", "\u296A"),
- HtmlEntity("lhblk", "\u2584"),
- HtmlEntity("ljcy", "\u0459"),
- HtmlEntity("ll", "\u226A"),
- HtmlEntity("llarr", "\u21C7"),
- HtmlEntity("llcorner", "\u231E"),
- HtmlEntity("llhard", "\u296B"),
- HtmlEntity("lltri", "\u25FA"),
- HtmlEntity("lmidot", "\u0140"),
- HtmlEntity("lmoust", "\u23B0"),
- HtmlEntity("lmoustache", "\u23B0"),
- HtmlEntity("lnE", "\u2268"),
- HtmlEntity("lnap", "\u2A89"),
- HtmlEntity("lnapprox", "\u2A89"),
- HtmlEntity("lne", "\u2A87"),
- HtmlEntity("lneq", "\u2A87"),
- HtmlEntity("lneqq", "\u2268"),
- HtmlEntity("lnsim", "\u22E6"),
- HtmlEntity("loang", "\u27EC"),
- HtmlEntity("loarr", "\u21FD"),
- HtmlEntity("lobrk", "\u27E6"),
- HtmlEntity("longleftarrow", "\u27F5"),
- HtmlEntity("longleftrightarrow", "\u27F7"),
- HtmlEntity("longmapsto", "\u27FC"),
- HtmlEntity("longrightarrow", "\u27F6"),
- HtmlEntity("looparrowleft", "\u21AB"),
- HtmlEntity("looparrowright", "\u21AC"),
- HtmlEntity("lopar", "\u2985"),
- HtmlEntity("lopf", x"D835DD5D"),
- HtmlEntity("loplus", "\u2A2D"),
- HtmlEntity("lotimes", "\u2A34"),
- HtmlEntity("lowast", "\u2217"),
- HtmlEntity("lowbar", "\u005F"),
- HtmlEntity("loz", "\u25CA"),
- HtmlEntity("lozenge", "\u25CA"),
- HtmlEntity("lozf", "\u29EB"),
- HtmlEntity("lpar", "\u0028"),
- HtmlEntity("lparlt", "\u2993"),
- HtmlEntity("lrarr", "\u21C6"),
- HtmlEntity("lrcorner", "\u231F"),
- HtmlEntity("lrhar", "\u21CB"),
- HtmlEntity("lrhard", "\u296D"),
- HtmlEntity("lrm", "\u200E"),
- HtmlEntity("lrtri", "\u22BF"),
- HtmlEntity("lsaquo", "\u2039"),
- HtmlEntity("lscr", x"D835DCC1"),
- HtmlEntity("lsh", "\u21B0"),
- HtmlEntity("lsim", "\u2272"),
- HtmlEntity("lsime", "\u2A8D"),
- HtmlEntity("lsimg", "\u2A8F"),
- HtmlEntity("lsqb", "\u005B"),
- HtmlEntity("lsquo", "\u2018"),
- HtmlEntity("lsquor", "\u201A"),
- HtmlEntity("lstrok", "\u0142"),
- HtmlEntity("lt", "\u003C"),
- HtmlEntity("ltcc", "\u2AA6"),
- HtmlEntity("ltcir", "\u2A79"),
- HtmlEntity("ltdot", "\u22D6"),
- HtmlEntity("lthree", "\u22CB"),
- HtmlEntity("ltimes", "\u22C9"),
- HtmlEntity("ltlarr", "\u2976"),
- HtmlEntity("ltquest", "\u2A7B"),
- HtmlEntity("ltrPar", "\u2996"),
- HtmlEntity("ltri", "\u25C3"),
- HtmlEntity("ltrie", "\u22B4"),
- HtmlEntity("ltrif", "\u25C2"),
- HtmlEntity("lurdshar", "\u294A"),
- HtmlEntity("luruhar", "\u2966"),
- HtmlEntity("lvertneqq", x"2268FE00"),
- HtmlEntity("lvnE", x"2268FE00"),
- HtmlEntity("mDDot", "\u223A"),
- HtmlEntity("macr", "\u00AF"),
- HtmlEntity("male", "\u2642"),
- HtmlEntity("malt", "\u2720"),
- HtmlEntity("maltese", "\u2720"),
- HtmlEntity("map", "\u21A6"),
- HtmlEntity("mapsto", "\u21A6"),
- HtmlEntity("mapstodown", "\u21A7"),
- HtmlEntity("mapstoleft", "\u21A4"),
- HtmlEntity("mapstoup", "\u21A5"),
- HtmlEntity("marker", "\u25AE"),
- HtmlEntity("mcomma", "\u2A29"),
- HtmlEntity("mcy", "\u043C"),
- HtmlEntity("mdash", "\u2014"),
- HtmlEntity("measuredangle", "\u2221"),
- HtmlEntity("mfr", x"D835DD2A"),
- HtmlEntity("mho", "\u2127"),
- HtmlEntity("micro", "\u00B5"),
- HtmlEntity("mid", "\u2223"),
- HtmlEntity("midast", "\u002A"),
- HtmlEntity("midcir", "\u2AF0"),
- HtmlEntity("middot", "\u00B7"),
- HtmlEntity("minus", "\u2212"),
- HtmlEntity("minusb", "\u229F"),
- HtmlEntity("minusd", "\u2238"),
- HtmlEntity("minusdu", "\u2A2A"),
- HtmlEntity("mlcp", "\u2ADB"),
- HtmlEntity("mldr", "\u2026"),
- HtmlEntity("mnplus", "\u2213"),
- HtmlEntity("models", "\u22A7"),
- HtmlEntity("mopf", x"D835DD5E"),
- HtmlEntity("mp", "\u2213"),
- HtmlEntity("mscr", x"D835DCC2"),
- HtmlEntity("mstpos", "\u223E"),
- HtmlEntity("mu", "\u03BC"),
- HtmlEntity("multimap", "\u22B8"),
- HtmlEntity("mumap", "\u22B8"),
- HtmlEntity("nGg", x"22D90338"),
- HtmlEntity("nGt", x"226B20D2"),
- HtmlEntity("nGtv", x"226B0338"),
- HtmlEntity("nLeftarrow", "\u21CD"),
- HtmlEntity("nLeftrightarrow", "\u21CE"),
- HtmlEntity("nLl", x"22D80338"),
- HtmlEntity("nLt", x"226A20D2"),
- HtmlEntity("nLtv", x"226A0338"),
- HtmlEntity("nRightarrow", "\u21CF"),
- HtmlEntity("nVDash", "\u22AF"),
- HtmlEntity("nVdash", "\u22AE"),
- HtmlEntity("nabla", "\u2207"),
- HtmlEntity("nacute", "\u0144"),
- HtmlEntity("nang", x"222020D2"),
- HtmlEntity("nap", "\u2249"),
- HtmlEntity("napE", x"2A700338"),
- HtmlEntity("napid", x"224B0338"),
- HtmlEntity("napos", "\u0149"),
- HtmlEntity("napprox", "\u2249"),
- HtmlEntity("natur", "\u266E"),
- HtmlEntity("natural", "\u266E"),
- HtmlEntity("naturals", "\u2115"),
- HtmlEntity("nbsp", "\u00A0"),
- HtmlEntity("nbump", x"224E0338"),
- HtmlEntity("nbumpe", x"224F0338"),
- HtmlEntity("ncap", "\u2A43"),
- HtmlEntity("ncaron", "\u0148"),
- HtmlEntity("ncedil", "\u0146"),
- HtmlEntity("ncong", "\u2247"),
- HtmlEntity("ncongdot", x"2A6D0338"),
- HtmlEntity("ncup", "\u2A42"),
- HtmlEntity("ncy", "\u043D"),
- HtmlEntity("ndash", "\u2013"),
- HtmlEntity("ne", "\u2260"),
- HtmlEntity("neArr", "\u21D7"),
- HtmlEntity("nearhk", "\u2924"),
- HtmlEntity("nearr", "\u2197"),
- HtmlEntity("nearrow", "\u2197"),
- HtmlEntity("nedot", x"22500338"),
- HtmlEntity("nequiv", "\u2262"),
- HtmlEntity("nesear", "\u2928"),
- HtmlEntity("nesim", x"22420338"),
- HtmlEntity("nexist", "\u2204"),
- HtmlEntity("nexists", "\u2204"),
- HtmlEntity("nfr", x"D835DD2B"),
- HtmlEntity("ngE", x"22670338"),
- HtmlEntity("nge", "\u2271"),
- HtmlEntity("ngeq", "\u2271"),
- HtmlEntity("ngeqq", x"22670338"),
- HtmlEntity("ngeqslant", x"2A7E0338"),
- HtmlEntity("nges", x"2A7E0338"),
- HtmlEntity("ngsim", "\u2275"),
- HtmlEntity("ngt", "\u226F"),
- HtmlEntity("ngtr", "\u226F"),
- HtmlEntity("nhArr", "\u21CE"),
- HtmlEntity("nharr", "\u21AE"),
- HtmlEntity("nhpar", "\u2AF2"),
- HtmlEntity("ni", "\u220B"),
- HtmlEntity("nis", "\u22FC"),
- HtmlEntity("nisd", "\u22FA"),
- HtmlEntity("niv", "\u220B"),
- HtmlEntity("njcy", "\u045A"),
- HtmlEntity("nlArr", "\u21CD"),
- HtmlEntity("nlE", x"22660338"),
- HtmlEntity("nlarr", "\u219A"),
- HtmlEntity("nldr", "\u2025"),
- HtmlEntity("nle", "\u2270"),
- HtmlEntity("nleftarrow", "\u219A"),
- HtmlEntity("nleftrightarrow", "\u21AE"),
- HtmlEntity("nleq", "\u2270"),
- HtmlEntity("nleqq", x"22660338"),
- HtmlEntity("nleqslant", x"2A7D0338"),
- HtmlEntity("nles", x"2A7D0338"),
- HtmlEntity("nless", "\u226E"),
- HtmlEntity("nlsim", "\u2274"),
- HtmlEntity("nlt", "\u226E"),
- HtmlEntity("nltri", "\u22EA"),
- HtmlEntity("nltrie", "\u22EC"),
- HtmlEntity("nmid", "\u2224"),
- HtmlEntity("nopf", x"D835DD5F"),
- HtmlEntity("not", "\u00AC"),
- HtmlEntity("notin", "\u2209"),
- HtmlEntity("notinE", x"22F90338"),
- HtmlEntity("notindot", x"22F50338"),
- HtmlEntity("notinva", "\u2209"),
- HtmlEntity("notinvb", "\u22F7"),
- HtmlEntity("notinvc", "\u22F6"),
- HtmlEntity("notni", "\u220C"),
- HtmlEntity("notniva", "\u220C"),
- HtmlEntity("notnivb", "\u22FE"),
- HtmlEntity("notnivc", "\u22FD"),
- HtmlEntity("npar", "\u2226"),
- HtmlEntity("nparallel", "\u2226"),
- HtmlEntity("nparsl", x"2AFD20E5"),
- HtmlEntity("npart", x"22020338"),
- HtmlEntity("npolint", "\u2A14"),
- HtmlEntity("npr", "\u2280"),
- HtmlEntity("nprcue", "\u22E0"),
- HtmlEntity("npre", x"2AAF0338"),
- HtmlEntity("nprec", "\u2280"),
- HtmlEntity("npreceq", x"2AAF0338"),
- HtmlEntity("nrArr", "\u21CF"),
- HtmlEntity("nrarr", "\u219B"),
- HtmlEntity("nrarrc", x"29330338"),
- HtmlEntity("nrarrw", x"219D0338"),
- HtmlEntity("nrightarrow", "\u219B"),
- HtmlEntity("nrtri", "\u22EB"),
- HtmlEntity("nrtrie", "\u22ED"),
- HtmlEntity("nsc", "\u2281"),
- HtmlEntity("nsccue", "\u22E1"),
- HtmlEntity("nsce", x"2AB00338"),
- HtmlEntity("nscr", x"D835DCC3"),
- HtmlEntity("nshortmid", "\u2224"),
- HtmlEntity("nshortparallel", "\u2226"),
- HtmlEntity("nsim", "\u2241"),
- HtmlEntity("nsime", "\u2244"),
- HtmlEntity("nsimeq", "\u2244"),
- HtmlEntity("nsmid", "\u2224"),
- HtmlEntity("nspar", "\u2226"),
- HtmlEntity("nsqsube", "\u22E2"),
- HtmlEntity("nsqsupe", "\u22E3"),
- HtmlEntity("nsub", "\u2284"),
- HtmlEntity("nsubE", x"2AC50338"),
- HtmlEntity("nsube", "\u2288"),
- HtmlEntity("nsubset", x"228220D2"),
- HtmlEntity("nsubseteq", "\u2288"),
- HtmlEntity("nsubseteqq", x"2AC50338"),
- HtmlEntity("nsucc", "\u2281"),
- HtmlEntity("nsucceq", x"2AB00338"),
- HtmlEntity("nsup", "\u2285"),
- HtmlEntity("nsupE", x"2AC60338"),
- HtmlEntity("nsupe", "\u2289"),
- HtmlEntity("nsupset", x"228320D2"),
- HtmlEntity("nsupseteq", "\u2289"),
- HtmlEntity("nsupseteqq", x"2AC60338"),
- HtmlEntity("ntgl", "\u2279"),
- HtmlEntity("ntilde", "\u00F1"),
- HtmlEntity("ntlg", "\u2278"),
- HtmlEntity("ntriangleleft", "\u22EA"),
- HtmlEntity("ntrianglelefteq", "\u22EC"),
- HtmlEntity("ntriangleright", "\u22EB"),
- HtmlEntity("ntrianglerighteq", "\u22ED"),
- HtmlEntity("nu", "\u03BD"),
- HtmlEntity("num", "\u0023"),
- HtmlEntity("numero", "\u2116"),
- HtmlEntity("numsp", "\u2007"),
- HtmlEntity("nvDash", "\u22AD"),
- HtmlEntity("nvHarr", "\u2904"),
- HtmlEntity("nvap", x"224D20D2"),
- HtmlEntity("nvdash", "\u22AC"),
- HtmlEntity("nvge", x"226520D2"),
- HtmlEntity("nvgt", x"003E20D2"),
- HtmlEntity("nvinfin", "\u29DE"),
- HtmlEntity("nvlArr", "\u2902"),
- HtmlEntity("nvle", x"226420D2"),
- HtmlEntity("nvlt", x"003C20D2"),
- HtmlEntity("nvltrie", x"22B420D2"),
- HtmlEntity("nvrArr", "\u2903"),
- HtmlEntity("nvrtrie", x"22B520D2"),
- HtmlEntity("nvsim", x"223C20D2"),
- HtmlEntity("nwArr", "\u21D6"),
- HtmlEntity("nwarhk", "\u2923"),
- HtmlEntity("nwarr", "\u2196"),
- HtmlEntity("nwarrow", "\u2196"),
- HtmlEntity("nwnear", "\u2927"),
- HtmlEntity("oS", "\u24C8"),
- HtmlEntity("oacute", "\u00F3"),
- HtmlEntity("oast", "\u229B"),
- HtmlEntity("ocir", "\u229A"),
- HtmlEntity("ocirc", "\u00F4"),
- HtmlEntity("ocy", "\u043E"),
- HtmlEntity("odash", "\u229D"),
- HtmlEntity("odblac", "\u0151"),
- HtmlEntity("odiv", "\u2A38"),
- HtmlEntity("odot", "\u2299"),
- HtmlEntity("odsold", "\u29BC"),
- HtmlEntity("oelig", "\u0153"),
- HtmlEntity("ofcir", "\u29BF"),
- HtmlEntity("ofr", x"D835DD2C"),
- HtmlEntity("ogon", "\u02DB"),
- HtmlEntity("ograve", "\u00F2"),
- HtmlEntity("ogt", "\u29C1"),
- HtmlEntity("ohbar", "\u29B5"),
- HtmlEntity("ohm", "\u03A9"),
- HtmlEntity("oint", "\u222E"),
- HtmlEntity("olarr", "\u21BA"),
- HtmlEntity("olcir", "\u29BE"),
- HtmlEntity("olcross", "\u29BB"),
- HtmlEntity("oline", "\u203E"),
- HtmlEntity("olt", "\u29C0"),
- HtmlEntity("omacr", "\u014D"),
- HtmlEntity("omega", "\u03C9"),
- HtmlEntity("omicron", "\u03BF"),
- HtmlEntity("omid", "\u29B6"),
- HtmlEntity("ominus", "\u2296"),
- HtmlEntity("oopf", x"D835DD60"),
- HtmlEntity("opar", "\u29B7"),
- HtmlEntity("operp", "\u29B9"),
- HtmlEntity("oplus", "\u2295"),
- HtmlEntity("or", "\u2228"),
- HtmlEntity("orarr", "\u21BB"),
- HtmlEntity("ord", "\u2A5D"),
- HtmlEntity("order", "\u2134"),
- HtmlEntity("orderof", "\u2134"),
- HtmlEntity("ordf", "\u00AA"),
- HtmlEntity("ordm", "\u00BA"),
- HtmlEntity("origof", "\u22B6"),
- HtmlEntity("oror", "\u2A56"),
- HtmlEntity("orslope", "\u2A57"),
- HtmlEntity("orv", "\u2A5B"),
- HtmlEntity("oscr", "\u2134"),
- HtmlEntity("oslash", "\u00F8"),
- HtmlEntity("osol", "\u2298"),
- HtmlEntity("otilde", "\u00F5"),
- HtmlEntity("otimes", "\u2297"),
- HtmlEntity("otimesas", "\u2A36"),
- HtmlEntity("ouml", "\u00F6"),
- HtmlEntity("ovbar", "\u233D"),
- HtmlEntity("par", "\u2225"),
- HtmlEntity("para", "\u00B6"),
- HtmlEntity("parallel", "\u2225"),
- HtmlEntity("parsim", "\u2AF3"),
- HtmlEntity("parsl", "\u2AFD"),
- HtmlEntity("part", "\u2202"),
- HtmlEntity("pcy", "\u043F"),
- HtmlEntity("percnt", "\u0025"),
- HtmlEntity("period", "\u002E"),
- HtmlEntity("permil", "\u2030"),
- HtmlEntity("perp", "\u22A5"),
- HtmlEntity("pertenk", "\u2031"),
- HtmlEntity("pfr", x"D835DD2D"),
- HtmlEntity("phi", "\u03C6"),
- HtmlEntity("phiv", "\u03D5"),
- HtmlEntity("phmmat", "\u2133"),
- HtmlEntity("phone", "\u260E"),
- HtmlEntity("pi", "\u03C0"),
- HtmlEntity("pitchfork", "\u22D4"),
- HtmlEntity("piv", "\u03D6"),
- HtmlEntity("planck", "\u210F"),
- HtmlEntity("planckh", "\u210E"),
- HtmlEntity("plankv", "\u210F"),
- HtmlEntity("plus", "\u002B"),
- HtmlEntity("plusacir", "\u2A23"),
- HtmlEntity("plusb", "\u229E"),
- HtmlEntity("pluscir", "\u2A22"),
- HtmlEntity("plusdo", "\u2214"),
- HtmlEntity("plusdu", "\u2A25"),
- HtmlEntity("pluse", "\u2A72"),
- HtmlEntity("plusmn", "\u00B1"),
- HtmlEntity("plussim", "\u2A26"),
- HtmlEntity("plustwo", "\u2A27"),
- HtmlEntity("pm", "\u00B1"),
- HtmlEntity("pointint", "\u2A15"),
- HtmlEntity("popf", x"D835DD61"),
- HtmlEntity("pound", "\u00A3"),
- HtmlEntity("pr", "\u227A"),
- HtmlEntity("prE", "\u2AB3"),
- HtmlEntity("prap", "\u2AB7"),
- HtmlEntity("prcue", "\u227C"),
- HtmlEntity("pre", "\u2AAF"),
- HtmlEntity("prec", "\u227A"),
- HtmlEntity("precapprox", "\u2AB7"),
- HtmlEntity("preccurlyeq", "\u227C"),
- HtmlEntity("preceq", "\u2AAF"),
- HtmlEntity("precnapprox", "\u2AB9"),
- HtmlEntity("precneqq", "\u2AB5"),
- HtmlEntity("precnsim", "\u22E8"),
- HtmlEntity("precsim", "\u227E"),
- HtmlEntity("prime", "\u2032"),
- HtmlEntity("primes", "\u2119"),
- HtmlEntity("prnE", "\u2AB5"),
- HtmlEntity("prnap", "\u2AB9"),
- HtmlEntity("prnsim", "\u22E8"),
- HtmlEntity("prod", "\u220F"),
- HtmlEntity("profalar", "\u232E"),
- HtmlEntity("profline", "\u2312"),
- HtmlEntity("profsurf", "\u2313"),
- HtmlEntity("prop", "\u221D"),
- HtmlEntity("propto", "\u221D"),
- HtmlEntity("prsim", "\u227E"),
- HtmlEntity("prurel", "\u22B0"),
- HtmlEntity("pscr", x"D835DCC5"),
- HtmlEntity("psi", "\u03C8"),
- HtmlEntity("puncsp", "\u2008"),
- HtmlEntity("qfr", x"D835DD2E"),
- HtmlEntity("qint", "\u2A0C"),
- HtmlEntity("qopf", x"D835DD62"),
- HtmlEntity("qprime", "\u2057"),
- HtmlEntity("qscr", x"D835DCC6"),
- HtmlEntity("quaternions", "\u210D"),
- HtmlEntity("quatint", "\u2A16"),
- HtmlEntity("quest", "\u003F"),
- HtmlEntity("questeq", "\u225F"),
- HtmlEntity("quot", "\u0022"),
- HtmlEntity("rAarr", "\u21DB"),
- HtmlEntity("rArr", "\u21D2"),
- HtmlEntity("rAtail", "\u291C"),
- HtmlEntity("rBarr", "\u290F"),
- HtmlEntity("rHar", "\u2964"),
- HtmlEntity("race", x"223D0331"),
- HtmlEntity("racute", "\u0155"),
- HtmlEntity("radic", "\u221A"),
- HtmlEntity("raemptyv", "\u29B3"),
- HtmlEntity("rang", "\u27E9"),
- HtmlEntity("rangd", "\u2992"),
- HtmlEntity("range", "\u29A5"),
- HtmlEntity("rangle", "\u27E9"),
- HtmlEntity("raquo", "\u00BB"),
- HtmlEntity("rarr", "\u2192"),
- HtmlEntity("rarrap", "\u2975"),
- HtmlEntity("rarrb", "\u21E5"),
- HtmlEntity("rarrbfs", "\u2920"),
- HtmlEntity("rarrc", "\u2933"),
- HtmlEntity("rarrfs", "\u291E"),
- HtmlEntity("rarrhk", "\u21AA"),
- HtmlEntity("rarrlp", "\u21AC"),
- HtmlEntity("rarrpl", "\u2945"),
- HtmlEntity("rarrsim", "\u2974"),
- HtmlEntity("rarrtl", "\u21A3"),
- HtmlEntity("rarrw", "\u219D"),
- HtmlEntity("ratail", "\u291A"),
- HtmlEntity("ratio", "\u2236"),
- HtmlEntity("rationals", "\u211A"),
- HtmlEntity("rbarr", "\u290D"),
- HtmlEntity("rbbrk", "\u2773"),
- HtmlEntity("rbrace", "\u007D"),
- HtmlEntity("rbrack", "\u005D"),
- HtmlEntity("rbrke", "\u298C"),
- HtmlEntity("rbrksld", "\u298E"),
- HtmlEntity("rbrkslu", "\u2990"),
- HtmlEntity("rcaron", "\u0159"),
- HtmlEntity("rcedil", "\u0157"),
- HtmlEntity("rceil", "\u2309"),
- HtmlEntity("rcub", "\u007D"),
- HtmlEntity("rcy", "\u0440"),
- HtmlEntity("rdca", "\u2937"),
- HtmlEntity("rdldhar", "\u2969"),
- HtmlEntity("rdquo", "\u201D"),
- HtmlEntity("rdquor", "\u201D"),
- HtmlEntity("rdsh", "\u21B3"),
- HtmlEntity("real", "\u211C"),
- HtmlEntity("realine", "\u211B"),
- HtmlEntity("realpart", "\u211C"),
- HtmlEntity("reals", "\u211D"),
- HtmlEntity("rect", "\u25AD"),
- HtmlEntity("reg", "\u00AE"),
- HtmlEntity("rfisht", "\u297D"),
- HtmlEntity("rfloor", "\u230B"),
- HtmlEntity("rfr", x"D835DD2F"),
- HtmlEntity("rhard", "\u21C1"),
- HtmlEntity("rharu", "\u21C0"),
- HtmlEntity("rharul", "\u296C"),
- HtmlEntity("rho", "\u03C1"),
- HtmlEntity("rhov", "\u03F1"),
- HtmlEntity("rightarrow", "\u2192"),
- HtmlEntity("rightarrowtail", "\u21A3"),
- HtmlEntity("rightharpoondown", "\u21C1"),
- HtmlEntity("rightharpoonup", "\u21C0"),
- HtmlEntity("rightleftarrows", "\u21C4"),
- HtmlEntity("rightleftharpoons", "\u21CC"),
- HtmlEntity("rightrightarrows", "\u21C9"),
- HtmlEntity("rightsquigarrow", "\u219D"),
- HtmlEntity("rightthreetimes", "\u22CC"),
- HtmlEntity("ring", "\u02DA"),
- HtmlEntity("risingdotseq", "\u2253"),
- HtmlEntity("rlarr", "\u21C4"),
- HtmlEntity("rlhar", "\u21CC"),
- HtmlEntity("rlm", "\u200F"),
- HtmlEntity("rmoust", "\u23B1"),
- HtmlEntity("rmoustache", "\u23B1"),
- HtmlEntity("rnmid", "\u2AEE"),
- HtmlEntity("roang", "\u27ED"),
- HtmlEntity("roarr", "\u21FE"),
- HtmlEntity("robrk", "\u27E7"),
- HtmlEntity("ropar", "\u2986"),
- HtmlEntity("ropf", x"D835DD63"),
- HtmlEntity("roplus", "\u2A2E"),
- HtmlEntity("rotimes", "\u2A35"),
- HtmlEntity("rpar", "\u0029"),
- HtmlEntity("rpargt", "\u2994"),
- HtmlEntity("rppolint", "\u2A12"),
- HtmlEntity("rrarr", "\u21C9"),
- HtmlEntity("rsaquo", "\u203A"),
- HtmlEntity("rscr", x"D835DCC7"),
- HtmlEntity("rsh", "\u21B1"),
- HtmlEntity("rsqb", "\u005D"),
- HtmlEntity("rsquo", "\u2019"),
- HtmlEntity("rsquor", "\u2019"),
- HtmlEntity("rthree", "\u22CC"),
- HtmlEntity("rtimes", "\u22CA"),
- HtmlEntity("rtri", "\u25B9"),
- HtmlEntity("rtrie", "\u22B5"),
- HtmlEntity("rtrif", "\u25B8"),
- HtmlEntity("rtriltri", "\u29CE"),
- HtmlEntity("ruluhar", "\u2968"),
- HtmlEntity("rx", "\u211E"),
- HtmlEntity("sacute", "\u015B"),
- HtmlEntity("sbquo", "\u201A"),
- HtmlEntity("sc", "\u227B"),
- HtmlEntity("scE", "\u2AB4"),
- HtmlEntity("scap", "\u2AB8"),
- HtmlEntity("scaron", "\u0161"),
- HtmlEntity("sccue", "\u227D"),
- HtmlEntity("sce", "\u2AB0"),
- HtmlEntity("scedil", "\u015F"),
- HtmlEntity("scirc", "\u015D"),
- HtmlEntity("scnE", "\u2AB6"),
- HtmlEntity("scnap", "\u2ABA"),
- HtmlEntity("scnsim", "\u22E9"),
- HtmlEntity("scpolint", "\u2A13"),
- HtmlEntity("scsim", "\u227F"),
- HtmlEntity("scy", "\u0441"),
- HtmlEntity("sdot", "\u22C5"),
- HtmlEntity("sdotb", "\u22A1"),
- HtmlEntity("sdote", "\u2A66"),
- HtmlEntity("seArr", "\u21D8"),
- HtmlEntity("searhk", "\u2925"),
- HtmlEntity("searr", "\u2198"),
- HtmlEntity("searrow", "\u2198"),
- HtmlEntity("sect", "\u00A7"),
- HtmlEntity("semi", "\u003B"),
- HtmlEntity("seswar", "\u2929"),
- HtmlEntity("setminus", "\u2216"),
- HtmlEntity("setmn", "\u2216"),
- HtmlEntity("sext", "\u2736"),
- HtmlEntity("sfr", x"D835DD30"),
- HtmlEntity("sfrown", "\u2322"),
- HtmlEntity("sharp", "\u266F"),
- HtmlEntity("shchcy", "\u0449"),
- HtmlEntity("shcy", "\u0448"),
- HtmlEntity("shortmid", "\u2223"),
- HtmlEntity("shortparallel", "\u2225"),
- HtmlEntity("shy", "\u00AD"),
- HtmlEntity("sigma", "\u03C3"),
- HtmlEntity("sigmaf", "\u03C2"),
- HtmlEntity("sigmav", "\u03C2"),
- HtmlEntity("sim", "\u223C"),
- HtmlEntity("simdot", "\u2A6A"),
- HtmlEntity("sime", "\u2243"),
- HtmlEntity("simeq", "\u2243"),
- HtmlEntity("simg", "\u2A9E"),
- HtmlEntity("simgE", "\u2AA0"),
- HtmlEntity("siml", "\u2A9D"),
- HtmlEntity("simlE", "\u2A9F"),
- HtmlEntity("simne", "\u2246"),
- HtmlEntity("simplus", "\u2A24"),
- HtmlEntity("simrarr", "\u2972"),
- HtmlEntity("slarr", "\u2190"),
- HtmlEntity("smallsetminus", "\u2216"),
- HtmlEntity("smashp", "\u2A33"),
- HtmlEntity("smeparsl", "\u29E4"),
- HtmlEntity("smid", "\u2223"),
- HtmlEntity("smile", "\u2323"),
- HtmlEntity("smt", "\u2AAA"),
- HtmlEntity("smte", "\u2AAC"),
- HtmlEntity("smtes", x"2AACFE00"),
- HtmlEntity("softcy", "\u044C"),
- HtmlEntity("sol", "\u002F"),
- HtmlEntity("solb", "\u29C4"),
- HtmlEntity("solbar", "\u233F"),
- HtmlEntity("sopf", x"D835DD64"),
- HtmlEntity("spades", "\u2660"),
- HtmlEntity("spadesuit", "\u2660"),
- HtmlEntity("spar", "\u2225"),
- HtmlEntity("sqcap", "\u2293"),
- HtmlEntity("sqcaps", x"2293FE00"),
- HtmlEntity("sqcup", "\u2294"),
- HtmlEntity("sqcups", x"2294FE00"),
- HtmlEntity("sqsub", "\u228F"),
- HtmlEntity("sqsube", "\u2291"),
- HtmlEntity("sqsubset", "\u228F"),
- HtmlEntity("sqsubseteq", "\u2291"),
- HtmlEntity("sqsup", "\u2290"),
- HtmlEntity("sqsupe", "\u2292"),
- HtmlEntity("sqsupset", "\u2290"),
- HtmlEntity("sqsupseteq", "\u2292"),
- HtmlEntity("squ", "\u25A1"),
- HtmlEntity("square", "\u25A1"),
- HtmlEntity("squarf", "\u25AA"),
- HtmlEntity("squf", "\u25AA"),
- HtmlEntity("srarr", "\u2192"),
- HtmlEntity("sscr", x"D835DCC8"),
- HtmlEntity("ssetmn", "\u2216"),
- HtmlEntity("ssmile", "\u2323"),
- HtmlEntity("sstarf", "\u22C6"),
- HtmlEntity("star", "\u2606"),
- HtmlEntity("starf", "\u2605"),
- HtmlEntity("straightepsilon", "\u03F5"),
- HtmlEntity("straightphi", "\u03D5"),
- HtmlEntity("strns", "\u00AF"),
- HtmlEntity("sub", "\u2282"),
- HtmlEntity("subE", "\u2AC5"),
- HtmlEntity("subdot", "\u2ABD"),
- HtmlEntity("sube", "\u2286"),
- HtmlEntity("subedot", "\u2AC3"),
- HtmlEntity("submult", "\u2AC1"),
- HtmlEntity("subnE", "\u2ACB"),
- HtmlEntity("subne", "\u228A"),
- HtmlEntity("subplus", "\u2ABF"),
- HtmlEntity("subrarr", "\u2979"),
- HtmlEntity("subset", "\u2282"),
- HtmlEntity("subseteq", "\u2286"),
- HtmlEntity("subseteqq", "\u2AC5"),
- HtmlEntity("subsetneq", "\u228A"),
- HtmlEntity("subsetneqq", "\u2ACB"),
- HtmlEntity("subsim", "\u2AC7"),
- HtmlEntity("subsub", "\u2AD5"),
- HtmlEntity("subsup", "\u2AD3"),
- HtmlEntity("succ", "\u227B"),
- HtmlEntity("succapprox", "\u2AB8"),
- HtmlEntity("succcurlyeq", "\u227D"),
- HtmlEntity("succeq", "\u2AB0"),
- HtmlEntity("succnapprox", "\u2ABA"),
- HtmlEntity("succneqq", "\u2AB6"),
- HtmlEntity("succnsim", "\u22E9"),
- HtmlEntity("succsim", "\u227F"),
- HtmlEntity("sum", "\u2211"),
- HtmlEntity("sung", "\u266A"),
- HtmlEntity("sup", "\u2283"),
- HtmlEntity("sup1", "\u00B9"),
- HtmlEntity("sup2", "\u00B2"),
- HtmlEntity("sup3", "\u00B3"),
- HtmlEntity("supE", "\u2AC6"),
- HtmlEntity("supdot", "\u2ABE"),
- HtmlEntity("supdsub", "\u2AD8"),
- HtmlEntity("supe", "\u2287"),
- HtmlEntity("supedot", "\u2AC4"),
- HtmlEntity("suphsol", "\u27C9"),
- HtmlEntity("suphsub", "\u2AD7"),
- HtmlEntity("suplarr", "\u297B"),
- HtmlEntity("supmult", "\u2AC2"),
- HtmlEntity("supnE", "\u2ACC"),
- HtmlEntity("supne", "\u228B"),
- HtmlEntity("supplus", "\u2AC0"),
- HtmlEntity("supset", "\u2283"),
- HtmlEntity("supseteq", "\u2287"),
- HtmlEntity("supseteqq", "\u2AC6"),
- HtmlEntity("supsetneq", "\u228B"),
- HtmlEntity("supsetneqq", "\u2ACC"),
- HtmlEntity("supsim", "\u2AC8"),
- HtmlEntity("supsub", "\u2AD4"),
- HtmlEntity("supsup", "\u2AD6"),
- HtmlEntity("swArr", "\u21D9"),
- HtmlEntity("swarhk", "\u2926"),
- HtmlEntity("swarr", "\u2199"),
- HtmlEntity("swarrow", "\u2199"),
- HtmlEntity("swnwar", "\u292A"),
- HtmlEntity("szlig", "\u00DF"),
- HtmlEntity("target", "\u2316"),
- HtmlEntity("tau", "\u03C4"),
- HtmlEntity("tbrk", "\u23B4"),
- HtmlEntity("tcaron", "\u0165"),
- HtmlEntity("tcedil", "\u0163"),
- HtmlEntity("tcy", "\u0442"),
- HtmlEntity("tdot", "\u20DB"),
- HtmlEntity("telrec", "\u2315"),
- HtmlEntity("tfr", x"D835DD31"),
- HtmlEntity("there4", "\u2234"),
- HtmlEntity("therefore", "\u2234"),
- HtmlEntity("theta", "\u03B8"),
- HtmlEntity("thetasym", "\u03D1"),
- HtmlEntity("thetav", "\u03D1"),
- HtmlEntity("thickapprox", "\u2248"),
- HtmlEntity("thicksim", "\u223C"),
- HtmlEntity("thinsp", "\u2009"),
- HtmlEntity("thkap", "\u2248"),
- HtmlEntity("thksim", "\u223C"),
- HtmlEntity("thorn", "\u00FE"),
- HtmlEntity("tilde", "\u02DC"),
- HtmlEntity("times", "\u00D7"),
- HtmlEntity("timesb", "\u22A0"),
- HtmlEntity("timesbar", "\u2A31"),
- HtmlEntity("timesd", "\u2A30"),
- HtmlEntity("tint", "\u222D"),
- HtmlEntity("toea", "\u2928"),
- HtmlEntity("top", "\u22A4"),
- HtmlEntity("topbot", "\u2336"),
- HtmlEntity("topcir", "\u2AF1"),
- HtmlEntity("topf", x"D835DD65"),
- HtmlEntity("topfork", "\u2ADA"),
- HtmlEntity("tosa", "\u2929"),
- HtmlEntity("tprime", "\u2034"),
- HtmlEntity("trade", "\u2122"),
- HtmlEntity("triangle", "\u25B5"),
- HtmlEntity("triangledown", "\u25BF"),
- HtmlEntity("triangleleft", "\u25C3"),
- HtmlEntity("trianglelefteq", "\u22B4"),
- HtmlEntity("triangleq", "\u225C"),
- HtmlEntity("triangleright", "\u25B9"),
- HtmlEntity("trianglerighteq", "\u22B5"),
- HtmlEntity("tridot", "\u25EC"),
- HtmlEntity("trie", "\u225C"),
- HtmlEntity("triminus", "\u2A3A"),
- HtmlEntity("triplus", "\u2A39"),
- HtmlEntity("trisb", "\u29CD"),
- HtmlEntity("tritime", "\u2A3B"),
- HtmlEntity("trpezium", "\u23E2"),
- HtmlEntity("tscr", x"D835DCC9"),
- HtmlEntity("tscy", "\u0446"),
- HtmlEntity("tshcy", "\u045B"),
- HtmlEntity("tstrok", "\u0167"),
- HtmlEntity("twixt", "\u226C"),
- HtmlEntity("twoheadleftarrow", "\u219E"),
- HtmlEntity("twoheadrightarrow", "\u21A0"),
- HtmlEntity("uArr", "\u21D1"),
- HtmlEntity("uHar", "\u2963"),
- HtmlEntity("uacute", "\u00FA"),
- HtmlEntity("uarr", "\u2191"),
- HtmlEntity("ubrcy", "\u045E"),
- HtmlEntity("ubreve", "\u016D"),
- HtmlEntity("ucirc", "\u00FB"),
- HtmlEntity("ucy", "\u0443"),
- HtmlEntity("udarr", "\u21C5"),
- HtmlEntity("udblac", "\u0171"),
- HtmlEntity("udhar", "\u296E"),
- HtmlEntity("ufisht", "\u297E"),
- HtmlEntity("ufr", x"D835DD32"),
- HtmlEntity("ugrave", "\u00F9"),
- HtmlEntity("uharl", "\u21BF"),
- HtmlEntity("uharr", "\u21BE"),
- HtmlEntity("uhblk", "\u2580"),
- HtmlEntity("ulcorn", "\u231C"),
- HtmlEntity("ulcorner", "\u231C"),
- HtmlEntity("ulcrop", "\u230F"),
- HtmlEntity("ultri", "\u25F8"),
- HtmlEntity("umacr", "\u016B"),
- HtmlEntity("uml", "\u00A8"),
- HtmlEntity("uogon", "\u0173"),
- HtmlEntity("uopf", x"D835DD66"),
- HtmlEntity("uparrow", "\u2191"),
- HtmlEntity("updownarrow", "\u2195"),
- HtmlEntity("upharpoonleft", "\u21BF"),
- HtmlEntity("upharpoonright", "\u21BE"),
- HtmlEntity("uplus", "\u228E"),
- HtmlEntity("upsi", "\u03C5"),
- HtmlEntity("upsih", "\u03D2"),
- HtmlEntity("upsilon", "\u03C5"),
- HtmlEntity("upuparrows", "\u21C8"),
- HtmlEntity("urcorn", "\u231D"),
- HtmlEntity("urcorner", "\u231D"),
- HtmlEntity("urcrop", "\u230E"),
- HtmlEntity("uring", "\u016F"),
- HtmlEntity("urtri", "\u25F9"),
- HtmlEntity("uscr", x"D835DCCA"),
- HtmlEntity("utdot", "\u22F0"),
- HtmlEntity("utilde", "\u0169"),
- HtmlEntity("utri", "\u25B5"),
- HtmlEntity("utrif", "\u25B4"),
- HtmlEntity("uuarr", "\u21C8"),
- HtmlEntity("uuml", "\u00FC"),
- HtmlEntity("uwangle", "\u29A7"),
- HtmlEntity("vArr", "\u21D5"),
- HtmlEntity("vBar", "\u2AE8"),
- HtmlEntity("vBarv", "\u2AE9"),
- HtmlEntity("vDash", "\u22A8"),
- HtmlEntity("vangrt", "\u299C"),
- HtmlEntity("varepsilon", "\u03F5"),
- HtmlEntity("varkappa", "\u03F0"),
- HtmlEntity("varnothing", "\u2205"),
- HtmlEntity("varphi", "\u03D5"),
- HtmlEntity("varpi", "\u03D6"),
- HtmlEntity("varpropto", "\u221D"),
- HtmlEntity("varr", "\u2195"),
- HtmlEntity("varrho", "\u03F1"),
- HtmlEntity("varsigma", "\u03C2"),
- HtmlEntity("varsubsetneq", x"228AFE00"),
- HtmlEntity("varsubsetneqq", x"2ACBFE00"),
- HtmlEntity("varsupsetneq", x"228BFE00"),
- HtmlEntity("varsupsetneqq", x"2ACCFE00"),
- HtmlEntity("vartheta", "\u03D1"),
- HtmlEntity("vartriangleleft", "\u22B2"),
- HtmlEntity("vartriangleright", "\u22B3"),
- HtmlEntity("vcy", "\u0432"),
- HtmlEntity("vdash", "\u22A2"),
- HtmlEntity("vee", "\u2228"),
- HtmlEntity("veebar", "\u22BB"),
- HtmlEntity("veeeq", "\u225A"),
- HtmlEntity("vellip", "\u22EE"),
- HtmlEntity("verbar", "\u007C"),
- HtmlEntity("vert", "\u007C"),
- HtmlEntity("vfr", x"D835DD33"),
- HtmlEntity("vltri", "\u22B2"),
- HtmlEntity("vnsub", x"228220D2"),
- HtmlEntity("vnsup", x"228320D2"),
- HtmlEntity("vopf", x"D835DD67"),
- HtmlEntity("vprop", "\u221D"),
- HtmlEntity("vrtri", "\u22B3"),
- HtmlEntity("vscr", x"D835DCCB"),
- HtmlEntity("vsubnE", x"2ACBFE00"),
- HtmlEntity("vsubne", x"228AFE00"),
- HtmlEntity("vsupnE", x"2ACCFE00"),
- HtmlEntity("vsupne", x"228BFE00"),
- HtmlEntity("vzigzag", "\u299A"),
- HtmlEntity("wcirc", "\u0175"),
- HtmlEntity("wedbar", "\u2A5F"),
- HtmlEntity("wedge", "\u2227"),
- HtmlEntity("wedgeq", "\u2259"),
- HtmlEntity("weierp", "\u2118"),
- HtmlEntity("wfr", x"D835DD34"),
- HtmlEntity("wopf", x"D835DD68"),
- HtmlEntity("wp", "\u2118"),
- HtmlEntity("wr", "\u2240"),
- HtmlEntity("wreath", "\u2240"),
- HtmlEntity("wscr", x"D835DCCC"),
- HtmlEntity("xcap", "\u22C2"),
- HtmlEntity("xcirc", "\u25EF"),
- HtmlEntity("xcup", "\u22C3"),
- HtmlEntity("xdtri", "\u25BD"),
- HtmlEntity("xfr", x"D835DD35"),
- HtmlEntity("xhArr", "\u27FA"),
- HtmlEntity("xharr", "\u27F7"),
- HtmlEntity("xi", "\u03BE"),
- HtmlEntity("xlArr", "\u27F8"),
- HtmlEntity("xlarr", "\u27F5"),
- HtmlEntity("xmap", "\u27FC"),
- HtmlEntity("xnis", "\u22FB"),
- HtmlEntity("xodot", "\u2A00"),
- HtmlEntity("xopf", x"D835DD69"),
- HtmlEntity("xoplus", "\u2A01"),
- HtmlEntity("xotime", "\u2A02"),
- HtmlEntity("xrArr", "\u27F9"),
- HtmlEntity("xrarr", "\u27F6"),
- HtmlEntity("xscr", x"D835DCCD"),
- HtmlEntity("xsqcup", "\u2A06"),
- HtmlEntity("xuplus", "\u2A04"),
- HtmlEntity("xutri", "\u25B3"),
- HtmlEntity("xvee", "\u22C1"),
- HtmlEntity("xwedge", "\u22C0"),
- HtmlEntity("yacute", "\u00FD"),
- HtmlEntity("yacy", "\u044F"),
- HtmlEntity("ycirc", "\u0177"),
- HtmlEntity("ycy", "\u044B"),
- HtmlEntity("yen", "\u00A5"),
- HtmlEntity("yfr", x"D835DD36"),
- HtmlEntity("yicy", "\u0457"),
- HtmlEntity("yopf", x"D835DD6A"),
- HtmlEntity("yscr", x"D835DCCE"),
- HtmlEntity("yucy", "\u044E"),
- HtmlEntity("yuml", "\u00FF"),
- HtmlEntity("zacute", "\u017A"),
- HtmlEntity("zcaron", "\u017E"),
- HtmlEntity("zcy", "\u0437"),
- HtmlEntity("zdot", "\u017C"),
- HtmlEntity("zeetrf", "\u2128"),
- HtmlEntity("zeta", "\u03B6"),
- HtmlEntity("zfr", x"D835DD37"),
- HtmlEntity("zhcy", "\u0436"),
- HtmlEntity("zigrarr", "\u21DD"),
- HtmlEntity("zopf", x"D835DD6B"),
- HtmlEntity("zscr", x"D835DCCF"),
- HtmlEntity("zwj", "\u200D"),
- HtmlEntity("zwnj", "\u200C")
-];
-
diff --git a/std/d/lexer.d b/std/d/lexer.d
deleted file mode 100644
index 1ad3ebe..0000000
--- a/std/d/lexer.d
+++ /dev/null
@@ -1,2188 +0,0 @@
-module std.d.lexer;
-
-import std.typecons;
-import std.typetuple;
-import std.array;
-import std.algorithm;
-import std.range;
-import std.lexer;
-
-private enum operators = [
- ",", ".", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=",
- "!>", "!>=", "$", "%", "%=", "&", "&&", "&=", "(", ")", "*", "*=", "+", "++",
- "+=", "-", "--", "-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=",
- "==", "=>", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "]", "^",
- "^=", "^^", "^^=", "{", "|", "|=", "||", "}", "~", "~="
-];
-
-private enum keywords = [
- "abstract", "alias", "align", "asm", "assert", "auto", "body", "bool",
- "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat",
- "char", "class", "const", "continue", "creal", "dchar", "debug", "default",
- "delegate", "delete", "deprecated", "do", "double", "else", "enum",
- "export", "extern", "false", "final", "finally", "float", "for", "foreach",
- "foreach_reverse", "function", "goto", "idouble", "if", "ifloat",
- "immutable", "import", "in", "inout", "int", "interface", "invariant",
- "ireal", "is", "lazy", "long", "macro", "mixin", "module", "new", "nothrow",
- "null", "out", "override", "package", "pragma", "private", "protected",
- "public", "pure", "real", "ref", "return", "scope", "shared", "short",
- "static", "struct", "super", "switch", "synchronized", "template", "this",
- "throw", "true", "try", "typedef", "typeid", "typeof", "ubyte", "ucent",
- "uint", "ulong", "union", "unittest", "ushort", "version", "virtual", "void",
- "volatile", "wchar", "while", "with", "__DATE__", "__EOF__", "__FILE__",
- "__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters",
- "__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits", "__vector",
- "__VENDOR__", "__VERSION__"
-];
-
-private enum dynamicTokens = [
- "specialTokenSequence", "comment", "identifier", "scriptLine",
- "whitespace", "doubleLiteral", "floatLiteral", "idoubleLiteral",
- "ifloatLiteral", "intLiteral", "longLiteral", "realLiteral",
- "irealLiteral", "uintLiteral", "ulongLiteral", "characterLiteral",
- "dstringLiteral", "stringLiteral", "wstringLiteral"
-];
-
-private enum pseudoTokenHandlers = [
- "\"", "lexStringLiteral",
- "`", "lexWysiwygString",
- "//", "lexSlashSlashComment",
- "/*", "lexSlashStarComment",
- "/+", "lexSlashPlusComment",
- ".", "lexDot",
- "'", "lexCharacterLiteral",
- "0", "lexNumber",
- "1", "lexDecimal",
- "2", "lexDecimal",
- "3", "lexDecimal",
- "4", "lexDecimal",
- "5", "lexDecimal",
- "6", "lexDecimal",
- "7", "lexDecimal",
- "8", "lexDecimal",
- "9", "lexDecimal",
- "q\"", "lexDelimitedString",
- "q{", "lexTokenString",
- "r\"", "lexWysiwygString",
- "x\"", "lexHexString",
- " ", "lexWhitespace",
- "\t", "lexWhitespace",
- "\r", "lexWhitespace",
- "\n", "lexWhitespace",
- "\u2028", "lexLongNewline",
- "\u2029", "lexLongNewline",
- "#!", "lexScriptLine",
- "#line", "lexSpecialTokenSequence"
-];
-
-public alias IdType = TokenIdType!(operators, dynamicTokens, keywords);
-public alias str = tokenStringRepresentation!(IdType, operators, dynamicTokens, keywords);
-public template tok(string token)
-{
- alias tok = TokenId!(IdType, operators, dynamicTokens, keywords, token);
-}
-private enum extraFields = q{
- string comment;
-
- int opCmp(size_t i) const pure nothrow @safe {
- if (index < i) return -1;
- if (index > i) return 1;
- return 0;
- }
-};
-public alias Token = std.lexer.TokenStructure!(IdType, extraFields);
-
-/**
- * Configure string lexing behavior
- */
-public enum StringBehavior : ubyte
-{
- /// Do not include quote characters, process escape sequences
- compiler = 0b0000_0000,
- /// Opening quotes, closing quotes, and string suffixes are included in the
- /// string token
- includeQuoteChars = 0b0000_0001,
- /// String escape sequences are not replaced
- notEscaped = 0b0000_0010,
- /// Not modified at all. Useful for formatters or highlighters
- source = includeQuoteChars | notEscaped
-}
-
-/**
- * Configure whitespace handling behavior
- */
-public enum WhitespaceBehavior : ubyte
-{
- /// Whitespace is skipped
- skip,
- /// 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
- */
-public enum CommentBehavior : ubyte
-{
- /// Comments are attached to the non-whitespace token that follows them
- attach,
- /// Comments are tokens, and can be returned by calls to the token range's front()
- include
-}
-
-public struct LexerConfig
-{
- string fileName;
- StringBehavior stringBehavior;
- WhitespaceBehavior whitespaceBehavior;
- CommentBehavior commentBehavior;
- SpecialTokenBehavior specialTokenBehavior;
-}
-
-public bool isBasicType(IdType type) nothrow pure @safe
-{
- switch (type)
- {
- case tok!"int":
- case tok!"uint":
- case tok!"double":
- case tok!"idouble":
- case tok!"float":
- case tok!"ifloat":
- case tok!"short":
- case tok!"ushort":
- case tok!"long":
- case tok!"ulong":
- case tok!"char":
- case tok!"wchar":
- case tok!"dchar":
- case tok!"bool":
- case tok!"void":
- case tok!"cent":
- case tok!"ucent":
- case tok!"real":
- case tok!"ireal":
- case tok!"byte":
- case tok!"ubyte":
- case tok!"cdouble":
- case tok!"cfloat":
- case tok!"creal":
- return true;
- default:
- return false;
- }
-}
-
-public bool isNumberLiteral(IdType type) nothrow pure @safe
-{
- switch (type)
- {
- case tok!"doubleLiteral":
- case tok!"floatLiteral":
- case tok!"idoubleLiteral":
- case tok!"ifloatLiteral":
- case tok!"intLiteral":
- case tok!"longLiteral":
- case tok!"realLiteral":
- case tok!"irealLiteral":
- case tok!"uintLiteral":
- case tok!"ulongLiteral":
- return true;
- default:
- return false;
- }
-}
-
-public bool isOperator(IdType type) nothrow pure @safe
-{
- switch (type)
- {
- case tok!",":
- case tok!".":
- case tok!"..":
- case tok!"...":
- case tok!"/":
- case tok!"/=":
- case tok!"!":
- case tok!"!<":
- case tok!"!<=":
- case tok!"!<>":
- case tok!"!<>=":
- case tok!"!=":
- case tok!"!>":
- case tok!"!>=":
- case tok!"$":
- case tok!"%":
- case tok!"%=":
- case tok!"&":
- case tok!"&&":
- case tok!"&=":
- case tok!"(":
- case tok!")":
- case tok!"*":
- case tok!"*=":
- case tok!"+":
- case tok!"++":
- case tok!"+=":
- case tok!"-":
- case tok!"--":
- case tok!"-=":
- case tok!":":
- case tok!";":
- case tok!"<":
- case tok!"<<":
- case tok!"<<=":
- case tok!"<=":
- case tok!"<>":
- case tok!"<>=":
- case tok!"=":
- case tok!"==":
- case tok!"=>":
- case tok!">":
- case tok!">=":
- case tok!">>":
- case tok!">>=":
- case tok!">>>":
- case tok!">>>=":
- case tok!"?":
- case tok!"@":
- case tok!"[":
- case tok!"]":
- case tok!"^":
- case tok!"^=":
- case tok!"^^":
- case tok!"^^=":
- case tok!"{":
- case tok!"|":
- case tok!"|=":
- case tok!"||":
- case tok!"}":
- case tok!"~":
- case tok!"~=":
- return true;
- default:
- return false;
- }
-}
-
-public bool isKeyword(IdType type) pure nothrow @safe
-{
- switch (type)
- {
- case tok!"abstract":
- case tok!"alias":
- case tok!"align":
- case tok!"asm":
- case tok!"assert":
- case tok!"auto":
- case tok!"body":
- case tok!"break":
- case tok!"case":
- case tok!"cast":
- case tok!"catch":
- case tok!"class":
- case tok!"const":
- case tok!"continue":
- case tok!"debug":
- case tok!"default":
- case tok!"delegate":
- case tok!"delete":
- case tok!"deprecated":
- case tok!"do":
- case tok!"else":
- case tok!"enum":
- case tok!"export":
- case tok!"extern":
- case tok!"false":
- case tok!"final":
- case tok!"finally":
- case tok!"for":
- case tok!"foreach":
- case tok!"foreach_reverse":
- case tok!"function":
- case tok!"goto":
- case tok!"if":
- case tok!"immutable":
- case tok!"import":
- case tok!"in":
- case tok!"inout":
- case tok!"interface":
- case tok!"invariant":
- case tok!"is":
- case tok!"lazy":
- case tok!"macro":
- case tok!"mixin":
- case tok!"module":
- case tok!"new":
- case tok!"nothrow":
- case tok!"null":
- case tok!"out":
- case tok!"override":
- case tok!"package":
- case tok!"pragma":
- case tok!"private":
- case tok!"protected":
- case tok!"public":
- case tok!"pure":
- case tok!"ref":
- case tok!"return":
- case tok!"scope":
- case tok!"shared":
- case tok!"static":
- case tok!"struct":
- case tok!"super":
- case tok!"switch":
- case tok!"synchronized":
- case tok!"template":
- case tok!"this":
- case tok!"throw":
- case tok!"true":
- case tok!"try":
- case tok!"typedef":
- case tok!"typeid":
- case tok!"typeof":
- case tok!"union":
- case tok!"unittest":
- case tok!"version":
- case tok!"volatile":
- case tok!"while":
- case tok!"with":
- case tok!"__DATE__":
- case tok!"__EOF__":
- case tok!"__FILE__":
- case tok!"__FUNCTION__":
- case tok!"__gshared":
- case tok!"__LINE__":
- case tok!"__MODULE__":
- case tok!"__parameters":
- case tok!"__PRETTY_FUNCTION__":
- case tok!"__TIME__":
- case tok!"__TIMESTAMP__":
- case tok!"__traits":
- case tok!"__vector":
- case tok!"__VENDOR__":
- case tok!"__VERSION__":
- return true;
- default:
- return false;
- }
-}
-
-public bool isStringLiteral(IdType type) pure nothrow @safe
-{
- switch (type)
- {
- case tok!"dstringLiteral":
- case tok!"stringLiteral":
- case tok!"wstringLiteral":
- return true;
- default:
- return false;
- }
-}
-
-public bool isProtection(IdType type) pure nothrow @safe
-{
- switch (type)
- {
- case tok!"export":
- case tok!"package":
- case tok!"private":
- case tok!"public":
- case tok!"protected":
- return true;
- default:
- return false;
- }
-}
-
-public struct DLexer
-{
- import core.vararg;
-
- mixin Lexer!(Token, lexIdentifier, isSeparating, operators, dynamicTokens,
- keywords, pseudoTokenHandlers);
-
- @disable this();
-
- this(ubyte[] range, const LexerConfig config, StringCache* cache)
- {
- auto r = (range.length >= 3 && range[0] == 0xef && range[1] == 0xbb && range[2] == 0xbf)
- ? range[3 .. $] : range;
- this.range = LexerRange(r);
- this.config = config;
- this.cache = cache;
- popFront();
- }
-
- private static bool isDocComment(string comment) pure nothrow @safe
- {
- return comment.length >= 3 && (comment[0 .. 3] == "///"
- || comment[0 .. 3] == "/++" || comment[0 .. 3] == "/**");
- }
-
- public void popFront() pure
- {
- _popFront();
- string comment;
- switch (front.type)
- {
- case tok!"comment":
- if (config.commentBehavior == CommentBehavior.attach)
- {
- import std.string;
- if (isDocComment(front.text))
- {
- comment = comment is null
- ? front.text
- : format("%s\n%s", comment, front.text);
- }
- 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":
- if (config.whitespaceBehavior == WhitespaceBehavior.skip)
- {
- 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:
- break;
- }
- _front.comment = comment;
- }
-
-
- bool isWhitespace() pure /*const*/ nothrow
- {
- switch (range.front)
- {
- case ' ':
- case '\r':
- case '\n':
- case '\t':
- return true;
- case 0xe2:
- auto peek = range.peek(2);
- return peek.length == 2
- && peek[0] == 0x80
- && (peek[1] == 0xa8 || peek[1] == 0xa9);
- default:
- return false;
- }
- }
-
- void popFrontWhitespaceAware() pure nothrow
- {
- switch (range.front)
- {
- case '\r':
- range.popFront();
- if (!range.empty && range.front == '\n')
- {
- range.popFront();
- range.incrementLine();
- }
- else
- range.incrementLine();
- return;
- case '\n':
- range.popFront();
- range.incrementLine();
- return;
- case 0xe2:
- auto lookahead = range.peek(3);
- if (lookahead.length == 3 && lookahead[1] == 0x80
- && (lookahead[2] == 0xa8 || lookahead[2] == 0xa9))
- {
- range.popFront();
- range.popFront();
- range.popFront();
- range.incrementLine();
- return;
- }
- else
- {
- range.popFront();
- return;
- }
- default:
- range.popFront();
- return;
- }
- }
-
- Token lexWhitespace() pure nothrow
- {
- mixin (tokenStart);
- version (none) while (index + 16 <= range.bytes.length)
- {
- ulong startAddr = (cast(ulong) range.bytes.ptr) + index;
- enum space = (cast(ulong) ' ') * 0x0101010101010101L;
- enum tab = (cast(ulong) '\t') * 0x0101010101010101L;
- enum cr = (cast(ulong) '\r') * 0x0101010101010101L;
- enum lf = (cast(ulong) '\n') * 0x0101010101010101L;
- ulong charsSkipped;
- ulong lineIncrement;
- asm
- {
- mov R10, space;
- mov R11, tab;
- mov R12, cr;
- mov R13, lf;
- mov R8, startAddr;
- movdqu XMM0, [R8];
-
- mov R9, line;
-
- // space pattern
- movq XMM1, R10;
- shufpd XMM1, XMM1, 0;
- pcmpeqb XMM1, XMM0;
-
- // tab pattern
- movq XMM2, R11;
- shufpd XMM2, XMM2, 0;
- pcmpeqb XMM2, XMM0;
-
- // CR pattern
- movq XMM3, R12;
- shufpd XMM3, XMM3, 0;
- pcmpeqb XMM3, XMM0;
-
- // LF pattern
- movq XMM4, R13;
- shufpd XMM4, XMM4, 0;
- pcmpeqb XMM4, XMM0;
-
- // Bit mask-of newlines to r10
- pmovmskb R10, XMM4;
-
- // and the masks together
- por XMM1, XMM2;
- por XMM1, XMM3;
- por XMM1, XMM4;
- pmovmskb RAX, XMM1;
- not RAX;
- bsf RCX, RAX;
- mov charsSkipped, RCX;
-
- mov RBX, 1;
- inc CL;
- shl RBX, CL;
- sub RBX, 1;
- and R10, RBX;
- popcnt R10, R10;
- mov lineIncrement, R10;
- }
- range.incrementLine(lineIncrement);
- range.popFrontN(charsSkipped);
- if (charsSkipped < 16)
- goto end;
- index += 16;
- }
- loop: do
- {
- switch (range.front)
- {
- case '\r':
- range.popFront();
- if (!range.empty && range.front == '\n')
- range.popFront();
- range.incrementLine();
- break;
- case '\n':
- range.popFront();
- range.incrementLine();
- break;
- case ' ':
- case '\t':
- range.popFront();
- break;
- case 0xe2:
- auto lookahead = range.peek(3);
- if (lookahead.length != 3)
- break loop;
- if (lookahead[1] != 0x80)
- break loop;
- if (lookahead[2] == 0xa8 || lookahead[2] == 0xa9)
- {
- range.popFront();
- range.popFront();
- range.popFront();
- range.incrementLine();
- break;
- }
- break loop;
- default:
- break loop;
- }
- } while (!range.empty);
- end:
- string text = config.whitespaceBehavior == WhitespaceBehavior.skip
- ? null : cache.intern(range.slice(mark));
- return Token(tok!"whitespace", text, line, column, index);
- }
-
- Token lexNumber() pure nothrow
- {
- mixin (tokenStart);
- if (range.front == '0' && range.canPeek(1))
- {
- auto ahead = range.peek(1)[1];
- switch (ahead)
- {
- case 'x':
- case 'X':
- range.popFront();
- range.popFront();
- return lexHex(mark, line, column, index);
- case 'b':
- case 'B':
- range.popFront();
- range.popFront();
- return lexBinary(mark, line, column, index);
- default:
- return lexDecimal(mark, line, column, index);
- }
- }
- else
- return lexDecimal(mark, line, column, index);
- }
-
- Token lexHex() pure nothrow
- {
- mixin (tokenStart);
- return lexHex(mark, line, column, index);
- }
-
- Token lexHex(size_t mark, size_t line, size_t column, size_t index) pure nothrow
- {
- IdType type = tok!"intLiteral";
- bool foundDot;
- hexLoop: while (!range.empty)
- {
- switch (range.front)
- {
- case 'a': .. case 'f':
- case 'A': .. case 'F':
- case '0': .. case '9':
- case '_':
- range.popFront();
- break;
- case 'u':
- case 'U':
- lexIntSuffix(type);
- break hexLoop;
- case 'i':
- if (foundDot)
- lexFloatSuffix(type);
- break hexLoop;
- case 'L':
- if (foundDot)
- lexFloatSuffix(type);
- else
- lexIntSuffix(type);
- break hexLoop;
- case 'p':
- case 'P':
- lexExponent(type);
- break hexLoop;
- case '.':
- if (foundDot || !range.canPeek(1) || range.peekAt(1) == '.')
- break hexLoop;
- else
- {
- // The following bit of silliness tries to tell the
- // difference between "int dot identifier" and
- // "double identifier".
- if (range.canPeek(1))
- {
- switch (range.peekAt(1))
- {
- case '0': .. case '9':
- case 'A': .. case 'F':
- case 'a': .. case 'f':
- goto doubleLiteral;
- default:
- break hexLoop;
- }
- }
- else
- {
- doubleLiteral:
- range.popFront();
- foundDot = true;
- type = tok!"doubleLiteral";
- }
- }
- break;
- default:
- break hexLoop;
- }
- }
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexBinary() pure nothrow
- {
- mixin (tokenStart);
- return lexBinary(mark, line, column, index);
- }
-
- Token lexBinary(size_t mark, size_t line, size_t column, size_t index) pure nothrow
- {
- IdType type = tok!"intLiteral";
- binaryLoop: while (!range.empty)
- {
- switch (range.front)
- {
- case '0':
- case '1':
- case '_':
- range.popFront();
- break;
- case 'u':
- case 'U':
- case 'L':
- lexIntSuffix(type);
- break binaryLoop;
- default:
- break binaryLoop;
- }
- }
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexDecimal() pure nothrow
- {
- mixin (tokenStart);
- return lexDecimal(mark, line, column, index);
- }
-
- Token lexDecimal(size_t mark, size_t line, size_t column, size_t index) pure nothrow
- {
- bool foundDot = range.front == '.';
- IdType type = tok!"intLiteral";
- if (foundDot)
- {
- range.popFront();
- type = tok!"doubleLiteral";
- }
-
- decimalLoop: while (!range.empty)
- {
- switch (range.front)
- {
- case '0': .. case '9':
- case '_':
- range.popFront();
- break;
- case 'u':
- case 'U':
- if (!foundDot)
- lexIntSuffix(type);
- break decimalLoop;
- case 'i':
- lexFloatSuffix(type);
- break decimalLoop;
- case 'L':
- if (foundDot)
- lexFloatSuffix(type);
- else
- lexIntSuffix(type);
- break decimalLoop;
- case 'f':
- case 'F':
- lexFloatSuffix(type);
- break decimalLoop;
- case 'e':
- case 'E':
- lexExponent(type);
- break decimalLoop;
- case '.':
- if (foundDot || !range.canPeek(1) || range.peekAt(1) == '.')
- break decimalLoop;
- else
- {
- // The following bit of silliness tries to tell the
- // difference between "int dot identifier" and
- // "double identifier".
- if (range.canPeek(1))
- {
- auto ch = range.peekAt(1);
- if (ch <= 0x2f
- || (ch >= '0' && ch <= '9')
- || (ch >= ':' && ch <= '@')
- || (ch >= '[' && ch <= '^')
- || (ch >= '{' && ch <= '~')
- || ch == '`' || ch == '_')
- {
- goto doubleLiteral;
- }
- else
- break decimalLoop;
- }
- else
- {
- doubleLiteral:
- range.popFront();
- foundDot = true;
- type = tok!"doubleLiteral";
- }
- }
- break;
- default:
- break decimalLoop;
- }
- }
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- void lexIntSuffix(ref IdType type) pure nothrow @safe
- {
- bool secondPass;
- if (range.front == 'u' || range.front == 'U')
- {
- U:
- if (type == tok!"intLiteral")
- type = tok!"uintLiteral";
- else
- type = tok!"ulongLiteral";
- range.popFront();
- if (secondPass)
- return;
- if (range.front == 'L' || range.front == 'l')
- goto L;
- return;
- }
- if (range.front == 'L' || range.front == 'l')
- {
- L:
- if (type == tok!"uintLiteral")
- type = tok!"ulongLiteral";
- else
- type = tok!"longLiteral";
- range.popFront();
- if (range.front == 'U' || range.front == 'u')
- {
- secondPass = true;
- goto U;
- }
- return;
- }
- }
-
- void lexFloatSuffix(ref IdType type) pure nothrow @safe
- {
- switch (range.front)
- {
- case 'L':
- range.popFront();
- type = tok!"doubleLiteral";
- break;
- case 'f':
- case 'F':
- range.popFront();
- type = tok!"floatLiteral";
- break;
- default:
- break;
- }
- if (!range.empty && range.front == 'i')
- {
- warning("Complex number literals are deprecated");
- range.popFront();
- if (type == tok!"floatLiteral")
- type = tok!"ifloatLiteral";
- else
- type = tok!"idoubleLiteral";
- }
- }
-
- void lexExponent(ref IdType type) pure nothrow @safe
- {
- range.popFront();
- bool foundSign = false;
- bool foundDigit = false;
- while (!range.empty)
- {
- switch (range.front)
- {
- case '-':
- case '+':
- if (foundSign)
- {
- if (!foundDigit)
- error("Expected an exponent");
- return;
- }
- foundSign = true;
- range.popFront();
- break;
- case '0': .. case '9':
- case '_':
- foundDigit = true;
- range.popFront();
- break;
- case 'L':
- case 'f':
- case 'F':
- case 'i':
- lexFloatSuffix(type);
- return;
- default:
- if (!foundDigit)
- error("Expected an exponent");
- return;
- }
- }
- }
-
- Token lexScriptLine() pure
- {
- mixin (tokenStart);
- while (!range.empty && !isNewline)
- range.popFront();
- return Token(tok!"scriptLine", cache.intern(range.slice(mark)),
- line, column, index);
- }
-
- Token lexSpecialTokenSequence() pure
- {
- mixin (tokenStart);
- while (!range.empty && !isNewline)
- range.popFront();
- return Token(tok!"specialTokenSequence", cache.intern(range.slice(mark)),
- line, column, index);
- }
-
- Token lexSlashStarComment() pure
- {
- mixin (tokenStart);
- IdType type = tok!"comment";
- range.popFrontN(2);
- version (none) while (range.index + 16 <= range.bytes.length)
- {
- ulong startAddress = cast(ulong) range.bytes.ptr + range.index;
- enum slash = (cast(ulong) '/') * 0x0101010101010101L;
- enum star = (cast(ulong) '*') * 0x0101010101010101L;
- enum lf = (cast(ulong) '\n') * 0x0101010101010101L;
- ulong charsSkipped;
- ulong newlineCount;
- bool done;
- asm
- {
- mov RAX, startAddress;
- movdqu XMM0, [RAX];
-
- mov R10, lf;
- movq XMM2, R10;
- shufpd XMM2, XMM2, 0;
- pcmpeqb XMM2, XMM0;
- pmovmskb R15, XMM2;
-
- mov R10, star;
- movq XMM3, R10;
- shufpd XMM3, XMM3, 0;
- pcmpeqb XMM3, XMM0;
- pmovmskb R8, XMM3;
-
- mov R10, slash;
- movq XMM4, R10;
- shufpd XMM4, XMM4, 0;
- pcmpeqb XMM4, XMM0;
- pmovmskb R9, XMM4;
- loop:
- cmp R8, 0;
- je notFound;
- cmp R9, 0;
- je notFound;
- bsf RAX, R8; // stIndex
- bsf RBX, R9; // slIndex
- mov RDX, RAX;
- inc RDX;
- cmp RDX, RBX;
- je found;
- cmp RAX, RBX;
- jae maskSlash;
- maskStar:
- mov RCX, RAX;
- mov R10, 1;
- shl R10, CL;
- xor R8, R10;
- jmp loop;
- maskSlash:
- mov RCX, RBX;
- mov R10, 1;
- shl R10, CL;
- xor R9, R10;
- jmp loop;
- notFound:
- mov R14, 16;
- mov charsSkipped, R14;
- popcnt R14, R15;
- mov newlineCount, R14;
- jmp asmEnd;
- found:
- inc RBX;
- mov charsSkipped, RBX;
- mov RAX, 1;
- mov done, AL;
- mov RCX, RBX;
- mov RBX, 1;
- shl RBX, CL;
- dec RBX;
- and R15, RBX;
- popcnt R14, R15;
- mov newlineCount, R14;
- asmEnd:
- nop;
- }
- range.popFrontN(charsSkipped);
- range.incrementLine(newlineCount);
- if (done)
- goto end;
- }
- while (!range.empty)
- {
- if (range.front == '*')
- {
- range.popFront();
- if (!range.empty && range.front == '/')
- {
- range.popFront();
- break;
- }
- }
- else
- popFrontWhitespaceAware();
- }
- end:
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexSlashSlashComment() pure nothrow
- {
- mixin (tokenStart);
- IdType type = tok!"comment";
- range.popFrontN(2);
- version (none) while (range.index + 16 <= range.bytes.length)
- {
- ulong startAddress = cast(ulong) range.bytes.ptr + range.index;
- enum cr = (cast(ulong) '\r') * 0x0101010101010101L;
- enum lf = (cast(ulong) '\n') * 0x0101010101010101L;
- ulong charsSkipped;
- asm
- {
- mov RAX, startAddress;
- movdqu XMM0, [RAX];
-
- mov R10, cr;
- movq XMM1, R10;
- shufpd XMM1, XMM1, 0;
- pcmpeqb XMM1, XMM0;
-
- mov R10, lf;
- movq XMM2, R10;
- shufpd XMM2, XMM2, 0;
- pcmpeqb XMM2, XMM0;
-
- por XMM1, XMM2;
- pmovmskb RBX, XMM1;
- bsf RCX, RBX;
- mov RDX, 16;
- cmp RBX, 0;
- cmove RCX, RDX;
- mov charsSkipped, RCX;
-
- }
- if (charsSkipped < 16)
- {
- index += charsSkipped;
- column += charsSkipped;
- range.popFrontN(charsSkipped);
- goto end;
- }
- else
- {
- assert (charsSkipped == 16);
- index += 16;
- column += 16;
- range.popFrontN(16);
- }
- }
- while (!range.empty)
- {
- if (range.front == '\r' || range.front == '\n')
- break;
- range.popFront();
- }
- end:
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexSlashPlusComment() pure nothrow
- {
- mixin (tokenStart);
- IdType type = tok!"comment";
- range.popFront();
- range.popFront();
- int depth = 1;
- while (depth > 0 && !range.empty)
- {
- if (range.front == '+')
- {
- range.popFront();
- if (!range.empty && range.front == '/')
- {
- range.popFront();
- depth--;
- }
- }
- else if (range.front == '/')
- {
- range.popFront();
- if (!range.empty && range.front == '+')
- {
- range.popFront();
- depth++;
- }
- }
- else
- popFrontWhitespaceAware();
- }
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexStringLiteral() pure nothrow
- {
- mixin (tokenStart);
- range.popFront();
- while (true)
- {
- if (range.empty)
- {
- error("Error: unterminated string literal");
- return Token();
- }
- else if (range.front == '"')
- {
- range.popFront();
- break;
- }
- else if (range.front == '\\')
- {
- lexEscapeSequence();
- }
- else
- popFrontWhitespaceAware();
- }
- IdType type = tok!"stringLiteral";
- lexStringSuffix(type);
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- Token lexWysiwygString() pure nothrow
- {
- mixin (tokenStart);
- IdType type = tok!"stringLiteral";
- bool backtick = range.front == '`';
- if (backtick)
- {
- range.popFront();
- while (true)
- {
- if (range.empty)
- {
- error("Error: unterminated string literal");
- return Token(tok!"");
- }
- else if (range.front == '`')
- {
- range.popFront();
- break;
- }
- else
- popFrontWhitespaceAware();
- }
- }
- else
- {
- range.popFront();
- if (range.empty)
- {
- error("Error: unterminated string literal");
- return Token(tok!"");
- }
- range.popFront();
- while (true)
- {
- if (range.empty)
- {
- error("Error: unterminated string literal");
- return Token(tok!"");
- }
- else if (range.front == '"')
- {
- range.popFront();
- break;
- }
- else
- popFrontWhitespaceAware();
- }
- }
- lexStringSuffix(type);
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- void lexStringSuffix(ref IdType type) pure nothrow
- {
- if (range.empty)
- type = tok!"stringLiteral";
- else
- {
- switch (range.front)
- {
- case 'w': range.popFront(); type = tok!"wstringLiteral"; break;
- case 'd': range.popFront(); type = tok!"dstringLiteral"; break;
- case 'c': range.popFront(); type = tok!"stringLiteral"; break;
- default: type = tok!"stringLiteral"; break;
- }
- }
- }
-
- Token lexDelimitedString() pure nothrow
- {
- import std.traits;
- mixin (tokenStart);
- range.popFront();
- range.popFront();
- ubyte open;
- ubyte close;
- switch (range.front)
- {
- case '<':
- open = '<';
- close = '>';
- range.popFront();
- return lexNormalDelimitedString(mark, line, column, index, open, close);
- case '{':
- open = '{';
- close = '}';
- range.popFront();
- return lexNormalDelimitedString(mark, line, column, index, open, close);
- case '[':
- open = '[';
- close = ']';
- range.popFront();
- return lexNormalDelimitedString(mark, line, column, index, open, close);
- case '(':
- open = '(';
- close = ')';
- range.popFront();
- return lexNormalDelimitedString(mark, line, column, index, open, close);
- default:
- return lexHeredocString(mark, line, column, index);
- }
- }
-
- Token lexNormalDelimitedString(size_t mark, size_t line, size_t column,
- size_t index, ubyte open, ubyte close)
- pure nothrow
- {
- int depth = 1;
- while (!range.empty && depth > 0)
- {
- if (range.front == open)
- {
- depth++;
- range.popFront();
- }
- else if (range.front == close)
- {
- depth--;
- range.popFront();
- if (depth <= 0)
- {
- if (range.front == '"')
- range.popFront();
- else
- {
- error("Error: \" expected to end delimited string literal");
- return Token(tok!"");
- }
- }
- }
- else
- popFrontWhitespaceAware();
- }
- IdType type = tok!"stringLiteral";
- lexStringSuffix(type);
- return Token(type, cache.intern(range.slice(mark)), line, column, index);
- }
-
- Token lexHeredocString(size_t mark, size_t line, size_t column, size_t index)
- pure nothrow
- {
- import std.regex;
- Token ident = lexIdentifier();
- if (isNewline())
- popFrontWhitespaceAware();
- else
- error("Newline expected");
- while (!range.empty)
- {
- if (isNewline())
- {
- popFrontWhitespaceAware();
- if (!range.canPeek(ident.text.length))
- {
- error(ident.text ~ " expected");
- break;
- }
- if (range.peek(ident.text.length - 1) == ident.text)
- {
- range.popFrontN(ident.text.length);
- break;
- }
- }
- else
- range.popFront();
- }
- if (!range.empty() && range.front == '"')
- range.popFront();
- else
- error(`" expected`);
- IdType type = tok!"stringLiteral";
- lexStringSuffix(type);
- return Token(type, cache.intern(range.slice(mark)), line, column, index);
- }
-
- Token lexTokenString() pure
- {
- mixin (tokenStart);
- assert (range.front == 'q');
- range.popFront();
- assert (range.front == '{');
- range.popFront();
- auto app = appender!string();
- app.put("q{");
- int depth = 1;
-
- LexerConfig c = config;
- scope(exit) config = c;
- config.whitespaceBehavior = WhitespaceBehavior.include;
- config.stringBehavior = StringBehavior.source;
- config.commentBehavior = CommentBehavior.include;
-
- _front = advance();
- while (depth > 0 && !empty)
- {
- auto t = front();
- if (t.text is null)
- app.put(str(t.type));
- else
- app.put(t.text);
- if (t.type == tok!"}")
- {
- depth--;
- if (depth > 0)
- popFront();
- }
- else if (t.type == tok!"{")
- {
- depth++;
- popFront();
- }
- else
- popFront();
- }
- IdType type = tok!"stringLiteral";
- lexStringSuffix(type);
- return Token(type, cache.intern(cast(const(ubyte)[]) app.data), line,
- column, index);
- }
-
- Token lexHexString() pure nothrow
- {
- mixin (tokenStart);
- range.popFront();
- range.popFront();
-
- loop: while (true)
- {
- if (range.empty)
- {
- error("Error: unterminated hex string literal");
- return Token();
- }
- else if (isWhitespace())
- popFrontWhitespaceAware();
- else switch (range.front)
- {
- case '0': .. case '9':
- case 'A': .. case 'F':
- case 'a': .. case 'f':
- range.popFront();
- break;
- case '"':
- range.popFront();
- break loop;
- default:
- error("Error: invalid character in hex string");
- return Token();
- }
- }
-
- IdType type = tok!"stringLiteral";
- lexStringSuffix(type);
- return Token(type, cache.intern(range.slice(mark)), line, column,
- index);
- }
-
- bool lexEscapeSequence() pure nothrow
- {
- range.popFront();
- if (range.empty)
- {
- error("Error: non-terminated character escape sequence.");
- return false;
- }
- switch (range.front)
- {
- case '\'':
- case '"':
- case '?':
- case '\\':
- case '0':
- case 'a':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- case 'v':
- range.popFront();
- break;
- case 'x':
- range.popFront();
- foreach (i; 0 .. 2)
- {
- if (range.empty)
- {
- error("Error: 2 hex digits expected.");
- return false;
- }
- switch (range.front)
- {
- case '0': .. case '9':
- case 'a': .. case 'f':
- case 'A': .. case 'F':
- range.popFront();
- break;
- default:
- error("Error: 2 hex digits expected.");
- return false;
- }
- }
- break;
- case '1': .. case '7':
- for (size_t i = 0; i < 3 && !range.empty && range.front >= '0' && range.front <= '7'; i++)
- range.popFront();
- break;
- case 'u':
- range.popFront();
- foreach (i; 0 .. 4)
- {
- if (range.empty)
- {
- error("Error: at least 4 hex digits expected.");
- return false;
- }
- switch (range.front)
- {
- case '0': .. case '9':
- case 'a': .. case 'f':
- case 'A': .. case 'F':
- range.popFront();
- break;
- default:
- error("Error: at least 4 hex digits expected.");
- return false;
- }
- }
- break;
- case 'U':
- range.popFront();
- foreach (i; 0 .. 8)
- {
- if (range.empty)
- {
- error("Error: at least 8 hex digits expected.");
- return false;
- }
- switch (range.front)
- {
- case '0': .. case '9':
- case 'a': .. case 'f':
- case 'A': .. case 'F':
- range.popFront();
- break;
- default:
- error("Error: at least 8 hex digits expected.");
- return false;
- }
- }
- break;
- default:
- while (true)
- {
- if (range.empty)
- {
- error("Error: non-terminated character escape sequence.");
- return false;
- }
- if (range.front == ';')
- {
- range.popFront();
- break;
- }
- else
- range.popFront();
- }
- }
- return true;
- }
-
- Token lexCharacterLiteral() pure nothrow
- {
- mixin (tokenStart);
- range.popFront();
- if (range.front == '\\')
- {
- lexEscapeSequence();
- goto close;
- }
- else if (range.front == '\'')
- {
- range.popFront();
- return Token(tok!"characterLiteral", cache.intern(range.slice(mark)),
- line, column, index);
- }
- else if (range.front & 0x80)
- {
- while (range.front & 0x80)
- range.popFront();
- goto close;
- }
- else
- {
- popFrontWhitespaceAware();
- goto close;
- }
- close:
- if (range.front == '\'')
- {
- range.popFront();
- return Token(tok!"characterLiteral", cache.intern(range.slice(mark)),
- line, column, index);
- }
- else
- {
- error("Error: Expected ' to end character literal");
- return Token();
- }
- }
-
- Token lexIdentifier() pure nothrow
- {
- import std.stdio;
- mixin (tokenStart);
- uint hash = 0;
- if (isSeparating(0) || range.empty)
- {
- error("Invalid identifier");
- range.popFront();
- }
- while (!range.empty && !isSeparating(0))
- {
- hash = StringCache.hashStep(range.front, hash);
- range.popFront();
- }
- return Token(tok!"identifier", cache.intern(range.slice(mark), hash), line,
- column, index);
- }
-
- Token lexDot() pure nothrow
- {
- mixin (tokenStart);
- if (!range.canPeek(1))
- {
- range.popFront();
- return Token(tok!".", null, line, column, index);
- }
- switch (range.peekAt(1))
- {
- case '0': .. case '9':
- return lexNumber();
- case '.':
- range.popFront();
- range.popFront();
- if (!range.empty && range.front == '.')
- {
- range.popFront();
- return Token(tok!"...", null, line, column, index);
- }
- else
- return Token(tok!"..", null, line, column, index);
- default:
- range.popFront();
- return Token(tok!".", null, line, column, index);
- }
- }
-
- Token lexLongNewline() pure nothrow
- {
- mixin (tokenStart);
- range.popFront();
- range.popFront();
- range.popFront();
- range.incrementLine();
- return Token(tok!"whitespace", cache.intern(range.slice(mark)), line,
- column, index);
- }
-
- bool isNewline() pure @safe nothrow
- {
- if (range.front == '\n') return true;
- if (range.front == '\r') return true;
- return (range.front & 0x80) && range.canPeek(2)
- && (range.peek(2) == "\u2028" || range.peek(2) == "\u2029");
- }
-
- bool isSeparating(size_t offset) pure nothrow @safe
- {
- if (!range.canPeek(offset)) return true;
- auto c = range.peekAt(offset);
- if (c >= 'A' && c <= 'Z') return false;
- if (c >= 'a' && c <= 'z') return false;
- if (c <= 0x2f) return true;
- if (c >= ':' && c <= '@') return true;
- if (c >= '[' && c <= '^') return true;
- if (c >= '{' && c <= '~') return true;
- if (c == '`') return true;
- if (c & 0x80)
- {
- auto r = range;
- range.popFrontN(offset);
- return (r.canPeek(2) && (r.peek(2) == "\u2028"
- || r.peek(2) == "\u2029"));
- }
- return false;
- }
-
- enum tokenStart = q{
- size_t index = range.index;
- size_t column = range.column;
- size_t line = range.line;
- auto mark = range.mark();
- };
-
- void error(string message) pure nothrow @safe
- {
- messages ~= Message(range.line, range.column, message, true);
- }
-
- void warning(string message) pure nothrow @safe
- {
- messages ~= Message(range.line, range.column, message, false);
- assert (messages.length > 0);
- }
-
- struct Message
- {
- size_t line;
- size_t column;
- string message;
- bool isError;
- }
-
- Message[] messages;
- StringCache* cache;
- LexerConfig config;
-}
-
-public auto byToken(ubyte[] range)
-{
- LexerConfig config;
- StringCache* cache = new StringCache(StringCache.defaultBucketCount);
- return DLexer(range, config, cache);
-}
-
-public auto byToken(ubyte[] range, StringCache* cache)
-{
- LexerConfig config;
- return DLexer(range, config, cache);
-}
-
-public auto byToken(ubyte[] range, const LexerConfig config, StringCache* cache)
-{
- return DLexer(range, config, cache);
-}
-
-/**
- * Removes "decoration" such as leading whitespace, leading + and * characters,
- * and places the result into the given output range
- */
-public void unDecorateComment(T)(string comment, auto ref T outputRange)
- if (isOutputRange!(T, string))
-in
-{
- assert (comment.length >= 3);
-}
-body
-{
- switch (comment[0 .. 3])
- {
- case "///":
- size_t i = 3;
- if (i < comment.length)
- {
- again:
- while (i < comment.length && comment[i] == ' ' || comment[i] == '\t')
- i++;
- size_t j = i + 1;
- while (j < comment.length)
- {
- if (comment[j] == '\r')
- j++;
- if (j >= comment.length)
- break;
- if (comment[j] == '\n')
- {
- outputRange.put(comment[i .. j]);
- j++;
- while (j < comment.length && comment[j] == '/')
- j++;
- outputRange.put(' ');
- i = j;
- goto again;
- }
- j++;
- }
- outputRange.put(comment[i .. j]);
- }
- break;
- case "/++":
- case "/**":
- size_t i = 3;
- immutable char c = comment[1];
- // Skip leading * and + characters
- while (comment[i] == c) i++;
- // Skip trailing * and + characters
- size_t j = comment.length - 2;
- while (j > i && comment[j] == c)
- j--;
- while (j > i && (comment[j] == ' ' || comment[j] == '\t'))
- j--;
- if (comment[i] == '\r') i++;
- if (comment[i] == '\n') i++;
- while (comment[i] == ' ' || comment[i] == '\t') i++;
- immutable bool skipBeginningChar = comment[i] == c;
- if (skipBeginningChar)
- i++;
- size_t whitespaceToSkip;
- while (comment[i] == ' ' || comment[i] == '\t')
- {
- whitespaceToSkip++;
- i++;
- }
- size_t l = i;
- while (i < j)
- {
- if (comment[i++] == '\n')
- break;
- }
- outputRange.put(comment[l .. i]);
- while (true)
- {
- if (skipBeginningChar)
- {
- while (i < j && (comment[i] == ' ' || comment[i] == '\t')) i++;
- if (i < j && comment[i] == c) i++;
- }
- for (size_t s = 0; (i < j) && (s <= whitespaceToSkip)
- && (comment[i] == ' ' || comment[i] == '\t');)
- {
- s++;
- i++;
- }
- size_t k = i;
- inner: while (k < j)
- {
- if (comment[k] == '\n')
- {
- k++;
- break inner;
- }
- k++;
- }
- outputRange.put(comment[i .. k]);
- i = k;
- if (i >= j)
- break;
- }
- break;
- default:
- assert (false, "Invalid doc comment");
- }
-}
-
-
-struct StringCache
-{
-public:
-
- @disable this();
-
- /**
- * Params: bucketCount = the initial number of buckets. Must be a
- * power of two
- */
- this(size_t bucketCount)
- {
- buckets = (cast(Node**) calloc((Node*).sizeof, bucketCount))[0 .. bucketCount];
- }
-
- ~this()
- {
- Block* current = rootBlock;
- while (current !is null)
- {
- Block* prev = current;
- current = current.next;
- free(cast(void*) prev.bytes.ptr);
- free(cast(void*) prev);
- }
- foreach (nodePointer; buckets)
- {
- Node* currentNode = nodePointer;
- while (currentNode !is null)
- {
- Node* prev = currentNode;
- currentNode = currentNode.next;
- free(prev);
- }
- }
- rootBlock = null;
- free(buckets.ptr);
- buckets = null;
- }
-
- /**
- * Caches a string.
- */
- string intern(const(ubyte)[] str) pure nothrow @safe
- {
- if (str is null || str.length == 0)
- return "";
- immutable uint hash = hashBytes(str);
- return intern(str, hash);
- }
-
- /**
- * ditto
- */
- string intern(string str) pure nothrow @trusted
- {
- return intern(cast(ubyte[]) str);
- }
-
- /**
- * Caches a string as above, but uses the given hash code instead of
- * calculating one itself. Use this alongside $(LREF hashStep)() can reduce the
- * amount of work necessary when lexing dynamic tokens.
- */
- string intern(const(ubyte)[] str, uint hash) pure nothrow @safe
- in
- {
- assert (str.length > 0);
- }
- body
- {
- return _intern(str, hash);
-// string s = _intern(str, hash);
-// size_t* ptr = s in debugMap;
-// if (ptr is null)
-// debugMap[s] = cast(size_t) s.ptr;
-// else
-// assert (*ptr == cast(size_t) s.ptr);
-// return s;
- }
-
- /**
- * Incremental hashing.
- * Params:
- * b = the byte to add to the hash
- * h = the hash that has been calculated so far
- * Returns: the new hash code for the string.
- */
- static uint hashStep(ubyte b, uint h) pure nothrow @safe
- {
- return (h ^ sbox[b]) * 3;
- }
-
- /**
- * The default bucket count for the string cache.
- */
- static enum defaultBucketCount = 4096;
-
- size_t allocated() pure nothrow @safe @property
- {
- return _allocated;
- }
-
-private:
-
- string _intern(const(ubyte)[] bytes, uint hash) pure nothrow @trusted
- {
- if (bytes is null || bytes.length == 0)
- return "";
- immutable size_t index = hash & (buckets.length - 1);
- Node* s = find(bytes, hash);
- if (s !is null)
- return cast(string) s.str;
- _allocated += bytes.length;
- ubyte[] mem = allocate(bytes.length);
- mem[] = bytes[];
- Node* node = cast(Node*) malloc(Node.sizeof);
- node.str = mem;
- node.hash = hash;
- node.next = buckets[index];
- buckets[index] = node;
- return cast(string) mem;
- }
-
- Node* find(const(ubyte)[] bytes, uint hash) pure nothrow @trusted
- {
- import std.algorithm;
- immutable size_t index = hash & (buckets.length - 1);
- Node* node = buckets[index];
- while (node !is null)
- {
- if (node.hash == hash && bytes.equal(cast(ubyte[]) node.str))
- return node;
- node = node.next;
- }
- return node;
- }
-
- static uint hashBytes(const(ubyte)[] data) pure nothrow @trusted
- in
- {
- assert (data !is null);
- assert (data.length > 0);
- }
- body
- {
- uint hash = 0;
- foreach (ubyte b; data)
- {
- hash ^= sbox[b];
- hash *= 3;
- }
- return hash;
- }
-
- ubyte[] allocate(size_t numBytes) pure nothrow @trusted
- in
- {
- assert (numBytes != 0);
- }
- out (result)
- {
- assert (result.length == numBytes);
- }
- body
- {
- if (numBytes > (blockSize / 4))
- return (cast(ubyte*) malloc(numBytes))[0 .. numBytes];
- Block* r = rootBlock;
- size_t i = 0;
- while (i <= 3 && r !is null)
- {
-
- immutable size_t available = r.bytes.length;
- immutable size_t oldUsed = r.used;
- immutable size_t newUsed = oldUsed + numBytes;
- if (newUsed <= available)
- {
- r.used = newUsed;
- return r.bytes[oldUsed .. newUsed];
- }
- i++;
- r = r.next;
- }
- Block* b = cast(Block*) malloc(Block.sizeof);
- b.bytes = (cast(ubyte*) malloc(blockSize))[0 .. blockSize];
- b.used = numBytes;
- b.next = rootBlock;
- rootBlock = b;
- return b.bytes[0 .. numBytes];
- }
-
- static struct Node
- {
- ubyte[] str;
- uint hash;
- Node* next;
- }
-
- static struct Block
- {
- ubyte[] bytes;
- size_t used;
- Block* next;
- }
-
- static enum blockSize = 1024 * 16;
-
- static immutable uint[] sbox = [
- 0xF53E1837, 0x5F14C86B, 0x9EE3964C, 0xFA796D53,
- 0x32223FC3, 0x4D82BC98, 0xA0C7FA62, 0x63E2C982,
- 0x24994A5B, 0x1ECE7BEE, 0x292B38EF, 0xD5CD4E56,
- 0x514F4303, 0x7BE12B83, 0x7192F195, 0x82DC7300,
- 0x084380B4, 0x480B55D3, 0x5F430471, 0x13F75991,
- 0x3F9CF22C, 0x2FE0907A, 0xFD8E1E69, 0x7B1D5DE8,
- 0xD575A85C, 0xAD01C50A, 0x7EE00737, 0x3CE981E8,
- 0x0E447EFA, 0x23089DD6, 0xB59F149F, 0x13600EC7,
- 0xE802C8E6, 0x670921E4, 0x7207EFF0, 0xE74761B0,
- 0x69035234, 0xBFA40F19, 0xF63651A0, 0x29E64C26,
- 0x1F98CCA7, 0xD957007E, 0xE71DDC75, 0x3E729595,
- 0x7580B7CC, 0xD7FAF60B, 0x92484323, 0xA44113EB,
- 0xE4CBDE08, 0x346827C9, 0x3CF32AFA, 0x0B29BCF1,
- 0x6E29F7DF, 0xB01E71CB, 0x3BFBC0D1, 0x62EDC5B8,
- 0xB7DE789A, 0xA4748EC9, 0xE17A4C4F, 0x67E5BD03,
- 0xF3B33D1A, 0x97D8D3E9, 0x09121BC0, 0x347B2D2C,
- 0x79A1913C, 0x504172DE, 0x7F1F8483, 0x13AC3CF6,
- 0x7A2094DB, 0xC778FA12, 0xADF7469F, 0x21786B7B,
- 0x71A445D0, 0xA8896C1B, 0x656F62FB, 0x83A059B3,
- 0x972DFE6E, 0x4122000C, 0x97D9DA19, 0x17D5947B,
- 0xB1AFFD0C, 0x6EF83B97, 0xAF7F780B, 0x4613138A,
- 0x7C3E73A6, 0xCF15E03D, 0x41576322, 0x672DF292,
- 0xB658588D, 0x33EBEFA9, 0x938CBF06, 0x06B67381,
- 0x07F192C6, 0x2BDA5855, 0x348EE0E8, 0x19DBB6E3,
- 0x3222184B, 0xB69D5DBA, 0x7E760B88, 0xAF4D8154,
- 0x007A51AD, 0x35112500, 0xC9CD2D7D, 0x4F4FB761,
- 0x694772E3, 0x694C8351, 0x4A7E3AF5, 0x67D65CE1,
- 0x9287DE92, 0x2518DB3C, 0x8CB4EC06, 0xD154D38F,
- 0xE19A26BB, 0x295EE439, 0xC50A1104, 0x2153C6A7,
- 0x82366656, 0x0713BC2F, 0x6462215A, 0x21D9BFCE,
- 0xBA8EACE6, 0xAE2DF4C1, 0x2A8D5E80, 0x3F7E52D1,
- 0x29359399, 0xFEA1D19C, 0x18879313, 0x455AFA81,
- 0xFADFE838, 0x62609838, 0xD1028839, 0x0736E92F,
- 0x3BCA22A3, 0x1485B08A, 0x2DA7900B, 0x852C156D,
- 0xE8F24803, 0x00078472, 0x13F0D332, 0x2ACFD0CF,
- 0x5F747F5C, 0x87BB1E2F, 0xA7EFCB63, 0x23F432F0,
- 0xE6CE7C5C, 0x1F954EF6, 0xB609C91B, 0x3B4571BF,
- 0xEED17DC0, 0xE556CDA0, 0xA7846A8D, 0xFF105F94,
- 0x52B7CCDE, 0x0E33E801, 0x664455EA, 0xF2C70414,
- 0x73E7B486, 0x8F830661, 0x8B59E826, 0xBB8AEDCA,
- 0xF3D70AB9, 0xD739F2B9, 0x4A04C34A, 0x88D0F089,
- 0xE02191A2, 0xD89D9C78, 0x192C2749, 0xFC43A78F,
- 0x0AAC88CB, 0x9438D42D, 0x9E280F7A, 0x36063802,
- 0x38E8D018, 0x1C42A9CB, 0x92AAFF6C, 0xA24820C5,
- 0x007F077F, 0xCE5BC543, 0x69668D58, 0x10D6FF74,
- 0xBE00F621, 0x21300BBE, 0x2E9E8F46, 0x5ACEA629,
- 0xFA1F86C7, 0x52F206B8, 0x3EDF1A75, 0x6DA8D843,
- 0xCF719928, 0x73E3891F, 0xB4B95DD6, 0xB2A42D27,
- 0xEDA20BBF, 0x1A58DBDF, 0xA449AD03, 0x6DDEF22B,
- 0x900531E6, 0x3D3BFF35, 0x5B24ABA2, 0x472B3E4C,
- 0x387F2D75, 0x4D8DBA36, 0x71CB5641, 0xE3473F3F,
- 0xF6CD4B7F, 0xBF7D1428, 0x344B64D0, 0xC5CDFCB6,
- 0xFE2E0182, 0x2C37A673, 0xDE4EB7A3, 0x63FDC933,
- 0x01DC4063, 0x611F3571, 0xD167BFAF, 0x4496596F,
- 0x3DEE0689, 0xD8704910, 0x7052A114, 0x068C9EC5,
- 0x75D0E766, 0x4D54CC20, 0xB44ECDE2, 0x4ABC653E,
- 0x2C550A21, 0x1A52C0DB, 0xCFED03D0, 0x119BAFE2,
- 0x876A6133, 0xBC232088, 0x435BA1B2, 0xAE99BBFA,
- 0xBB4F08E4, 0xA62B5F49, 0x1DA4B695, 0x336B84DE,
- 0xDC813D31, 0x00C134FB, 0x397A98E6, 0x151F0E64,
- 0xD9EB3E69, 0xD3C7DF60, 0xD2F2C336, 0x2DDD067B,
- 0xBD122835, 0xB0B3BD3A, 0xB0D54E46, 0x8641F1E4,
- 0xA0B38F96, 0x51D39199, 0x37A6AD75, 0xDF84EE41,
- 0x3C034CBA, 0xACDA62FC, 0x11923B8B, 0x45EF170A,
- ];
-
-// deprecated size_t[string] debugMap;
- size_t _allocated;
- Node*[] buckets;
- Block* rootBlock;
-}
-
-private extern(C) void* calloc(size_t, size_t) nothrow pure;
-private extern(C) void* malloc(size_t) nothrow pure;
-private extern(C) void free(void*) nothrow pure;
-
-unittest
-{
- import std.stdio;
- auto source = cast(ubyte[]) q{ import std.stdio;}c;
- auto tokens = byToken(source);
- assert (tokens.map!"a.type"().equal([tok!"import", tok!"identifier", tok!".",
- tok!"identifier", tok!";"]));
-}
-
-/// Test \x char sequence
-unittest
-{
- auto toks = (string s) => byToken(cast(ubyte[])s);
-
- // valid
- enum hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F'];
- auto source = "";
- foreach (h1; hex)
- foreach (h2; hex)
- source ~= "'\\x" ~ h1 ~ h2 ~ "'";
- assert (toks(source).filter!(t => t.type != tok!"characterLiteral").empty);
-
- // invalid
- assert (toks(`'\x'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true));
- assert (toks(`'\x_'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true));
- assert (toks(`'\xA'`).messages[0] == DLexer.Message(1,5,"Error: 2 hex digits expected.",true));
- assert (toks(`'\xAY'`).messages[0] == DLexer.Message(1,5,"Error: 2 hex digits expected.",true));
- assert (toks(`'\xXX'`).messages[0] == DLexer.Message(1,4,"Error: 2 hex digits expected.",true));
-}
-
diff --git a/std/d/parser.d b/std/d/parser.d
deleted file mode 100644
index 7f10434..0000000
--- a/std/d/parser.d
+++ /dev/null
@@ -1,7067 +0,0 @@
-// Written in the D programming language
-
-/**
- * MACROS:
- * GRAMMAR = $0
- * RULEDEF = $(B $(DDOC_ANCHOR $0) $0)
- * RULE = $(LINK2 #$0, $0)
- * LITERAL = $(D_STRING $(I $0))
- */
-
-module std.d.parser;
-
-import std.d.lexer;
-import std.d.ast;
-import std.allocator;
-import std.conv;
-import std.algorithm;
-import std.array;
-import std.stdio;
-import std.string : format;
-
-// Uncomment this if you want ALL THE OUTPUT
-// Caution: generates 180 megabytes of logging for std.datetime
-//version = std_parser_verbose;
-
-alias ParseAllocator = CAllocatorImpl!(Mallocator);
-
-/**
- * Params:
- * tokens = the tokens parsed by std.d.lexer
- * fileName = the name of the file being parsed
- * messageFunction = a function to call on error or warning messages.
- * The parameters are the file name, line number, column number,
- * the error or warning message, and a boolean (true means error, false
- * means warning).
- * Returns: the parsed module
- */
-Module parseModule(const(Token)[] tokens, string fileName, CAllocator allocator = null,
- void function(string, size_t, size_t, string, bool) messageFunction = null)
-{
- auto parser = new Parser();
- parser.fileName = fileName;
- parser.tokens = tokens;
- parser.messageFunction = messageFunction;
- parser.allocator = allocator;
- auto mod = parser.parseModule();
- // writefln("Parsing finished with %d errors and %d warnings.",
- // parser.errorCount, parser.warningCount);
- return mod;
-}
-
-/**
- * Parser structure
- */
-class Parser
-{
- /**
- * Parses an AddExpression.
- *
- * $(GRAMMAR $(RULEDEF addExpression):
- * $(RULE mulExpression)
- * | $(RULE addExpression) $(LPAREN)$(LITERAL '+') | $(LITERAL'-') | $(LITERAL'~')$(RPAREN) $(RULE mulExpression)
- * ;)
- */
- ExpressionNode parseAddExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(AddExpression, MulExpression,
- tok!"+", tok!"-", tok!"~")();
- }
-
- /**
- * Parses an AliasDeclaration.
- *
- * $(GRAMMAR $(RULEDEF aliasDeclaration):
- * $(LITERAL 'alias') $(RULE aliasInitializer) $(LPAREN)$(LITERAL ',') $(RULE aliasInitializer)$(RPAREN)* $(LITERAL ';')
- * | $(LITERAL 'alias') $(RULE storageClass)* $(RULE type) $(LITERAL identifier) $(LITERAL ';')
- * ;)
- */
- AliasDeclaration parseAliasDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AliasDeclaration;
- if (expect(tok!"alias") is null) return null;
- node.comment = comment;
- comment = null;
-
- if (startsWith(tok!"identifier", tok!"=") || startsWith(tok!"identifier", tok!"("))
- {
- AliasInitializer[] initializers;
- do
- {
- auto initializer = parseAliasInitializer();
- if (initializer is null) return null;
- initializers ~= initializer;
- if (currentIs(tok!","))
- advance();
- else
- break;
- }
- while (moreTokens());
- node.initializers = ownArray(initializers);
- }
- else
- {
- StorageClass[] storageClasses;
- while (moreTokens() && isStorageClass())
- storageClasses ~= parseStorageClass();
- if (storageClasses.length > 0)
- node.storageClasses = ownArray(storageClasses);
- warn("Prefer the new \"'alias' identifier '=' type ';'\" 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)
- return null;
- node.name = *ident;
- }
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- unittest
- {
- auto sourceCode =
-q{
-alias core.sys.posix.stdio.fileno fileno;
-}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseAliasDeclaration");
-
- AliasDeclaration d = p.parseAliasDeclaration();
- assert (d !is null);
- assert (p.errorCount == 0);
-
- stderr.writeln("Unittest for parseAliasDeclaration() passed.");
- }
-
- /**
- * Parses an AliasInitializer
- * $(GRAMMAR $(RULEDEF aliasInitializer):
- * $(LITERAL Identifier) $(RULE templateParameters)? $(LITERAL '=') $(RULE storageClass)* $(RULE type)
- * ;)
- */
- AliasInitializer parseAliasInitializer()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AliasInitializer;
- auto i = expect(tok!"identifier");
- if (i is null) return null;
- node.name = *i;
- if (currentIs(tok!"("))
- node.templateParameters = parseTemplateParameters();
- if (expect(tok!"=") is null) return null;
- StorageClass[] storageClasses;
- while (moreTokens() && isStorageClass())
- storageClasses ~= parseStorageClass();
- if (storageClasses.length > 0)
- node.storageClasses = ownArray(storageClasses);
- node.type = parseType();
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{a = abcde!def};
- Parser p = getParserForUnittest(sourceCode, "parseAliasInitializer");
- auto initializer = p.parseAliasInitializer();
- assert (initializer !is null);
- assert (p.errorCount == 0);
- stderr.writeln("Unittest for parseAliasInitializer() passed.");
- }
-
- /**
- * Parses an AliasThisDeclaration
- * $(GRAMMAR $(RULEDEF aliasThisDeclaration):
- * $(LITERAL 'alias') $(LITERAL Identifier) $(LITERAL 'this') $(LITERAL ';')
- * ;)
- */
- AliasThisDeclaration parseAliasThisDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AliasThisDeclaration;
- if (expect(tok!"alias") is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (expect(tok!"this") is null) return null;
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{alias oneTwoThree this;};
- Parser p = getParserForUnittest(sourceCode, "parseAliasThisDeclaration");
- auto aliasThis = p.parseAliasThisDeclaration();
- assert (aliasThis !is null);
- assert (p.errorCount == 0);
- stderr.writeln("Unittest for parseAliasThisDeclaration() passed.");
- }
-
- /**
- * Parses an AlignAttribute.
- * $(GRAMMAR $(RULEDEF alignAttribute):
- * $(LITERAL 'align') ($(LITERAL '$(LPAREN)') $(LITERAL IntegerLiteral) $(LITERAL '$(RPAREN)'))?
- * ;)
- */
- AlignAttribute parseAlignAttribute()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AlignAttribute;
- expect(tok!"align");
- if (currentIs(tok!"("))
- {
- if (expect(tok!"(") is null) return null;
- auto intLit = expect(tok!"intLiteral");
- if (intLit is null) return null;
- node.intLiteral = *intLit;
- if (expect(tok!")") is null) return null;
- }
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{align(42) align};
- Parser p = getParserForUnittest(sourceCode, "parseAlignAttribute");
- auto attribute = p.parseAlignAttribute();
- assert (attribute !is null);
- attribute = p.parseAlignAttribute();
- assert (attribute !is null);
- assert (p.errorCount == 0);
- stderr.writeln("Unittest for parseAlignAttribute() passed.");
- }
-
- /**
- * Parses an AndAndExpression
- * $(GRAMMAR $(RULEDEF andAndExpression):
- * $(RULE orExpression)
- * | $(RULE andAndExpression) $(LITERAL '&&') $(RULE orExpression)
- * ;)
- */
- ExpressionNode parseAndAndExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(AndAndExpression, OrExpression,
- tok!"&&")();
- }
-
- /**
- * Parses an AndExpression
- *
- * $(GRAMMAR $(RULEDEF andExpression):
- * $(RULE cmpExpression)
- * | $(RULE andExpression) $(LITERAL '&') $(RULE cmpExpression)
- * ;)
- */
- ExpressionNode parseAndExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(AndExpression, CmpExpression,
- tok!"&")();
- }
-
- /**
- * Parses an ArgumentList
- *
- * $(GRAMMAR $(RULEDEF argumentList):
- * $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression)?)*
- * ;)
- */
- ArgumentList parseArgumentList()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- size_t startLocation = current().index;
- auto ret= parseCommaSeparatedRule!(ArgumentList, AssignExpression)(true);
- ret.startLocation = startLocation;
- ret.endLocation = current().index;
- return ret;
- }
-
- /**
- * Parses Arguments
- *
- * $(GRAMMAR $(RULEDEF arguments):
- * $(LITERAL '$(LPAREN)') $(RULE argumentList)? $(LITERAL '$(RPAREN)')
- * ;)
- */
- Arguments parseArguments()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Arguments;
- if (expect(tok!"(") is null) return null;
- if (!currentIs(tok!")"))
- node.argumentList = parseArgumentList();
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses an ArrayInitializer
- *
- * $(GRAMMAR $(RULEDEF arrayInitializer):
- * $(LITERAL '[') $(LITERAL ']')
- * | $(LITERAL '[') $(RULE arrayMemberInitialization) ($(LITERAL ',') $(RULE arrayMemberInitialization)?)* $(LITERAL ']')
- * ;)
- */
- ArrayInitializer parseArrayInitializer()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ArrayInitializer;
- if (expect(tok!"[") is null) return null;
- ArrayMemberInitialization[] arrayMemberInitializations;
- while (moreTokens())
- {
- if (currentIs(tok!"]"))
- break;
- arrayMemberInitializations ~= parseArrayMemberInitialization();
- if (currentIs(tok!","))
- advance();
- else
- break;
- }
- node.arrayMemberInitializations = ownArray(arrayMemberInitializations);
- if (expect(tok!"]") is null) return null;
- return node;
- }
-
- /**
- * Parses an ArrayLiteral
- *
- * $(GRAMMAR $(RULEDEF arrayLiteral):
- * $(LITERAL '[') $(RULE argumentList)? $(LITERAL ']')
- * ;)
- */
- ArrayLiteral parseArrayLiteral()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ArrayLiteral;
- if (expect(tok!"[") is null) return null;
- if (!currentIs(tok!"]"))
- node.argumentList = parseArgumentList();
- if (expect(tok!"]") is null) return null;
- return node;
- }
-
- /**
- * Parses an ArrayMemberInitialization
- *
- * $(GRAMMAR $(RULEDEF arrayMemberInitialization):
- * ($(RULE assignExpression) $(LITERAL ':'))? $(RULE nonVoidInitializer)
- * ;)
- */
- ArrayMemberInitialization parseArrayMemberInitialization()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ArrayMemberInitialization;
- switch (current.type)
- {
- case tok!"{":
- case tok!"[":
- node.nonVoidInitializer = parseNonVoidInitializer();
- if (node.nonVoidInitializer is null) return null;
- break;
- default:
- auto assignExpression = parseAssignExpression();
- if (assignExpression is null) return null;
- if (currentIs(tok!":"))
- {
- node.assignExpression = assignExpression;
- advance();
- node.nonVoidInitializer = parseNonVoidInitializer();
- if (node.nonVoidInitializer is null) return null;
- }
- else
- {
- node.nonVoidInitializer = allocate!NonVoidInitializer;
- node.nonVoidInitializer.assignExpression = assignExpression;
- }
- }
- return node;
- }
-
- /**
- * Parses an AsmAddExp
- *
- * $(GRAMMAR $(RULEDEF asmAddExp):
- * $(RULE asmMulExp)
- * | $(RULE asmAddExp) ($(LITERAL '+') | $(LITERAL '-')) $(RULE asmMulExp)
- * ;)
- */
- ExpressionNode parseAsmAddExp()
- {
- return parseLeftAssocBinaryExpression!(AsmAddExp, AsmMulExp,
- tok!"+", tok!"-")();
- }
-
- /**
- * Parses an AsmAndExp
- *
- * $(GRAMMAR $(RULEDEF asmAndExp):
- * $(RULE asmEqualExp) ($(LITERAL '&') $(RULE asmEqualExp))?
- * ;)
- */
- AsmAndExp parseAsmAndExp()
- {
-// auto node = allocate!AsmAndExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmBrExp
- *
- * $(GRAMMAR $(RULEDEF asmBrExp):
- * $(RULE asmUnaExp)
- * | $(RULE asmBrExp) $(LITERAL '[') $(RULE asmExp) $(LITERAL ']')
- * ;)
- */
- AsmBrExp parseAsmBrExp()
- {
-// auto node = allocate!AsmBrExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmEqualExp
- *
- * $(GRAMMAR $(RULEDEF asmEqualExp):
- * $(RULE asmRelExp) (('==' | '!=') $(RULE asmRelExp))?
- * ;)
- */
- AsmEqualExp parseAsmEqualExp()
- {
-// auto node = allocate!AsmEqualExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmExp
- *
- * $(GRAMMAR $(RULEDEF asmExp):
- * $(RULE asmLogOrExp) ($(LITERAL '?') $(RULE asmExp) $(LITERAL ':') $(RULE asmExp))?
- * ;)
- */
- AsmExp parseAsmExp()
- {
-// auto node = allocate!AsmExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmInstruction
- *
- * $(GRAMMAR $(RULEDEF asmInstruction):
- * $(LITERAL Identifier)
- * | $(LITERAL 'align') $(LITERAL IntegerLiteral)
- * | $(LITERAL 'align') $(LITERAL Identifier)
- * | $(LITERAL Identifier) $(LITERAL ':') $(RULE asmInstruction)
- * | $(LITERAL Identifier) $(RULE asmExp)
- * | $(LITERAL Identifier) $(RULE operands)
- * ;)
- */
- AsmInstruction parseAsmInstruction()
- {
-// auto node = allocate!AsmInstruction;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmLogAndExp
- *
- * $(GRAMMAR $(RULEDEF asmLogAndExp):
- * $(RULE asmOrExp) ('&&' $(RULE asmOrExp))?
- * ;)
- */
- AsmLogAndExp parseAsmLogAndExp()
- {
-// auto node = allocate!AsmLogAndExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmLogOrExp
- *
- * $(GRAMMAR $(RULEDEF asmLogOrExp):
- * $(RULE asmLogAndExp) ('||' $(RULE asmLogAndExp))?
- * ;)
- */
- AsmLogOrExp parseAsmLogOrExp()
- {
-// auto node = allocate!AsmLogOrExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmMulExp
- *
- * $(GRAMMAR $(RULEDEF asmMulExp):
- * $(RULE asmBrExp) (($(LITERAL '*') | $(LITERAL '/') | $(LITERAL '%')) $(RULE asmBrExp))?
- * ;)
- */
- AsmMulExp parseAsmMulExp()
- {
-// auto node = allocate!AsmMulExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmOrExp
- *
- * $(GRAMMAR $(RULEDEF asmOrExp):
- * $(RULE asmXorExp) ($(LITERAL '|') $(RULE asmXorExp))?
- * ;)
- */
- AsmOrExp parseAsmOrExp()
- {
-// auto node = allocate!AsmOrExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmPrimaryExp
- *
- * $(GRAMMAR $(RULEDEF asmPrimaryExp):
- * $(LITERAL IntegerLiteral)
- * | $(LITERAL FloatLiteral)
- * | $(RULE register)
- * | $(RULE identifierChain)
- * | $(LITERAL '$')
- * ;)
- */
- AsmPrimaryExp parseAsmPrimaryExp()
- {
-// auto node = allocate!AsmPrimaryExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmRelExp
- *
- * $(GRAMMAR $(RULEDEF asmRelExp):
- * $(RULE asmShiftExp) (($(LITERAL '<') | $(LITERAL '<=') | $(LITERAL '>') | $(LITERAL '>=')) $(RULE asmShiftExp))?
- * ;)
- */
- AsmRelExp parseAsmRelExp()
- {
-// auto node = allocate!AsmRelExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmShiftExp
- *
- * $(GRAMMAR $(RULEDEF asmShiftExp):
- * $(RULE asmAddExp) (($(LITERAL '<<') | $(LITERAL '>>') | $(LITERAL '>>>')) $(RULE asmAddExp))?
- * ;)
- */
- AsmShiftExp parseAsmShiftExp()
- {
-// auto node = allocate!AsmShiftExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmStatement
- *
- * $(GRAMMAR $(RULEDEF asmStatement):
- * $(LITERAL 'asm') $(LITERAL '{') $(RULE asmInstruction)+ $(LITERAL '}')
- * ;)
- */
- AsmStatement parseAsmStatement()
- {
- // TODO asm
- auto node = allocate!AsmStatement;
- warn("Skipping assembly statement. Not supported.");
- advance();
- skipBraces();
- return node;
- }
-
- /**
- * Parses an AsmTypePrefix
- *
- * $(GRAMMAR $(RULEDEF asmTypePrefix):
- * $(LITERAL Identifier) $(LITERAL Identifier)
- * | $(LITERAL 'byte') $(LITERAL Identifier)
- * | $(LITERAL 'short') $(LITERAL Identifier)
- * | $(LITERAL 'int') $(LITERAL Identifier)
- * | $(LITERAL 'float') $(LITERAL Identifier)
- * | $(LITERAL 'double') $(LITERAL Identifier)
- * | $(LITERAL 'real') $(LITERAL Identifier)
- * ;)
- */
- AsmTypePrefix parseAsmTypePrefix()
- {
-// auto node = allocate!AsmTypePrefix;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmUnaExp
- *
- * $(GRAMMAR $(RULEDEF asmUnaExp):
- * $(RULE asmTypePrefix) $(RULE asmExp)
- * | $(LITERAL Identifier) $(RULE asmExp)
- * | $(LITERAL '+') $(RULE asmUnaExp)
- * | $(LITERAL '-') $(RULE asmUnaExp)
- * | $(LITERAL '!') $(RULE asmUnaExp)
- * | $(LITERAL '~') $(RULE asmUnaExp)
- * | $(RULE asmPrimaryExp)
- * ;)
- */
- AsmUnaExp parseAsmUnaExp()
- {
-// auto node = allocate!AsmUnaExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AsmXorExp
- *
- * $(GRAMMAR $(RULEDEF asmXorExp):
- * $(RULE asmAndExp) ($(LITERAL '^') $(RULE asmAndExp))?
- * ;)
- */
- AsmXorExp parseAsmXorExp()
- {
-// auto node = allocate!AsmXorExp;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an AssertExpression
- *
- * $(GRAMMAR $(RULEDEF assertExpression):
- * $(LITERAL 'assert') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL '$(RPAREN)')
- * ;)
- */
- AssertExpression parseAssertExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AssertExpression;
- expect(tok!"assert");
- if (expect(tok!"(") is null) return null;
- node.assertion = parseAssignExpression();
- if (currentIs(tok!","))
- {
- advance();
- node.message = parseAssignExpression();
- }
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses an AssignExpression
- *
- * $(GRAMMAR $(RULEDEF assignExpression):
- * $(RULE ternaryExpression) ($(RULE assignOperator) $(RULE assignExpression))?
- * ;
- *$(RULEDEF assignOperator):
- * $(LITERAL '=')
- * | $(LITERAL '>>>=')
- * | $(LITERAL '>>=')
- * | $(LITERAL '<<=')
- * | $(LITERAL '+=')
- * | $(LITERAL '-=')
- * | $(LITERAL '*=')
- * | $(LITERAL '%=')
- * | $(LITERAL '&=')
- * | $(LITERAL '/=')
- * | $(LITERAL '|=')
- * | $(LITERAL '^^=')
- * | $(LITERAL '^=')
- * | $(LITERAL '~=')
- * ;)
- */
- AssignExpression parseAssignExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AssignExpression;
- node.line = current().line;
- node.column = current().column;
- node.ternaryExpression = parseTernaryExpression();
- if (currentIsOneOf(tok!"=", tok!">>>=",
- tok!">>=", tok!"<<=",
- tok!"+=", tok!"-=", tok!"*=",
- tok!"%=", tok!"&=", tok!"/=",
- tok!"|=", tok!"^^=", tok!"^=",
- tok!"~="))
- {
- node.operator = advance().type;
- node.assignExpression = parseAssignExpression();
- }
- return node;
- }
-
- /**
- * Parses an AssocArrayLiteral
- *
- * $(GRAMMAR $(RULEDEF assocArrayLiteral):
- * $(LITERAL '[') $(RULE keyValuePairs) $(LITERAL ']')
- * ;)
- */
- AssocArrayLiteral parseAssocArrayLiteral()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(AssocArrayLiteral, tok!"[",
- "keyValuePairs|parseKeyValuePairs", tok!"]"));
- }
-
- /**
- * Parses an AtAttribute
- *
- * $(GRAMMAR $(RULEDEF atAttribute):
- * $(LITERAL '@') ($(LITERAL Identifier) | $(LITERAL '$(LPAREN)') $(RULE argumentList) $(LITERAL '$(RPAREN)') | $(RULE functionCallExpression))
- * ;)
- */
- AtAttribute parseAtAttribute()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AtAttribute;
- auto start = expect(tok!"@");
- if (start is null) return null;
- node.startLocation = start.index;
- switch (current.type)
- {
- case tok!"identifier":
- if (peekIsOneOf(tok!"(", tok!".", tok!"!"))
- node.functionCallExpression = parseFunctionCallExpression();
- else
- node.identifier = advance();
- break;
- case tok!"(":
- advance();
- node.argumentList = parseArgumentList();
- expect(tok!")");
- break;
- default:
- error(`"(", or identifier expected`);
- return null;
- }
- node.endLocation = current().index;
- return node;
- }
-
- /**
- * Parses an Attribute
- *
- * $(GRAMMAR $(RULEDEF attribute):
- * | $(RULE pragmaExpression)
- * | $(RULE storageClass)
- * | $(LITERAL 'export')
- * | $(LITERAL 'package')
- * | $(LITERAL 'private')
- * | $(LITERAL 'protected')
- * | $(LITERAL 'public')
- * ;)
- */
- Attribute parseAttribute()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Attribute;
- switch (current.type)
- {
- case tok!"pragma":
- node.pragmaExpression = parsePragmaExpression();
- break;
- case tok!"private":
- case tok!"package":
- case tok!"protected":
- case tok!"public":
- case tok!"export":
- node.attribute = advance().type;
- break;
- default:
- node.storageClass = parseStorageClass();
- break;
- }
- return node;
- }
-
- /**
- * Parses an AttributeDeclaration
- *
- * $(GRAMMAR $(RULEDEF attributeDeclaration):
- * $(RULE attribute) $(LITERAL ':')
- * ;)
- */
- AttributeDeclaration parseAttributeDeclaration(Attribute attribute = null)
- {
- auto node = allocate!AttributeDeclaration;
- node.attribute = attribute is null ? parseAttribute() : attribute;
- expect(tok!":");
- return node;
- }
-
- /**
- * Parses an AutoDeclaration
- *
- * $(GRAMMAR $(RULEDEF autoDeclaration):
- * $(RULE storageClass) $(LITERAL Identifier) $(LITERAL '=') $(RULE initializer) ($(LITERAL ',') $(LITERAL Identifier) $(LITERAL '=') $(RULE initializer))* $(LITERAL ';')
- * ;)
- */
- AutoDeclaration parseAutoDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!AutoDeclaration;
- Token[] identifiers;
- Initializer[] initializers;
- do
- {
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- identifiers ~= *ident;
- if (expect(tok!"=") is null) return null;
- auto init = parseInitializer();
- if (init is null) return null;
- initializers ~= init;
- if (currentIs(tok!","))
- advance();
- else
- break;
- } while (moreTokens());
- node.identifiers = ownArray(identifiers);
- node.initializers = ownArray(initializers);
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses a BlockStatement
- *
- * $(GRAMMAR $(RULEDEF blockStatement):
- * $(LITERAL '{') $(RULE declarationsAndStatements)? $(LITERAL '}')
- * ;)
- */
- BlockStatement parseBlockStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!BlockStatement;
- auto openBrace = expect(tok!"{");
- if (openBrace is null) return null;
- node.startLocation = openBrace.index;
- if (!currentIs(tok!"}"))
- node.declarationsAndStatements = parseDeclarationsAndStatements();
- auto closeBrace = expect(tok!"}");
- if (closeBrace !is null)
- node.endLocation = closeBrace.index;
- else
- node.endLocation = size_t.max;
- return node;
- }
-
- /**
- * Parses a BodyStatement
- *
- * $(GRAMMAR $(RULEDEF bodyStatement):
- * $(LITERAL 'body') $(RULE blockStatement)
- * ;)
- */
- BodyStatement parseBodyStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(BodyStatement, tok!"body",
- "blockStatement|parseBlockStatement"));
- }
-
- /**
- * Parses a BreakStatement
- *
- * $(GRAMMAR $(RULEDEF breakStatement):
- * $(LITERAL 'break') $(LITERAL Identifier)? $(LITERAL ';')
- * ;)
- */
- BreakStatement parseBreakStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- expect(tok!"break");
- auto node = allocate!BreakStatement;
- switch (current.type)
- {
- case tok!"identifier":
- node.label = advance();
- if (expect(tok!";") is null) return null;
- break;
- case tok!";":
- advance();
- break;
- default:
- error("Identifier or semicolon expected following \"break\"");
- return null;
- }
- return node;
- }
-
- /**
- * Parses a BaseClass
- *
- * $(GRAMMAR $(RULEDEF baseClass):
- * ($(RULE typeofExpression) $(LITERAL '.'))? $(RULE identifierOrTemplateChain)
- * ;)
- */
- BaseClass parseBaseClass()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!BaseClass;
- if (current.type.isProtection())
- {
- warn("Use of base class protection is deprecated.");
- advance();
- }
- if (currentIs(tok!"typeof"))
- {
- node.typeofExpression = parseTypeofExpression();
- if (expect(tok!".") is null) return null;
- }
- node.identifierOrTemplateChain = parseIdentifierOrTemplateChain();
- return node;
- }
-
- /**
- * Parses a BaseClassList
- *
- * $(GRAMMAR $(RULEDEF baseClassList):
- * $(RULE baseClass) ($(LITERAL ',') $(RULE baseClass))*
- * ;)
- */
- BaseClassList parseBaseClassList()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseCommaSeparatedRule!(BaseClassList, BaseClass)();
- }
-
- /**
- * Parses an BuiltinType
- *
- * $(GRAMMAR $(RULEDEF builtinType):
- * $(LITERAL 'bool')
- * | $(LITERAL 'byte')
- * | $(LITERAL 'ubyte')
- * | $(LITERAL 'short')
- * | $(LITERAL 'ushort')
- * | $(LITERAL 'int')
- * | $(LITERAL 'uint')
- * | $(LITERAL 'long')
- * | $(LITERAL 'ulong')
- * | $(LITERAL 'char')
- * | $(LITERAL 'wchar')
- * | $(LITERAL 'dchar')
- * | $(LITERAL 'float')
- * | $(LITERAL 'double')
- * | $(LITERAL 'real')
- * | $(LITERAL 'ifloat')
- * | $(LITERAL 'idouble')
- * | $(LITERAL 'ireal')
- * | $(LITERAL 'cfloat')
- * | $(LITERAL 'cdouble')
- * | $(LITERAL 'creal')
- * | $(LITERAL 'void')
- * ;)
- */
- IdType parseBasicType()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- if (isBasicType(current.type))
- return advance().type;
- error("Basic type expected");
- return tok!"";
- }
-
- /**
- * Parses a CaseRangeStatement
- *
- * $(GRAMMAR $(RULEDEF caseRangeStatement):
- * $(LITERAL 'case') $(RULE assignExpression) $(LITERAL ':') $(LITERAL '...') $(LITERAL 'case') $(RULE assignExpression) $(LITERAL ':') $(RULE declarationsAndStatements)
- * ;)
- */
- CaseRangeStatement parseCaseRangeStatement(AssignExpression low = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CaseRangeStatement;
- if (low is null)
- {
- expect(tok!"case");
- node.low = parseAssignExpression();
- }
- else
- node.low = low;
- if (expect(tok!":") is null) return null;
- if (expect(tok!"..") is null) return null;
- expect(tok!"case");
- node.high = parseAssignExpression();
- if (expect(tok!":") is null) return null;
- node.declarationsAndStatements = parseDeclarationsAndStatements();
- return node;
- }
-
- /**
- * Parses an CaseStatement
- *
- * $(GRAMMAR $(RULEDEF caseStatement):
- * $(LITERAL 'case') $(RULE argumentList) $(LITERAL ':') $(RULE declarationsAndStatements)
- * ;)
- */
- CaseStatement parseCaseStatement(ArgumentList argumentList = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CaseStatement;
- if (argumentList is null)
- {
- expect(tok!"case");
- node.argumentList = parseArgumentList();
- }
- else
- node.argumentList = argumentList;
- if (expect(tok!":") is null) return null;
- node.declarationsAndStatements = parseDeclarationsAndStatements();
- return node;
- }
-
- /**
- * Parses a CastExpression
- *
- * $(GRAMMAR $(RULEDEF castExpression):
- * $(LITERAL 'cast') $(LITERAL '$(LPAREN)') ($(RULE type) | $(RULE castQualifier))? $(LITERAL '$(RPAREN)') $(RULE unaryExpression)
- * ;)
- */
- CastExpression parseCastExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CastExpression;
- expect(tok!"cast");
- if (expect(tok!"(") is null) return null;
- if (!currentIs(tok!")"))
- {
- if (isCastQualifier())
- node.castQualifier = parseCastQualifier();
- else
- node.type = parseType();
- }
- if (expect(tok!")") is null) return null;
- node.unaryExpression = parseUnaryExpression();
- return node;
- }
-
- /**
- * Parses a CastQualifier
- *
- * $(GRAMMAR $(RULEDEF castQualifier):
- * $(LITERAL 'const')
- * | $(LITERAL 'const') $(LITERAL 'shared')
- * | $(LITERAL 'immutable')
- * | $(LITERAL 'inout')
- * | $(LITERAL 'inout') $(LITERAL 'shared')
- * | $(LITERAL 'shared')
- * | $(LITERAL 'shared') $(LITERAL 'const')
- * | $(LITERAL 'shared') $(LITERAL 'inout')
- * ;)
- */
- CastQualifier parseCastQualifier()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CastQualifier;
- switch (current.type)
- {
- case tok!"inout":
- case tok!"const":
- node.first = advance();
- if (currentIs(tok!"shared"))
- node.second = advance();
- break;
- case tok!"shared":
- node.first = advance();
- if (currentIsOneOf(tok!"const", tok!"inout"))
- node.second = advance();
- break;
- case tok!"immutable":
- node.first = advance();
- break;
- default:
- error("const, immutable, inout, or shared expected");
- return null;
- }
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{
-const;
-const shared;
-immutable;
-inout;
-inout shared;
-shared;
-shared const;
-shared inout;
-incorrect;
- };
-
- Parser p = getParserForUnittest(sourceCode, "parseCastQualifier");
-
- CastQualifier one = p.parseCastQualifier();
- assert (one.first == tok!"const");
- assert (one.second == tok!"");
- p.expect(tok!";");
-
- CastQualifier two = p.parseCastQualifier();
- assert (two.first == tok!"const");
- assert (two.second == tok!"shared");
- p.expect(tok!";");
-
- CastQualifier three = p.parseCastQualifier();
- assert (three.first == tok!"immutable");
- assert (three.second == tok!"");
- p.expect(tok!";");
-
- CastQualifier four = p.parseCastQualifier();
- assert (four.first == tok!"inout");
- assert (four.second == tok!"");
- p.expect(tok!";");
-
- CastQualifier five = p.parseCastQualifier();
- assert (five.first == tok!"inout");
- assert (five.second == tok!"shared");
- p.expect(tok!";");
-
- CastQualifier six = p.parseCastQualifier();
- assert (six.first == tok!"shared");
- assert (six.second == tok!"");
- p.expect(tok!";");
-
- CastQualifier seven = p.parseCastQualifier();
- assert (seven.first == tok!"shared");
- assert (seven.second == tok!"const");
- p.expect(tok!";");
-
- CastQualifier eight = p.parseCastQualifier();
- assert (eight.first == tok!"shared");
- assert (eight.second == tok!"inout");
- p.expect(tok!";");
-
- CastQualifier nine = p.parseCastQualifier();
- assert (nine is null);
- assert (p.errorCount > 0);
-
- stderr.writeln("Unittest for parseCastQualifier() passed.");
- }
-
- /**
- * Parses a Catch
- *
- * $(GRAMMAR $(RULEDEF catch):
- * $(LITERAL 'catch') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL Identifier)? $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
- * ;)
- */
- Catch parseCatch()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Catch;
- expect(tok!"catch");
- if (expect(tok!"(") is null) return null;
- node.type = parseType();
- if (currentIs(tok!"identifier"))
- node.identifier = advance();
- if (expect(tok!")") is null) return null;
- node.declarationOrStatement = parseDeclarationOrStatement();
- return node;
- }
-
- /**
- * Parses a Catches
- *
- * $(GRAMMAR $(RULEDEF catches):
- * $(RULE catch)+
- * | $(RULE catch)* $(RULE lastCatch)
- * ;)
- */
- Catches parseCatches()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Catches;
- Catch[] catches;
- while (moreTokens())
- {
- if (!currentIs(tok!"catch"))
- break;
- if (peekIs(tok!"("))
- catches ~= parseCatch();
- else
- {
- node.lastCatch = parseLastCatch();
- break;
- }
- }
- node.catches = ownArray(catches);
- return node;
- }
-
- /**
- * Parses a ClassDeclaration
- *
- * $(GRAMMAR $(RULEDEF classDeclaration):
- * $(LITERAL 'class') $(LITERAL Identifier) ($(LITERAL ':') $(RULE baseClassList))? $(LITERAL ';')
- * | $(LITERAL 'class') $(LITERAL Identifier) ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)
- * | $(LITERAL 'class') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)
- * | $(LITERAL 'class') $(LITERAL Identifier) $(RULE templateParameters) ($(LITERAL ':') $(RULE baseClassList))? $(RULE constraint)? $(RULE structBody)
- * ;)
- */
- ClassDeclaration parseClassDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ClassDeclaration;
- expect(tok!"class");
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.name = *ident;
- node.comment = comment;
- comment = null;
- if (currentIs(tok!";"))
- {
- advance();
- return node;
- }
- templateStuff: if (currentIs(tok!"("))
- {
- node.templateParameters = parseTemplateParameters();
- constraint: if (currentIs(tok!"if"))
- node.constraint = parseConstraint();
- if (node.baseClassList !is null)
- goto structBody;
- if (currentIs(tok!":"))
- {
- advance();
- node.baseClassList = parseBaseClassList();
- }
- if (currentIs(tok!"if"))
- goto constraint;
- }
- if (currentIs(tok!":"))
- {
- advance();
- node.baseClassList = parseBaseClassList();
- }
- structBody:
- node.structBody = parseStructBody();
- return node;
- }
-
- unittest
- {
- string sourceCode =
-q{class ClassZero;
-class ClassOne {}
-class ClassTwo : Super {}
-class ClassThree(A, B) : Super {}
-class ClassFour(A, B) if (someTest()) : Super {}
-class ClassFive(A, B) : Super if (someTest()) {}}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseClassDeclaration");
-
- auto classZero = p.parseClassDeclaration();
- assert (classZero.name.text == "ClassZero");
- assert (classZero.structBody is null);
-
- auto classOne = p.parseClassDeclaration();
- assert (classOne.name.text == "ClassOne");
- assert (classOne.structBody.declarations.length == 0);
- assert (classOne.baseClassList is null);
- assert (classOne.constraint is null);
- assert (classOne.templateParameters is null);
-
- auto classTwo = p.parseClassDeclaration();
- assert (classTwo.name.text == "ClassTwo", classTwo.name.text);
- assert (classTwo.baseClassList !is null);
- assert (classTwo.baseClassList.items.length == 1,
- to!string(classTwo.baseClassList.items.length));
- assert (classTwo.structBody.declarations.length == 0,
- to!string(classTwo.structBody.declarations.length));
-
- auto classThree = p.parseClassDeclaration();
- assert (classThree.name.text == "ClassThree", classThree.name.text);
- assert (classThree.templateParameters !is null);
- assert (classThree.templateParameters.templateParameterList.items.length == 2);
- assert (classThree.baseClassList !is null);
- assert (classThree.baseClassList.items.length == 1);
- assert (classThree.structBody.declarations.length == 0,
- to!string(classThree.structBody.declarations.length));
-
- auto classFour = p.parseClassDeclaration();
- assert (classFour.name.text == "ClassFour", classFour.name.text);
- assert (classFour.templateParameters !is null);
- assert (classFour.baseClassList !is null);
- assert (classFour.constraint !is null);
- assert (classFour.baseClassList.items.length == 1);
- assert (classFour.structBody.declarations.length == 0,
- to!string(classFour.structBody.declarations.length));
-
- stderr.writeln("Unittest for parseClassDeclaration() passed.");
- }
-
- /**
- * Parses a CmpExpression
- *
- * $(GRAMMAR $(RULEDEF cmpExpression):
- * $(RULE shiftExpression)
- * | $(RULE equalExpression)
- * | $(RULE identityExpression)
- * | $(RULE relExpression)
- * | $(RULE inExpression)
- * ;)
- */
- ExpressionNode parseCmpExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CmpExpression;
- auto shift = parseShiftExpression();
- if (!moreTokens())
- return shift;
- switch (current.type)
- {
- case tok!"is":
- node.identityExpression = parseIdentityExpression(shift);
- break;
- case tok!"in":
- node.inExpression = parseInExpression(shift);
- break;
- case tok!"!":
- if (peekIs(tok!"is"))
- node.identityExpression = parseIdentityExpression(shift);
- else if (peekIs(tok!"in"))
- node.inExpression = parseInExpression(shift);
- break;
- case tok!"<":
- case tok!"<=":
- case tok!">":
- case tok!">=":
- case tok!"!<>=":
- case tok!"!<>":
- case tok!"<>":
- case tok!"<>=":
- case tok!"!>":
- case tok!"!>=":
- case tok!"!<":
- case tok!"!<=":
- node.relExpression = parseRelExpression(shift);
- break;
- case tok!"==":
- case tok!"!=":
- node.equalExpression = parseEqualExpression(shift);
- break;
- default:
- node.shiftExpression = shift;
- break;
- }
- return node;
- }
-
- /**
- * Parses a CompileCondition
- *
- * $(GRAMMAR $(RULEDEF compileCondition):
- * $(RULE versionCondition)
- * | $(RULE debugCondition)
- * | $(RULE staticIfCondition)
- * ;)
- */
- CompileCondition parseCompileCondition()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!CompileCondition;
- switch (current.type)
- {
- case tok!"version":
- node.versionCondition = parseVersionCondition();
- break;
- case tok!"debug":
- node.debugCondition = parseDebugCondition();
- break;
- case tok!"static":
- node.staticIfCondition = parseStaticIfCondition();
- break;
- default:
- error(`"version", "debug", or "static" expected`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a ConditionalDeclaration
- *
- * $(GRAMMAR $(RULEDEF conditionalDeclaration):
- * $(RULE compileCondition) $(RULE declaration)
- * | $(RULE compileCondition) $(LITERAL ':') $(RULE declaration)+
- * | $(RULE compileCondition) $(RULE declaration) ($(LITERAL 'else') $(RULE declaration))?
- * ;)
- */
- ConditionalDeclaration parseConditionalDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ConditionalDeclaration;
- node.compileCondition = parseCompileCondition();
-
- Declaration[] trueDeclarations;
- if (currentIs(tok!":"))
- {
- advance();
- while (isDeclaration())
- trueDeclarations ~= parseDeclaration();
- node.trueDeclarations = ownArray(trueDeclarations);
- return node;
- }
-
- auto dec = parseDeclaration();
- if (dec is null) return null;
- trueDeclarations ~= dec;
- node.trueDeclarations = ownArray(trueDeclarations);
-
- if (currentIs(tok!"else"))
- advance();
- else
- return node;
-
- auto elseDec = parseDeclaration();
- if (elseDec is null) return null;
- node.falseDeclaration = elseDec;
- return node;
- }
-
- /**
- * Parses a ConditionalStatement
- *
- * $(GRAMMAR $(RULEDEF conditionalStatement):
- * $(RULE compileCondition) $(RULE declarationOrStatement) ($(LITERAL 'else') $(RULE declarationOrStatement))?
- * ;)
- */
- ConditionalStatement parseConditionalStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ConditionalStatement;
- node.compileCondition = parseCompileCondition();
- node.trueStatement = parseDeclarationOrStatement();
- if (currentIs(tok!"else"))
- {
- advance();
- node.falseStatement = parseDeclarationOrStatement();
- }
- return node;
- }
-
- /**
- * Parses a Constraint
- *
- * $(GRAMMAR $(RULEDEF constraint):
- * $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)')
- * ;)
- */
- Constraint parseConstraint()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Constraint;
- if (expect(tok!"if") is null) return null;
- if (expect(tok!"(") is null) return null;
- node.expression = parseExpression();
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses a Constructor
- *
- * $(GRAMMAR $(RULEDEF constructor):
- * $(LITERAL 'this') $(RULE templateParameters) $(RULE parameters) $(RULE memberFunctionAttribute)* $(RULE constraint)? ($(RULE functionBody) | $(LITERAL ';'))
- * ;)
- */
- Constructor parseConstructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- Constructor node = allocate!Constructor;
- node.comment = comment;
- comment = null;
- 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!"(")
- {
- isTemplate = true;
- node.templateParameters = parseTemplateParameters();
- }
- node.parameters = parseParameters();
- if (node.parameters is null) return null;
-
- MemberFunctionAttribute[] memberFunctionAttributes;
- while (moreTokens() && currentIsMemberFunctionAttribute())
- memberFunctionAttributes ~= parseMemberFunctionAttribute();
- node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
-
- if (isTemplate && currentIs(tok!"if"))
- node.constraint = parseConstraint();
-
- if (currentIs(tok!";"))
- advance();
- else
- {
- node.functionBody = parseFunctionBody();
- if (node.functionBody is null) return null;
- }
-
- return node;
- }
-
- /**
- * Parses an ContinueStatement
- *
- * $(GRAMMAR $(RULEDEF continueStatement):
- * $(LITERAL 'continue') $(LITERAL Identifier)? $(LITERAL ';')
- * ;)
- */
- ContinueStatement parseContinueStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- if (expect(tok!"continue") is null) return null;
- auto node = allocate!ContinueStatement;
- switch (current.type)
- {
- case tok!"identifier":
- node.label = advance();
- if (expect(tok!";") is null) return null;
- break;
- case tok!";":
- advance();
- break;
- default:
- error(`Identifier or semicolon expected following "continue"`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a DebugCondition
- *
- * $(GRAMMAR $(RULEDEF debugCondition):
- * $(LITERAL 'debug') ($(LITERAL '$(LPAREN)') ($(LITERAL IntegerLiteral) | $(LITERAL Identifier)) $(LITERAL '$(RPAREN)'))?
- * ;)
- */
- DebugCondition parseDebugCondition()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DebugCondition;
- if (expect(tok!"debug") is null) return null;
- if (currentIs(tok!"("))
- {
- advance();
- if (currentIsOneOf(tok!"intLiteral", tok!"identifier"))
- node.identifierOrInteger = advance();
- else
- {
- error(`Integer literal or identifier expected`);
- return null;
- }
- if (expect(tok!")") is null) return null;
- }
- return node;
- }
-
- /**
- * Parses a DebugSpecification
- *
- * $(GRAMMAR $(RULEDEF debugSpecification):
- * $(LITERAL 'debug') $(LITERAL '=') ($(LITERAL Identifier) | $(LITERAL IntegerLiteral)) $(LITERAL ';')
- * ;)
- */
- DebugSpecification parseDebugSpecification()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DebugSpecification;
- if (expect(tok!"debug") is null) return null;
- if (expect(tok!"=") is null) return null;
- if (currentIsOneOf(tok!"identifier", tok!"intLiteral"))
- node.identifierOrInteger = advance();
- else
- {
- error("Integer literal or identifier expected");
- return null;
- }
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses a Declaration
- *
- * $(GRAMMAR $(RULEDEF declaration):
- * $(RULE attribute)* $(declaration2)
- * ;
- * $(RULEDEF declaration2):
- * $(RULE aliasDeclaration)
- * | $(RULE aliasThisDeclaration)
- * | $(RULE classDeclaration)
- * | $(RULE conditionalDeclaration)
- * | $(RULE constructor)
- * | $(RULE destructor)
- * | $(RULE enumDeclaration)
- * | $(RULE functionDeclaration)
- * | $(RULE importDeclaration)
- * | $(RULE interfaceDeclaration)
- * | $(RULE mixinDeclaration)
- * | $(RULE mixinTemplateDeclaration)
- * | $(RULE pragmaDeclaration)
- * | $(RULE sharedStaticConstructor)
- * | $(RULE sharedStaticDestructor)
- * | $(RULE staticAssertDeclaration)
- * | $(RULE staticConstructor)
- * | $(RULE staticDestructor)
- * | $(RULE structDeclaration)
- * | $(RULE templateDeclaration)
- * | $(RULE unionDeclaration)
- * | $(RULE unittest)
- * | $(RULE variableDeclaration)
- * | $(RULE attributeDeclaration)
- * | $(RULE invariant)
- * | $(LITERAL '{') $(RULE declaration)+ $(LITERAL '}')
- * ;)
- */
- Declaration parseDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Declaration;
- comment = current.comment;
- Attribute[] attributes;
- do
- {
- if (!isAttribute())
- break;
- auto attr = parseAttribute();
- if (attr is null)
- {
- error("attribute is null");
- break;
- }
- if (currentIs(tok!":"))
- {
- node.attributeDeclaration = parseAttributeDeclaration(attr);
- node.attributes = ownArray(attributes);
- return node;
- }
- else
- attributes ~= attr;
- } while (moreTokens());
- node.attributes = ownArray(attributes);
-
- switch (current.type)
- {
- case tok!";":
- // http://d.puremagic.com/issues/show_bug.cgi?id=4559
- warn("Empty declaration");
- advance();
- break;
- case tok!"{":
- advance();
- Declaration[] declarations;
- while (moreTokens() && !currentIs(tok!"}"))
- {
- auto declaration = parseDeclaration();
- if (declaration !is null)
- declarations ~= declaration;
- }
- node.declarations = ownArray(declarations);
- if (expect(tok!"}") is null) return null;
- break;
- case tok!"alias":
- if (startsWith(tok!"alias", tok!"identifier", tok!"this"))
- node.aliasThisDeclaration = parseAliasThisDeclaration();
- else
- node.aliasDeclaration = parseAliasDeclaration();
- break;
- case tok!"class":
- node.classDeclaration = parseClassDeclaration();
- break;
- case tok!"this":
- if (startsWith(tok!"this", tok!"(", tok!"this"))
- {
- node.postblit = parsePostblit();
- if (node.postblit is null) return null;
- }
- else
- {
- node.constructor = parseConstructor();
- if (node.constructor is null) return null;
- }
- break;
- case tok!"~":
- node.destructor = parseDestructor();
- if (node.destructor is null) return null;
- break;
- case tok!"enum":
- if (startsWith(tok!"enum", tok!"identifier", tok!"("))
- goto case tok!"template";
- node.enumDeclaration = parseEnumDeclaration();
- if (node.enumDeclaration is null) return null;
- break;
- case tok!"import":
- node.importDeclaration = parseImportDeclaration();
- if (node.importDeclaration is null) return null;
- break;
- case tok!"interface":
- node.interfaceDeclaration = parseInterfaceDeclaration();
- if (node.interfaceDeclaration is null) return null;
- break;
- case tok!"mixin":
- if (peekIs(tok!"template"))
- node.mixinTemplateDeclaration = parseMixinTemplateDeclaration();
- else
- {
- auto b = setBookmark();
- advance();
- if (currentIs(tok!"("))
- {
- auto t = peekPastParens();
- if (t !is null && t.type == tok!";")
- {
- goToBookmark(b);
- node.mixinDeclaration = parseMixinDeclaration();
- }
- else
- {
- goToBookmark(b);
- error("Declaration expected");
- advance();
- return null;
- }
- }
- else
- {
- goToBookmark(b);
- node.mixinDeclaration = parseMixinDeclaration();
- }
- }
- break;
- case tok!"pragma":
- node.pragmaDeclaration = parsePragmaDeclaration();
- break;
- case tok!"shared":
- if (startsWith(tok!"shared", tok!"static", tok!"this"))
- node.sharedStaticConstructor = parseSharedStaticConstructor();
- else if (startsWith(tok!"shared", tok!"static", tok!"~"))
- node.sharedStaticDestructor = parseSharedStaticDestructor();
- else
- goto type;
- break;
- case tok!"static":
- if (peekIs(tok!"this"))
- node.staticConstructor = parseStaticConstructor();
- else if (peekIs(tok!"~"))
- node.staticDestructor = parseStaticDestructor();
- else if (peekIs(tok!"if"))
- node.conditionalDeclaration = parseConditionalDeclaration();
- else if (peekIs(tok!"assert"))
- node.staticAssertDeclaration = parseStaticAssertDeclaration();
- else
- goto type;
- break;
- case tok!"struct":
- node.structDeclaration = parseStructDeclaration();
- break;
- case tok!"template":
- node.templateDeclaration = parseTemplateDeclaration();
- break;
- case tok!"union":
- node.unionDeclaration = parseUnionDeclaration();
- break;
- case tok!"invariant":
- node.invariant_ = parseInvariant();
- break;
- case tok!"unittest":
- node.unittest_ = parseUnittest();
- break;
- case tok!"identifier":
- if (node.attributes.length > 0
- && node.attributes[$ - 1].storageClass !is null)
- {
- if (peekIs(tok!"="))
- node.variableDeclaration = parseVariableDeclaration(null, true);
- else if (peekIs(tok!"("))
- node.functionDeclaration = parseFunctionDeclaration(null, true, node.attributes);
- else
- goto type;
- }
- else
- goto type;
- break;
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"scope":
- case tok!"typeof":
- mixin (BASIC_TYPE_CASES);
- type:
- Type type = parseType();
- if (!currentIs(tok!"identifier"))
- {
- error("Identifier expected");
- return null;
- }
- if (peekIs(tok!"("))
- node.functionDeclaration = parseFunctionDeclaration(type, false, node.attributes);
- else
- node.variableDeclaration = parseVariableDeclaration(type);
- break;
- case tok!"version":
- if (peekIs(tok!"("))
- node.conditionalDeclaration = parseConditionalDeclaration();
- else if (peekIs(tok!"="))
- node.versionSpecification = parseVersionSpecification();
- else
- {
- error(`"=" or "(" expected following "version"`);
- return null;
- }
- break;
- case tok!"debug":
- node.conditionalDeclaration = parseConditionalDeclaration();
- if (node.conditionalDeclaration is null) return null;
- break;
- default:
- error("Declaration expected");
- if (moreTokens())
- advance();
- return null;
- }
- return node;
- }
-
- /**
- * Parses DeclarationsAndStatements
- *
- * $(GRAMMAR $(RULEDEF declarationsAndStatements):
- * $(RULE declarationOrStatement)+
- * ;)
- */
- DeclarationsAndStatements parseDeclarationsAndStatements()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DeclarationsAndStatements;
- DeclarationOrStatement[] declarationsAndStatements;
- while (!currentIsOneOf(tok!"}") && moreTokens())
- {
- auto dos = parseDeclarationOrStatement();
- if (dos !is null)
- declarationsAndStatements ~= dos;
- }
- node.declarationsAndStatements = ownArray(declarationsAndStatements);
- return node;
- }
-
- /**
- * Parses a DeclarationOrStatement
- *
- * $(GRAMMAR $(RULEDEF declarationOrStatement):
- * $(RULE declaration)
- * | $(RULE statement)
- * ;)
- */
- DeclarationOrStatement parseDeclarationOrStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DeclarationOrStatement;
- // "Any ambiguities in the grammar between Statements and
- // Declarations are resolved by the declarations taking precedence."
- if (isDeclaration())
- {
- trace("\033[01;36mparsing declaration\033[0m");
- node.declaration = parseDeclaration();
- }
- else
- {
- trace("\033[01;36mparsing statement\033[0m");
- node.statement = parseStatement();
- }
-
- if (node.statement is null && node.declaration is null)
- {
- error("Could not parse declaration or statement");
- return null;
- }
- return node;
- }
-
- /**
- * Parses a Declarator
- *
- * $(GRAMMAR $(RULEDEF declarator):
- * $(LITERAL Identifier) ($(LITERAL '=') $(RULE initializer))?
- * ;)
- */
- Declarator parseDeclarator()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Declarator;
- auto id = expect(tok!"identifier");
- if (id is null) return null;
- node.name = *id;
- if (currentIs(tok!"[")) // dmd doesn't accept pointer after identifier
- {
- warn("C-style array declaration.");
- TypeSuffix[] typeSuffixes;
- while (moreTokens() && currentIs(tok!"["))
- {
- auto suffix = parseTypeSuffix();
- if (suffix !is null)
- typeSuffixes ~= suffix;
- else
- return null;
- }
- node.cstyle = ownArray(typeSuffixes);
- }
- if (currentIs(tok!"="))
- {
- advance();
- node.initializer = parseInitializer();
- }
- return node;
- }
-
- /**
- * Parses a DefaultStatement
- *
- * $(GRAMMAR $(RULEDEF defaultStatement):
- * $(LITERAL 'default') $(LITERAL ':') $(RULE declarationsAndStatements)
- * ;)
- */
- DefaultStatement parseDefaultStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DefaultStatement;
- if (expect(tok!"default") is null) return null;
- if (expect(tok!":") is null) return null;
- node.declarationsAndStatements = parseDeclarationsAndStatements();
- return node;
- }
-
- /**
- * Parses a DeleteExpression
- *
- * $(GRAMMAR $(RULEDEF deleteExpression):
- * $(LITERAL 'delete') $(RULE unaryExpression)
- * ;)
- */
- DeleteExpression parseDeleteExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DeleteExpression;
- node.line = current.line;
- node.column = current.column;
- if (expect(tok!"delete") is null) return null;
- node.unaryExpression = parseUnaryExpression();
- return node;
- }
-
- /**
- * Parses a Deprecated attribute
- *
- * $(GRAMMAR $(RULEDEF deprecated):
- * $(LITERAL 'deprecated') ($(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)'))?
- * ;)
- */
- Deprecated parseDeprecated()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Deprecated;
- if (expect(tok!"deprecated") is null) return null;
- if (currentIs(tok!"("))
- {
- advance();
- node.assignExpression = parseAssignExpression();
- if (expect(tok!")") is null) return null;
- }
- return node;
- }
-
- /**
- * Parses a Destructor
- *
- * $(GRAMMAR $(RULEDEF destructor):
- * $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';'))
- * ;)
- */
- Destructor parseDestructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Destructor;
- 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;
- }
-
- unittest
- {
- auto sourceCode = q{~this(){}}c;
- Parser p = getParserForUnittest(sourceCode, "parseDestructor");
- Destructor d = p.parseDestructor();
- assert (d !is null);
- assert (d.functionBody !is null);
- assert (p.errorCount == 0);
- stderr.writeln("Unittest for parseDestructor() passed.");
- }
-
- /**
- * Parses a DoStatement
- *
- * $(GRAMMAR $(RULEDEF doStatement):
- * $(LITERAL 'do') $(RULE statementNoCaseNoDefault) $(LITERAL 'while') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(LITERAL ';')
- * ;)
- */
- DoStatement parseDoStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!DoStatement;
- if (expect(tok!"do") is null) return null;
- node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault();
- if (expect(tok!"while") is null) return null;
- if (expect(tok!"(") is null) return null;
- node.expression = parseExpression();
- if (expect(tok!")") is null) return null;
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses an EnumBody
- *
- * $(GRAMMAR $(RULEDEF enumBody):
- * $(LITERAL ';')
- * | $(LITERAL '{') $(RULE enumMember) ($(LITERAL ',') $(RULE enumMember)?)* $(LITERAL '}')
- * ;)
- */
- EnumBody parseEnumBody()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- EnumBody node = allocate!EnumBody;
- if (!currentIs(tok!";"))
- {
- auto open = expect (tok!"{");
- if (open is null) goto ret;
- node.startLocation = open.index;
- EnumMember[] enumMembers;
- while (moreTokens())
- {
- if (!currentIsOneOf(tok!",", tok!"}"))
- enumMembers ~= parseEnumMember();
- else if (currentIs(tok!","))
- {
- advance();
- continue;
- }
- else if (currentIs(tok!"}"))
- break;
- else
- {
- error(`",", "}", or enum member expected`);
- goto ret;
- }
- }
- node.enumMembers = ownArray(enumMembers);
- auto close = expect (tok!"}");
- if (close !is null)
- node.endLocation = close.index;
- }
- ret:
- return node;
- }
-
- /**
- * Parses an EnumDeclaration
- *
- * $(GRAMMAR $(RULEDEF enumDeclaration):
- * $(LITERAL 'enum') $(LITERAL Identifier)? ($(LITERAL ':') $(RULE type))? $(RULE enumBody)
- * ;)
- */
- EnumDeclaration parseEnumDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!EnumDeclaration;
- if (expect(tok!"enum") is null) return null;
- if (currentIs(tok!"identifier"))
- node.name = advance();
- else
- node.name.line = tokens[index - 1].line; // preserve line number if anonymous
- node.comment = comment;
- comment = null;
- if (currentIs(tok!":"))
- {
- advance();
- node.type = parseType();
- }
- node.enumBody = parseEnumBody();
- return node;
- }
-
- /**
- * Parses an EnumMember
- *
- * $(GRAMMAR $(RULEDEF enumMember):
- * $(LITERAL Identifier)
- * | ($(LITERAL Identifier) | $(RULE type)) $(LITERAL '=') $(RULE assignExpression)
- * ;)
- */
- EnumMember parseEnumMember()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!EnumMember;
- node.comment = current.comment;
- if (currentIs(tok!"identifier"))
- {
- if (peekIsOneOf(tok!",", tok!"}"))
- node.name = advance();
- else if (peekIs(tok!"="))
- {
- node.name = advance();
- goto assign;
- }
- else
- goto type;
- }
- else
- {
- type:
- node.type = parseType();
- assign:
- expect(tok!"=");
- node.assignExpression = parseAssignExpression();
- }
- return node;
- }
-
- /**
- * Parses an EqualExpression
- *
- * $(GRAMMAR $(RULEDEF equalExpression):
- * $(RULE shiftExpression) ($(LITERAL '==') | $(LITERAL '!=')) $(RULE shiftExpression)
- * ;)
- */
- EqualExpression parseEqualExpression(ExpressionNode shift = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!EqualExpression;
- node.left = shift is null ? parseShiftExpression() : shift;
- if (currentIsOneOf(tok!"==", tok!"!="))
- node.operator = advance().type;
- node.right = parseShiftExpression();
- return node;
- }
-
- /**
- * Parses an Expression
- *
- * $(GRAMMAR $(RULEDEF expression):
- * $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))*
- * ;)
- */
- Expression parseExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseCommaSeparatedRule!(Expression, AssignExpression)();
- }
-
- /**
- * Parses an ExpressionStatement
- *
- * $(GRAMMAR $(RULEDEF expressionStatement):
- * $(RULE expression) $(LITERAL ';')
- * ;)
- */
- ExpressionStatement parseExpressionStatement(Expression expression = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ExpressionStatement;
- node.expression = expression is null ? parseExpression() : expression;
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses a FinalSwitchStatement
- *
- * $(GRAMMAR $(RULEDEF finalSwitchStatement):
- * $(LITERAL 'final') $(RULE switchStatement)
- * ;)
- */
- FinalSwitchStatement parseFinalSwitchStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!FinalSwitchStatement;
- if (expect(tok!"final") is null) return null;
- node.switchStatement = parseSwitchStatement();
- if (node.switchStatement is null) return null;
- return node;
- }
-
- /**
- * Parses a Finally
- *
- * $(GRAMMAR $(RULEDEF finally):
- * $(LITERAL 'finally') $(RULE declarationOrStatement)
- * ;)
- */
- Finally parseFinally()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Finally;
- if (expect(tok!"finally") is null) return null;
- node.declarationOrStatement = parseDeclarationOrStatement();
- return node;
- }
-
- /**
- * Parses a ForStatement
- *
- * $(GRAMMAR $(RULEDEF forStatement):
- * $(LITERAL 'for') $(LITERAL '$(LPAREN)') $(RULE declarationOrStatement) $(RULE expression)? $(LITERAL ';') $(RULE expression)? $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
- * ;)
- */
- ForStatement parseForStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ForStatement;
- if (expect(tok!"for") is null) return null;
- node.startIndex = current().index;
- if (expect(tok!"(") is null) return null;
-
- if (currentIs(tok!";"))
- advance();
- else
- node.initialization = parseDeclarationOrStatement();
-
- if (currentIs(tok!";"))
- advance();
- else
- node.test = parseExpressionStatement();
-
- if (!currentIs(tok!")"))
- node.increment = parseExpression();
-
- if (expect(tok!")") is null) return null;
- if (currentIs(tok!"}"))
- {
- error("Statement expected", false);
- return node; // this line makes DCD better
- }
- node.declarationOrStatement = parseDeclarationOrStatement();
- if (node.declarationOrStatement is null) return null;
- return node;
- }
-
- /**
- * Parses a ForeachStatement
- *
- * $(GRAMMAR $(RULEDEF foreachStatement):
- * ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachTypeList) $(LITERAL ';') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
- * | ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachType) $(LITERAL ';') $(RULE expression) $(LITERAL '..') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
- * ;)
- */
- ForeachStatement parseForeachStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- ForeachStatement node = allocate!ForeachStatement;
- if (currentIsOneOf(tok!"foreach", tok!"foreach_reverse"))
- node.type = advance().type;
- else
- {
- error(`"foreach" or "foreach_reverse" expected`);
- return null;
- }
- node.startIndex = current().index;
- if (expect(tok!"(") is null) return null;
- ForeachTypeList feType = parseForeachTypeList();
- bool canBeRange = feType.items.length == 1;
-
- if (expect(tok!";") is null) return null;
- node.low = parseExpression();
- if (node.low is null) return null;
- if (currentIs(tok!".."))
- {
- if (!canBeRange)
- {
- error(`Cannot have more than one foreach variable for a foreach range statement`);
- return null;
- }
- advance();
- node.high = parseExpression();
- node.foreachType = feType.items[0];
- if (node.high is null) return null;
- }
- else
- {
- node.foreachTypeList = feType;
- }
- if (expect(tok!")") is null) return null;
- if (currentIs(tok!"}"))
- {
- error("Statement expected", false);
- return node; // this line makes DCD better
- }
- node.declarationOrStatement = parseDeclarationOrStatement();
- if (node.declarationOrStatement is null) return null;
- return node;
- }
-
- /**
- * Parses a ForeachType
- *
- * $(GRAMMAR $(RULEDEF foreachType):
- * $(RULE typeConstructors)? $(RULE type)? $(LITERAL Identifier)
- * ;)
- */
- ForeachType parseForeachType()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ForeachType;
- if (currentIsOneOf(tok!"ref", tok!"const", tok!"immutable",
- tok!"shared", tok!"inout"))
- {
- trace("\033[01;36mType constructor");
- if ((node.typeConstructors = parseTypeConstructors()) is null)
- return null;
- }
- if (currentIs(tok!"identifier") && peekIsOneOf(tok!",", tok!";"))
- {
- node.identifier = advance();
- return node;
- }
- if ((node.type = parseType()) is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- return node;
- }
-
- /**
- * Parses a ForeachTypeList
- *
- * $(GRAMMAR $(RULEDEF foreachTypeList):
- * $(RULE foreachType) ($(LITERAL ',') $(RULE foreachType))*
- * ;)
- */
- ForeachTypeList parseForeachTypeList()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseCommaSeparatedRule!(ForeachTypeList, ForeachType)();
- }
-
- /**
- * Parses a FunctionAttribute
- *
- * $(GRAMMAR $(RULEDEF functionAttribute):
- * $(RULE atAttribute)
- * | $(LITERAL 'pure')
- * | $(LITERAL 'nothrow')
- * ;)
- */
- FunctionAttribute parseFunctionAttribute(bool validate = true)
- {
- auto node = allocate!FunctionAttribute;
- switch (current.type)
- {
- case tok!"@":
- node.atAttribute = parseAtAttribute();
- break;
- case tok!"pure":
- case tok!"nothrow":
- node.token = advance();
- break;
- default:
- if (validate)
- error(`@attribute, "pure", or "nothrow" expected`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a FunctionBody
- *
- * $(GRAMMAR $(RULEDEF functionBody):
- * $(RULE blockStatement)
- * | ($(RULE inStatement) | $(RULE outStatement) | $(RULE outStatement) $(RULE inStatement) | $(RULE inStatement) $(RULE outStatement))? $(RULE bodyStatement)
- * ;)
- */
- FunctionBody parseFunctionBody()
- {
- auto node = allocate!FunctionBody;
- if (currentIs(tok!";"))
- {
- advance();
- return node;
- }
- else if (currentIs(tok!"{"))
- node.blockStatement = parseBlockStatement();
- else
- {
- if (currentIs(tok!"in"))
- {
- node.inStatement = parseInStatement();
- if (currentIs(tok!"out"))
- node.outStatement = parseOutStatement();
- }
- else if (currentIs(tok!"out"))
- {
- node.outStatement = parseOutStatement();
- if (currentIs(tok!"in"))
- node.inStatement = parseInStatement();
- }
- node.bodyStatement = parseBodyStatement();
- }
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{
-{} // one
-in {} body{} // two
-out {} body{} // three
-in {} out {} body {} // four
-out {} in {} body {} // five
-body {} // six
- };
-
- Parser p = getParserForUnittest(sourceCode, "parseFunctionBody");
-
- FunctionBody functionBodyOne = p.parseFunctionBody();
- assert (functionBodyOne.blockStatement !is null);
-
- FunctionBody functionBodyTwo = p.parseFunctionBody();
- assert (functionBodyTwo.blockStatement is null);
- assert (functionBodyTwo.inStatement !is null);
- assert (functionBodyTwo.outStatement is null);
- assert (functionBodyTwo.bodyStatement !is null);
-
- FunctionBody functionBodyThree = p.parseFunctionBody();
- assert (functionBodyThree.blockStatement is null);
- assert (functionBodyThree.inStatement is null);
- assert (functionBodyThree.outStatement !is null);
- assert (functionBodyThree.bodyStatement !is null);
-
- FunctionBody functionBodyFour = p.parseFunctionBody();
- assert (functionBodyFour.blockStatement is null);
- assert (functionBodyFour.inStatement !is null);
- assert (functionBodyFour.outStatement !is null);
- assert (functionBodyFour.bodyStatement !is null);
-
- FunctionBody functionBodyFive = p.parseFunctionBody();
- assert (functionBodyFive.blockStatement is null);
- assert (functionBodyFive.inStatement !is null);
- assert (functionBodyFive.outStatement !is null);
- assert (functionBodyFive.bodyStatement !is null);
-
- FunctionBody functionBodySix = p.parseFunctionBody();
- assert (functionBodySix.blockStatement is null);
- assert (functionBodySix.inStatement is null);
- assert (functionBodySix.outStatement is null);
- assert (functionBodySix.bodyStatement !is null);
-
- stderr.writeln("Unittest for parseFunctionBody() passed.");
- }
-
- /**
- * Parses a FunctionCallExpression
- *
- * $(GRAMMAR $(RULEDEF functionCallExpression):
- * $(RULE unaryExpression) $(RULE templateArguments)? $(RULE arguments)
- * | $(RULE type) $(RULE arguments)
- * ;)
- */
- FunctionCallExpression parseFunctionCallExpression(UnaryExpression unary = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!FunctionCallExpression;
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"scope":
- case tok!"pure":
- case tok!"nothrow":
- node.type = parseType();
- node.arguments = parseArguments();
- break;
- default:
- if (unary !is null)
- node.unaryExpression = unary;
- else
- node.unaryExpression = parseUnaryExpression();
- if (currentIs(tok!"!"))
- node.templateArguments = parseTemplateArguments();
- if (unary !is null)
- node.arguments = parseArguments();
- }
- return node.arguments is null ? null : node;
- }
-
- /**
- * Parses a FunctionCallStatement
- *
- * $(GRAMMAR $(RULEDEF functionCallStatement):
- * $(RULE functionCallExpression) $(LITERAL ';')
- * ;)
- */
- FunctionCallStatement parseFunctionCallStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!FunctionCallStatement;
- node.functionCallExpression = parseFunctionCallExpression();
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses a FunctionDeclaration
- *
- * $(GRAMMAR $(RULEDEF functionDeclaration):
- * ($(RULE storageClass) | $(RULE _type)) $(LITERAL Identifier) $(RULE templateParameters) $(RULE parameters) $(RULE memberFunctionAttribute)* $(RULE constraint)? ($(RULE functionBody) | $(LITERAL ';'))
- * ;)
- */
- FunctionDeclaration parseFunctionDeclaration(Type type = null, bool isAuto = false, Attribute[] attributes = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!FunctionDeclaration;
- node.comment = comment;
- comment = null;
- MemberFunctionAttribute[] memberFunctionAttributes;
-
- node.attributes = attributes;
-
- if (isAuto)
- {
- foreach (a; node.attributes)
- {
- if (a.storageClass is null)
- continue;
- if (a.storageClass.token == tok!"auto")
- node.hasAuto = true;
- if (a.storageClass.token == tok!"ref")
- node.hasRef = true;
- }
- goto functionName;
- }
-
- while (moreTokens() && currentIsMemberFunctionAttribute())
- memberFunctionAttributes ~= parseMemberFunctionAttribute();
-
- node.returnType = type is null ? parseType() : type;
-
- functionName:
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
-
- node.name = *ident;
-
- if (!currentIs(tok!"("))
- {
- error(`"(" expected`);
- return null;
- }
-
- assert (currentIs(tok!"("));
- auto p = peekPastParens();
- bool isTemplate = p !is null && p.type == tok!"(";
-
- if (isTemplate)
- node.templateParameters = parseTemplateParameters();
-
- node.parameters = parseParameters();
- if (node.parameters is null) return null;
-
- while (moreTokens() && currentIsMemberFunctionAttribute())
- memberFunctionAttributes ~= parseMemberFunctionAttribute();
-
- if (isTemplate && currentIs(tok!"if"))
- node.constraint = parseConstraint();
-
- if (currentIs(tok!";"))
- advance();
- else
- node.functionBody = parseFunctionBody();
- node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
- return node;
- }
-
- /**
- * Parses a FunctionLiteralExpression
- *
- * $(GRAMMAR $(RULEDEF functionLiteralExpression):
- * (($(LITERAL 'function') | $(LITERAL 'delegate')) $(RULE type)?)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody)
- * ;)
- */
- FunctionLiteralExpression parseFunctionLiteralExpression()
- {
- auto node = allocate!FunctionLiteralExpression;
- if (currentIsOneOf(tok!"function", tok!"delegate"))
- {
- node.functionOrDelegate = advance().type;
- if (!currentIsOneOf(tok!"(", tok!"in", tok!"body",
- tok!"out", tok!"}"))
- {
- node.type = parseType();
- if (node.type is null) return null;
- }
- }
- if (currentIs(tok!"("))
- {
- node.parameters = parseParameters();
- if (node.parameters is null) return null;
- FunctionAttribute[] functionAttributes;
- do
- {
- auto attr = parseFunctionAttribute(false);
- if (attr is null)
- break;
- else
- functionAttributes ~= attr;
- } while (moreTokens());
- node.functionAttributes = ownArray(functionAttributes);
- }
- node.functionBody = parseFunctionBody();
- if (node.functionBody is null) return null;
- return node;
- }
-
- /**
- * Parses a GotoStatement
- *
- * $(GRAMMAR $(RULEDEF gotoStatement):
- * $(LITERAL 'goto') ($(LITERAL Identifier) | $(LITERAL 'default') | $(LITERAL 'case') $(RULE expression)?) $(LITERAL ';')
- * ;)
- */
- GotoStatement parseGotoStatement()
- {
- auto node = allocate!GotoStatement;
- if (expect(tok!"goto") is null) return null;
- switch (current.type)
- {
- case tok!"identifier":
- case tok!"default":
- node.label = advance();
- break;
- case tok!"case":
- node.label = advance();
- if (!currentIs(tok!";"))
- node.expression = parseExpression();
- break;
- default:
- error(`Identifier, "default", or "case" expected`);
- return null;
- }
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- /**
- * Parses an IdentifierChain
- *
- * $(GRAMMAR $(RULEDEF identifierChain):
- * $(LITERAL Identifier) ($(LITERAL '.') $(LITERAL Identifier))*
- * ;)
- */
- IdentifierChain parseIdentifierChain()
- {
- auto node = allocate!IdentifierChain;
- Token[] identifiers;
- while (moreTokens())
- {
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- identifiers ~= *ident;
- if (currentIs(tok!"."))
- {
- advance();
- continue;
- }
- else
- break;
- }
- node.identifiers = ownArray(identifiers);
- return node;
- }
-
- /**
- * Parses an IdentifierList
- *
- * $(GRAMMAR $(RULEDEF identifierList):
- * $(LITERAL Identifier) ($(LITERAL ',') $(LITERAL Identifier))*
- * ;)
- */
- IdentifierList parseIdentifierList()
- {
- auto node = allocate!IdentifierList;
- Token[] identifiers;
- do
- {
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- identifiers ~= *ident;
- if (currentIs(tok!","))
- {
- advance();
- continue;
- }
- else
- break;
- } while (moreTokens());
- node.identifiers = ownArray(identifiers);
- return node;
- }
-
- /**
- * Parses an IdentifierOrTemplateChain
- *
- * $(GRAMMAR $(RULEDEF identifierOrTemplateChain):
- * $(RULE identifierOrTemplateInstance) ($(LITERAL '.') $(RULE identifierOrTemplateInstance))*
- * ;)
- */
- IdentifierOrTemplateChain parseIdentifierOrTemplateChain()
- {
- auto node = allocate!IdentifierOrTemplateChain;
- IdentifierOrTemplateInstance[] identifiersOrTemplateInstances;
- while (moreTokens())
- {
- identifiersOrTemplateInstances ~= parseIdentifierOrTemplateInstance();
- if (!currentIs(tok!"."))
- break;
- else
- advance();
- }
- node.identifiersOrTemplateInstances = ownArray(identifiersOrTemplateInstances);
- return node;
- }
-
- /**
- * Parses an IdentifierOrTemplateInstance
- *
- * $(GRAMMAR $(RULEDEF identifierOrTemplateInstance):
- * $(LITERAL Identifier)
- * | $(RULE templateInstance)
- * ;)
- */
- IdentifierOrTemplateInstance parseIdentifierOrTemplateInstance()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!IdentifierOrTemplateInstance;
- if (peekIs(tok!"!") && !startsWith(tok!"identifier",
- tok!"!", tok!"is")
- && !startsWith(tok!"identifier", tok!"!", tok!"in"))
- {
- node.templateInstance = parseTemplateInstance();
- }
- else
- {
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- }
- return node;
- }
-
- /**
- * Parses an IdentityExpression
- *
- * $(GRAMMAR $(RULEDEF identityExpression):
- * $(RULE shiftExpression) ($(LITERAL 'is') | $(LITERAL '!') $(LITERAL 'is')) $(RULE shiftExpression)
- * ;)
- */
- ExpressionNode parseIdentityExpression(ExpressionNode shift = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!IdentityExpression;
- node.left = shift is null ? parseShiftExpression() : shift;
- if (currentIs(tok!"!"))
- {
- advance();
- node.negated = true;
- }
- if (expect(tok!"is") is null) return null;
- node.right = parseShiftExpression();
- return node;
- }
-
- /**
- * Parses an IfStatement
- *
- * $(GRAMMAR $(RULEDEF ifStatement):
- * $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE ifCondition) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) ($(LITERAL 'else') $(RULE declarationOrStatement))?
- * $(RULEDEF ifCondition):
- * $(LITERAL 'auto') $(LITERAL Identifier) $(LITERAL '=') $(RULE expression)
- * | $(RULE type) $(LITERAL Identifier) $(LITERAL '=') $(RULE expression)
- * | $(RULE expression)
- * ;)
- */
- IfStatement parseIfStatement()
- {
- 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;
-
- if (currentIs(tok!"auto"))
- {
- advance();
- auto i = expect(tok!"identifier");
- if (i !is null)
- node.identifier = *i;
- expect(tok!"=");
- node.expression = parseExpression();
- }
- else
- {
- auto b = setBookmark();
- auto t = parseType();
- if (t is null || !currentIs(tok!"identifier")
- || !peekIs(tok!"="))
- {
- goToBookmark(b);
- node.expression = parseExpression();
- }
- else
- {
- goToBookmark(b);
- node.type = parseType();
- auto i = expect(tok!"identifier");
- if (i !is null)
- node.identifier = *i;
- expect(tok!"=");
- node.expression = parseExpression();
- }
- }
-
- if (expect(tok!")") is null) return null;
- if (currentIs(tok!"}"))
- {
- error("Statement expected", false);
- return node; // this line makes DCD better
- }
- node.thenStatement = parseDeclarationOrStatement();
- if (currentIs(tok!"else"))
- {
- advance();
- node.elseStatement = parseDeclarationOrStatement();
- }
- return node;
- }
-
- /**
- * Parses an ImportBind
- *
- * $(GRAMMAR $(RULEDEF importBind):
- * $(LITERAL Identifier) ($(LITERAL '=') $(LITERAL Identifier))?
- * ;)
- */
- ImportBind parseImportBind()
- {
- auto node = allocate!ImportBind;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.left = *ident;
- if (currentIs(tok!"="))
- {
- advance();
- auto id = expect(tok!"identifier");
- if (id is null) return null;
- node.right = *id;
- }
- return node;
- }
-
- /**
- * Parses ImportBindings
- *
- * $(GRAMMAR $(RULEDEF importBindings):
- * $(RULE singleImport) $(LITERAL ':') $(RULE importBind) ($(LITERAL ',') $(RULE importBind))*
- * ;)
- */
- ImportBindings parseImportBindings(SingleImport singleImport)
- {
- auto node = allocate!ImportBindings;
- node.singleImport = singleImport is null ? parseSingleImport() : singleImport;
- if (expect(tok!":") is null) return null;
- ImportBind[] importBinds;
- while (moreTokens())
- {
- importBinds ~= parseImportBind();
- if (currentIs(tok!","))
- advance();
- else
- break;
- }
- node.importBinds = ownArray(importBinds);
- return node;
- }
-
- /**
- * Parses an ImportDeclaration
- *
- * $(GRAMMAR $(RULEDEF importDeclaration):
- * $(LITERAL 'import') $(RULE singleImport) ($(LITERAL ',') $(RULE singleImport))* ($(LITERAL ',') $(RULE importBindings))? $(LITERAL ';')
- * | $(LITERAL 'import') $(RULE importBindings) $(LITERAL ';')
- * ;)
- */
- ImportDeclaration parseImportDeclaration()
- {
- auto node = allocate!ImportDeclaration;
- if (expect(tok!"import") is null) return null;
- SingleImport si = parseSingleImport();
- if (currentIs(tok!":"))
- node.importBindings = parseImportBindings(si);
- else
- {
- SingleImport[] singleImports;
- singleImports ~= si;
- if (currentIs(tok!","))
- {
- advance();
- while (moreTokens())
- {
- auto single = parseSingleImport();
- if (single is null)
- return null;
- if (currentIs(tok!":"))
- {
- node.importBindings = parseImportBindings(single);
- break;
- }
- else
- {
- singleImports ~= single;
- if (currentIs(tok!","))
- advance();
- else
- break;
- }
- }
- }
- node.singleImports = ownArray(singleImports);
- }
- if (expect(tok!";") is null) return null;
- return node;
- }
-
- unittest
- {
- auto sourceCode =
-q{import std.stdio;
-import foo, bar;
-import io = std.stdio;
-import std.stdio: writefln, foo = writef;
-import io = std.stdio : foo = writefln;
-import foo, bar, baz;
-import core.stdc.stdio, std.string : KeepTerminator;
-}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseImportDeclaration");
-
- ImportDeclaration one = p.parseImportDeclaration();
- assert (one !is null);
- assert (one.singleImports.length == 1);
- assert (p.errorCount == 0);
-
- ImportDeclaration two = p.parseImportDeclaration();
- assert (two !is null);
- assert (two.singleImports.length == 2);
- assert (p.errorCount == 0);
-
- ImportDeclaration three = p.parseImportDeclaration();
- assert (three !is null);
- assert (three.singleImports.length == 1);
- assert (p.errorCount == 0);
-
- ImportDeclaration four = p.parseImportDeclaration();
- assert (four !is null);
- assert (four.importBindings !is null);
- assert (four.importBindings.importBinds.length == 2);
- assert (p.errorCount == 0);
-
- ImportDeclaration five = p.parseImportDeclaration();
- assert (five !is null);
- assert (p.errorCount == 0);
-
- ImportDeclaration six = p.parseImportDeclaration();
- assert (six !is null);
- assert (six.singleImports.length == 3);
- assert (p.errorCount == 0);
-
- ImportDeclaration seven = p.parseImportDeclaration();
- assert (seven !is null);
- assert (seven.singleImports.length == 1);
- assert (seven.importBindings !is null);
- assert (p.errorCount == 0);
-
- stderr.writeln("Unittest for parseImportDeclaration() passed.");
- }
-
- /**
- * Parses an ImportExpression
- *
- * $(GRAMMAR $(RULEDEF importExpression):
- * $(LITERAL 'import') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
- * ;)
- */
- ImportExpression parseImportExpression()
- {
- auto node = allocate!ImportExpression;
- if (expect(tok!"import") is null) return null;
- if (expect(tok!"(") is null) return null;
- node.assignExpression = parseAssignExpression();
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses an IndexExpression
- *
- * $(GRAMMAR $(RULEDEF indexExpression):
- * $(RULE unaryExpression) $(LITERAL '[') $(RULE argumentList) $(LITERAL ']')
- * ;)
- */
- IndexExpression parseIndexExpression(UnaryExpression unaryExpression = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!IndexExpression;
- node.unaryExpression = unaryExpression is null ? parseUnaryExpression() : unaryExpression;
- if (expect(tok!"[") is null) return null;
- node.argumentList = parseArgumentList();
- if (expect(tok!"]") is null) return null;
- return node;
- }
-
- /**
- * Parses an InExpression
- *
- * $(GRAMMAR $(RULEDEF inExpression):
- * $(RULE shiftExpression) ($(LITERAL 'in') | $(LITERAL '!') $(LITERAL 'in')) $(RULE shiftExpression)
- * ;)
- */
- ExpressionNode parseInExpression(ExpressionNode shift = null)
- {
- auto node = allocate!InExpression;
- node.left = shift is null ? parseShiftExpression() : shift;
- if (currentIs(tok!"!"))
- {
- node.negated = true;
- advance();
- }
- if (expect(tok!"in") is null) return null;
- node.right = parseShiftExpression();
- return node;
- }
-
- /**
- * Parses an InStatement
- *
- * $(GRAMMAR $(RULEDEF inStatement):
- * $(LITERAL 'in') $(RULE blockStatement)
- * ;)
- */
- InStatement parseInStatement()
- {
- auto node = allocate!InStatement;
- if (expect(tok!"in") is null) return null;
- node.blockStatement = parseBlockStatement();
- return node;
- }
-
- /**
- * Parses an Initialize
- *
- * $(GRAMMAR $(RULEDEF initialize):
- * $(LITERAL ';')
- * | $(RULE statementNoCaseNoDefault)
- * ;)
- */
- Initialize parseInitialize()
- {
- auto node = allocate!Initialize;
- if (!currentIs(tok!";"))
- {
- node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault();
- if (node.statementNoCaseNoDefault is null) return null;
- }
- else if (expect(tok!";") is null)
- return null;
- return node;
- }
-
- /**
- * Parses an Initializer
- *
- * $(GRAMMAR $(RULEDEF initializer):
- * $(LITERAL 'void')
- * | $(RULE nonVoidInitializer)
- * ;)
- */
- Initializer parseInitializer()
- {
- auto node = allocate!Initializer;
- if (currentIs(tok!"void"))
- advance();
- else
- node.nonVoidInitializer = parseNonVoidInitializer();
- return node;
- }
-
- /**
- * Parses an InterfaceDeclaration
- *
- * $(GRAMMAR $(RULEDEF interfaceDeclaration):
- * $(LITERAL 'interface') $(LITERAL Identifier) ($(LITERAL ';') | ($(RULE templateParameters) $(RULE constraint)?)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody))
- * ;)
- */
- InterfaceDeclaration parseInterfaceDeclaration()
- {
- auto node = allocate!InterfaceDeclaration;
- if (expect(tok!"interface") is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.name = *ident;
- node.comment = comment;
- comment = null;
- if (currentIs(tok!";"))
- {
- advance();
- return node;
- }
- if (currentIs(tok!"("))
- {
- node.templateParameters = parseTemplateParameters();
- if (currentIs(tok!"if"))
- node.constraint = parseConstraint();
- }
- if (currentIs(tok!":"))
- {
- advance();
- node.baseClassList = parseBaseClassList();
- }
- node.structBody = parseStructBody();
- return node;
- }
-
- unittest
- {
- auto sourceCode =
-q{interface One {}
-interface Two : Number {}
-interface Three(T) if (someTest(T)) {}
-interface "Four"
-}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseInterfaceDeclaration");
-
- InterfaceDeclaration one = p.parseInterfaceDeclaration();
- assert (one !is null);
- assert (one.name.text == "One");
- assert (one.constraint is null);
- assert (one.templateParameters is null);
- assert (one.structBody !is null);
- assert (one.baseClassList is null);
- assert (p.errorCount == 0);
-
- InterfaceDeclaration two = p.parseInterfaceDeclaration();
- assert (two !is null);
- assert (two.name.text == "Two");
- assert (two.constraint is null);
- assert (two.templateParameters is null);
- assert (two.structBody !is null);
- assert (two.baseClassList !is null);
- assert (p.errorCount == 0);
-
- InterfaceDeclaration three = p.parseInterfaceDeclaration();
- assert (three !is null);
- assert (three.name.text == "Three");
- assert (three.constraint !is null);
- assert (three.templateParameters !is null);
- assert (three.structBody !is null);
- assert (three.baseClassList is null);
- assert (p.errorCount == 0);
-
- InterfaceDeclaration four = p.parseInterfaceDeclaration();
- assert (four is null);
- assert (p.errorCount > 0);
-
- stderr.writeln("Unittest for parseInterfaceDeclaration() passed.");
- }
-
- /**
- * Parses an Invariant
- *
- * $(GRAMMAR $(RULEDEF invariant):
- * $(LITERAL 'invariant') ($(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)'))? $(RULE blockStatement)
- * ;)
- */
- 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!"("))
- {
- advance();
- if (expect(tok!")") is null) return null;
- }
- if ((node.blockStatement = parseBlockStatement()) is null) return null;
- return node;
- }
-
- unittest
- {
- auto sourceCode =
-q{invariant() {}
-invariant{}
-invariant() foo();
-}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseInvariant");
-
- auto inv1 = p.parseInvariant();
- assert (inv1 !is null);
- assert (inv1.blockStatement !is null);
- assert (p.errorCount == 0);
-
- auto inv2 = p.parseInvariant();
- assert (inv2 !is null);
- assert (inv2.blockStatement !is null);
- assert (p.errorCount == 0);
-
- auto inv3 = p.parseInvariant();
- assert (inv3 is null);
- assert (p.errorCount > 0);
- }
-
- /**
- * Parses an IsExpression
- *
- * $(GRAMMAR $(RULEDEF isExpression):
- * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL Identifier)? (($(LITERAL ':') | $(LITERAL '==')) $(RULE typeSpecialization) ($(LITERAL ',') $(RULE templateParameterList))?)? $(LITERAL '$(RPAREN)')
- * ;)
- */
- IsExpression parseIsExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!IsExpression;
- if (expect(tok!"is") is null) return null;
- if (expect(tok!"(") is null) return null;
- node.type = parseType();
- if (node.type is null) return null;
- if (currentIs(tok!"identifier"))
- node.identifier = advance();
- if (currentIsOneOf(tok!"==", tok!":"))
- {
- node.equalsOrColon = advance().type;
- node.typeSpecialization = parseTypeSpecialization();
- if (currentIs(tok!","))
- {
- advance();
- node.templateParameterList = parseTemplateParameterList();
- }
- }
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- unittest
- {
- auto sourceCode = q{is ( x : uybte)}c;
- Parser p = getParserForUnittest(sourceCode, "parseIsExpression");
- auto isExp1 = p.parseIsExpression();
- assert (isExp1 !is null);
- assert (p.errorCount == 0);
- stderr.writeln("Unittest for parseIsExpression passed.");
- }
-
- /**
- * Parses a KeyValuePair
- *
- * $(GRAMMAR $(RULEDEF keyValuePair):
- * $(RULE assignExpression) $(LITERAL ':') $(RULE assignExpression)
- * ;)
- */
- KeyValuePair parseKeyValuePair()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!KeyValuePair;
- node.key = parseAssignExpression();
- if (expect(tok!":") is null) return null;
- node.value = parseAssignExpression();
- return node;
- }
-
- /**
- * Parses KeyValuePairs
- *
- * $(GRAMMAR $(RULEDEF keyValuePairs):
- * $(RULE keyValuePair) ($(LITERAL ',') $(RULE keyValuePair))* $(LITERAL ',')?
- * ;)
- */
- KeyValuePairs parseKeyValuePairs()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!KeyValuePairs;
- KeyValuePair[] keyValuePairs;
- while (moreTokens())
- {
- auto kvPair = parseKeyValuePair();
- if (kvPair !is null)
- keyValuePairs ~= kvPair;
- if (currentIs(tok!","))
- {
- advance();
- if (currentIs(tok!"]"))
- break;
- }
- else
- break;
- }
- node.keyValuePairs = ownArray(keyValuePairs);
- return node;
- }
-
- /**
- * Parses a LabeledStatement
- *
- * $(GRAMMAR $(RULEDEF labeledStatement):
- * $(LITERAL Identifier) $(LITERAL ':') $(RULE declarationOrStatement)
- * ;)
- */
- LabeledStatement parseLabeledStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!LabeledStatement;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- expect(tok!":");
- node.declarationOrStatement = parseDeclarationOrStatement();
- return node;
- }
-
- /**
- * Parses a LambdaExpression
- *
- * $(GRAMMAR $(RULEDEF lambdaExpression):
- * $(LITERAL Identifier) $(LITERAL '=>') $(RULE assignExpression)
- * | $(LITERAL 'function') $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
- * | $(LITERAL 'delegate') $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
- * | $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
- * ;)
- */
- LambdaExpression parseLambdaExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!LambdaExpression;
- if (currentIsOneOf(tok!"function", tok!"delegate"))
- {
- node.functionType = advance().type;
- goto lParen;
- }
- else if (currentIs(tok!"identifier"))
- node.identifier = advance();
- else if (currentIs(tok!"("))
- {
- lParen:
- node.parameters = parseParameters();
- FunctionAttribute[] functionAttributes;
- do
- {
- auto attribute = parseFunctionAttribute(false);
- if (attribute is null)
- break;
- functionAttributes ~= attribute;
- }
- while (moreTokens());
- node.functionAttributes = ownArray(functionAttributes);
- }
- else
- {
- error(`Identifier or argument list expected`);
- return null;
- }
-
- if (expect(tok!"=>") is null) return null;
-
- if ((node.assignExpression = parseAssignExpression()) is null)
- return null;
-
- return node;
- }
-
- /**
- * Parses a LastCatch
- *
- * $(GRAMMAR $(RULEDEF lastCatch):
- * $(LITERAL 'catch') $(RULE statementNoCaseNoDefault)
- * ;)
- */
- LastCatch parseLastCatch()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!LastCatch;
- auto t = expect(tok!"catch");
- if (t is null) return null;
- node.line = t.line;
- node.column = t.column;
- if ((node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault()) is null)
- return null;
- return node;
- }
-
- /**
- * Parses a LinkageAttribute
- *
- * $(GRAMMAR $(RULEDEF linkageAttribute):
- * $(LITERAL 'extern') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL '++') ($(LITERAL ',') $(RULE identifierChain))?)? $(LITERAL '$(RPAREN)')
- * ;)
- */
- LinkageAttribute parseLinkageAttribute()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!LinkageAttribute;
- expect(tok!"extern");
- expect(tok!"(");
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!"++"))
- {
- advance();
- node.hasPlusPlus = true;
- version (DIP61) if (currentIs(tok!","))
- {
- advance();
- node.identifierChain = parseIdentifierChain();
- }
- }
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a MemberFunctionAttribute
- *
- * $(GRAMMAR $(RULEDEF memberFunctionAttribute):
- * $(RULE functionAttribute)
- * | $(LITERAL 'immutable')
- * | $(LITERAL 'inout')
- * | $(LITERAL 'shared')
- * | $(LITERAL 'const')
- * ;)
- */
- MemberFunctionAttribute parseMemberFunctionAttribute()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!MemberFunctionAttribute;
- switch (current.type)
- {
- case tok!"@":
- node.atAttribute = parseAtAttribute();
- break;
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"const":
- case tok!"pure":
- case tok!"nothrow":
- node.tokenType = advance().type;
- break;
- default:
- error(`Member funtion attribute expected`);
- }
- return node;
- }
-
- /**
- * Parses a MixinDeclaration
- *
- * $(GRAMMAR $(RULEDEF mixinDeclaration):
- * $(RULE mixinExpression) $(LITERAL ';')
- * | $(RULE templateMixinExpression) $(LITERAL ';')
- * ;)
- */
- MixinDeclaration parseMixinDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!MixinDeclaration;
- if (peekIs(tok!"identifier") || peekIs(tok!"typeof"))
- node.templateMixinExpression = parseTemplateMixinExpression();
- else if (peekIs(tok!"("))
- node.mixinExpression = parseMixinExpression();
- else
- {
- error(`"(" or identifier expected`);
- return null;
- }
- expect(tok!";");
- return node;
- }
-
- /**
- * Parses a MixinExpression
- *
- * $(GRAMMAR $(RULEDEF mixinExpression):
- * $(LITERAL 'mixin') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
- * ;)
- */
- MixinExpression parseMixinExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!MixinExpression;
- expect(tok!"mixin");
- expect(tok!"(");
- node.assignExpression = parseAssignExpression();
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a MixinTemplateDeclaration
- *
- * $(GRAMMAR $(RULEDEF mixinTemplateDeclaration):
- * $(LITERAL 'mixin') $(RULE templateDeclaration)
- * ;)
- */
- MixinTemplateDeclaration parseMixinTemplateDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!MixinTemplateDeclaration;
- if (expect(tok!"mixin") is null) return null;
- node.templateDeclaration = parseTemplateDeclaration();
- if (node.templateDeclaration is null) return null;
- return node;
- }
-
- /**
- * Parses a MixinTemplateName
- *
- * $(GRAMMAR $(RULEDEF mixinTemplateName):
- * $(RULE symbol)
- * | $(RULE typeofExpression) $(LITERAL '.') $(RULE identifierOrTemplateChain)
- * ;)
- */
- MixinTemplateName parseMixinTemplateName()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!MixinTemplateName;
- if (currentIs(tok!"typeof"))
- {
- node.typeofExpression = parseTypeofExpression();
- expect(tok!".");
- node.identifierOrTemplateChain = parseIdentifierOrTemplateChain();
- }
- else
- node.symbol = parseSymbol();
- return node;
- }
-
- unittest
- {
- }
-
- /**
- * Parses a Module
- *
- * $(GRAMMAR $(RULEDEF module):
- * $(RULE moduleDeclaration)? $(RULE declaration)*
- * ;)
- */
- Module parseModule()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- Module m = allocate!Module;
- if (currentIs(tok!"scriptLine"))
- m.scriptLine = advance();
- if (currentIs(tok!"module"))
- m.moduleDeclaration = parseModuleDeclaration();
- Declaration[] declarations;
- while (moreTokens())
- {
- auto declaration = parseDeclaration();
- if (declaration !is null)
- declarations ~= declaration;
- }
- m.declarations = ownArray(declarations);
- return m;
- }
-
- /**
- * Parses a ModuleDeclaration
- *
- * $(GRAMMAR $(RULEDEF moduleDeclaration):
- * $(LITERAL 'module') $(RULE identifierChain) $(LITERAL ';')
- * ;)
- */
- ModuleDeclaration parseModuleDeclaration()
- {
- auto node = allocate!ModuleDeclaration;
- auto start = expect(tok!"module");
- node.moduleName = parseIdentifierChain();
- node.comment = start.comment;
- comment = null;
- auto end = expect(tok!";");
- node.startLocation = start.index;
- node.endLocation = end.index;
- return node;
- }
-
- /**
- * Parses a MulExpression
- * $(GRAMMAR $(RULEDEF mulExpression):
- * $(RULE powExpression)
- * | $(RULE mulExpression) ($(LITERAL '*') | $(LITERAL '/') | $(LITERAL '%')) $(RULE powExpression)
- * ;)
- */
- ExpressionNode parseMulExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(MulExpression, PowExpression,
- tok!"*", tok!"/", tok!"%")();
- }
-
- /**
- * Parses a NewAnonClassExpression
- *
- * $(GRAMMAR $(RULEDEF newAnonClassExpression):
- * $(LITERAL 'new') $(RULE arguments)? $(LITERAL 'class') $(RULE arguments)? $(RULE baseClassList)? $(RULE structBody)
- * ;)
- */
- NewAnonClassExpression parseNewAnonClassExpression()
- {
- auto node = allocate!NewAnonClassExpression;
- expect(tok!"new");
- if (currentIs(tok!"("))
- node.allocatorArguments = parseArguments();
- expect(tok!"class");
- if (currentIs(tok!"("))
- node.constructorArguments = parseArguments();
- if (!currentIs(tok!"{"))
- node.baseClassList = parseBaseClassList();
- node.structBody = parseStructBody();
- return node;
- }
-
- /**
- * Parses a NewExpression
- *
- * $(GRAMMAR $(RULEDEF newExpression):
- * $(LITERAL 'new') $(RULE type) ($(LITERAL '[') $(RULE assignExpression) $(LITERAL ']') | $(RULE arguments))?
- * | $(RULE newAnonClassExpression)
- * ;)
- */
- NewExpression parseNewExpression()
- {
- auto node = allocate!NewExpression;
- if (peekIsOneOf(tok!"class", tok!"("))
- node.newAnonClassExpression = parseNewAnonClassExpression();
- else
- {
- expect(tok!"new");
- if (!moreTokens())
- return null;
- node.type = parseType();
- if (currentIs(tok!"["))
- {
- advance();
- node.assignExpression = parseAssignExpression();
- expect(tok!"]");
- }
- else if (currentIs(tok!"("))
- node.arguments = parseArguments();
- }
- return node;
- }
-
- /**
- * Parses a StatementNoCaseNoDefault
- *
- * $(GRAMMAR $(RULEDEF statementNoCaseNoDefault):
- * $(RULE labeledStatement)
- * | $(RULE blockStatement)
- * | $(RULE ifStatement)
- * | $(RULE whileStatement)
- * | $(RULE doStatement)
- * | $(RULE forStatement)
- * | $(RULE foreachStatement)
- * | $(RULE switchStatement)
- * | $(RULE finalSwitchStatement)
- * | $(RULE continueStatement)
- * | $(RULE breakStatement)
- * | $(RULE returnStatement)
- * | $(RULE gotoStatement)
- * | $(RULE withStatement)
- * | $(RULE synchronizedStatement)
- * | $(RULE tryStatement)
- * | $(RULE throwStatement)
- * | $(RULE scopeGuardStatement)
- * | $(RULE asmStatement)
- * | $(RULE conditionalStatement)
- * | $(RULE staticAssertStatement)
- * | $(RULE versionSpecification)
- * | $(RULE debugSpecification)
- * | $(RULE expressionStatement)
- * ;)
- */
- StatementNoCaseNoDefault parseStatementNoCaseNoDefault()
- {
- auto node = allocate!StatementNoCaseNoDefault;
- switch (current.type)
- {
- case tok!"{":
- node.blockStatement = parseBlockStatement();
- break;
- case tok!"if":
- node.ifStatement = parseIfStatement();
- break;
- case tok!"while":
- node.whileStatement = parseWhileStatement();
- break;
- case tok!"do":
- node.doStatement = parseDoStatement();
- break;
- case tok!"for":
- node.forStatement = parseForStatement();
- break;
- case tok!"foreach":
- case tok!"foreach_reverse":
- node.foreachStatement = parseForeachStatement();
- break;
- case tok!"switch":
- node.switchStatement = parseSwitchStatement();
- break;
- case tok!"continue":
- node.continueStatement = parseContinueStatement();
- break;
- case tok!"break":
- node.breakStatement = parseBreakStatement();
- break;
- case tok!"return":
- node.returnStatement = parseReturnStatement();
- break;
- case tok!"goto":
- node.gotoStatement = parseGotoStatement();
- break;
- case tok!"with":
- node.withStatement = parseWithStatement();
- break;
- case tok!"synchronized":
- node.synchronizedStatement = parseSynchronizedStatement();
- break;
- case tok!"try":
- node.tryStatement = parseTryStatement();
- break;
- case tok!"throw":
- node.throwStatement = parseThrowStatement();
- break;
- case tok!"scope":
- node.scopeGuardStatement = parseScopeGuardStatement();
- break;
- case tok!"asm":
- node.asmStatement = parseAsmStatement();
- break;
- case tok!"final":
- if (peekIs(tok!"switch"))
- {
- node.finalSwitchStatement = parseFinalSwitchStatement();
- break;
- }
- else
- {
- error(`"switch" expected`);
- return null;
- }
- case tok!"debug":
- if (peekIs(tok!"="))
- node.debugSpecification = parseDebugSpecification();
- else
- node.conditionalStatement = parseConditionalStatement();
- break;
- case tok!"version":
- if (peekIs(tok!"="))
- node.versionSpecification = parseVersionSpecification();
- else
- node.conditionalStatement = parseConditionalStatement();
- break;
- case tok!"static":
- if (peekIs(tok!"if"))
- node.conditionalStatement = parseConditionalStatement();
- else if (peekIs(tok!"assert"))
- node.staticAssertStatement = parseStaticAssertStatement();
- break;
- case tok!"identifier":
- if (peekIs(tok!":"))
- {
- node.labeledStatement = parseLabeledStatement();
- break;
- }
- goto default;
- case tok!"delete":
- case tok!"assert":
- default:
- node.expressionStatement = parseExpressionStatement();
- break;
- }
- return node;
- }
-
- /**
- * Parses a NonVoidInitializer
- *
- * $(GRAMMAR $(RULEDEF nonVoidInitializer):
- * $(RULE assignExpression)
- * | $(RULE arrayInitializer)
- * | $(RULE structInitializer)
- * | $(RULE functionBody)
- * ;)
- */
- NonVoidInitializer parseNonVoidInitializer()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!NonVoidInitializer;
- if (currentIs(tok!"{"))
- {
- 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();
- }
- else if (currentIs(tok!"["))
- {
- auto b = peekPastBrackets();
- if (b !is null && (b.type == tok!","
- || b.type == tok!")"
- || b.type == tok!"]"
- || b.type == tok!"}"
- || b.type == tok!";"))
- {
- node.arrayInitializer = parseArrayInitializer();
- }
- 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;
- }
-
- /**
- * Parses Operands
- *
- * $(GRAMMAR $(RULEDEF operands):
- * $(RULE asmExp)+
- * ;)
- */
- Operands parseOperands()
- {
-// auto node = allocate!Operands;
- assert (false, "asm"); // TODO asm
- }
-
- /**
- * Parses an OrExpression
- *
- * $(GRAMMAR $(RULEDEF orExpression):
- * $(RULE xorExpression)
- * | $(RULE orExpression) $(LITERAL '|') $(RULE xorExpression)
- * ;)
- */
- ExpressionNode parseOrExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(OrExpression, XorExpression,
- tok!"|")();
- }
-
- /**
- * Parses an OrOrExpression
- *
- * $(GRAMMAR $(RULEDEF orOrExpression):
- * $(RULE andAndExpression)
- * | $(RULE orOrExpression) $(LITERAL '||') $(RULE andAndExpression)
- * ;)
- */
- ExpressionNode parseOrOrExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(OrOrExpression, AndAndExpression,
- tok!"||")();
- }
-
- /**
- * Parses an OutStatement
- *
- * $(GRAMMAR $(RULEDEF outStatement):
- * $(LITERAL 'out') ($(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)'))? $(RULE blockStatement)
- * ;)
- */
- OutStatement parseOutStatement()
- {
- auto node = allocate!OutStatement;
- expect(tok!"out");
- if (currentIs(tok!"("))
- {
- advance();
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.parameter = *ident;
- expect(tok!")");
- }
- node.blockStatement = parseBlockStatement();
- return node;
- }
-
- /**
- * Parses a Parameter
- *
- * $(GRAMMAR $(RULEDEF parameter):
- * $(RULE parameterAttribute)* $(RULE type) (($(LITERAL Identifier) $(RULE typeSuffix)*)? $(LITERAL '...') | ($(LITERAL Identifier)? ($(LITERAL '=') $(RULE assignExpression))?))?
- * ;)
- */
- Parameter parseParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Parameter;
- IdType[] parameterAttributes;
- while (moreTokens())
- {
- IdType type = parseParameterAttribute(false);
- if (type == tok!"")
- break;
- else
- parameterAttributes ~= type;
- }
- node.parameterAttributes = ownArray(parameterAttributes);
- node.type = parseType();
- if (node.type is null) return null;
- if (currentIs(tok!"identifier"))
- {
- node.name = advance();
- if (currentIs(tok!"..."))
- {
- advance();
- node.vararg = true;
- }
- else if (currentIs(tok!"="))
- {
- advance();
- node.default_ = parseAssignExpression();
- }
- else if (currentIs(tok!"["))
- {
- TypeSuffix[] typeSuffixes;
- while(moreTokens() && currentIs(tok!"["))
- {
- auto suffix = parseTypeSuffix();
- if (suffix !is null)
- typeSuffixes ~= suffix;
- else
- return null;
- }
- node.cstyle = ownArray(typeSuffixes);
- }
- }
- else if (currentIs(tok!"..."))
- {
- node.vararg = true;
- advance();
- }
- else if (currentIs(tok!"="))
- {
- advance();
- node.default_ = parseAssignExpression();
- }
- return node;
- }
-
- /**
- * Parses a ParameterAttribute
- *
- * $(GRAMMAR $(RULEDEF parameterAttribute):
- * $(RULE typeConstructor)
- * | $(LITERAL 'final')
- * | $(LITERAL 'in')
- * | $(LITERAL 'lazy')
- * | $(LITERAL 'out')
- * | $(LITERAL 'ref')
- * | $(LITERAL 'scope')
- * | $(LITERAL 'auto')
- * ;)
- */
- IdType parseParameterAttribute(bool validate = false)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- switch (current.type)
- {
- case tok!"immutable":
- case tok!"shared":
- case tok!"const":
- case tok!"inout":
- if (peekIs(tok!"("))
- return tok!"";
- else
- goto _auto;
- case tok!"final":
- case tok!"in":
- case tok!"lazy":
- case tok!"out":
- case tok!"ref":
- case tok!"scope":
- _auto:
- case tok!"auto":
- return advance().type;
- default:
- if (validate)
- error("Parameter attribute expected");
- return tok!"";
- }
- }
-
- /**
- * Parses Parameters
- *
- * $(GRAMMAR $(RULEDEF parameters):
- * $(LITERAL '$(LPAREN)') $(RULE parameter) ($(LITERAL ',') $(RULE parameter))* ($(LITERAL ',') $(LITERAL '...'))? $(LITERAL '$(RPAREN)')
- * | $(LITERAL '$(LPAREN)') $(LITERAL '...') $(LITERAL '$(RPAREN)')
- * | $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)')
- * ;)
- */
- Parameters parseParameters()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Parameters;
- if (expect(tok!"(") is null) return null;
- Parameter[] parameters;
- if (currentIs(tok!")"))
- goto end;
- if (currentIs(tok!"..."))
- {
- advance();
- node.hasVarargs = true;
- goto end;
- }
- while (moreTokens())
- {
- if (currentIs(tok!"..."))
- {
- advance();
- node.hasVarargs = true;
- break;
- }
- if (currentIs(tok!")"))
- break;
- auto param = parseParameter();
- if (param is null)
- return null;
- parameters ~= param;
- if (currentIs(tok!","))
- advance();
- else
- break;
- }
- node.parameters = ownArray(parameters);
- end:
- if (expect(tok!")") is null)
- return null;
- return node;
- }
-
- unittest
- {
- string sourceCode =
-q{(int a, ...)
-(double ...)
-(Range r)}c;
-
- Parser p = getParserForUnittest(sourceCode, "parseParameters");
-
- Parameters params1 = p.parseParameters();
- assert (params1.hasVarargs);
- assert (params1.parameters.length == 1);
- assert (params1.parameters[0].name.text == "a");
-
- Parameters params2 = p.parseParameters();
- assert (params2.parameters.length == 1);
- assert (params2.parameters[0].vararg);
- assert (params2.parameters[0].type !is null);
-
- Parameters params3 = p.parseParameters();
- assert (params3.parameters.length == 1);
- assert (!params3.parameters[0].vararg);
- assert (params3.parameters[0].type !is null);
-
- stderr.writeln("Unittest for parseParameters() passed.");
- }
-
- /**
- * Parses a Postblit
- *
- * $(GRAMMAR $(RULEDEF postblit):
- * $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL 'this') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';'))
- * ;)
- */
- Postblit parsePostblit()
- {
- auto node = allocate!Postblit;
- expect(tok!"this");
- expect(tok!"(");
- expect(tok!"this");
- expect(tok!")");
- MemberFunctionAttribute[] memberFunctionAttributes;
- while (currentIsMemberFunctionAttribute())
- memberFunctionAttributes ~= parseMemberFunctionAttribute();
- node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
- if (currentIs(tok!";"))
- advance();
- else
- node.functionBody = parseFunctionBody();
- return node;
- }
-
- /**
- * Parses a PostIncDecExpression
- *
- * $(GRAMMAR $(RULEDEF postIncDecExpression):
- * $(RULE unaryExpression) ($(LITERAL '++') | $(LITERAL '--'))
- * ;)
- */
- PostIncDecExpression parsePostIncDecExpression(UnaryExpression unary = null)
- {
- auto node = allocate!PostIncDecExpression;
- node.unaryExpression = unary is null ? parseUnaryExpression() : unary;
- node.operator = advance().type;
- return node;
- }
-
- /**
- * Parses a PowExpression
- *
- * $(GRAMMAR $(RULEDEF powExpression):
- * $(RULE unaryExpression)
- * | $(RULE powExpression) $(LITERAL '^^') $(RULE unaryExpression)
- * ;)
- */
- ExpressionNode parsePowExpression()
- {
- return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpression,
- tok!"^^")();
- }
-
- /**
- * Parses a PragmaDeclaration
- *
- * $(GRAMMAR $(RULEDEF pragmaDeclaration):
- * $(RULE pragmaExpression) $(LITERAL ';')
- * ;)
- */
- PragmaDeclaration parsePragmaDeclaration()
- {
- mixin (traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!PragmaDeclaration;
- node.pragmaExpression = parsePragmaExpression();
- expect(tok!";");
- return node;
- }
-
- /**
- * Parses a PragmaExpression
- *
- * $(GRAMMAR $(RULEDEF pragmaExpression):
- * $(RULE 'pragma') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL ',') $(RULE argumentList))? $(LITERAL '$(RPAREN)')
- * ;)
- */
- PragmaExpression parsePragmaExpression()
- {
- mixin (traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!PragmaExpression;
- expect(tok!"pragma");
- expect(tok!"(");
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!","))
- {
- advance();
- node.argumentList = parseArgumentList();
- }
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a PreIncDecExpression
- *
- * $(GRAMMAR $(RULEDEF preIncDecExpression):
- * ($(LITERAL '++') | $(LITERAL '--')) $(RULE unaryExpression)
- * ;)
- */
- PreIncDecExpression parsePreIncDecExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!PreIncDecExpression;
- if (currentIsOneOf(tok!"++", tok!"--"))
- advance();
- else
- {
- error(`"++" or "--" expected`);
- return null;
- }
- node.unaryExpression = parseUnaryExpression();
- return node;
- }
-
- /**
- * Parses a PrimaryExpression
- *
- * $(GRAMMAR $(RULEDEF primaryExpression):
- * $(RULE identifierOrTemplateInstance)
- * | $(LITERAL '.') $(RULE identifierOrTemplateInstance)
- * | $(RULE typeConstructor) $(LITERAL '(') $(RULE basicType) $(LITERAL ')') $(LITERAL '.') $(LITERAL Identifier)
- * | $(RULE basicType) $(LITERAL '.') $(LITERAL Identifier)
- * | $(RULE basicType) $(RULE arguments)
- * | $(RULE typeofExpression)
- * | $(RULE typeidExpression)
- * | $(RULE vector)
- * | $(RULE arrayLiteral)
- * | $(RULE assocArrayLiteral)
- * | $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)')
- * | $(RULE isExpression)
- * | $(RULE lambdaExpression)
- * | $(RULE functionLiteralExpression)
- * | $(RULE traitsExpression)
- * | $(RULE mixinExpression)
- * | $(RULE importExpression)
- * | $(LITERAL '$')
- * | $(LITERAL 'this')
- * | $(LITERAL 'super')
- * | $(LITERAL '_null')
- * | $(LITERAL '_true')
- * | $(LITERAL '_false')
- * | $(LITERAL '___DATE__')
- * | $(LITERAL '___TIME__')
- * | $(LITERAL '___TIMESTAMP__')
- * | $(LITERAL '___VENDOR__')
- * | $(LITERAL '___VERSION__')
- * | $(LITERAL '___FILE__')
- * | $(LITERAL '___LINE__')
- * | $(LITERAL '___MODULE__')
- * | $(LITERAL '___FUNCTION__')
- * | $(LITERAL '___PRETTY_FUNCTION__')
- * | $(LITERAL IntegerLiteral)
- * | $(LITERAL FloatLiteral)
- * | $(LITERAL StringLiteral)+
- * | $(LITERAL CharacterLiteral)
- * ;)
- */
- PrimaryExpression parsePrimaryExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!PrimaryExpression;
- if (!moreTokens())
- {
- error("Expected primary statement instead of EOF");
- return null;
- }
- switch (current.type)
- {
- case tok!".":
- node.dot = advance();
- goto case;
- case tok!"identifier":
- if (peekIs(tok!"=>"))
- node.lambdaExpression = parseLambdaExpression();
- else
- node.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance();
- break;
- case tok!"immutable":
- case tok!"const":
- case tok!"inout":
- case tok!"shared":
- advance();
- expect(tok!"(");
- node.type = parseType();
- expect(tok!")");
- expect(tok!".");
- auto ident = expect(tok!"identifier");
- if (ident !is null)
- node.primary = *ident;
- break;
- mixin (BASIC_TYPE_CASES);
- node.basicType = advance();
- if (currentIs(tok!"."))
- {
- advance();
- auto t = expect(tok!"identifier");
- if (t !is null)
- node.primary = *t;
- }
- else if (currentIs(tok!"("))
- node.arguments = parseArguments();
- break;
- case tok!"function":
- case tok!"delegate":
- if (peekIs(tok!"("))
- {
- auto b = setBookmark();
- advance(); // function | delegate
- skipParens();
- while (isAttribute())
- parseAttribute();
- if (currentIs(tok!"=>"))
- {
- goToBookmark(b);
- node.lambdaExpression = parseLambdaExpression();
- break;
- }
- else
- goToBookmark(b);
- }
- goto case;
- case tok!"{":
- case tok!"in":
- case tok!"out":
- case tok!"body":
- node.functionLiteralExpression = parseFunctionLiteralExpression();
- break;
- case tok!"typeof":
- node.typeofExpression = parseTypeofExpression();
- break;
- case tok!"typeid":
- node.typeidExpression = parseTypeidExpression();
- break;
- case tok!"__vector":
- node.vector = parseVector();
- break;
- case tok!"[":
- if (isAssociativeArrayLiteral())
- node.assocArrayLiteral = parseAssocArrayLiteral();
- else
- node.arrayLiteral = parseArrayLiteral();
- break;
- case tok!"(":
- auto b = setBookmark();
- skipParens();
- while (isAttribute())
- parseAttribute();
- if (currentIs(tok!"=>"))
- {
- goToBookmark(b);
- node.lambdaExpression = parseLambdaExpression();
- }
- else if (currentIs(tok!"{"))
- {
- goToBookmark(b);
- node.functionLiteralExpression = parseFunctionLiteralExpression();
- }
- else
- {
- goToBookmark(b);
- advance();
- node.expression = parseExpression();
- expect(tok!")");
- }
- break;
- case tok!"is":
- node.isExpression = parseIsExpression();
- break;
- case tok!"__traits":
- node.traitsExpression = parseTraitsExpression();
- break;
- case tok!"mixin":
- node.mixinExpression = parseMixinExpression();
- break;
- case tok!"import":
- node.importExpression = parseImportExpression();
- break;
- case tok!"$":
- case tok!"this":
- case tok!"super":
- case tok!"null":
- case tok!"true":
- case tok!"false":
- mixin (SPECIAL_CASES);
- mixin (LITERAL_CASES);
- if (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral", tok!"dstringLiteral"))
- {
- node.primary = advance();
- bool alreadyWarned = false;
- while (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral",
- tok!"dstringLiteral"))
- {
- if (!alreadyWarned)
- {
- warn("Implicit concatenation of string literals");
- alreadyWarned = true;
- }
- node.primary.text~= advance().text;
- }
- }
- else
- node.primary = advance();
- break;
- default:
- error(`Primary expression expected`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a Register
- *
- * $(GRAMMAR $(RULEDEF register):
- * $(LITERAL Identifier)
- * | $(LITERAL Identifier) $(LITERAL '$(LPAREN)') $(LITERAL IntegerLiteral) $(LITERAL '$(RPAREN)')
- * ;)
- */
- Register parseRegister()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Register;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!"("))
- {
- advance();
- auto intLit = expect(tok!"intLiteral");
- if (intLit is null) return null;
- node.intLiteral = *intLit;
- expect(tok!")");
- }
- return node;
- }
-
- /**
- * Parses a RelExpression
- *
- * $(GRAMMAR $(RULEDEF relExpression):
- * $(RULE shiftExpression)
- * | $(RULE relExpression) $(RULE relOperator) $(RULE shiftExpression)
- * ;
- *$(RULEDEF relOperator):
- * $(LITERAL '<')
- * | $(LITERAL '<=')
- * | $(LITERAL '>')
- * | $(LITERAL '>=')
- * | $(LITERAL '!<>=')
- * | $(LITERAL '!<>')
- * | $(LITERAL '<>')
- * | $(LITERAL '<>=')
- * | $(LITERAL '!>')
- * | $(LITERAL '!>=')
- * | $(LITERAL '!<')
- * | $(LITERAL '!<=')
- * ;)
- */
- ExpressionNode parseRelExpression(ExpressionNode shift)
- {
- mixin (traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(RelExpression, ShiftExpression,
- tok!"<", tok!"<=", tok!">", tok!">=", tok!"!<>=", tok!"!<>",
- tok!"<>", tok!"<>=", tok!"!>", tok!"!>=", tok!"!>=", tok!"!<",
- tok!"!<=")(shift);
- }
-
- /**
- * Parses a ReturnStatement
- *
- * $(GRAMMAR $(RULEDEF returnStatement):
- * $(LITERAL 'return') $(RULE expression)? $(LITERAL ';')
- * ;)
- */
- ReturnStatement parseReturnStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ReturnStatement;
- auto start = expect(tok!"return");
- if (start is null) return null;
- node.startLocation = start.index;
- if (!currentIs(tok!";"))
- node.expression = parseExpression();
- auto semicolon = expect(tok!";");
- if (semicolon is null) return null;
- node.endLocation = semicolon.index;
- return node;
- }
-
- /**
- * Parses a ScopeGuardStatement
- *
- * $(GRAMMAR $(RULEDEF scopeGuardStatement):
- * $(LITERAL 'scope') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault)
- * ;)
- */
- ScopeGuardStatement parseScopeGuardStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ScopeGuardStatement;
- expect(tok!"scope");
- expect(tok!"(");
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- expect(tok!")");
- node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault();
- return node;
- }
-
- /**
- * Parses a SharedStaticConstructor
- *
- * $(GRAMMAR $(RULEDEF sharedStaticConstructor):
- * $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
- * ;)
- */
- SharedStaticConstructor parseSharedStaticConstructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(SharedStaticConstructor, tok!"shared", tok!"static",
- tok!"this", tok!"(", tok!")", "functionBody|parseFunctionBody"));
- }
-
- /**
- * Parses a SharedStaticDestructor
- *
- * $(GRAMMAR $(RULEDEF sharedStaticDestructor):
- * $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
- * ;)
- */
- SharedStaticDestructor parseSharedStaticDestructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(SharedStaticDestructor, tok!"shared", tok!"static",
- tok!"~", tok!"this", tok!"(", tok!")",
- "functionBody|parseFunctionBody"));
- }
-
- /**
- * Parses a ShiftExpression
- *
- * $(GRAMMAR $(RULEDEF shiftExpression):
- * $(RULE addExpression)
- * | $(RULE shiftExpression) ($(LITERAL '<<') | $(LITERAL '>>') | $(LITERAL '>>>')) $(RULE addExpression)
- * ;)
- */
- ExpressionNode parseShiftExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(ShiftExpression, AddExpression,
- tok!"<<", tok!">>", tok!">>>")();
- }
-
- /**
- * Parses a SingleImport
- *
- * $(GRAMMAR $(RULEDEF singleImport):
- * ($(LITERAL Identifier) $(LITERAL '='))? $(RULE identifierChain)
- * ;)
- */
- SingleImport parseSingleImport()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!SingleImport;
- if (startsWith(tok!"identifier", tok!"="))
- {
- node.rename = advance();
- advance(); // =
- }
- node.identifierChain = parseIdentifierChain();
- if (node.identifierChain is null)
- return null;
- return node;
- }
-
- /**
- * Parses a SliceExpression
- *
- * $(GRAMMAR $(RULEDEF sliceExpression):
- * $(RULE unaryExpression) $(LITERAL '[') $(RULE assignExpression) $(LITERAL '..') $(RULE assignExpression) $(LITERAL ']')
- * | $(RULE unaryExpression) $(LITERAL '[') $(LITERAL ']')
- * ;)
- */
- SliceExpression parseSliceExpression(UnaryExpression unary = null)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!SliceExpression;
- node.unaryExpression = unary is null ? parseUnaryExpression() : unary;
- if (expect(tok!"[") is null) return null;
- 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;
- }
-
- /**
- * Parses a Statement
- *
- * $(GRAMMAR $(RULEDEF statement):
- * $(RULE statementNoCaseNoDefault)
- * | $(RULE caseStatement)
- * | $(RULE caseRangeStatement)
- * | $(RULE defaultStatement)
- * ;)
- */
- Statement parseStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Statement;
- if (!moreTokens())
- {
- error("Expected statement instead of EOF");
- return null;
- }
- switch (current.type)
- {
- case tok!"case":
- advance();
- auto argumentList = parseArgumentList();
- if (argumentList.items.length == 1 && startsWith(tok!":", tok!".."))
- node.caseRangeStatement = parseCaseRangeStatement(argumentList.items[0]);
- else
- node.caseStatement = parseCaseStatement(argumentList);
- break;
- case tok!"default":
- node.defaultStatement = parseDefaultStatement();
- break;
- default:
- node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault();
- break;
- }
- return node;
- }
-
- /**
- * Parses a StaticAssertDeclaration
- *
- * $(GRAMMAR $(RULEDEF staticAssertDeclaration):
- * $(RULE staticAssertStatement)
- * ;)
- */
- StaticAssertDeclaration parseStaticAssertDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(StaticAssertDeclaration,
- "staticAssertStatement|parseStaticAssertStatement"));
- }
-
-
- /**
- * Parses a StaticAssertStatement
- *
- * $(GRAMMAR $(RULEDEF staticAssertStatement):
- * $(LITERAL 'static') $(RULE assertExpression) $(LITERAL ';')
- * ;)
- */
- StaticAssertStatement parseStaticAssertStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(StaticAssertStatement,
- tok!"static", "assertExpression|parseAssertExpression", tok!";"));
- }
-
- /**
- * Parses a StaticConstructor
- *
- * $(GRAMMAR $(RULEDEF staticConstructor):
- * $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
- * ;)
- */
- StaticConstructor parseStaticConstructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(StaticConstructor, tok!"static", tok!"this",
- tok!"(", tok!")", "functionBody|parseFunctionBody"));
- }
-
- /**
- * Parses a StaticDestructor
- *
- * $(GRAMMAR $(RULEDEF staticDestructor):
- * $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
- * ;)
- */
- StaticDestructor parseStaticDestructor()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(StaticDestructor, tok!"static", tok!"~", tok!"this",
- tok!"(", tok!")", "functionBody|parseFunctionBody"));
- }
-
- /**
- * Parses an StaticIfCondition
- *
- * $(GRAMMAR $(RULEDEF staticIfCondition):
- * $(LITERAL 'static') $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
- * ;)
- */
- StaticIfCondition parseStaticIfCondition()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(StaticIfCondition, tok!"static", tok!"if", tok!"(",
- "assignExpression|parseAssignExpression", tok!")"));
- }
-
- /**
- * Parses a StorageClass
- *
- * $(GRAMMAR $(RULEDEF storageClass):
- * $(RULE alignAttribute)
- * | $(RULE linkageAttribute)
- * | $(RULE atAttribute)
- * | $(RULE typeConstructor)
- * | $(RULE deprecated)
- * | $(LITERAL 'abstract')
- * | $(LITERAL 'auto')
- * | $(LITERAL 'enum')
- * | $(LITERAL 'extern')
- * | $(LITERAL 'final')
- * | $(LITERAL 'virtual')
- * | $(LITERAL 'nothrow')
- * | $(LITERAL 'override')
- * | $(LITERAL 'pure')
- * | $(LITERAL 'ref')
- * | $(LITERAL '___gshared')
- * | $(LITERAL 'scope')
- * | $(LITERAL 'static')
- * | $(LITERAL 'synchronized')
- * ;)
- */
- StorageClass parseStorageClass()
- {
- auto node = allocate!StorageClass;
- switch (current.type)
- {
- case tok!"@":
- node.atAttribute = parseAtAttribute();
- if (node.atAttribute is null) return null;
- break;
- case tok!"deprecated":
- node.deprecated_ = parseDeprecated();
- break;
- case tok!"align":
- node.alignAttribute = parseAlignAttribute();
- break;
- case tok!"extern":
- if (peekIs(tok!"("))
- {
- node.linkageAttribute = parseLinkageAttribute();
- break;
- }
- else goto case;
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"abstract":
- case tok!"auto":
- case tok!"enum":
- case tok!"final":
- case tok!"virtual":
- case tok!"nothrow":
- case tok!"override":
- case tok!"pure":
- case tok!"ref":
- case tok!"__gshared":
- case tok!"scope":
- case tok!"static":
- case tok!"synchronized":
- node.token = advance();
- break;
- default:
- error(`Storage class expected`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a StructBody
- *
- * $(GRAMMAR $(RULEDEF structBody):
- * $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')
- * ;)
- */
- StructBody parseStructBody()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!StructBody;
- auto start = expect(tok!"{");
- if (start !is null) node.startLocation = start.index;
- Declaration[] declarations;
- while (!currentIs(tok!"}") && moreTokens())
- {
- auto dec = parseDeclaration();
- if (dec !is null)
- declarations ~= dec;
- }
- node.declarations = ownArray(declarations);
- auto end = expect(tok!"}");
- if (end !is null) node.endLocation = end.index;
- return node;
- }
-
- /**
- * Parses a StructDeclaration
- *
- * $(GRAMMAR $(RULEDEF structDeclaration):
- * $(LITERAL 'struct') $(LITERAL Identifier)? ($(RULE templateParameters) $(RULE constraint)? $(RULE structBody) | ($(RULE structBody) | $(LITERAL ';')))
- * ;)
- */
- StructDeclaration parseStructDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!StructDeclaration;
- expect(tok!"struct");
- if (currentIs(tok!"identifier"))
- {
- node.name = advance();
- }
- node.comment = comment;
- comment = null;
-
- if (currentIs(tok!"("))
- {
- node.templateParameters = parseTemplateParameters();
- if (tokens[index] == tok!"if")
- node.constraint = parseConstraint();
- node.structBody = parseStructBody();
- }
- else if (currentIs(tok!"{"))
- {
- node.structBody = parseStructBody();
- }
- else if (currentIs(tok!";"))
- advance();
- else
- {
- error("Template Parameters, Struct Body, or Semicolon expected");
- return null;
- }
- return node;
- }
-
- /**
- * Parses an StructInitializer
- *
- * $(GRAMMAR $(RULEDEF structInitializer):
- * $(LITERAL '{') $(RULE structMemberInitializers)? $(LITERAL '}')
- * ;)
- */
- StructInitializer parseStructInitializer()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!StructInitializer;
- expect(tok!"{");
- if (currentIs(tok!"}"))
- advance();
- else
- {
- node.structMemberInitializers = parseStructMemberInitializers();
- expect(tok!"}");
- }
- return node;
- }
-
- /**
- * Parses a StructMemberInitializer
- *
- * $(GRAMMAR $(RULEDEF structMemberInitializer):
- * ($(LITERAL Identifier) $(LITERAL ':'))? $(RULE nonVoidInitializer)
- * ;)
- */
- StructMemberInitializer parseStructMemberInitializer()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!StructMemberInitializer;
- if (startsWith(tok!"identifier", tok!":"))
- {
- node.identifier = tokens[index++];
- index++;
- }
- node.nonVoidInitializer = parseNonVoidInitializer();
- return node;
- }
-
- /**
- * Parses StructMemberInitializers
- *
- * $(GRAMMAR $(RULEDEF structMemberInitializers):
- * $(RULE structMemberInitializer) ($(LITERAL ',') $(RULE structMemberInitializer)?)*
- * ;)
- */
- StructMemberInitializers parseStructMemberInitializers()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!StructMemberInitializers;
- StructMemberInitializer[] structMemberInitializers;
- do
- {
- auto structMemberInitializer = parseStructMemberInitializer();
- if (structMemberInitializer !is null)
- structMemberInitializers ~= structMemberInitializer;
- if (currentIs(tok!","))
- {
- advance();
- if (!currentIs(tok!"}"))
- continue;
- else
- break;
- }
- else
- break;
- } while (moreTokens());
- node.structMemberInitializers = ownArray(structMemberInitializers);
- return node;
- }
-
- /**
- * Parses a SwitchStatement
- *
- * $(GRAMMAR $(RULEDEF switchStatement):
- * $(LITERAL 'switch') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statement)
- * ;)
- */
- SwitchStatement parseSwitchStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!SwitchStatement;
- expect(tok!"switch");
- expect(tok!"(");
- node.expression = parseExpression();
- expect(tok!")");
- node.statement = parseStatement();
- return node;
- }
-
- /**
- * Parses a Symbol
- *
- * $(GRAMMAR $(RULEDEF symbol):
- * $(LITERAL '.')? $(RULE identifierOrTemplateChain)
- * ;)
- */
- Symbol parseSymbol()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Symbol;
- if (currentIs(tok!"."))
- {
- node.dot = true;
- advance();
- }
- node.identifierOrTemplateChain = parseIdentifierOrTemplateChain();
- return node;
- }
-
- /**
- * Parses a SynchronizedStatement
- *
- * $(GRAMMAR $(RULEDEF synchronizedStatement):
- * $(LITERAL 'synchronized') ($(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)'))? $(RULE statementNoCaseNoDefault)
- * ;)
- */
- SynchronizedStatement parseSynchronizedStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!SynchronizedStatement;
- expect(tok!"synchronized");
- if (currentIs(tok!"("))
- {
- expect(tok!"(");
- node.expression = parseExpression();
- expect(tok!")");
- }
- node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault();
- return node;
- }
-
- /**
- * Parses a TemplateAliasParameter
- *
- * $(GRAMMAR $(RULEDEF templateAliasParameter):
- * $(LITERAL 'alias') $(RULE type)? $(LITERAL Identifier) ($(LITERAL ':') ($(RULE type) | $(RULE assignExpression)))? ($(LITERAL '=') ($(RULE type) | $(RULE assignExpression)))?
- * ;)
- */
- TemplateAliasParameter parseTemplateAliasParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateAliasParameter;
- expect(tok!"alias");
- if (currentIs(tok!"identifier"))
- {
- if (peekIsOneOf(tok!",", tok!")", tok!"=",
- tok!":"))
- {
- node.identifier = advance();
- }
- }
- else
- {
- if ((node.type = parseType()) is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- }
-
- if (currentIs(tok!":"))
- {
- advance();
- if (isType())
- node.colonType = parseType();
- else
- node.colonExpression = parseAssignExpression();
- }
- if (currentIs(tok!"="))
- {
- advance();
- if (isType())
- node.assignType = parseType();
- else
- node.assignExpression = parseAssignExpression();
- }
- return node;
- }
-
- /**
- * Parses a TemplateArgument
- *
- * $(GRAMMAR $(RULEDEF templateArgument):
- * $(RULE type)
- * | $(RULE assignExpression)
- * ;)
- */
- TemplateArgument parseTemplateArgument()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateArgument;
- auto b = setBookmark();
- auto t = parseType();
- if (t !is null && currentIsOneOf(tok!",", tok!")"))
- {
- goToBookmark(b);
- node.type = parseType();
- }
- else
- {
- goToBookmark(b);
- if ((node.assignExpression = parseAssignExpression()) is null) return null;
- }
- return node;
- }
-
- /**
- * Parses a TemplateArgumentList
- *
- * $(GRAMMAR $(RULEDEF templateArgumentList):
- * $(RULE templateArgument) ($(LITERAL ',') $(RULE templateArgument)?)*
- * ;)
- */
- TemplateArgumentList parseTemplateArgumentList()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseCommaSeparatedRule!(TemplateArgumentList, TemplateArgument)(true);
- }
-
- /**
- * Parses TemplateArguments
- *
- * $(GRAMMAR $(RULEDEF templateArguments):
- * $(LITERAL '!') ($(LITERAL '$(LPAREN)') $(RULE templateArgumentList)? $(LITERAL '$(RPAREN)') | $(RULE templateSingleArgument))
- * ;)
- */
- TemplateArguments parseTemplateArguments()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateArguments;
- expect(tok!"!");
- if (currentIs(tok!"("))
- {
- advance();
- if (!currentIs(tok!")"))
- node.templateArgumentList = parseTemplateArgumentList();
- expect(tok!")");
- }
- else
- node.templateSingleArgument = parseTemplateSingleArgument();
- return node;
- }
-
- /**
- * Parses a TemplateDeclaration
- *
- * $(GRAMMAR $(RULEDEF templateDeclaration):
- * $(LITERAL 'template') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')
- * | $(RULE eponymousTemplateDeclaration)
- * ;)
- */
- TemplateDeclaration parseTemplateDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateDeclaration;
- node.comment = comment;
- comment = null;
- if (currentIs(tok!"enum"))
- {
- node.eponymousTemplateDeclaration = parseEponymousTemplateDeclaration();
- return node;
- }
- expect(tok!"template");
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.name = *ident;
- node.templateParameters = parseTemplateParameters();
- if (currentIs(tok!"if"))
- node.constraint = parseConstraint();
- if (expect(tok!"{") is null) return null;
- Declaration[] declarations;
- while (moreTokens() && !currentIs(tok!"}"))
- {
- auto decl = parseDeclaration();
- if (decl !is null)
- declarations ~= decl;
- }
- node.declarations = ownArray(declarations);
- expect(tok!"}");
- return node;
- }
-
- /**
- * Parses an EponymousTemplateDeclaration
- *
- * $(GRAMMAR $(RULEDEF eponymousTemplateDeclaration):
- * $(LITERAL 'enum') $(LITERAL Identifier) $(RULE templateParameters) $(LITERAL '=') $(RULE assignExpression) $(LITERAL ';')
- * $(LITERAL 'enum') $(LITERAL Identifier) $(RULE templateParameters) $(LITERAL '=') $(RULE type) $(LITERAL ';')
- * ;)
- */
- EponymousTemplateDeclaration parseEponymousTemplateDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!EponymousTemplateDeclaration;
- if (currentIsOneOf(tok!"enum", tok!"alias"))
- advance();
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.name = *ident;
- node.templateParameters = parseTemplateParameters();
- expect(tok!"=");
- if (isExpression())
- node.assignExpression = parseAssignExpression();
- else
- node.type = parseType();
- expect(tok!";");
- return node;
- }
-
- /**
- * Parses a TemplateInstance
- *
- * $(GRAMMAR $(RULEDEF templateInstance):
- * $(LITERAL Identifier) $(RULE templateArguments)
- * ;)
- */
- TemplateInstance parseTemplateInstance()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateInstance;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- node.templateArguments = parseTemplateArguments();
- if (node.templateArguments is null)
- return null;
- return node;
- }
-
- /**
- * Parses a TemplateMixinExpression
- *
- * $(GRAMMAR $(RULEDEF templateMixinExpression):
- * $(LITERAL 'mixin') $(RULE mixinTemplateName) $(RULE templateArguments)? $(LITERAL Identifier)?
- * ;)
- */
- TemplateMixinExpression parseTemplateMixinExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateMixinExpression;
- if (expect(tok!"mixin") is null) return null;
- node.mixinTemplateName = parseMixinTemplateName();
- if (currentIs(tok!"!"))
- node.templateArguments = parseTemplateArguments();
- if (currentIs(tok!"identifier"))
- node.identifier = advance();
- return node;
- }
-
- /**
- * Parses a TemplateParameter
- *
- * $(GRAMMAR $(RULEDEF templateParameter):
- * $(RULE templateTypeParameter)
- * | $(RULE templateValueParameter)
- * | $(RULE templateAliasParameter)
- * | $(RULE templateTupleParameter)
- * | $(RULE templateThisParameter)
- * ;)
- */
- TemplateParameter parseTemplateParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateParameter;
- switch (current.type)
- {
- case tok!"alias":
- node.templateAliasParameter = parseTemplateAliasParameter();
- break;
- case tok!"identifier":
- if (peekIs(tok!"..."))
- node.templateTupleParameter = parseTemplateTupleParameter();
- else if (peekIsOneOf(tok!":", tok!"=", tok!",", tok!")"))
- node.templateTypeParameter = parseTemplateTypeParameter();
- else
- node.templateValueParameter = parseTemplateValueParameter();
- break;
- case tok!"this":
- node.templateThisParameter = parseTemplateThisParameter();
- break;
- default:
- node.templateValueParameter = parseTemplateValueParameter();
- break;
- }
- return node;
- }
-
- /**
- * Parses an TemplateParameterList
- *
- * $(GRAMMAR $(RULEDEF templateParameterList):
- * $(RULE templateParameter) ($(LITERAL ',') $(RULE templateParameter)?)*
- * ;)
- */
- TemplateParameterList parseTemplateParameterList()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseCommaSeparatedRule!(TemplateParameterList, TemplateParameter)();
- }
-
- /**
- * Parses TemplateParameters
- *
- * $(GRAMMAR $(RULEDEF templateParameters):
- * $(LITERAL '$(LPAREN)') $(RULE templateParameterList)? $(LITERAL '$(RPAREN)')
- * ;)
- */
- TemplateParameters parseTemplateParameters()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateParameters;
- if (expect(tok!"(") is null) return null;
- if (!currentIs(tok!")"))
- node.templateParameterList = parseTemplateParameterList();
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses a TemplateSingleArgument
- *
- * $(GRAMMAR $(RULEDEF templateSingleArgument):
- * $(RULE builtinType)
- * | $(LITERAL Identifier)
- * | $(LITERAL CharacterLiteral)
- * | $(LITERAL StringLiteral)
- * | $(LITERAL IntegerLiteral)
- * | $(LITERAL FloatLiteral)
- * | $(LITERAL '_true')
- * | $(LITERAL '_false')
- * | $(LITERAL '_null')
- * | $(LITERAL 'this')
- * | $(LITERAL '___DATE__')
- * | $(LITERAL '___TIME__')
- * | $(LITERAL '___TIMESTAMP__')
- * | $(LITERAL '___VENDOR__')
- * | $(LITERAL '___VERSION__')
- * | $(LITERAL '___FILE__')
- * | $(LITERAL '___LINE__')
- * | $(LITERAL '___MODULE__')
- * | $(LITERAL '___FUNCTION__')
- * | $(LITERAL '___PRETTY_FUNCTION__')
- * ;)
- */
- TemplateSingleArgument parseTemplateSingleArgument()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateSingleArgument;
- switch (current.type)
- {
- case tok!"true":
- case tok!"false":
- case tok!"null":
- case tok!"this":
- case tok!"identifier":
- mixin (SPECIAL_CASES);
- mixin (LITERAL_CASES);
- mixin (BASIC_TYPE_CASES);
- node.token = advance();
- break;
- default:
- error(`Invalid template argument. (Try enclosing in parenthesis?)`);
- return null;
- }
- return node;
- }
-
- /**
- * Parses a TemplateThisParameter
- *
- * $(GRAMMAR $(RULEDEF templateThisParameter):
- * $(LITERAL 'this') $(RULE templateTypeParameter)
- * ;)
- */
- TemplateThisParameter parseTemplateThisParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateThisParameter;
- expect(tok!"this");
- node.templateTypeParameter = parseTemplateTypeParameter();
- return node;
- }
-
- /**
- * Parses an TemplateTupleParameter
- *
- * $(GRAMMAR $(RULEDEF templateTupleParameter):
- * $(LITERAL Identifier) $(LITERAL '...')
- * ;)
- */
- TemplateTupleParameter parseTemplateTupleParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateTupleParameter;
- auto i = expect(tok!"identifier");
- if (i is null)
- return null;
- node.identifier = *i;
- if (expect(tok!"...") is null) return null;
- return node;
- }
-
- /**
- * Parses a TemplateTypeParameter
- *
- * $(GRAMMAR $(RULEDEF templateTypeParameter):
- * $(LITERAL Identifier) ($(LITERAL ':') $(RULE type))? ($(LITERAL '=') $(RULE type))?
- * ;)
- */
- TemplateTypeParameter parseTemplateTypeParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateTypeParameter;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!":"))
- {
- advance();
- node.colonType = parseType();
- }
- if (currentIs(tok!"="))
- {
- advance();
- node.assignType = parseType();
- }
- return node;
- }
-
- /**
- * Parses a TemplateValueParameter
- *
- * $(GRAMMAR $(RULEDEF templateValueParameter):
- * $(RULE type) $(LITERAL Identifier) ($(LITERAL ':') $(RULE expression))? $(RULE templateValueParameterDefault)?
- * ;)
- */
- TemplateValueParameter parseTemplateValueParameter()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateValueParameter;
- if ((node.type = parseType()) is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!":"))
- {
- advance();
- if ((node.expression = parseExpression()) is null) return null;
- }
- if (currentIs(tok!"="))
- {
- if ((node.templateValueParameterDefault = parseTemplateValueParameterDefault()) is null)
- return null;
- }
- return node;
- }
-
- /**
- * Parses a TemplateValueParameterDefault
- *
- * $(GRAMMAR $(RULEDEF templateValueParameterDefault):
- * $(LITERAL '=') ($(LITERAL '___FILE__') | $(LITERAL '___MODULE__') | $(LITERAL '___LINE__') | $(LITERAL '___FUNCTION__') | $(LITERAL '___PRETTY_FUNCTION__') | $(RULE assignExpression))
- * ;)
- */
- TemplateValueParameterDefault parseTemplateValueParameterDefault()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TemplateValueParameterDefault;
- expect(tok!"=");
- switch (current.type)
- {
- case tok!"__FILE__":
- case tok!"__MODULE__":
- case tok!"__LINE__":
- case tok!"__FUNCTION__":
- case tok!"__PRETTY_FUNCTION__":
- node.token = advance();
- break;
- default:
- node.assignExpression = parseAssignExpression();
- break;
- }
- return node;
- }
-
- /**
- * Parses a TernaryExpression
- *
- * $(GRAMMAR $(RULEDEF ternaryExpression):
- * $(RULE orOrExpression) ($(LITERAL '?') $(RULE expression) $(LITERAL ':') $(RULE ternaryExpression))?
- * ;)
- */
- ExpressionNode parseTernaryExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TernaryExpression;
- node.orOrExpression = parseOrOrExpression();
- if (currentIs(tok!"?"))
- {
- advance();
- node.expression = parseExpression();
- if (expect(tok!":") is null) return null;
- node.ternaryExpression = parseTernaryExpression();
- }
- return node;
- }
-
- /**
- * Parses a ThrowStatement
- *
- * $(GRAMMAR $(RULEDEF throwStatement):
- * $(LITERAL 'throw') $(RULE expression) $(LITERAL ';')
- * ;)
- */
- ThrowStatement parseThrowStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!ThrowStatement;
- expect(tok!"throw");
- node.expression = parseExpression();
- expect(tok!";");
- return node;
- }
-
- /**
- * Parses an TraitsExpression
- *
- * $(GRAMMAR $(RULEDEF traitsExpression):
- * $(LITERAL '___traits') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL ',') $(RULE TemplateArgumentList) $(LITERAL '$(RPAREN)')
- * ;)
- */
- TraitsExpression parseTraitsExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TraitsExpression;
- if (expect(tok!"__traits") is null) return null;
- if (expect(tok!"(") is null) return null;
- auto ident = expect(tok!"identifier");
- if (ident is null) return null;
- node.identifier = *ident;
- if (currentIs(tok!","))
- {
- advance();
- if ((node.templateArgumentList = parseTemplateArgumentList()) is null) return null;
- }
- if (expect(tok!")") is null) return null;
- return node;
- }
-
- /**
- * Parses a TryStatement
- *
- * $(GRAMMAR $(RULEDEF tryStatement):
- * $(LITERAL 'try') $(RULE declarationOrStatement) ($(RULE catches) | $(RULE catches) $(RULE finally) | $(RULE finally))
- * ;)
- */
- TryStatement parseTryStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TryStatement;
- expect(tok!"try");
- node.declarationOrStatement = parseDeclarationOrStatement();
- if (currentIs(tok!"catch"))
- node.catches = parseCatches();
- if (currentIs(tok!"finally"))
- node.finally_ = parseFinally();
- return node;
- }
-
- /**
- * Parses a Type
- *
- * $(GRAMMAR $(RULEDEF type):
- * $(RULE attribute)? $(RULE type2) $(RULE typeSuffix)*
- * ;)
- */
- Type parseType()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Type;
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"scope":
- case tok!"pure":
- case tok!"nothrow":
- if (!peekIs(tok!"("))
- node.typeConstructors = parseTypeConstructors();
- break;
- default:
- break;
- }
- node.type2 = parseType2();
- if (node.type2 is null)
- return null;
- TypeSuffix[] typeSuffixes;
- loop: while (moreTokens()) switch (current.type)
- {
- case tok!"*":
- case tok!"[":
- case tok!"delegate":
- case tok!"function":
- auto suffix = parseTypeSuffix();
- if (suffix !is null)
- typeSuffixes ~= suffix;
- else
- return null;
- break;
- default:
- break loop;
- }
- node.typeSuffixes = ownArray(typeSuffixes);
- return node;
- }
-
- /**
- * Parses a Type2
- *
- * $(GRAMMAR $(RULEDEF type2):
- * $(RULE builtinType)
- * | $(RULE symbol)
- * | $(RULE typeofExpression) ($(LITERAL '.') $(RULE identifierOrTemplateChain))?
- * | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)')
- * ;)
- */
- Type2 parseType2()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!Type2;
- switch (current.type)
- {
- case tok!"identifier":
- case tok!".":
- if ((node.symbol = parseSymbol()) is null)
- return null;
- break;
- mixin (BASIC_TYPE_CASES);
- if ((node.builtinType = parseBasicType()) == tok!"")
- return null;
- break;
- case tok!"typeof":
- if ((node.typeofExpression = parseTypeofExpression()) is null)
- return null;
- if (currentIs(tok!"."))
- {
- advance();
- node.identifierOrTemplateChain = parseIdentifierOrTemplateChain();
- if (node.identifierOrTemplateChain is null)
- return null;
- }
- break;
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- node.typeConstructor = advance().type;
- if (expect(tok!"(") is null) return null;
- if ((node.type = parseType()) is null) return null;
- if (expect(tok!")") is null) return null;
- break;
- default:
- error("Basic type, type constructor, symbol, or typeof expected");
- return null;
- }
- return node;
- }
-
- /**
- * Parses a TypeConstructor
- *
- * $(GRAMMAR $(RULEDEF typeConstructor):
- * $(LITERAL 'const')
- * | $(LITERAL 'immutable')
- * | $(LITERAL 'inout')
- * | $(LITERAL 'shared')
- * | $(LITERAL 'scope')
- * ;)
- */
- IdType parseTypeConstructor(bool validate = true)
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"scope":
- case tok!"ref":
- case tok!"pure":
- case tok!"nothrow":
- if (!peekIs(tok!"("))
- return advance().type;
- goto default;
- default:
- if (validate)
- error(`"const", "immutable", "inout", "shared", or "scope" expected`);
- return tok!"";
- }
- }
-
- /**
- * Parses TypeConstructors
- *
- * $(GRAMMAR $(RULEDEF typeConstructors):
- * $(RULE typeConstructor)+
- * ;)
- */
- IdType[] parseTypeConstructors()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- IdType[] r;
- while (moreTokens())
- {
- IdType type = parseTypeConstructor(false);
- if (type == tok!"")
- break;
- else
- r ~= type;
- }
- return r;
- }
-
- /**
- * Parses a TypeSpecialization
- *
- * $(GRAMMAR $(RULEDEF typeSpecialization):
- * $(RULE type)
- * | $(LITERAL 'struct')
- * | $(LITERAL 'union')
- * | $(LITERAL 'class')
- * | $(LITERAL 'interface')
- * | $(LITERAL 'enum')
- * | $(LITERAL 'function')
- * | $(LITERAL 'delegate')
- * | $(LITERAL 'super')
- * | $(LITERAL 'const')
- * | $(LITERAL 'immutable')
- * | $(LITERAL 'inout')
- * | $(LITERAL 'shared')
- * | $(LITERAL 'return')
- * | $(LITERAL 'typedef')
- * | $(LITERAL '___parameters')
- * ;)
- */
- TypeSpecialization parseTypeSpecialization()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TypeSpecialization;
- switch (current.type)
- {
- case tok!"struct":
- case tok!"union":
- case tok!"class":
- case tok!"interface":
- case tok!"enum":
- case tok!"function":
- case tok!"delegate":
- case tok!"super":
- case tok!"return":
- case tok!"typedef":
- case tok!"__parameters":
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- if (peekIsOneOf(tok!")", tok!","))
- {
- node.token = advance();
- break;
- }
- goto default;
- default:
- node.type = parseType();
- break;
- }
- return node;
- }
-
- /**
- * Parses a TypeSuffix
- *
- * $(GRAMMAR $(RULEDEF typeSuffix):
- * $(LITERAL '*')
- * | $(LITERAL '[') $(RULE type)? $(LITERAL ']')
- * | $(LITERAL '[') $(RULE assignExpression) $(LITERAL ']')
- * | $(LITERAL '[') $(RULE assignExpression) $(LITERAL '..') $(RULE assignExpression) $(LITERAL ']')
- * | ($(LITERAL 'delegate') | $(LITERAL 'function')) $(RULE parameters) $(RULE memberFunctionAttribute)*
- * ;)
- */
- TypeSuffix parseTypeSuffix()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TypeSuffix;
- switch (current.type)
- {
- case tok!"*":
- node.star = true;
- advance();
- return node;
- case tok!"[":
- node.array = true;
- advance();
- if (currentIs(tok!"]"))
- {
- advance();
- return node;
- }
- auto bookmark = setBookmark();
- auto type = parseType();
- if (type !is null && currentIs(tok!"]"))
- {
- goToBookmark(bookmark);
- type = parseType();
- node.type = type;
- }
- else
- {
- goToBookmark(bookmark);
- node.low = parseAssignExpression();
- if (node.low is null) return null;
- if (currentIs(tok!".."))
- {
- advance();
- node.high = parseAssignExpression();
- if (node.high is null) return null;
- }
- }
- if (expect(tok!"]") is null) return null;
- return node;
- case tok!"delegate":
- case tok!"function":
- node.delegateOrFunction = advance();
- node.parameters = parseParameters();
- MemberFunctionAttribute[] memberFunctionAttributes;
- while (currentIsMemberFunctionAttribute())
- memberFunctionAttributes ~= parseMemberFunctionAttribute();
- node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
- return node;
- default:
- error(`"*", "[", "delegate", or "function" expected.`);
- return null;
- }
- }
-
- /**
- * Parses a TypeidExpression
- *
- * $(GRAMMAR $(RULEDEF typeidExpression):
- * $(LITERAL 'typeid') $(LITERAL '$(LPAREN)') ($(RULE type) | $(RULE expression)) $(LITERAL '$(RPAREN)')
- * ;)
- */
- TypeidExpression parseTypeidExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TypeidExpression;
- expect(tok!"typeid");
- expect(tok!"(");
- auto b = setBookmark();
- auto t = parseType();
- if (t is null || !currentIs(tok!")"))
- {
- goToBookmark(b);
- node.expression = parseExpression();
- if (node.expression is null) return null;
- }
- else
- {
- goToBookmark(b);
- node.type = parseType();
- if (node.type is null) return null;
- }
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a TypeofExpression
- *
- * $(GRAMMAR $(RULEDEF typeofExpression):
- * $(LITERAL 'typeof') $(LITERAL '$(LPAREN)') ($(RULE expression) | $(LITERAL 'return')) $(LITERAL '$(RPAREN)')
- * ;)
- */
- TypeofExpression parseTypeofExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!TypeofExpression;
- expect(tok!"typeof");
- expect(tok!"(");
- if (currentIs(tok!"return"))
- node.return_ = advance();
- else
- node.expression = parseExpression();
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a UnaryExpression
- *
- * $(GRAMMAR $(RULEDEF unaryExpression):
- * $(RULE primaryExpression)
- * | $(LITERAL '&') $(RULE unaryExpression)
- * | $(LITERAL '!') $(RULE unaryExpression)
- * | $(LITERAL '*') $(RULE unaryExpression)
- * | $(LITERAL '+') $(RULE unaryExpression)
- * | $(LITERAL '-') $(RULE unaryExpression)
- * | $(LITERAL '~') $(RULE unaryExpression)
- * | $(LITERAL '++') $(RULE unaryExpression)
- * | $(LITERAL '--') $(RULE unaryExpression)
- * | $(RULE newExpression)
- * | $(RULE deleteExpression)
- * | $(RULE castExpression)
- * | $(RULE assertExpression)
- * | $(RULE functionCallExpression)
- * | $(RULE sliceExpression)
- * | $(RULE indexExpression)
- * | $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(RULE identifierOrTemplateInstance)
- * | $(RULE unaryExpression) $(LITERAL '.') $(RULE identifierOrTemplateInstance)
- * | $(RULE unaryExpression) $(LITERAL '--')
- * | $(RULE unaryExpression) $(LITERAL '++')
- * ;)
- */
- UnaryExpression parseUnaryExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- if (!moreTokens())
- return null;
- auto node = allocate!UnaryExpression;
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- auto b = setBookmark();
- if (peekIs(tok!"("))
- {
- advance();
- auto past = peekPastParens();
- if (past !is null && past.type == tok!".")
- {
- goToBookmark(b);
- goto default;
- }
- }
- goToBookmark(b);
- goto case;
- case tok!"scope":
- case tok!"pure":
- case tok!"nothrow":
- node.functionCallExpression = parseFunctionCallExpression();
- break;
- case tok!"&":
- case tok!"!":
- case tok!"*":
- case tok!"+":
- case tok!"-":
- case tok!"~":
- case tok!"++":
- case tok!"--":
- node.prefix = advance();
- node.unaryExpression = parseUnaryExpression();
- break;
- case tok!"new":
- node.newExpression = parseNewExpression();
- break;
- case tok!"delete":
- node.deleteExpression = parseDeleteExpression();
- break;
- case tok!"cast":
- node.castExpression = parseCastExpression();
- break;
- case tok!"assert":
- node.assertExpression = parseAssertExpression();
- break;
- case tok!"(":
- // handle (type).identifier
- auto b = setBookmark();
- skipParens();
- if (startsWith(tok!".", tok!"identifier"))
- {
- // go back to the (
- index = b;
- advance();
- auto t = parseType();
- if (t is null || !currentIs(tok!")"))
- {
- goToBookmark(b);
- goto default;
- }
- node.type = t;
- advance(); // )
- advance(); // .
- node.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance();
- break;
- }
- else
- {
- // not (type).identifier, so treat as primary expression
- goToBookmark(b);
- goto default;
- }
- default:
- node.primaryExpression = parsePrimaryExpression();
- break;
- }
-
- loop: while (moreTokens()) switch (current.type)
- {
- case tok!"!":
- if (peekIs(tok!"is"))
- break loop;
- index++;
- bool jump = (currentIs(tok!"(") && peekPastParens().type == tok!"(")
- || peekIs(tok!"(");
- index--;
- if (jump)
- goto case tok!"(";
- else
- break loop;
- case tok!"(":
- auto newUnary = allocate!UnaryExpression();
- newUnary.functionCallExpression = parseFunctionCallExpression(node);
- node = newUnary;
- break;
- case tok!"++":
- case tok!"--":
- auto n = allocate!UnaryExpression();
- n.unaryExpression = node;
- n.suffix = advance();
- node = n;
- break;
- case tok!"[":
- auto n = allocate!UnaryExpression;
- if (isSliceExpression())
- n.sliceExpression = parseSliceExpression(node);
- else
- n.indexExpression = parseIndexExpression(node);
- node = n;
- break;
- case tok!".":
- advance();
- auto n = allocate!UnaryExpression();
- n.unaryExpression = node;
- n.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance();
- node = n;
- break;
- default:
- break loop;
- }
- return node;
- }
-
- unittest
- {
- auto sourceCode =
-q{doStuff(5)}c;
- Parser p = getParserForUnittest(sourceCode, "parseUnaryExpression");
- auto unary = p.parseUnaryExpression();
- assert (unary !is null);
- assert (unary.functionCallExpression !is null);
- stderr.writeln("Unittest for parseUnaryExpression() passed.");
- }
-
- /**
- * Parses an UnionDeclaration
- *
- * $(GRAMMAR $(RULEDEF unionDeclaration):
- * $(LITERAL 'union') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(RULE structBody)
- * | $(LITERAL 'union') $(LITERAL Identifier) ($(RULE structBody) | $(LITERAL ';'))
- * | $(LITERAL 'union') $(RULE structBody)
- * ;)
- */
- UnionDeclaration parseUnionDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!UnionDeclaration;
- // grab line number even if it's anonymous
- auto l = expect(tok!"union").line;
- if (currentIs(tok!"identifier"))
- {
- node.name = advance();
- if (currentIs(tok!"("))
- {
- node.templateParameters = parseTemplateParameters();
- if (currentIs(tok!"if"))
- node.constraint = parseConstraint();
- node.structBody = parseStructBody();
- }
- else
- goto semiOrStructBody;
- }
- else
- {
- node.name.line = l;
- semiOrStructBody:
- if (currentIs(tok!";"))
- advance();
- else
- node.structBody = parseStructBody();
- }
- return node;
- }
-
- /**
- * Parses a Unittest
- *
- * $(GRAMMAR $(RULEDEF unittest):
- * $(LITERAL 'unittest') $(RULE blockStatement)
- * ;)
- */
- Unittest parseUnittest()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(Unittest, tok!"unittest", "blockStatement|parseBlockStatement"));
- }
-
- /**
- * Parses a VariableDeclaration
- *
- * $(GRAMMAR $(RULEDEF variableDeclaration):
- * $(RULE _type) $(RULE declarator) ($(LITERAL ',') $(RULE declarator))* $(LITERAL ';')
- * | $(RULE _type) $(RULE declarator) $(LITERAL '=') $(RULE functionBody)
- * | $(RULE autoDeclaration)
- * ;)
- */
- VariableDeclaration parseVariableDeclaration(Type type = null, bool isAuto = false)
- {
- mixin (traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!VariableDeclaration;
- if (isAuto)
- {
- node.autoDeclaration = parseAutoDeclaration();
- return node;
- }
-
- node.type = type is null ? parseType() : type;
- node.comment = comment;
-
- Declarator[] declarators;
- while (true)
- {
- auto declarator = parseDeclarator();
- if (declarator is null) return null;
- declarators ~= declarator;
- if (moreTokens() && currentIs(tok!","))
- advance();
- else
- break;
- }
- node.declarators = ownArray(declarators);
-// 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
- {
- if (expect(tok!";") is null) return null;
- return node;
- }
- }
-
- /**
- * Parses a Vector
- *
- * $(GRAMMAR $(RULEDEF vector):
- * $(LITERAL '___vector') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)')
- * ;)
- */
- Vector parseVector()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(Vector, tok!"__vector", tok!"(", "type|parseType", tok!")"));
- }
-
- /**
- * Parses a VersionCondition
- *
- * $(GRAMMAR $(RULEDEF versionCondition):
- * $(LITERAL 'version') $(LITERAL '$(LPAREN)') ($(LITERAL IntegerLiteral) | $(LITERAL Identifier) | $(LITERAL 'unittest') | $(LITERAL 'assert')) $(LITERAL '$(RPAREN)')
- * ;)
- */
- VersionCondition parseVersionCondition()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!VersionCondition;
- mixin (expectSequence!(tok!"version", tok!"("));
- if (currentIsOneOf(tok!"intLiteral", tok!"identifier",
- tok!"unittest", tok!"assert"))
- {
- node.token = advance();
- }
- else
- {
- error(`Expected an integer literal, an identifier, "assert", or "unittest"`);
- return null;
- }
- expect(tok!")");
- return node;
- }
-
- /**
- * Parses a VersionSpecification
- *
- * $(GRAMMAR $(RULEDEF versionSpecification):
- * $(LITERAL 'version') $(LITERAL '=') ($(LITERAL Identifier) | $(LITERAL IntegerLiteral)) $(LITERAL ';')
- * ;)
- */
- VersionSpecification parseVersionSpecification()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!VersionSpecification;
- mixin (expectSequence!(tok!"version", tok!"="));
- if (!currentIsOneOf(tok!"identifier", tok!"intLiteral"))
- {
- error("Identifier or integer literal expected");
- return null;
- }
- node.token = advance();
- expect(tok!";");
- return node;
- }
-
- /**
- * Parses a WhileStatement
- *
- * $(GRAMMAR $(RULEDEF whileStatement):
- * $(LITERAL 'while') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
- * ;)
- */
- WhileStatement parseWhileStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto node = allocate!WhileStatement;
- expect(tok!"while");
- node.startIndex = current().index;
- expect(tok!"(");
- node.expression = parseExpression();
- expect(tok!")");
- if (currentIs(tok!"}"))
- {
- error("Statement expected", false);
- return node; // this line makes DCD better
- }
- node.declarationOrStatement = parseDeclarationOrStatement();
- return node;
- }
-
- /**
- * Parses a WithStatement
- *
- * $(GRAMMAR $(RULEDEF withStatement):
- * $(LITERAL 'with') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault)
- * ;)
- */
- WithStatement parseWithStatement()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- mixin (simpleParse!(WithStatement, tok!"with", tok!"(",
- "expression|parseExpression", tok!")",
- "statementNoCaseNoDefault|parseStatementNoCaseNoDefault"));
- }
-
- /**
- * Parses an XorExpression
- *
- * $(GRAMMAR $(RULEDEF xorExpression):
- * $(RULE andExpression)
- * | $(RULE xorExpression) $(LITERAL '^') $(RULE andExpression)
- * ;)
- */
- ExpressionNode parseXorExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- return parseLeftAssocBinaryExpression!(XorExpression, AndExpression,
- tok!"^")();
- }
-
- /**
- * Current error count
- */
- uint errorCount;
-
- /**
- * Current warning count
- */
- uint warningCount;
-
- /**
- * Name used when reporting warnings and errors
- */
- string fileName;
-
- /**
- * Allocator used for creating AST nodes
- */
- CAllocator allocator;
-
- /**
- * Function that is called when a warning or error is encountered.
- * The parameters are the file name, line number, column number,
- * and the error or warning message.
- */
- void function(string, size_t, size_t, string, bool) messageFunction;
-
- bool isSliceExpression()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- if (startsWith(tok!"[", tok!"]"))
- return true;
- return hasMagicDelimiter!(tok!"[", tok!"..")();
- }
-
- void setTokens(const(Token)[] tokens)
- {
- this.tokens = tokens;
- }
-
- /**
- * Returns: true if there are more tokens
- */
- bool moreTokens() const nothrow pure @safe
- {
- return index < tokens.length;
- }
-
-protected:
-
- T[] ownArray(T)(T[] from)
- {
- 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;
- }
-
- T allocate(T, Args...)(auto ref Args args)
- {
- import std.stdio;
- if (allocator is null)
- 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;
- }
-
- bool isCastQualifier() const
- {
- switch (current.type)
- {
- case tok!"const":
- return peekIsOneOf(tok!"shared", tok!")");
- case tok!"immutable":
- return peekIs(tok!")");
- case tok!"inout":
- return peekIsOneOf(tok!"shared", tok!")");
- case tok!"shared":
- return peekIsOneOf(tok!"const", tok!"inout", tok!")");
- default:
- return false;
- }
- }
-
- bool isAssociativeArrayLiteral()
- {
- auto b = setBookmark();
- scope(exit) goToBookmark(b);
- advance();
- return !currentIs(tok!"]") && parseExpression() !is null && currentIs(tok!":");
- }
-
- bool hasMagicDelimiter(alias L, alias T)()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- auto i = index;
- scope(exit) index = i;
- assert (currentIs(L));
- advance();
- while (moreTokens()) switch (current.type)
- {
- case tok!"{": skipBraces(); break;
- case tok!"(": skipParens(); break;
- case tok!"[": skipBrackets(); break;
- case tok!"]": case tok!"}": return false;
- case T: return true;
- default: advance(); break;
- }
- return false;
- }
-
- bool isDeclaration()
- {
- mixin(traceEnterAndExit!(__FUNCTION__));
- if (!moreTokens()) return false;
- switch (current.type)
- {
- case tok!"final":
- return !peekIs(tok!"switch");
- case tok!"debug":
- case tok!"version":
- {
- if (peekIs(tok!"="))
- return false;
-
- auto b = setBookmark();
- scope (exit) goToBookmark(b);
- advance();
- return isDeclaration();
- }
- case tok!"synchronized":
- if (peekIs(tok!"("))
- return false;
- else
- {
- auto b = setBookmark();
- scope (exit) goToBookmark(b);
- advance();
- return isDeclaration();
- }
- case tok!"static":
- if (peekIs(tok!"if"))
- return false;
- goto case;
- case tok!"scope":
- if (peekIs(tok!"("))
- return false;
- goto case;
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"__gshared":
- case tok!"alias":
- case tok!"class":
- case tok!"enum":
- case tok!"interface":
- case tok!"struct":
- case tok!"union":
- case tok!"unittest":
- case tok!"auto":
- case tok!"ref":
- case tok!"@":
- case tok!"align":
- case tok!"deprecated":
- case tok!"private":
- case tok!"package":
- case tok!"protected":
- case tok!"public":
- case tok!"export":
- case tok!"extern":
- case tok!"override":
- case tok!"abstract":
- case tok!"pure":
- case tok!"nothrow":
- case tok!"virtual":
- return true;
- mixin(BASIC_TYPE_CASES);
- return !peekIs(tok!".");
- case tok!"case":
- case tok!"default":
- case tok!"return":
- case tok!"if":
- case tok!"while":
- case tok!"do":
- case tok!"for":
- case tok!"foreach":
- case tok!"switch":
- case tok!"continue":
- case tok!"break":
- case tok!"goto":
- case tok!"try":
- case tok!"throw":
- case tok!"asm":
- case tok!"foreach_reverse":
- case tok!"{":
- case tok!"assert":
- return false;
- default:
- break;
- }
- auto b = setBookmark();
- scope(exit) goToBookmark(b);
-
- return parseDeclaration() !is null;
- }
-
- bool isStatement()
- {
- if (!moreTokens()) return false;
- auto b = setBookmark();
- scope (exit) goToBookmark(b);
- return parseStatement() !is null;
- }
-
- bool isExpression()
- {
- if (!moreTokens()) return false;
- auto b = setBookmark();
- scope (exit) goToBookmark(b);
- return parseExpression() !is null;
- }
-
- bool isType()
- {
- if (!moreTokens()) return false;
- auto b = setBookmark();
- scope (exit) goToBookmark(b);
- if (parseType() is null) return false;
- if (currentIsOneOf(tok!",", tok!")")) return true;
- return false;
- }
-
- bool isStorageClass()
- {
- if (!moreTokens()) return false;
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- return !peekIs(tok!"(");
- case tok!"@":
- case tok!"deprecated":
- case tok!"abstract":
- case tok!"align":
- case tok!"auto":
- case tok!"enum":
- case tok!"extern":
- case tok!"final":
- case tok!"virtual":
- case tok!"nothrow":
- case tok!"override":
- case tok!"pure":
- case tok!"ref":
- case tok!"__gshared":
- case tok!"scope":
- case tok!"static":
- case tok!"synchronized":
- return true;
- default:
- return false;
- }
- }
-
- bool isAttribute()
- {
- if (!moreTokens()) return false;
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"scope":
- return !peekIs(tok!"(");
- case tok!"static":
- return !peekIsOneOf(tok!"assert", tok!"this", tok!"if", tok!"~");
- case tok!"shared":
- return !(startsWith(tok!"shared", tok!"static", tok!"this")
- || startsWith(tok!"shared", tok!"static", tok!"~")
- || peekIs(tok!"("));
- case tok!"enum":
- if (peekIsOneOf(tok!"{", tok!":", tok!";"))
- return false;
- else if (peekIs(tok!"identifier"))
- {
- if (startsWith(tok!"enum", tok!"identifier", tok!"("))
- return false;
- auto b = setBookmark();
- scope(exit) goToBookmark(b);
- advance();
- if (peekIsOneOf(tok!"{", tok!":", tok!";"))
- return false;
- 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":
- case tok!"protected":
- case tok!"public":
- case tok!"export":
- case tok!"final":
- case tok!"virtual":
- case tok!"synchronized":
- case tok!"override":
- case tok!"abstract":
- case tok!"auto":
- case tok!"__gshared":
- case tok!"pure":
- case tok!"nothrow":
- case tok!"@":
- case tok!"ref":
- case tok!"extern":
- case tok!"align":
- return true;
- default:
- return false;
- }
- }
-
- bool currentIsMemberFunctionAttribute() const
- {
- switch (current.type)
- {
- case tok!"const":
- case tok!"immutable":
- case tok!"inout":
- case tok!"shared":
- case tok!"@":
- case tok!"pure":
- case tok!"nothrow":
- return true;
- default:
- return false;
- }
- }
-
- ExpressionNode parseLeftAssocBinaryExpression(alias ExpressionType,
- alias ExpressionPartType, Operators ...)(ExpressionNode part = null)
- {
- ExpressionNode node;
- mixin ("node = part is null ? parse" ~ ExpressionPartType.stringof ~ "() : part;");
- while (currentIsOneOf(Operators))
- {
- auto n = allocate!ExpressionType;
- static if (__traits(hasMember, ExpressionType, "operator"))
- {
- n.line = current.line;
- n.column = current.column;
- n.operator = advance().type;
- }
- else
- advance();
- n.left = node;
- mixin ("n.right = parse" ~ ExpressionPartType.stringof ~ "();");
- node = n;
- }
- return node;
- }
-
- ListType parseCommaSeparatedRule(alias ListType, alias ItemType)(bool allowTrailingComma = false)
- {
- auto node = allocate!ListType;
- ItemType[] items;
- while (moreTokens())
- {
- mixin ("items ~= parse" ~ ItemType.stringof ~ "();");
- if (currentIs(tok!","))
- {
- advance();
- if (allowTrailingComma && currentIsOneOf(tok!")",
- tok!"}", tok!"]"))
- {
- break;
- }
- else
- continue;
- }
- else
- break;
- }
- node.items = ownArray(items);
- return node;
- }
-
- void warn(lazy string message)
- {
- if (suppressMessages > 0)
- return;
- ++warningCount;
- auto column = index < tokens.length ? tokens[index].column : 0;
- auto line = index < tokens.length ? tokens[index].line : 0;
- if (messageFunction is null)
- stderr.writefln("%s(%d:%d)[warn]: %s", fileName, line, column, message);
- else
- messageFunction(fileName, line, column, message, false);
- }
-
- void error(lazy string message, bool shouldAdvance = true)
- {
- import std.stdio;
- if (suppressMessages <= 0)
- {
- ++errorCount;
- auto column = index < tokens.length ? tokens[index].column : tokens[$ - 1].column;
- auto line = index < tokens.length ? tokens[index].line : tokens[$ - 1].line;
- if (messageFunction is null)
- {
- stderr.writefln("%s(%d:%d)[error]: %s", fileName, line, column, message);
- }
- else
- messageFunction(fileName, line, column, message, true);
- }
- while (shouldAdvance && moreTokens())
- {
- if (currentIsOneOf(tok!";", tok!"}",
- tok!")", tok!"]"))
- {
- advance();
- break;
- }
- else
- advance();
- }
- }
-
- void skip(alias O, alias C)()
- {
- assert (currentIs(O), current().text);
- advance();
- int depth = 1;
- while (moreTokens())
- {
- switch (tokens[index].type)
- {
- case C:
- advance();
- depth--;
- if (depth <= 0)
- return;
- break;
- case O:
- depth++;
- advance();
- break;
- default:
- advance();
- break;
- }
- }
- }
-
- void skipBraces()
- {
- skip!(tok!"{", tok!"}")();
- }
-
- void skipParens()
- {
- skip!(tok!"(", tok!")")();
- }
-
- void skipBrackets()
- {
- skip!(tok!"[", tok!"]")();
- }
-
- const(Token)* peek() const
- {
- return index + 1 < tokens.length ? &tokens[index + 1] : null;
- }
-
- const(Token)* peekPast(alias O, alias C)() const nothrow
- {
- if (index >= tokens.length)
- return null;
- int depth = 1;
- size_t i = index;
- ++i;
- while (i < tokens.length)
- {
- if (tokens[i] == O)
- {
- ++depth;
- ++i;
- }
- else if (tokens[i] == C)
- {
- --depth;
- ++i;
- if (depth <= 0)
- break;
- }
- else
- ++i;
- }
- return i >= tokens.length ? null : depth == 0 ? &tokens[i] : null;
- }
-
- const(Token)* peekPastParens() const nothrow
- {
- return peekPast!(tok!"(", tok!")")();
- }
-
- const(Token)* peekPastBrackets() const nothrow
- {
- return peekPast!(tok!"[", tok!"]")();
- }
-
- const(Token)* peekPastBraces() const nothrow
- {
- return peekPast!(tok!"{", tok!"}")();
- }
-
- bool peekIs(IdType t) const nothrow
- {
- return index + 1 < tokens.length && tokens[index + 1].type == t;
- }
-
- bool peekIsOneOf(IdType[] types...) const nothrow
- {
- if (index + 1 >= tokens.length) return false;
- return canFind(types, tokens[index + 1].type);
- }
-
- /**
- * Returns a token of the specified type if it was the next token, otherwise
- * calls the error function and returns null.
- */
- const(Token)* expect(IdType type)
- {
- if (index < tokens.length && tokens[index].type == type)
- return &tokens[index++];
- else
- {
- string tokenString = str(type) is null
- ? to!string(type) : str(type);
- bool shouldNotAdvance = index < tokens.length
- && (tokens[index].type == tok!")"
- || tokens[index].type == tok!";"
- || tokens[index].type == tok!"}");
- auto token = (index < tokens.length
- ? (tokens[index].text is null ? str(tokens[index].type) : tokens[index].text)
- : "EOF");
- error("Expected " ~ tokenString ~ " instead of " ~ token,
- !shouldNotAdvance);
- return null;
- }
- }
-
- /**
- * Returns: the _current token
- */
- Token current() const @property
- {
- return tokens[index];
- }
-
- /**
- * Advances to the next token and returns the current token
- */
- Token advance()
- {
- return tokens[index++];
- }
-
- /**
- * Returns: true if the current token has the given type
- */
- bool currentIs(IdType type) const
- {
- return index < tokens.length && tokens[index] == type;
- }
-
- /**
- * Returns: true if the current token is one of the given types
- */
- bool currentIsOneOf(IdType[] types...) const
- {
- if (index >= tokens.length)
- return false;
- return canFind(types, current.type);
- }
-
- bool startsWith(IdType[] types...) const nothrow
- {
- if (index + types.length >= tokens.length)
- return false;
- for (size_t i = 0; (i < types.length) && ((index + i) < tokens.length); ++i)
- {
- if (tokens[index + i].type != types[i])
- return false;
- }
- return true;
- }
-
- size_t setBookmark()
- {
-// mixin(traceEnterAndExit!(__FUNCTION__));
- suppressMessages++;
- auto i = index;
- return i;
- }
-
- void goToBookmark(size_t i) nothrow
- {
- --suppressMessages;
- index = i;
- }
-
- version (unittest) static void doNothingErrorFunction(string,
- size_t, size_t, string, bool) {}
-
- version (unittest) static Parser getParserForUnittest(string sourceCode,
- string testName)
- {
- auto r = byToken(cast(ubyte[]) sourceCode);
-
- CAllocator allocator = new ParseAllocator();
- enum numBytes = __traits(classInstanceSize, Parser);
- void[] mem = allocator.allocate(numBytes);
- assert (mem.length == numBytes, format("%d", mem.length));
- Parser p = emplace!Parser(mem);
- assert (cast(void*) p == mem.ptr, "%x, %x".format(cast(void*) p, mem.ptr));
-
- p.messageFunction = &doNothingErrorFunction;
- p.fileName = testName ~ ".d";
- p.tokens = r.array();
- return p;
- }
-
- template simpleParse(NodeType, parts ...)
- {
- static if (__traits(hasMember, NodeType, "comment"))
- enum simpleParse = "auto node = allocate!" ~ NodeType.stringof ~ ";\n"
- ~ "node.comment = comment;\n"
- ~ "comment = null;\n"
- ~ simpleParseItems!(parts)
- ~ "\nreturn node;\n";
- else
- enum simpleParse = "auto node = allocate!" ~ NodeType.stringof ~ ";\n"
- ~ simpleParseItems!(parts)
- ~ "\nreturn node;\n";
- }
-
- template simpleParseItems(items ...)
- {
- static if (items.length > 1)
- enum simpleParseItems = simpleParseItem!(items[0]) ~ "\n"
- ~ simpleParseItems!(items[1 .. $]);
- else static if (items.length == 1)
- enum simpleParseItems = simpleParseItem!(items[0]);
- else
- enum simpleParseItems = "";
- }
-
- template simpleParseItem(alias item)
- {
- static if (is (typeof(item) == string))
- enum simpleParseItem = "if ((node." ~ item[0 .. item.countUntil("|")]
- ~ " = " ~ item[item.countUntil("|") + 1 .. $] ~ "()) is null) return null;";
- else
- enum simpleParseItem = "if (expect(" ~ item.stringof ~ ") is null) return null;";
- }
-
- template expectSequence(sequence ...)
- {
- static if (sequence.length == 1)
- enum expectSequence = "if (expect(" ~ sequence[0].stringof ~ ") is null) return null;";
- else
- enum expectSequence = "if (expect(" ~ sequence[0].stringof ~ ") is null) return null;\n"
- ~ expectSequence!(sequence[1..$]);
- }
-
- template traceEnterAndExit(string fun)
- {
- enum traceEnterAndExit = `version (std_parser_verbose) { _traceDepth++; trace("`
- ~ `\033[01;32m` ~ fun ~ `\033[0m"); }`
- ~ `version (std_parser_verbose) scope(exit) { trace("`
- ~ `\033[01;31m` ~ fun ~ `\033[0m"); _traceDepth--; }`;
- }
-
- version (std_parser_verbose)
- {
- void trace(lazy string message)
- {
- auto depth = format("%4d ", _traceDepth);
- if (suppressMessages > 0)
- return;
- if (index < tokens.length)
- writeln(depth, message, "(", current.line, ":", current.column, ")");
- else
- writeln(depth, message, "(EOF:0)");
- }
- }
- else
- {
- void trace(lazy string) {}
- }
-
- enum string BASIC_TYPE_CASES = q{
- case tok!"int":
- case tok!"uint":
- case tok!"double":
- case tok!"idouble":
- case tok!"float":
- case tok!"ifloat":
- case tok!"short":
- case tok!"ushort":
- case tok!"long":
- case tok!"ulong":
- case tok!"char":
- case tok!"wchar":
- case tok!"dchar":
- case tok!"bool":
- case tok!"void":
- case tok!"cent":
- case tok!"ucent":
- case tok!"real":
- case tok!"ireal":
- case tok!"byte":
- case tok!"ubyte":
- case tok!"cdouble":
- case tok!"cfloat":
- case tok!"creal":
- };
- enum string LITERAL_CASES = q{
- case tok!"doubleLiteral":
- case tok!"floatLiteral":
- case tok!"idoubleLiteral":
- case tok!"ifloatLiteral":
- case tok!"intLiteral":
- case tok!"longLiteral":
- case tok!"realLiteral":
- case tok!"irealLiteral":
- case tok!"uintLiteral":
- case tok!"ulongLiteral":
- case tok!"stringLiteral":
- case tok!"wstringLiteral":
- case tok!"dstringLiteral":
- case tok!"characterLiteral":
- };
- enum string SPECIAL_CASES = q{
- case tok!"__DATE__":
- case tok!"__EOF__":
- case tok!"__FILE__":
- case tok!"__FUNCTION__":
- case tok!"__LINE__":
- case tok!"__MODULE__":
- case tok!"__PRETTY_FUNCTION__":
- case tok!"__TIME__":
- case tok!"__TIMESTAMP__":
- case tok!"__VENDOR__":
- case tok!"__VERSION__":
- };
- const(Token)[] tokens;
- int suppressMessages;
- size_t index;
- int _traceDepth;
- string comment;
-}
-
diff --git a/std/lexer.d b/std/lexer.d
deleted file mode 100644
index d29895f..0000000
--- a/std/lexer.d
+++ /dev/null
@@ -1,834 +0,0 @@
-// Written in the D programming language
-
-/**
- * $(H2 Summary)
- * This module contains a range-based compile-time _lexer generator.
- *
- * $(H2 Overview)
- * The _lexer generator consists of a template mixin, $(LREF Lexer), along with
- * several helper templates for generating such things as token identifiers.
- *
- * To write a _lexer using this API:
- * $(OL
- * $(LI Create the string array costants for your language.
- * $(UL
- * $(LI $(LINK2 #.staticTokens, staticTokens))
- * $(LI $(LINK2 #.dynamicTokens, dynamicTokens))
- * $(LI $(LINK2 #.possibleDefaultTokens, possibleDefaultTokens))
- * $(LI $(LINK2 #.tokenHandlers, tokenHandlers))
- * ))
- * $(LI Create aliases for the various token and token identifier types
- * specific to your language.
- * $(UL
- * $(LI $(LREF TokenIdType))
- * $(LI $(LREF tokenStringRepresentation))
- * $(LI $(LREF TokenStructure))
- * $(LI $(LREF TokenId))
- * ))
- * $(LI Create a struct that mixes in the Lexer template mixin and
- * implements the necessary functions.
- * $(UL
- * $(LI $(LREF Lexer))
- * ))
- * )
- * Examples:
- * $(UL
- * $(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).)
- * )
- * $(DDOC_ANCHOR TemplateParameters) $(H2 Template Parameter Definitions)
- * $(DL
- * $(DT $(DDOC_ANCHOR defaultTokenFunction) $(B defaultTokenFunction)
- * $(DD A function that serves as the default token lexing function. For most
- * languages this will be the identifier lexing function.))
- * $(DT $(DDOC_ANCHOR tokenSeparatingFunction) $(B tokenSeparatingFunction))
- * $(DD A function that is able to determine if an identifier/keyword has come
- * to an end. This function must return bool and take a single size_t
- * argument representing the number of bytes to skip over before looking for
- * a separating character.)
- * $(DT $(DDOC_ANCHOR staticTokens) $(B staticTokens))
- * $(DD A listing of the tokens whose exact value never changes and which cannot
- * possibly be a token handled by the default token lexing function. The
- * most common example of this kind of token is an operator such as
- * $(D_STRING "*"), or $(D_STRING "-") in a programming language.)
- * $(DT $(DDOC_ANCHOR dynamicTokens) $(B dynamicTokens))
- * $(DD A listing of tokens whose value is variable, such as whitespace,
- * identifiers, number literals, and string literals.)
- * $(DT $(DDOC_ANCHOR possibleDefaultTokens) $(B possibleDefaultTokens))
- * $(DD A listing of tokens that could posibly be one of the tokens handled by
- * the default token handling function. An common example of this is
- * a keyword such as $(D_STRING "for"), which looks like the beginning of
- * the identifier $(D_STRING "fortunate"). $(B tokenSeparatingFunction) is
- * called to determine if the character after the $(D_STRING 'r') separates
- * the identifier, indicating that the token is $(D_STRING "for"), or if
- * lexing should be turned over to the $(B defaultTokenFunction).)
- * $(DT $(DDOC_ANCHOR tokenHandlers) $(B tokenHandlers))
- * $(DD A mapping of prefixes to custom token handling function names. The
- * generated _lexer will search for the even-index elements of this array,
- * and then call the function whose name is the element immedately after the
- * even-indexed element. This is used for lexing complex tokens whose prefix
- * is fixed.)
- * )
- *
- * Here are some example constants for a simple calculator _lexer:
- * ---
- * // There are a near infinite number of valid number literals, so numbers are
- * // dynamic tokens.
- * enum string[] dynamicTokens = ["numberLiteral", "whitespace"];
- *
- * // The operators are always the same, and cannot start a numberLiteral, so
- * // they are staticTokens
- * enum string[] staticTokens = ["-", "+", "*", "/"];
- *
- * // In this simple example there are no keywords or other tokens that could
- * // look like dynamic tokens, so this is blank.
- * enum string[] possibleDefaultTokens = [];
- *
- * // If any whitespace character or digit is encountered, pass lexing over to
- * // our custom handler functions. These will be demonstrated in an example
- * // later on.
- * enum string[] tokenHandlers = [
- * "0", "lexNumber",
- * "1", "lexNumber",
- * "2", "lexNumber",
- * "3", "lexNumber",
- * "4", "lexNumber",
- * "5", "lexNumber",
- * "6", "lexNumber",
- * "7", "lexNumber",
- * "8", "lexNumber",
- * "9", "lexNumber",
- * " ", "lexWhitespace",
- * "\n", "lexWhitespace",
- * "\t", "lexWhitespace",
- * "\r", "lexWhitespace"
- * ];
- * ---
- *
- * Copyright: Brian Schott 2013
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt Boost, License 1.0)
- * Authors: Brian Schott, with ideas shamelessly stolen from Andrei Alexandrescu
- * Source: $(PHOBOSSRC std/_lexer.d)
- */
-
-module std.lexer;
-
-/**
- * Template for determining the type used for a token type. Selects the smallest
- * unsigned integral type that is able to hold the value
- * staticTokens.length + dynamicTokens.length + possibleDefaultTokens.length.
- * For example if there are 20 static tokens, 30 dynamic tokens,
- * and 10 possible default tokens, this template will alias itself to ubyte,
- * as 20 + 30 + 10 < $(D_KEYWORD ubyte).max.
- * Examples:
- * ---
- * // In our calculator example this means that IdType is an alias for ubyte.
- * alias IdType = TokenIdType!(staticTokens, dynamicTokens, possibleDefaultTokens);
- * ---
- */
-template TokenIdType(alias staticTokens, alias dynamicTokens,
- alias possibleDefaultTokens)
-{
- immutable tokenCount = staticTokens.length + dynamicTokens.length
- + possibleDefaultTokens.length + 1;
- static if (tokenCount <= ubyte.max)
- alias TokenIdType = ubyte;
- else static if (tokenCount <= ushort.max)
- alias TokenIdType = ushort;
- else static if (tokenCount <= uint.max)
- alias TokenIdType = uint;
- else
- static assert (false, "The number of tokens must be less than uint.max");
-}
-
-/**
- * Looks up the string representation of the given token type. This is the
- * opposite of the function of the TokenId template.
- * Params: type = the token type identifier
- * Examples:
- * ---
- * alias str = tokenStringRepresentation(IdType, staticTokens, dynamicTokens, possibleDefaultTokens);
- * assert (str(tok!"*") == "*");
- * ---
- * See_also: $(LREF TokenId)
- */
-string tokenStringRepresentation(IdType, alias staticTokens, alias dynamicTokens,
- alias possibleDefaultTokens)(IdType type) @property
-{
- enum tokens = staticTokens ~ dynamicTokens ~ possibleDefaultTokens;
-
- if (type == 0)
- return "!ERROR!";
- else if (type < tokens.length + 1)
- return tokens[type - 1];
- else
- return null;
-}
-
-unittest
-{
- /// Fix https://github.com/Hackerpilot/Dscanner/issues/96
- alias IdType = TokenIdType!(["foo"], ["bar"], ["doo"]);
- enum tok(string token) = TokenId!(IdType, ["foo"], ["bar"], ["doo"], token);
- alias str = tokenStringRepresentation!(IdType, ["foo"], ["bar"], ["doo"]);
-
- static assert (str(tok!"foo") == "foo");
- static assert (str(tok!"bar") == "bar");
- static assert (str(tok!"doo") == "doo");
-}
-
-/**
- * Generates the token type identifier for the given symbol. There are two
- * special cases:
- * $(UL
- * $(LI If symbol is $(D_STRING ""), then the token identifier will be 0)
- * $(LI If symbol is $(D_STRING "\0"), then the token identifier will be the maximum
- * valid token type identifier)
- * )
- * In all cases this template will alias itself to a constant of type IdType.
- * This template will fail at compile time if $(D_PARAM symbol) is not one of
- * the staticTokens, dynamicTokens, or possibleDefaultTokens.
- * Examples:
- * ---
- * template tok(string symbol)
- * {
- * alias tok = TokenId!(IdType, staticTokens, dynamicTokens,
- * possibleDefaultTokens, symbol);
- * }
- * // num and plus are of type ubyte.
- * IdType plus = tok!"+";
- * IdType num = tok!"numberLiteral";
- * ---
- */
-template TokenId(IdType, alias staticTokens, alias dynamicTokens,
- alias possibleDefaultTokens, string symbol)
-{
- enum tokens = staticTokens ~ dynamicTokens ~ possibleDefaultTokens;
-
- import std.algorithm;
- static if (symbol == "")
- {
- enum id = 0;
- alias TokenId = id;
- }
- else static if (symbol == "\0")
- {
- enum id = 1 + tokens.length;
- alias TokenId = id;
- }
- else
- {
- enum i = tokens.countUntil(symbol);
- static if (i != -1)
- {
- enum id = i + 1;
- static assert (id >= 0 && id < IdType.max, "Invalid token: " ~ symbol);
- alias TokenId = id;
- }
- else
- static assert (0, "Invalid token: " ~ symbol);
- }
-}
-
-/**
- * The token that is returned by the lexer.
- * Params:
- * IdType = The D type of the "type" token type field.
- * extraFields = A string containing D code for any extra fields that should
- * be included in the token structure body. This string is passed
- * directly to a mixin statement.
- * Examples:
- * ---
- * // No extra struct fields are desired in this example, so leave it blank.
- * alias Token = TokenStructure!(IdType, "");
- * Token minusToken = Token(tok!"-");
- * ---
- */
-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.
- */
- bool opEquals(IdType type) const pure nothrow @safe
- {
- return this.type == type;
- }
-
- /**
- * Constructs a token from a token type.
- * Params: type = the token type
- */
- this(IdType type)
- {
- this.type = type;
- }
-
- /**
- * Constructs a token.
- * Params:
- * type = the token type
- * text = the text of the token, which may be null
- * line = the line number at which this token occurs
- * column = the column number at which this token occurs
- * index = the byte offset from the beginning of the input at which this
- * token occurs
- */
- this(IdType type, string text, size_t line, size_t column, size_t index)
- {
- this.text = text;
- this.line = line;
- this.column = column;
- this.type = type;
- this.index = index;
- }
-
- /**
- * The _text of the token.
- */
- string text;
-
- /**
- * The _line number at which this token occurs.
- */
- size_t line;
-
- /**
- * The _column number at which this token occurs. This is measured in bytes
- * and may not be correct when tab characters are involved.
- */
- size_t column;
-
- /**
- * The byte offset from the beginning of the input at which this token
- * occurs.
- */
- size_t index;
-
- /**
- * The token type.
- */
- IdType type;
-
- mixin (extraFields);
-}
-
-/**
- * The implementation of the _lexer is contained within this mixin template.
- * To use it, this template should be mixed in to a struct that represents the
- * _lexer for your language. This struct should implement the following methods:
- * $(UL
- * $(LI popFront, which should call this mixin's _popFront() and
- * additionally perform any token filtering or shuffling you deem
- * necessary. For example, you can implement popFront to skip comment or
- * tokens.)
- * $(LI A function that serves as the default token lexing function. For
- * most languages this will be the identifier lexing function. This
- * should then be passed to the $(LREF Lexer) template mixin as the
- * $(LINK2 #.defaultTokenFunction defaultTokenFunction) template
- * parameter).
- * $(LI A function that is able to determine if an identifier/keyword has
- * come to an end. This function must return $(D_KEYWORD bool) and take
- * a single $(D_KEYWORD size_t) argument representing the number of
- * bytes to skip over before looking for a separating character.)
- * $(LI Any functions referred to in the tokenHandlers template paramater.
- * These functions must be marked $(D_KEYWORD pure nothrow), take no
- * arguments, and return a token)
- * $(LI A constructor that initializes the range field as well as calls
- * popFront() exactly once (to initialize the _front field).)
- * )
- * Params:
- * Token = $(LREF TokenStructure)
- * defaultTokenFunction = $(LINK2 #.defaultTokenFunction, defaultTokenFunction)
- * tokenSeparatingFunction = $(LINK2 #.tokenSeparatingFunction, tokenSeparatingFunction)
- * staticTokens = $(LINK2 #.staticTokens, staticTokens)
- * dynamicTokens = $(LINK2 #.dynamicTokens, dynamicTokens)
- * possibleDefaultTokens = $(LINK2 #.possibleDefaultTokens, possibleDefaultTokens)
- * tokenHandlers = $(LINK2 #.tokenHandlers, tokenHandlers)
- * Examples:
- * ---
- * struct CalculatorLexer
- * {
- * mixin Lexer!(IdType, Token, defaultTokenFunction, isSeparating,
- * staticTokens, dynamicTokens, possibleDefaultTokens, tokenHandlers);
- *
- * this (ubyte[] bytes)
- * {
- * this.range = LexerRange(bytes);
- * popFront();
- * }
- *
- * void popFront() pure
- * {
- * _popFront();
- * }
- *
- * Token lexNumber() pure nothrow @safe
- * {
- * // implementation goes here
- * }
- *
- * Token lexWhitespace() pure nothrow @safe
- * {
- * // implementation goes here
- * }
- *
- * Token defaultTokenFunction() pure nothrow @safe
- * {
- * // There is no default token in the example calculator language, so
- * // this is always an error.
- * range.popFront();
- * return Token(tok!"");
- * }
- *
- * bool isSeparating(size_t offset) pure nothrow @safe
- * {
- * // For this example language, always return true.
- * return true;
- * }
- * }
- * ---
- */
-mixin template Lexer(Token, alias defaultTokenFunction,
- alias tokenSeparatingFunction, alias staticTokens, alias dynamicTokens,
- alias possibleDefaultTokens, alias tokenHandlers)
-{
- private alias _IDType = typeof(Token.type);
- private enum _tok(string symbol) = TokenId!(_IDType, staticTokens, dynamicTokens, possibleDefaultTokens, symbol);
-
- static assert (tokenHandlers.length % 2 == 0, "Each pseudo-token must"
- ~ " have a corresponding handler function name.");
-
- static string generateMask(const ubyte[] arr)
- {
- import std.string;
- ulong u;
- for (size_t i = 0; i < arr.length && i < 8; i++)
- {
- u |= (cast(ulong) arr[i]) << (i * 8);
- }
- return format("0x%016x", u);
- }
-
- private static string generateByteMask(size_t l)
- {
- import std.string;
- return format("0x%016x", ulong.max >> ((8 - l) * 8));
- }
-
- private static size_t calcSplitCount(size_t a, size_t b) pure nothrow
- {
- int i;
- while (true)
- {
- i++;
- a /= 2;
- if (a < b)
- break;
- }
- return i;
- }
-
- private static char[] getBeginningChars(string[] allTokens)
- {
- char[] beginningChars;
- for (size_t i = 0; i < allTokens.length; i++)
- {
- if (allTokens[i].length == 0)
- continue;
- beginningChars ~= allTokens[i][0];
- size_t j = i + 1;
- while (j < allTokens.length && allTokens[i][0] == allTokens[j][0])
- j++;
- i = j - 1;
- }
- return beginningChars;
- }
-
- private static string generateStatements()
- {
- import std.algorithm;
- import std.conv;
- import std.string;
- import std.range;
-
- string[] pseudoTokens = stupidToArray(tokenHandlers.stride(2));
- string[] allTokens = stupidToArray(sort(staticTokens ~ possibleDefaultTokens ~ pseudoTokens).uniq);
- // Array consisting of a sorted list of the first characters of the
- // tokens.
- char[] beginningChars = getBeginningChars(allTokens);
- size_t i = calcSplitCount(beginningChars.length, 8);
- return generateStatementsStep(allTokens, pseudoTokens, beginningChars, i);
- }
-
- private static string generateStatementsStep(string[] allTokens,
- string[] pseudoTokens, char[] chars, size_t i, string indent = "")
- {
- import std.string;
- string code;
- if (i > 0)
- {
- size_t p = chars.length / 2;
- code ~= indent ~ format("if (f < 0x%02x) // %s \n%s{\n", chars[p], chars[p], indent);
- code ~= generateStatementsStep(allTokens, pseudoTokens, chars[0 .. p], i - 1, indent ~ " ");
- code ~= indent ~ "}\n" ~ indent ~ "else\n" ~ indent ~ "{\n";
- code ~= generateStatementsStep(allTokens, pseudoTokens, chars[p .. $], i - 1, indent ~ " ");
- code ~= indent ~ "}\n";
- }
- else
- {
- code ~= indent ~ "switch (f)\n" ~ indent ~ "{\n";
- foreach (char c; chars)
- {
- size_t begin;
- size_t end;
- for (size_t j = 0; j < allTokens.length; j++)
- {
- if (allTokens[j].length == 0 || allTokens[j][0] != c)
- continue;
- begin = j;
- end = j + 1;
- while (end < allTokens.length && allTokens[begin][0] == allTokens[end][0])
- end++;
- break;
- }
- code ~= format("%scase 0x%02x:\n", indent, c);
- code ~= printCase(allTokens[begin .. end], pseudoTokens, indent ~ " ");
- }
- code ~= indent ~ "default: goto _defaultTokenFunction;\n";
- code ~= indent ~ "}\n";
- }
-
- return code;
- }
-
- private static string printCase(string[] tokens, string[] pseudoTokens, string indent)
- {
- import std.algorithm;
- string[] sortedTokens = stupidToArray(sort!"a.length > b.length"(tokens));
- import std.conv;
-
- if (tokens.length == 1 && tokens[0].length == 1)
- {
- if (pseudoTokens.countUntil(tokens[0]) >= 0)
- {
- return indent ~ "return "
- ~ tokenHandlers[tokenHandlers.countUntil(tokens[0]) + 1]
- ~ "();\n";
- }
- else if (staticTokens.countUntil(tokens[0]) >= 0)
- {
- return indent ~ "range.popFront();\n"
- ~ indent ~ "return Token(_tok!\"" ~ escape(tokens[0]) ~ "\", null, line, column, index);\n";
- }
- else if (pseudoTokens.countUntil(tokens[0]) >= 0)
- {
- return indent ~ "return "
- ~ tokenHandlers[tokenHandlers.countUntil(tokens[0]) + 1]
- ~ "();\n";
- }
- }
-
- string code;
-
- foreach (i, token; sortedTokens)
- {
- immutable mask = generateMask(cast (const ubyte[]) token);
- if (token.length >= 8)
- code ~= indent ~ "if (frontBytes == " ~ mask ~ ")\n";
- else
- code ~= indent ~ "if ((frontBytes & " ~ generateByteMask(token.length) ~ ") == " ~ mask ~ ")\n";
- code ~= indent ~ "{\n";
- if (pseudoTokens.countUntil(token) >= 0)
- {
- if (token.length <= 8)
- {
- code ~= indent ~ " return "
- ~ tokenHandlers[tokenHandlers.countUntil(token) + 1]
- ~ "();\n";
- }
- else
- {
- code ~= indent ~ " if (range.peek(" ~ text(token.length - 1) ~ ") == \"" ~ escape(token) ~"\")\n";
- code ~= indent ~ " return "
- ~ tokenHandlers[tokenHandlers.countUntil(token) + 1]
- ~ "();\n";
- }
- }
- else if (staticTokens.countUntil(token) >= 0)
- {
- if (token.length <= 8)
- {
- code ~= indent ~ " range.popFrontN(" ~ text(token.length) ~ ");\n";
- code ~= indent ~ " return Token(_tok!\"" ~ escape(token) ~ "\", null, line, column, index);\n";
- }
- else
- {
- code ~= indent ~ " pragma(msg, \"long static tokens not supported\"); // " ~ escape(token) ~ "\n";
- }
- }
- else
- {
- // possible default
- if (token.length <= 8)
- {
- code ~= indent ~ " if (tokenSeparatingFunction(" ~ text(token.length) ~ "))\n";
- code ~= indent ~ " {\n";
- code ~= indent ~ " range.popFrontN(" ~ text(token.length) ~ ");\n";
- code ~= indent ~ " return Token(_tok!\"" ~ escape(token) ~ "\", null, line, column, index);\n";
- code ~= indent ~ " }\n";
- code ~= indent ~ " else\n";
- code ~= indent ~ " goto _defaultTokenFunction;\n";
- }
- else
- {
- code ~= indent ~ " if (range.peek(" ~ text(token.length - 1) ~ ") == \"" ~ escape(token) ~"\" && isSeparating(" ~ text(token.length) ~ "))\n";
- code ~= indent ~ " {\n";
- code ~= indent ~ " range.popFrontN(" ~ text(token.length) ~ ");\n";
- code ~= indent ~ " return Token(_tok!\"" ~ escape(token) ~ "\", null, line, column, index);\n";
- code ~= indent ~ " }\n";
- code ~= indent ~ " else\n";
- code ~= indent ~ " goto _defaultTokenFunction;\n";
- }
- }
- code ~= indent ~ "}\n";
- }
- code ~= indent ~ "else\n";
- code ~= indent ~ " goto _defaultTokenFunction;\n";
- return code;
- }
-
- /**
- * Implements the range primitive _front.
- */
- ref const(Token) front() pure nothrow const @property
- {
- return _front;
- }
-
- /**
- * Advances the lexer to the next token and stores the new current token in
- * the _front variable.
- */
- void _popFront() pure
- {
- _front = advance();
- }
-
- /**
- * Implements the range primitive _empty.
- */
- bool empty() pure const nothrow @property
- {
- return _front.type == _tok!"\0";
- }
-
- static string escape(string input)
- {
- string retVal;
- foreach (ubyte c; cast(ubyte[]) input)
- {
- switch (c)
- {
- case '\\': retVal ~= `\\`; break;
- case '"': retVal ~= `\"`; break;
- case '\'': retVal ~= `\'`; break;
- case '\t': retVal ~= `\t`; break;
- case '\n': retVal ~= `\n`; break;
- case '\r': retVal ~= `\r`; break;
- default: retVal ~= c; break;
- }
- }
- return retVal;
- }
-
- // This only exists because the real array() can't be called at compile-time
- static string[] stupidToArray(R)(R range)
- {
- string[] retVal;
- foreach (v; range)
- retVal ~= v;
- return retVal;
- }
-
- enum tokenSearch = generateStatements();
-
- static ulong getFront(const ubyte[] arr) pure nothrow @trusted
- {
- import std.stdio;
- immutable importantBits = *(cast (ulong*) arr.ptr);
- immutable filler = ulong.max >> ((8 - arr.length) * 8);
- return importantBits & filler;
- }
-
- Token advance() pure
- {
- if (range.empty)
- return Token(_tok!"\0");
- immutable size_t index = range.index;
- immutable size_t column = range.column;
- immutable size_t line = range.line;
- immutable ulong frontBytes = getFront(range.peek(7));
- ubyte f = frontBytes & 0xff;
-// pragma(msg, tokenSearch);
- mixin(tokenSearch);
- _defaultTokenFunction:
- return defaultTokenFunction();
- }
-
- /**
- * The lexer input.
- */
- LexerRange range;
-
- /**
- * The token that is currently at the front of the range.
- */
- Token _front;
-}
-
-/**
- * Range structure that wraps the _lexer's input.
- */
-struct LexerRange
-{
- /**
- * Params:
- * bytes = the _lexer input
- * index = the initial offset from the beginning of $(D_PARAM bytes)
- * column = the initial _column number
- * line = the initial _line number
- */
- this(const(ubyte)[] bytes, size_t index = 0, size_t column = 1, size_t line = 1) pure nothrow @safe
- {
- this.bytes = bytes;
- this.index = index;
- this.column = column;
- this.line = line;
- }
-
- /**
- * Returns: a mark at the current position that can then be used with slice.
- */
- size_t mark() const nothrow pure @safe
- {
- return index;
- }
-
- /**
- * Sets the range to the given position.
- * Params: m = the position to seek to
- */
- void seek(size_t m) nothrow pure @safe
- {
- index = m;
- }
-
- /**
- * Returs a slice of the input byte array between the given mark and the
- * current position.
- * Params m = the beginning index of the slice to return
- */
- const(ubyte)[] slice(size_t m) const nothrow pure @safe
- {
- return bytes[m .. index];
- }
-
- /**
- * Implements the range primitive _empty.
- */
- bool empty() const nothrow pure @safe
- {
- return index >= bytes.length;
- }
-
- /**
- * Implements the range primitive _front.
- */
- ubyte front() const nothrow pure @safe
- {
- return bytes[index];
- }
-
- /**
- * Returns: the current item as well as the items $(D_PARAM p) items ahead.
- */
- const(ubyte)[] peek(size_t p) const nothrow pure @safe
- {
- return index + p + 1 > bytes.length
- ? bytes[index .. $]
- : bytes[index .. index + p + 1];
- }
-
- /**
- *
- */
- ubyte peekAt(size_t offset) const nothrow pure @safe
- {
- return bytes[index + offset];
- }
-
- /**
- * Returns: true if it is possible to peek $(D_PARAM p) bytes ahead.
- */
- bool canPeek(size_t p) const nothrow pure @safe
- {
- return index + p < bytes.length;
- }
-
- /**
- * Implements the range primitive _popFront.
- */
- void popFront() pure nothrow @safe
- {
- index++;
- column++;
- }
-
- /**
- * Implements the algorithm _popFrontN more efficiently. This function does
- * not detect or handle newlines.
- */
- void popFrontN(size_t n) pure nothrow @safe
- {
- index += n;
- column += n;
- }
-
- /**
- * Increments the range's line number and resets the column counter.
- */
- void incrementLine(size_t i = 1) pure nothrow @safe
- {
- column = 1;
- line += i;
- }
-
- /**
- * The input _bytes.
- */
- const(ubyte)[] bytes;
-
- /**
- * The range's current position.
- */
- size_t index;
-
- /**
- * The current _column number.
- */
- size_t column;
-
- /**
- * The current _line number.
- */
- size_t line;
-}
-