CTAGS and AST printing

This commit is contained in:
Hackerpilot 2013-07-26 23:34:56 -07:00
parent 1aec76fdea
commit fe1bdef759
6 changed files with 1176 additions and 313 deletions

View File

@ -2,9 +2,473 @@ import std.d.lexer;
import std.d.ast;
import std.stdio;
template tagAndAccept(string tagName)
{
immutable tagAndAccept = `output.writeln("<` ~ tagName ~ `>");`
~ tagName ~ `.accept(this);`
~ `output.writeln("</` ~ tagName ~ `>");`;
}
class XMLPrinter : ASTVisitor
{
override void visit(Module mod)
override void visit(AddExpression addExpression)
{
output.writeln("<addExpression operator=\"", getTokenValue(addExpression.operator) ,"\">");
output.writeln("<left>");
addExpression.left.accept(this);
output.writeln("</left>");
if (addExpression.right !is null)
{
output.writeln("<right>");
addExpression.right.accept(this);
output.writeln("</right>");
}
output.writeln("</addExpression>");
}
override void visit(AliasDeclaration aliasDeclaration)
{
mixin (tagAndAccept!"aliasDeclaration");
}
override void visit(AliasInitializer aliasInitializer)
{
mixin (tagAndAccept!"aliasInitializer");
}
override void visit(AliasThisDeclaration aliasThisDeclaration)
{
mixin (tagAndAccept!"aliasThisDeclaration");
}
override void visit(AlignAttribute alignAttribute)
{
output.writeln("<alignAttribute align=\"", alignAttribute.intLiteral.value, "\">");
}
override void visit(AndAndExpression andAndExpression)
{
output.writeln("<andAndExpression>");
output.writeln("<left>");
andAndExpression.left.accept(this);
output.writeln("<left>");
if (andAndExpression.right !is null)
{
output.writeln("<right>");
andAndExpression.right.accept(this);
output.writeln("<right>");
}
output.writeln("</andAndExpression>");
}
override void visit(AndExpression andExpression)
{
output.writeln("<andExpression>");
output.writeln("<left>");
andExpression.left.accept(this);
output.writeln("<left>");
if (andExpression.right !is null)
{
output.writeln("<right>");
andExpression.right.accept(this);
output.writeln("<right>");
}
output.writeln("</andExpression>");
}
override void visit(ArgumentList argumentList)
{
mixin (tagAndAccept!"argumentList");
}
override void visit(Arguments arguments)
{
mixin (tagAndAccept!"arguments");
}
override void visit(ArrayInitializer arrayInitializer)
{
mixin (tagAndAccept!"arrayInitializer");
}
override void visit(ArrayLiteral arrayLiteral)
{
mixin (tagAndAccept!"arrayLiteral");
}
override void visit(ArrayMemberInitialization arrayMemberInitialization)
{
mixin (tagAndAccept!"arrayMemberInitialization");
}
override void visit(AssertExpression assertExpression)
{
output.writeln("<assertExpression>");
output.writeln("<assertion>");
assertExpression.assertion.accept(this);
output.writeln("</assertion>");
if (assertExpression.message !is null)
{
output.writeln("<message>");
assertExpression.message.accept(this);
output.writeln("</message>");
}
output.writeln("</assertExpression>");
}
override void visit(AssignExpression assignExpression)
{
if (assignExpression.assignExpression is null)
output.writeln("<assignExpression>");
else
output.writeln("<assignExpression operator=\"",
getTokenValue(assignExpression.operator), "\">");
assignExpression.accept(this);
output.writeln("</assignExpression>");
}
override void visit(AssocArrayLiteral assocArrayLiteral)
{
mixin (tagAndAccept!"assocArrayLiteral");
}
override void visit(AtAttribute atAttribute)
{
output.writeln("<atAttribute>");
if (atAttribute.identifier.type == TokenType.invalid)
atAttribute.accept(this);
else
output.writeln("<identifier>", atAttribute.identifier.value, "</identifier>");
output.writeln("</atAttribute>");
}
override void visit(Attribute attribute)
{
output.writeln("<attribute>");
if (attribute.attribute == TokenType.invalid)
attribute.accept(this);
else
output.writeln(getTokenValue(attribute.attribute));
output.writeln("</attribute>");
}
override void visit(AttributeDeclaration attributeDeclaration)
{
assert (attributeDeclaration !is null);
mixin (tagAndAccept!"attributeDeclaration");
}
override void visit(AutoDeclaration autoDec)
{
output.writeln("<autoDeclaration>");
for (size_t i = 0; i < autoDec.identifiers.length; i++)
{
output.writeln("<item>");
output.writeln("<name line=\"", autoDec.identifiers[i].line, "\">",
autoDec.identifiers[i].value, "</name>");
visit(autoDec.initializers[i]);
output.writeln("</item>");
}
output.writeln("</autoDeclaration>");
}
override void visit(BlockStatement blockStatement)
{
output.writeln("<blockStatement>");
blockStatement.accept(this);
output.writeln("</blockStatement>");
}
override void visit(BodyStatement bodyStatement)
{
output.writeln("<bodyStatement>");
bodyStatement.accept(this);
output.writeln("</bodyStatement>");
}
override void visit(BreakStatement breakStatement)
{
if (breakStatement.label.type == TokenType.invalid)
output.writeln("<breakStatement>");
else
output.writeln("<breakStatement label=\"", breakStatement.label, "\">");
}
override void visit(BaseClass baseClass)
{
mixin (tagAndAccept!"baseClass");
}
override void visit(BaseClassList baseClassList)
{
mixin (tagAndAccept!"baseClassList");
}
override void visit(CaseRangeStatement caseRangeStatement)
{
output.writeln("<caseRangeStatement>");
output.writeln("<low>");
visit(caseRangeStatement.low);
output.writeln("</low>");
output.writeln("<high>");
visit(caseRangeStatement.high);
output.writeln("</high>");
if (caseRangeStatement.declarationsAndStatements !is null)
visit(caseRangeStatement.declarationsAndStatements);
output.writeln("</caseRangeStatement>");
}
override void visit(CaseStatement caseStatement)
{
mixin (tagAndAccept!"caseStatement");
}
override void visit(CastExpression castExpression)
{
mixin (tagAndAccept!"castExpression");
}
override void visit(CastQualifier castQualifier)
{
mixin (tagAndAccept!"castQualifier");
}
override void visit(Catches catches)
{
mixin (tagAndAccept!"catches");
}
override void visit(Catch catch_)
{
output.writeln("<catch>");
catch_.accept(this);
output.writeln("</catch>");
}
override void visit(ClassDeclaration classDec)
{
output.writeln("<classDeclaration line=\"", classDec.name.line, "\">");
output.writeln("<name>", classDec.name.value, "</name>");
classDec.accept(this);
output.writeln("</classDeclaration>");
}
override void visit(CmpExpression cmpExpression)
{
mixin (tagAndAccept!"cmpExpression");
}
override void visit(CompileCondition compileCondition)
{
mixin (tagAndAccept!"compileCondition");
}
override void visit(ConditionalDeclaration conditionalDeclaration)
{
output.writeln("<conditionalDeclaration>");
visit(conditionalDeclaration.compileCondition);
output.writeln("<trueDeclaration>");
visit(conditionalDeclaration.trueDeclaration);
output.writeln("</trueDeclaration>");
if (conditionalDeclaration.falseDeclaration !is null)
{
output.writeln("<falseDeclaration>");
visit(conditionalDeclaration.falseDeclaration);
output.writeln("</falseDeclaration>");
}
output.writeln("</conditionalDeclaration>");
}
override void visit(ConditionalStatement conditionalStatement)
{
output.writeln("<conditionalStatement>");
visit(conditionalStatement.compileCondition);
output.writeln("<trueStatement>");
visit(conditionalStatement.trueStatement);
output.writeln("</trueStatement>");
if (conditionalStatement.falseStatement !is null)
{
output.writeln("<falseStatement>");
visit(conditionalStatement.falseStatement);
output.writeln("</falseStatement>");
}
output.writeln("</conditionalStatement>");
}
override void visit(Constraint constraint)
{
output.writeln("<constraint>");
constraint.accept(this);
output.writeln("</constraint>");
}
override void visit(Constructor constructor)
{
mixin (tagAndAccept!"constructor");
}
override void visit(ContinueStatement continueStatement)
{
if (continueStatement.label.type == TokenType.invalid)
output.writeln("<continueStatement/>");
else
output.writeln("<continueStatement label=\"",
continueStatement.label, "\"/>");
}
override void visit(DebugCondition debugCondition)
{
if (debugCondition.identifierOrInteger.type == TokenType.invalid)
output.writeln("<debugCondition/>");
else
output.writeln("<debugCondition condition=\"",
debugCondition.identifierOrInteger.value, "\"/>");
}
override void visit(DebugSpecification debugSpecification)
{
if (debugSpecification.identifierOrInteger.type == TokenType.invalid)
output.writeln("<debugSpecification/>");
else
output.writeln("<debugSpecification condition=\"",
debugSpecification.identifierOrInteger.value, "\"/>");
}
override void visit(Declaration declaration)
{
mixin (tagAndAccept!"declaration");
}
override void visit(DeclarationsAndStatements declarationsAndStatements)
{
mixin (tagAndAccept!"declarationsAndStatements");
}
override void visit(DeclarationOrStatement declarationOrStatement)
{
mixin (tagAndAccept!"declarationOrStatement");
}
override void visit(Declarator declarator)
{
output.writeln("<declarator line=\"", declarator.name.line, "\">");
output.writeln("<name>", declarator.name.value, "</name>");
declarator.accept(this);
output.writeln("</declarator>");
}
override void visit(DefaultStatement defaultStatement)
{
mixin (tagAndAccept!"defaultStatement");
}
override void visit(DeleteExpression deleteExpression)
{
mixin (tagAndAccept!"deleteExpression");
}
override void visit(DeleteStatement deleteStatement)
{
mixin (tagAndAccept!"deleteStatement");
}
override void visit(Deprecated deprecated_)
{
if (deprecated_.assignExpression !is null)
{
output.writeln("<deprecated>");
deprecated_.accept(this);
output.writeln("</deprecated>");
}
else
output.writeln("<deprecated/>");
}
override void visit(Destructor destructor)
{
mixin (tagAndAccept!"destructor");
}
override void visit(DoStatement doStatement)
{
mixin (tagAndAccept!"doStatement");
}
override void visit(EnumBody enumBody)
{
mixin (tagAndAccept!"enumBody");
}
override void visit(EnumDeclaration enumDec)
{
output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">");
if (enumDec.name.type == TokenType.identifier)
output.writeln("<name>", enumDec.name.value, "</name>");
enumDec.accept(this);
output.writeln("</enumDeclaration>");
}
override void visit(EnumMember enumMem)
{
output.writeln("<enumMember line=\"", enumMem.name.line, "\">");
enumMem.accept(this);
output.writeln("</enumMember>");
}
override void visit(EqualExpression equalExpression)
{
output.writeln("<enumMember operator=\"", getTokenValue(equalExpression.operator), "\">");
output.writeln("<left>");
visit(equalExpression.left);
output.writeln("</left>");
output.writeln("<right>");
visit(equalExpression.right);
output.writeln("</right>");
output.writeln("</enumMember>");
}
override void visit(Expression expression)
{
output.writeln("<expression>");
expression.accept(this);
output.writeln("</expression>");
}
override void visit(ExpressionStatement expressionStatement)
{
output.writeln("<expressionStatement>");
expressionStatement.accept(this);
output.writeln("</expressionStatement>");
}
override void visit(FinalSwitchStatement finalSwitchStatement)
{
output.writeln("<finalSwitchStatement>");
finalSwitchStatement.accept(this);
output.writeln("</finalSwitchStatement>");
}
override void visit(Finally finally_)
{
output.writeln("<finally>");
finally_.accept(this);
output.writeln("</finally>");
}
override void visit(ForStatement forStatement)
{
output.writeln("<forStatement>");
// TODO
forStatement.accept(this);
output.writeln("</forStatement>");
}
/***************************************************************************
* BOOKMARK
**************************************************************************/
override void visit(Module mod)
{
output.writeln("<module>");
mod.accept(this);
@ -21,49 +485,113 @@ class XMLPrinter : ASTVisitor
override void visit(IdentifierChain chain)
{
output.writeln("<identifierChain>");
foreach (ident; chain.identifiers)
{
output.writeln("<identifier>", ident.value, "</identifier>");
}
chain.accept(this);
output.writeln("</identifierChain>");
}
override void visit(ClassDeclaration classDec)
override void visit(IdentifierList list)
{
output.writeln("<classDeclaration line=\"", classDec.name.line, "\">");
output.writeln("<name>", classDec.name.value, "</name>");
output.writeln("</classDeclaration>");
output.writeln("<identifierList>");
list.accept(this);
output.writeln("</identifierList>");
}
override void visit(FunctionBody functionBody)
{
mixin (tagAndAccept!"functionBody");
}
override void visit(FunctionDeclaration functionDec)
{
output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">");
output.writeln("<name>", functionDec.name.value, "</name>");
functionDec.accept(this);
output.writeln("</functionDeclaration>");
}
override void visit(ImportDeclaration importDeclaration)
{
mixin (tagAndAccept!"importDeclaration");
}
override void visit(InterfaceDeclaration interfaceDec)
{
output.writeln("<interfaceDeclaration line=\"", interfaceDec.name.line, "\">");
output.writeln("<name>", interfaceDec.name.value, "</name>");
interfaceDec.accept(this);
output.writeln("</interfaceDeclaration>");
}
override void visit(Parameters parameters)
{
mixin (tagAndAccept!"parameters");
}
override void visit(Parameter param)
{
output.writeln("<parameter>");
if (param.name.type == TokenType.identifier)
output.writeln("<name>", param.name.value, "</name>");
foreach (attribute; param.parameterAttributes)
{
output.writeln("<parameterAttribute>", getTokenValue(attribute), "</parameterAttribute>");
}
param.accept(this);
if (param.vararg)
output.writeln("<vararg/>");
output.writeln("</parameter>");
}
override void visit(StructDeclaration structDec)
{
output.writeln("<structDeclaration line=\"", structDec.name.line, "\">");
output.writeln("<name>", structDec.name.value, "</name>");
structDec.accept(this);
output.writeln("</structDeclaration>");
}
override void visit(FunctionDeclaration functionDec)
{
output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">");
output.writeln("<name>", functionDec.name.value, "</name>");
output.writeln("</functionDeclaration>");
}
override void visit(Token token)
{
string tagName;
with (TokenType) switch (token.type)
{
case identifier: tagName = "identifier"; break;
case doubleLiteral: tagName = "doubleLiteral"; break;
case idoubleLiteral: tagName = "idoubleLiteral"; break;
case floatLiteral: tagName = "floatLiteral"; break;
case ifloatLiteral: tagName = "ifloatLiteral"; break;
case intLiteral: tagName = "intLiteral"; break;
case uintLiteral: tagName = "uintLiteral"; break;
case longLiteral: tagName = "longLiteral"; break;
case ulongLiteral: tagName = "ulongLiteral"; break;
case realLiteral: tagName = "realLiteral"; break;
case irealLiteral: tagName = "irealLiteral"; break;
case characterLiteral: tagName = "characterLiteral"; break;
case stringLiteral: tagName = "stringLiteral"; break;
case dstringLiteral: tagName = "dstringLiteral"; break;
case wstringLiteral: tagName = "wstringLiteral"; break;
default: tagName = "token";
}
output.writeln("<", tagName, "><![CDATA[", token.value, "]]></", tagName, ">");
}
override void visit(EnumDeclaration enumDec)
{
output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">");
if (enumDec.name.type == TokenType.identifier)
output.writeln("<name>", enumDec.name.value, "</name>");
enumDec.accept(this);
output.writeln("</enumDeclaration>");
}
override void visit(Type type)
{
output.writeln("<type pretty=\"", type.toString(), "\">");
type.accept(this);
output.writeln("</type>");
}
override void visit(EnumMember enumMem)
override void visit(Unittest unittest_)
{
output.writeln("<unittest>");
unittest_.accept(this);
output.writeln("</unittest>");
}
override void visit(VariableDeclaration variableDeclaration)
{
output.writeln("<enumMember line=\"", enumMem.name.line, "\">");
output.writeln("<name>", enumMem.name.value, "</name>");
enumMem.accept(this);
output.writeln("</enumMember>");
mixin (tagAndAccept!"variableDeclaration")
}
alias ASTVisitor.visit visit;

80
ctags.d
View File

@ -9,18 +9,33 @@ import std.d.parser;
import std.d.lexer;
import std.d.ast;
import std.algorithm;
import std.range;
import std.stdio;
import std.array;
void doNothing(string, int, int, string) {}
void printCtags(Tokens)(File output, ref Tokens tokens, string fileName)
void printCtags(File output, string[] fileNames)
{
Module m = parseModule(tokens.array(), fileName, &doNothing);
auto printer = new CTagsPrinter;
printer.fileName = fileName;
printer.visit(m);
printer.print(output);
string[] tags;
foreach (fileName; fileNames)
{
File f = File(fileName);
auto bytes = uninitializedArray!(ubyte[])(f.size);
f.rawRead(bytes);
LexerConfig config;
auto tokens = byToken(bytes, config);
Module m = parseModule(tokens.array(), fileName, &doNothing);
auto printer = new CTagsPrinter;
printer.fileName = fileName;
printer.visit(m);
tags ~= printer.tagLines;
}
output.write("!_TAG_FILE_FORMAT\t2\n"
~ "!_TAG_FILE_SORTED\t1\n"
~ "!_TAG_FILE_AUTHOR\tBrian Schott\n"
~ "!_TAG_PROGRAM_URL\thttps://github.com/Hackerpilot/Dscanner/\n");
tags.sort().copy(output.lockingTextWriter);
}
class CTagsPrinter : ASTVisitor
@ -30,48 +45,67 @@ class CTagsPrinter : ASTVisitor
override void visit(ClassDeclaration dec)
{
tagLines ~= "%s\t%s\t%d;\"\tc".format(dec.name.value, fileName, dec.name.line);
tagLines ~= "%s\t%s\t%d;\"\tc%s\n".format(dec.name.value, fileName, dec.name.line, context);
auto c = context;
context = "\tclass:" ~ dec.name.value;
dec.accept(this);
context = c;
}
override void visit(InterfaceDeclaration dec)
{
tagLines ~= "%s\t%s\t%d;\"\tc".format(dec.name.value, fileName, dec.name.line);
tagLines ~= "%s\t%s\t%d;\"\tc%s\n".format(dec.name.value, fileName, dec.name.line, context);
auto c = context;
context = "\tclass:" ~ dec.name.value;
dec.accept(this);
context = c;
}
override void visit(FunctionDeclaration dec)
{
tagLines ~= "%s\t%s\t%d;\"\tf\tarity:%d".format(dec.name.value, fileName,
dec.name.line, dec.parameters.parameters.length);
tagLines ~= "%s\t%s\t%d;\"\tf\tarity:%d%s\n".format(dec.name.value, fileName,
dec.name.line, dec.parameters.parameters.length, context);
auto c = context;
context = "\tfunction:" ~ dec.name.value;
dec.accept(this);
context = c;
}
override void visit(EnumDeclaration dec)
{
tagLines ~= "%s\t%s\t%d;\"\tg".format(dec.name.value, fileName, dec.name.line);
tagLines ~= "%s\t%s\t%d;\"\tg%s\n".format(dec.name.value, fileName,
dec.name.line, context);
auto c = context;
context = "\tenum:" ~ dec.name.value;
dec.accept(this);
context = c;
}
override void visit(EnumMember mem)
{
tagLines ~= "%s\t%s\t%d;\"\te%s\n".format(mem.name.value, fileName,
mem.name.line, context);
}
override void visit(VariableDeclaration dec)
{
foreach (d; dec.declarators)
tagLines ~= "%s\t%s\t%d;\"\tv".format(d.name.value, fileName, d.name.line);
{
tagLines ~= "%s\t%s\t%d;\"\tv%s\n".format(d.name.value, fileName,
d.name.line, context);
}
dec.accept(this);
}
void print(File output)
{
output.write("!_TAG_FILE_FORMAT\t2\n"
~ "!_TAG_FILE_SORTED\t1\n"
~ "!_TAG_FILE_AUTHOR\tBrian Schott\n"
~ "!_TAG_PROGRAM_URL\thttps://github.com/Hackerpilot/Dscanner/\n");
foreach (str; sort(tagLines))
{
output.writeln(str);
}
}
override void visit(FunctionBody fBody)
{
++suppressDepth;
fBody.accept(this);
--suppressDepth;
}
string fileName;
string[] tagLines;
int suppressDepth;
string context;
}

15
main.d
View File

@ -79,6 +79,17 @@ int main(string[] args)
args.length == 1 ? "stdin" : args[1]);
return 0;
}
else if (ctags)
{
if (recursive)
{
stdout.printCtags(dirEntries(args[1], SpanMode.depth)
.filter!(a => a.name.endsWith(".d") || a.name.endsWith(".di"))()
.map!(a => a.name)().array());
}
else
stdout.printCtags(args[1 .. $]);
}
else
{
LexerConfig config;
@ -98,10 +109,6 @@ int main(string[] args)
{
printTokenCount(stdout, tokens, f.size);
}
else if (ctags)
{
printCtags(stdout, tokens, args[1]);
}
else if (syntaxCheck)
{
parseModule(tokens.array(), args[1]);

File diff suppressed because it is too large Load Diff

View File

@ -2250,6 +2250,18 @@ enum TokenType: ushort
wstringLiteral, /// $(D_STRING "16-bit string"w)
}
/**
* Look up a token's string representation by its type.
* Params:
* type = the token type
* Returns: a string representing the token, or null for token types such as
* identifier or integer literal whose string representations vary
*/
pure string getTokenValue(const TokenType type)
{
return tokenValues[type];
}
// Implementation details follow
private:
@ -2539,8 +2551,8 @@ bool isRangeEoF(R)(ref R range)
return range.empty || range.front == 0 || range.front == 0x1a;
}
// Lookup table for token values
package immutable(string[TokenType.max + 1]) tokenValues = [
// Lookup table for token string representations
immutable(string[TokenType.max + 1]) tokenValues = [
null,
"=",
"@",
@ -2743,11 +2755,6 @@ package immutable(string[TokenType.max + 1]) tokenValues = [
null,
];
pure string getTokenValue(const TokenType type)
{
return tokenValues[type];
}
template tokenValue(TokenType val)
{
enum tokenValue = getTokenValue(val);
@ -2939,8 +2946,7 @@ pure TokenType lookupTokenType(R)(R input)
}
break;
case 11:
if (input[1..$].equal("_VERSION__"))
return TokenType.specialVersion;
if (input.equal("__VERSION__")) return TokenType.specialVersion;
break;
case 12:
switch (input[0])
@ -2952,16 +2958,13 @@ pure TokenType lookupTokenType(R)(R input)
}
break;
case 13:
if (input[1..$].equal("_TIMESTAMP__"))
return TokenType.specialTimestamp;
if (input.equal("__TIMESTAMP__")) return TokenType.specialTimestamp;
break;
case 15:
if (input[1..$].equal("oreach_reverse"))
return TokenType.foreach_reverse_;
if (input.equal("foreach_reverse")) return TokenType.foreach_reverse_;
break;
case 19:
if (input[1..$].equal("_PRETTY_FUNCTION__"))
return TokenType.specialPrettyFunction;
if (input.equal("__PRETTY_FUNCTION__")) return TokenType.specialPrettyFunction;
break;
default: break;
}

View File

@ -877,7 +877,7 @@ alias core.sys.posix.stdio.fileno fileno;
switch (current.type)
{
case TokenType.identifier:
node.identifier = advance();
node.label = advance();
if (expect(TokenType.semicolon) is null) return null;
break;
case TokenType.semicolon:
@ -951,14 +951,13 @@ alias core.sys.posix.stdio.fileno fileno;
* | $(LITERAL 'void')
* ;)
*/
Token parseBasicType()
TokenType parseBasicType()
{
mixin(traceEnterAndExit!(__FUNCTION__));
if (isBasicType(current.type))
return advance();
return advance().type;
error("Basic type expected");
Token t;
return t;
return TokenType.invalid;
}
/**
@ -1483,7 +1482,7 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
switch (current.type)
{
case TokenType.identifier:
node.identifier = advance();
node.label = advance();
if (expect(TokenType.semicolon) is null) return null;
break;
case TokenType.semicolon:
@ -1511,7 +1510,6 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
if (currentIs(TokenType.lParen))
{
advance();
node.hasIdentifierOrInteger = true;
if (currentIsOneOf(TokenType.intLiteral, TokenType.identifier))
node.identifierOrInteger = advance();
else
@ -1521,8 +1519,6 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
}
if (expect(TokenType.rParen) is null) return null;
}
else
node.hasIdentifierOrInteger = false;
return node;
}
@ -3116,7 +3112,7 @@ invariant() foo();
* Parses KeyValuePairs
*
* $(GRAMMAR $(RULEDEF keyValuePairs):
* $(RULE keyValuePair) ($(LITERAL ',') $(RULE keyValuePair))*
* $(RULE keyValuePair) ($(LITERAL ',') $(RULE keyValuePair))* $(LITERAL ',')?
* ;)
*/
KeyValuePairs parseKeyValuePairs()
@ -3129,7 +3125,11 @@ invariant() foo();
if (kvPair !is null)
node.keyValuePairs ~= kvPair;
if (currentIs(TokenType.comma))
{
advance();
if (currentIs(TokenType.rBracket))
break;
}
else
break;
}
@ -5287,7 +5287,7 @@ q{(int a, ...)
return null;
break;
case bool_: .. case wchar_:
if ((node.basicType = parseBasicType()) == TokenType.invalid)
if ((node.builtinType = parseBasicType()) == TokenType.invalid)
return null;
break;
case typeof_:
@ -5479,7 +5479,7 @@ q{(int a, ...)
return node;
case delegate_:
case function_:
advance();
node.delegateOrFunction = advance();
node.parameters = parseParameters();
while (currentIsMemberFunctionAttribute())
node.memberFunctionAttributes ~= parseMemberFunctionAttribute();
@ -6338,11 +6338,11 @@ private:
return &tokens[index++];
else
{
if (tokenValues[type] is null)
if (getTokenValue(type) is null)
error("Expected " ~ to!string(type) ~ " instead of "
~ (index < tokens.length ? tokens[index].value : "EOF"));
else
error("Expected " ~ tokenValues[type] ~ " instead of "
error("Expected " ~ getTokenValue(type) ~ " instead of "
~ (index < tokens.length ? tokens[index].value : "EOF"));
return null;
}