1829 lines
35 KiB
D
Executable File
1829 lines
35 KiB
D
Executable File
// Written in the D programming language
|
|
|
|
/**
|
|
* This module contains a parser for D source code.
|
|
*/
|
|
|
|
module std.d.parser;
|
|
|
|
import std.d.lexer;
|
|
import std.d.ast;
|
|
version(unittest) import std.stdio;
|
|
|
|
Module parseModule(R)(R tokens) if (is (ElementType!R == Token))
|
|
{
|
|
auto parser = new Parser();
|
|
parser.tokens = tokens.array();
|
|
return parser.parseModule();
|
|
}
|
|
|
|
private:
|
|
|
|
struct Parser
|
|
{
|
|
AddExpression parseAddExpression()
|
|
{
|
|
auto node = new AddExpression;
|
|
return node;
|
|
}
|
|
|
|
AliasDeclaration parseAliasDeclaration()
|
|
{
|
|
auto node = new AliasDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
AliasInitializer parseAliasInitializer()
|
|
{
|
|
auto node = new AliasInitializer;
|
|
|
|
return node;
|
|
}
|
|
|
|
AliasThisDeclaration parseAliasThisDeclaration()
|
|
{
|
|
auto node = new AliasThisDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
AlignAttribute parseAlignAttribute()
|
|
{
|
|
auto node = new AlignAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
AndAndExpression parseAndAndExpression()
|
|
{
|
|
auto node = new AndAndExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
AndExpression parseAndExpression()
|
|
{
|
|
auto node = new AndExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
ArgumentList parseArgumentList()
|
|
{
|
|
auto node = new ArgumentList;
|
|
|
|
return node;
|
|
}
|
|
|
|
Arguments parseArguments()
|
|
{
|
|
auto node = new Arguments;
|
|
expect(TokenType.lParen);
|
|
node.argumentList = parseArgumentList();
|
|
expect(TokenType.rParen);
|
|
return node;
|
|
}
|
|
|
|
ArrayInitializer parseArrayInitializer()
|
|
{
|
|
auto node = new ArrayInitializer;
|
|
|
|
return node;
|
|
}
|
|
|
|
ArrayLiteral parseArrayLiteral()
|
|
{
|
|
auto node = new ArrayLiteral;
|
|
expect(TokenType.lBracket);
|
|
node.argumentList = parseArgumentList();
|
|
expect(TokenType.rBracket);
|
|
return node;
|
|
}
|
|
|
|
ArrayMemberInitialization parseArrayMemberInitialization()
|
|
{
|
|
auto node = new ArrayMemberInitialization;
|
|
|
|
return node;
|
|
}
|
|
|
|
ArrayMemberInitializations parseArrayMemberInitializations()
|
|
{
|
|
auto node = new ArrayMemberInitializations;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmAddExp parseAsmAddExp()
|
|
{
|
|
auto node = new AsmAddExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmAndExp parseAsmAndExp()
|
|
{
|
|
auto node = new AsmAndExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmBrExp parseAsmBrExp()
|
|
{
|
|
auto node = new AsmBrExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmEqualExp parseAsmEqualExp()
|
|
{
|
|
auto node = new AsmEqualExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmExp parseAsmExp()
|
|
{
|
|
auto node = new AsmExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmInstruction parseAsmInstruction()
|
|
{
|
|
auto node = new AsmInstruction;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmLogAndExp parseAsmLogAndExp()
|
|
{
|
|
auto node = new AsmLogAndExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmLogOrExp parseAsmLogOrExp()
|
|
{
|
|
auto node = new AsmLogOrExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmMulExp parseAsmMulExp()
|
|
{
|
|
auto node = new AsmMulExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmOrExp parseAsmOrExp()
|
|
{
|
|
auto node = new AsmOrExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmPrimaryExp parseAsmPrimaryExp()
|
|
{
|
|
auto node = new AsmPrimaryExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmRelExp parseAsmRelExp()
|
|
{
|
|
auto node = new AsmRelExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmShiftExp parseAsmShiftExp()
|
|
{
|
|
auto node = new AsmShiftExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmStatement parseAsmStatement()
|
|
{
|
|
auto node = new AsmStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmTypePrefix parseAsmTypePrefix()
|
|
{
|
|
auto node = new AsmTypePrefix;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmUnaExp parseAsmUnaExp()
|
|
{
|
|
auto node = new AsmUnaExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AsmXorExp parseAsmXorExp()
|
|
{
|
|
auto node = new AsmXorExp;
|
|
|
|
return node;
|
|
}
|
|
|
|
AssertExpression parseAssertExpression()
|
|
{
|
|
auto node = new AssertExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
AssertStatement parseAssertStatement()
|
|
{
|
|
auto node = new AssertStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
AssignExpression parseAssignExpression()
|
|
{
|
|
auto node = new AssignExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
AssignStatement parseAssignStatement()
|
|
{
|
|
auto node = new AssignStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
AssocArrayLiteral parseAssocArrayLiteral()
|
|
{
|
|
auto node = new AssocArrayLiteral;
|
|
|
|
return node;
|
|
}
|
|
|
|
AtAttribute parseAtAttribute()
|
|
{
|
|
auto node = new AtAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
Attribute parseAttribute()
|
|
{
|
|
auto node = new Attribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
AttributedDeclaration parseAttributedDeclaration()
|
|
{
|
|
auto node = new AttributedDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
AutoDeclaration parseAutoDeclaration()
|
|
{
|
|
auto node = new AutoDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
BlockStatement parseBlockStatement()
|
|
{
|
|
auto node = new BlockStatement();
|
|
expect(TokenType.lBrace);
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.rBrace:
|
|
break;
|
|
default:
|
|
node.declarationsAndStatements = parseDeclarationsAndStatements();
|
|
}
|
|
return node;
|
|
}
|
|
|
|
BodyStatement parseBodyStatement()
|
|
{
|
|
auto node = new BodyStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
BreakStatement parseBreakStatement()
|
|
{
|
|
expect(TokenType.break_);
|
|
return parseContinueBreakStatement!(BreakStatement)();
|
|
}
|
|
|
|
BuiltinType parseBuiltinType()
|
|
{
|
|
auto node = new BuiltinType;
|
|
|
|
return node;
|
|
}
|
|
|
|
CaseRangeStatement parseCaseRangeStatement()
|
|
{
|
|
auto node = new CaseRangeStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
CaseStatement parseCaseStatement()
|
|
{
|
|
auto node = new CaseStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
CastExpression parseCastExpression()
|
|
{
|
|
auto node = new CastExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
CastQualifier parseCastQualifier()
|
|
{
|
|
auto node = new CastQualifier;
|
|
|
|
return node;
|
|
}
|
|
|
|
Catch parseCatch()
|
|
{
|
|
auto node = new Catch;
|
|
|
|
return node;
|
|
}
|
|
|
|
Catches parseCatches()
|
|
{
|
|
auto node = new Catches;
|
|
|
|
return node;
|
|
}
|
|
|
|
ClassBody parseClassBody()
|
|
{
|
|
auto node = new ClassBody;
|
|
|
|
return node;
|
|
}
|
|
|
|
ClassDeclaration parseClassDeclaration()
|
|
{
|
|
auto node = new ClassDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
CmpExpression parseCmpExpression()
|
|
{
|
|
auto node = new CmpExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
CompileCondition parseCompileCondition()
|
|
{
|
|
auto node = new CompileCondition;
|
|
|
|
return node;
|
|
}
|
|
|
|
ConditionalDeclaration parseConditionalDeclaration()
|
|
{
|
|
auto node = new ConditionalDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
ConditionalStatement parseConditionalStatement()
|
|
{
|
|
auto node = new ConditionalStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Constraint parseConstraint()
|
|
{
|
|
auto node = new Constraint;
|
|
|
|
return node;
|
|
}
|
|
|
|
Constructor parseConstructor()
|
|
{
|
|
auto node = new Constructor;
|
|
|
|
return node;
|
|
}
|
|
|
|
ContinueStatement parseContinueStatement()
|
|
{
|
|
expect(TokenType.continue_);
|
|
return parseContinueBreakStatement!(ContinueStatement)();
|
|
}
|
|
|
|
DebugCondition parseDebugCondition()
|
|
{
|
|
auto node = new DebugCondition;
|
|
|
|
return node;
|
|
}
|
|
|
|
DebugSpecification parseDebugSpecification()
|
|
{
|
|
auto node = new DebugSpecification;
|
|
|
|
return node;
|
|
}
|
|
|
|
Declaration parseDeclaration()
|
|
{
|
|
auto node = new Declaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
DeclarationsAndStatements parseDeclarationsAndStatements()
|
|
{
|
|
auto node = new DeclarationsAndStatements;
|
|
|
|
return node;
|
|
}
|
|
|
|
Declarator parseDeclarator()
|
|
{
|
|
auto node = new Declarator;
|
|
|
|
return node;
|
|
}
|
|
|
|
DeclaratorSuffix parseDeclaratorSuffix()
|
|
{
|
|
auto node = new DeclaratorSuffix;
|
|
|
|
return node;
|
|
}
|
|
|
|
DefaultStatement parseDefaultStatement()
|
|
{
|
|
auto node = new DefaultStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
DeleteExpression parseDeleteExpression()
|
|
{
|
|
auto node = new DeleteExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
DeleteStatement parseDeleteStatement()
|
|
{
|
|
auto node = new DeleteStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Deprecated parseDeprecated()
|
|
{
|
|
auto node = new Deprecated;
|
|
|
|
return node;
|
|
}
|
|
|
|
Destructor parseDestructor()
|
|
{
|
|
auto node = new Destructor;
|
|
|
|
return node;
|
|
}
|
|
|
|
DoStatement parseDoStatement()
|
|
{
|
|
auto node = new DoStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
EnumBody parseEnumBody()
|
|
{
|
|
auto node = new EnumBody;
|
|
|
|
return node;
|
|
}
|
|
|
|
EnumDeclaration parseEnumDeclaration()
|
|
{
|
|
auto node = new EnumDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
EnumMember parseEnumMember()
|
|
{
|
|
auto node = new EnumMember;
|
|
|
|
return node;
|
|
}
|
|
|
|
EqualExpression parseEqualExpression()
|
|
{
|
|
auto node = new EqualExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
Expression parseExpression()
|
|
{
|
|
auto node = new Expression;
|
|
|
|
return node;
|
|
}
|
|
|
|
FinalSwitchStatement parseFinalSwitchStatement()
|
|
{
|
|
auto node = new FinalSwitchStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Finally parseFinally()
|
|
{
|
|
auto node = new Finally;
|
|
|
|
return node;
|
|
}
|
|
|
|
ForStatement parseForStatement()
|
|
{
|
|
auto node = new ForStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
ForeachRangeStatement parseForeachRangeStatement()
|
|
{
|
|
auto node = new ForeachRangeStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
ForeachStatement parseForeachStatement()
|
|
{
|
|
auto node = new ForeachStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
ForeachType parseForeachType()
|
|
{
|
|
auto node = new ForeachType;
|
|
|
|
return node;
|
|
}
|
|
|
|
ForeachTypeList parseForeachTypeList()
|
|
{
|
|
auto node = new ForeachTypeList;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionAttribute parseFunctionAttribute()
|
|
{
|
|
auto node = new FunctionAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionBody parseFunctionBody()
|
|
{
|
|
auto node = new FunctionBody;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionCallExpression parseFunctionCallExpression()
|
|
{
|
|
auto node = new FunctionCallExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionCallStatement parseFunctionCallStatement()
|
|
{
|
|
auto node = new FunctionCallStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionDeclaration parseFunctionDeclaration()
|
|
{
|
|
auto node = new FunctionDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
FunctionLiteralExpression parseFunctionLiteralExpression()
|
|
{
|
|
auto node = new FunctionLiteralExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
GotoStatement parseGotoStatement()
|
|
{
|
|
auto node = new GotoStatement;
|
|
return node;
|
|
}
|
|
|
|
IdentifierChain parseIdentifierChain()
|
|
{
|
|
auto node = new IdentifierChain;
|
|
|
|
return node;
|
|
}
|
|
|
|
IdentifierList parseIdentifierList()
|
|
{
|
|
auto node = new IdentifierList;
|
|
|
|
return node;
|
|
}
|
|
|
|
IdentifierOrTemplateChain parseIdentifierOrTemplateChain()
|
|
{
|
|
auto node = new IdentifierOrTemplateChain;
|
|
|
|
return node;
|
|
}
|
|
|
|
IdentifierOrTemplateInstance parseIdentifierOrTemplateInstance()
|
|
{
|
|
auto node = new IdentifierOrTemplateInstance;
|
|
|
|
return node;
|
|
}
|
|
|
|
IdentityExpression parseIdentityExpression()
|
|
{
|
|
auto node = new IdentityExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
IfStatement parseIfStatement()
|
|
{
|
|
auto node = new IfStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
ImportBind parseImportBind()
|
|
{
|
|
auto node = new ImportBind;
|
|
|
|
return node;
|
|
}
|
|
|
|
ImportBindings parseImportBindings()
|
|
{
|
|
auto node = new ImportBindings;
|
|
|
|
return node;
|
|
}
|
|
|
|
ImportDeclaration parseImportDeclaration(Tokens)(ref Tokens tokens)
|
|
in
|
|
{
|
|
assert(tokens[i] == TokenType.import_);
|
|
}
|
|
body
|
|
{
|
|
auto declaration = new ImportDeclaration;
|
|
tokens.popFront();
|
|
Import im;
|
|
|
|
if (tokens[i].type != TokenType.identifier)
|
|
{
|
|
tokens.skipPastSemicolon();
|
|
return declaration;
|
|
}
|
|
|
|
void completeImport()
|
|
{
|
|
im.moduleName = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
declaration.imports ~= im;
|
|
}
|
|
|
|
void parseImportBindings()
|
|
{
|
|
loop: while (!tokens.empty)
|
|
{
|
|
if (tokens[i].type != TokenType.identifier)
|
|
break;
|
|
switch (tokens.peek().type)
|
|
{
|
|
case TokenType.assign:
|
|
Import.ImportSymbol s;
|
|
s.alias_ = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
if (tokens.empty || tokens[i].type != TokenType.identifier)
|
|
break loop;
|
|
s.symbolName = tokens.moveFront().value;
|
|
im.symbols ~= s;
|
|
if (!tokens.empty())
|
|
{
|
|
if (tokens[i].type == TokenType.comma)
|
|
tokens.popFront();
|
|
if (tokens[i].type == TokenType.semicolon)
|
|
{
|
|
tokens.popFront();
|
|
declaration.imports ~= im;
|
|
break loop;
|
|
}
|
|
}
|
|
break;
|
|
case TokenType.comma:
|
|
Import.ImportSymbol s;
|
|
s.symbolName = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
im.symbols ~= s;
|
|
break;
|
|
case TokenType.semicolon:
|
|
Import.ImportSymbol s;
|
|
s.symbolName = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
im.symbols ~= s;
|
|
declaration.imports ~= im;
|
|
break loop;
|
|
default:
|
|
break loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
loop: while (!tokens.empty)
|
|
{
|
|
switch (tokens.peek().type)
|
|
{
|
|
case TokenType.dot:
|
|
im.packageParts ~= tokens.moveFront().value;
|
|
tokens.popFront();
|
|
break;
|
|
case TokenType.comma:
|
|
completeImport();
|
|
im = Import.init;
|
|
break;
|
|
case TokenType.semicolon:
|
|
completeImport();
|
|
break loop;
|
|
case TokenType.colon:
|
|
im.moduleName = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
parseImportBindings();
|
|
break loop;
|
|
case TokenType.assign:
|
|
im.alias_ = tokens.moveFront().value;
|
|
tokens.popFront();
|
|
break;
|
|
default:
|
|
tokens.popFront();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return declaration;
|
|
}
|
|
|
|
ImportExpression parseImportExpression()
|
|
{
|
|
auto node = new ImportExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
ImportList parseImportList()
|
|
{
|
|
auto node = new ImportList;
|
|
|
|
return node;
|
|
}
|
|
|
|
InExpression parseInExpression()
|
|
{
|
|
auto node = new InExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
InStatement parseInStatement()
|
|
{
|
|
auto node = new InStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Initialize parseInitialize()
|
|
{
|
|
auto node = new Initialize;
|
|
|
|
return node;
|
|
}
|
|
|
|
Initializer parseInitializer()
|
|
{
|
|
auto node = new Initializer;
|
|
|
|
return node;
|
|
}
|
|
|
|
InterfaceDeclaration parseInterfaceDeclaration()
|
|
{
|
|
auto node = new InterfaceDeclaration;
|
|
return node;
|
|
}
|
|
|
|
Invariant parseInvariant()
|
|
{
|
|
auto node = new Invariant;
|
|
|
|
return node;
|
|
}
|
|
|
|
IsExpression parseIsExpression()
|
|
{
|
|
auto node = new IsExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
KeyValuePair parseKeyValuePair()
|
|
{
|
|
auto node = new KeyValuePair;
|
|
|
|
return node;
|
|
}
|
|
|
|
KeyValuePairs parseKeyValuePairs()
|
|
{
|
|
auto node = new KeyValuePairs;
|
|
|
|
return node;
|
|
}
|
|
|
|
LabeledStatement parseLabeledStatement()
|
|
{
|
|
auto node = new LabeledStatement;
|
|
node.identifier = *expect(TokenType.identifier);
|
|
expect(TokenType.colon);
|
|
node.statement = parseStatement();
|
|
return node;
|
|
}
|
|
|
|
LambdaExpression parseLambdaExpression()
|
|
{
|
|
auto node = new LambdaExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
LastCatch parseLastCatch()
|
|
{
|
|
auto node = new LastCatch;
|
|
|
|
return node;
|
|
}
|
|
|
|
LinkageAttribute parseLinkageAttribute()
|
|
{
|
|
auto node = new LinkageAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
MemberFunctionAttribute parseMemberFunctionAttribute()
|
|
{
|
|
auto node = new MemberFunctionAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
MixinDeclaration parseMixinDeclaration()
|
|
{
|
|
auto node = new MixinDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
MixinExpression parseMixinExpression()
|
|
{
|
|
auto node = new MixinExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
MixinTemplateName parseMixinTemplateName()
|
|
{
|
|
auto node = new MixinTemplateName;
|
|
|
|
return node;
|
|
}
|
|
|
|
Module parseModule()
|
|
{
|
|
Module m = new Module;
|
|
while (index < tokens.length)
|
|
{
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.module_:
|
|
if (m.moduleDeclaration !is null)
|
|
m.moduleDeclaration = parseModuleDeclaration();
|
|
else
|
|
error("Only one module declaration is allowed per module");
|
|
break;
|
|
default:
|
|
m.declarations ~= parseDeclaration();
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
ModuleDeclaration parseModuleDeclaration()
|
|
{
|
|
auto node = new ModuleDeclaration;
|
|
expect(TokenType.module_);
|
|
node.moduleName = parseIdentifierChain();
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
MulExpression parseMulExpression()
|
|
{
|
|
auto node = new MulExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
NewAnonClassExpression parseNewAnonClassExpression()
|
|
{
|
|
auto node = new NewAnonClassExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
NewExpression parseNewExpression()
|
|
{
|
|
auto node = new NewExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
NonEmptyStatement parseNonEmptyStatement()
|
|
{
|
|
auto node = new NonEmptyStatement;
|
|
return node;
|
|
}
|
|
|
|
NonEmptyStatementNoCaseNoDefault parseNonEmptyStatementNoCaseNoDefault()
|
|
{
|
|
auto node = new NonEmptyStatementNoCaseNoDefault;
|
|
|
|
return node;
|
|
}
|
|
|
|
NonVoidInitializer parseNonVoidInitializer()
|
|
{
|
|
auto node = new NonVoidInitializer;
|
|
|
|
return node;
|
|
}
|
|
|
|
Opcode parseOpcode()
|
|
{
|
|
auto node = new Opcode;
|
|
|
|
return node;
|
|
}
|
|
|
|
Operand parseOperand()
|
|
{
|
|
auto node = new Operand;
|
|
|
|
return node;
|
|
}
|
|
|
|
Operands parseOperands()
|
|
{
|
|
auto node = new Operands;
|
|
|
|
return node;
|
|
}
|
|
|
|
OrExpression parseOrExpression()
|
|
{
|
|
auto node = new OrExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
OrOrExpression parseOrOrExpression()
|
|
{
|
|
auto node = new OrOrExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
OutStatement parseOutStatement()
|
|
{
|
|
auto node = new OutStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Parameter parseParameter()
|
|
{
|
|
auto node = new Parameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
ParameterAttribute parseParameterAttribute()
|
|
{
|
|
auto node = new ParameterAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
Parameters parseParameters()
|
|
{
|
|
auto node = new Parameters;
|
|
|
|
return node;
|
|
}
|
|
|
|
PostIncDecExpression parsePostIncDecExpression()
|
|
{
|
|
auto node = new PostIncDecExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
PowExpression parsePowExpression()
|
|
{
|
|
auto node = new PowExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
PragmaDeclaration parsePragmaDeclaration()
|
|
{
|
|
auto node = new PragmaDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
PragmaExpression parsePragmaExpression()
|
|
{
|
|
auto node = new PragmaExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
PreIncDecExpression parsePreIncDecExpression()
|
|
{
|
|
auto node = new PreIncDecExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
PrimaryExpression parsePrimaryExpression()
|
|
{
|
|
auto node = new PrimaryExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
ProtectionAttribute parseProtectionAttribute()
|
|
{
|
|
auto node = new ProtectionAttribute;
|
|
|
|
return node;
|
|
}
|
|
|
|
Register parseRegister()
|
|
{
|
|
auto node = new Register;
|
|
|
|
return node;
|
|
}
|
|
|
|
RelExpression parseRelExpression()
|
|
{
|
|
auto node = new RelExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
ReturnStatement parseReturnStatement()
|
|
{
|
|
auto node = new ReturnStatement;
|
|
expect(TokenType.return_);
|
|
if (tokens[index] != TokenType.semicolon)
|
|
node.expression = parseExpression();
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
ScopeGuardStatement parseScopeGuardStatement()
|
|
{
|
|
auto node = new ScopeGuardStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
SharedStaticConstructor parseSharedStaticConstructor()
|
|
{
|
|
auto node = new SharedStaticConstructor;
|
|
|
|
return node;
|
|
}
|
|
|
|
SharedStaticDestructor parseSharedStaticDestructor()
|
|
{
|
|
auto node = new SharedStaticDestructor;
|
|
|
|
return node;
|
|
}
|
|
|
|
ShiftExpression parseShiftExpression()
|
|
{
|
|
auto node = new ShiftExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
SingleImport parseSingleImport()
|
|
{
|
|
auto node = new SingleImport;
|
|
|
|
return node;
|
|
}
|
|
|
|
Statement parseStatement()
|
|
{
|
|
auto node = new Statement;
|
|
if (tokens[index] != TokenType.semicolon)
|
|
node.nonEmptyStatement = parseNonEmptyStatement();
|
|
else
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
StatementNoCaseNoDefault parseStatementNoCaseNoDefault()
|
|
{
|
|
auto node = new StatementNoCaseNoDefault;
|
|
if (tokens[index] != TokenType.semicolon)
|
|
node.nonEmptyStatementNoCaseNoDefault = parseNonEmptyStatementNoCaseNoDefault();
|
|
else
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
StaticAssertDeclaration parseStaticAssertDeclaration()
|
|
{
|
|
auto node = new StaticAssertDeclaration;
|
|
node.staticAssertStatement = parseStaticAssertStatement();
|
|
return node;
|
|
}
|
|
|
|
StaticAssertStatement parseStaticAssertStatement()
|
|
{
|
|
auto node = new StaticAssertStatement;
|
|
expect(TokenType.static_);
|
|
node.assertStatement = parseAssertStatement();
|
|
return node;
|
|
}
|
|
|
|
StaticConstructor parseStaticConstructor()
|
|
{
|
|
auto node = new StaticConstructor;
|
|
expect(TokenType.static_);
|
|
expect(TokenType.this_);
|
|
expect(TokenType.lParen);
|
|
expect(TokenType.rParen);
|
|
node.functionBody = parseFunctionBody();
|
|
return node;
|
|
}
|
|
|
|
StaticDestructor parseStaticDestructor()
|
|
{
|
|
auto node = new StaticDestructor;
|
|
expect(TokenType.static_);
|
|
expect(TokenType.tilde);
|
|
expect(TokenType.this_);
|
|
expect(TokenType.lParen);
|
|
expect(TokenType.rParen);
|
|
node.functionBody = parseFunctionBody();
|
|
return node;
|
|
}
|
|
|
|
StaticIfCondition parseStaticIfCondition()
|
|
{
|
|
auto node = new StaticIfCondition;
|
|
expect(TokenType.static_);
|
|
expect(TokenType.if_);
|
|
expect(TokenType.lParen);
|
|
node.assignExpression = parseAssignExpression();
|
|
expect(TokenType.rParen);
|
|
return node;
|
|
}
|
|
|
|
StorageClass parseStorageClass()
|
|
{
|
|
auto node = new StorageClass;
|
|
|
|
return node;
|
|
}
|
|
|
|
StructBody parseStructBody()
|
|
{
|
|
auto node = new StructBody;
|
|
expect(TokenType.lBrace);
|
|
while (tokens[index] != TokenType.rBrace && moreTokens())
|
|
node.declarations ~= parseDeclaration();
|
|
expect(TokenType.rBrace);
|
|
return node;
|
|
}
|
|
|
|
StructDeclaration parseStructDeclaration()
|
|
{
|
|
auto node = new StructDeclaration;
|
|
expect(TokenType.struct_);
|
|
node.identifier = *expect(TokenType.identifier);
|
|
if (tokens[index] == TokenType.lParen)
|
|
{
|
|
node.templateParameters = parseTemplateParameters();
|
|
if (tokens[index] == TokenType.if_)
|
|
node.constraint = parseConstraint();
|
|
node.structBody = parseStructBody();
|
|
}
|
|
else if (tokens[index] == TokenType.lBrace)
|
|
{
|
|
node.structBody = parseStructBody();
|
|
}
|
|
else if (tokens[index] != TokenType.semicolon)
|
|
error("Template Parameters, Struct Body, or Semicolon expected");
|
|
return node;
|
|
}
|
|
|
|
StructInitializer parseStructInitializer()
|
|
{
|
|
auto node = new StructInitializer;
|
|
expect(TokenType.lBrace);
|
|
node.structMemberInitializers = parseStructMemberInitializers();
|
|
expect(TokenType.rBrace);
|
|
return node;
|
|
}
|
|
|
|
StructMemberInitializer parseStructMemberInitializer()
|
|
{
|
|
auto node = new StructMemberInitializer;
|
|
if (startsWith(TokenType.identifier, TokenType.colon))
|
|
{
|
|
node.identifier = tokens[index++];
|
|
index++;
|
|
}
|
|
node.nonVoidInitializer = parseNonVoidInitializer();
|
|
return node;
|
|
}
|
|
|
|
StructMemberInitializers parseStructMemberInitializers()
|
|
{
|
|
auto node = new StructMemberInitializers;
|
|
|
|
return node;
|
|
}
|
|
|
|
SwitchBody parseSwitchBody()
|
|
{
|
|
auto node = new SwitchBody;
|
|
expect(TokenType.lBrace);
|
|
while (moreTokens() && tokens[index] != TokenType.rBrace)
|
|
node.statements ~= parseStatement();
|
|
expect(TokenType.rBrace);
|
|
return node;
|
|
}
|
|
|
|
SwitchStatement parseSwitchStatement()
|
|
{
|
|
auto node = new SwitchStatement;
|
|
expect(TokenType.switch_);
|
|
expect(TokenType.lParen);
|
|
node.expression = parseExpression();
|
|
expect(TokenType.rParen);
|
|
node.switchBody = parseSwitchBody();
|
|
return node;
|
|
}
|
|
|
|
Symbol parseSymbol()
|
|
{
|
|
auto node = new Symbol;
|
|
if (tokens[index] == TokenType.dot)
|
|
{
|
|
node.hasDot = true;
|
|
++index;
|
|
}
|
|
node.identifierOrTemplateChain = parseIdentifierOrTemplateChain();
|
|
return node;
|
|
}
|
|
|
|
SynchronizedStatement parseSynchronizedStatement()
|
|
{
|
|
auto node = new SynchronizedStatement;
|
|
expect(TokenType.synchronized_);
|
|
if (tokens[index] == TokenType.lParen)
|
|
{
|
|
expect(TokenType.lParen);
|
|
node.expression = parseExpression();
|
|
expect(TokenType.rParen);
|
|
}
|
|
node.nonEmptyStatementNoCaseNoDefault = parseNonEmptyStatementNoCaseNoDefault();
|
|
return node;
|
|
}
|
|
|
|
TemplateAliasParameter parseTemplateAliasParameter()
|
|
{
|
|
auto node = new TemplateAliasParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateArgument parseTemplateArgument()
|
|
{
|
|
auto node = new TemplateArgument;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateArgumentList parseTemplateArgumentList()
|
|
{
|
|
auto node = new TemplateArgumentList;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateArguments parseTemplateArguments()
|
|
{
|
|
auto node = new TemplateArguments;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateDeclaration parseTemplateDeclaration()
|
|
{
|
|
auto node = new TemplateDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateInstance parseTemplateInstance()
|
|
{
|
|
auto node = new TemplateInstance;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateMixinStatement parseTemplateMixinStatement()
|
|
{
|
|
auto node = new TemplateMixinStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateParameter parseTemplateParameter()
|
|
{
|
|
auto node = new TemplateParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateParameterList parseTemplateParameterList()
|
|
{
|
|
auto node = new TemplateParameterList;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateParameters parseTemplateParameters()
|
|
{
|
|
auto node = new TemplateParameters;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateSingleArgument parseTemplateSingleArgument()
|
|
{
|
|
auto node = new TemplateSingleArgument;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateThisParameter parseTemplateThisParameter()
|
|
{
|
|
auto node = new TemplateThisParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateTupleParameter parseTemplateTupleParameter()
|
|
{
|
|
auto node = new TemplateTupleParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateTypeParameter parseTemplateTypeParameter()
|
|
{
|
|
auto node = new TemplateTypeParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateValueParameter parseTemplateValueParameter()
|
|
{
|
|
auto node = new TemplateValueParameter;
|
|
|
|
return node;
|
|
}
|
|
|
|
TemplateValueParameterDefault parseTemplateValueParameterDefault()
|
|
{
|
|
auto node = new TemplateValueParameterDefault;
|
|
|
|
return node;
|
|
}
|
|
|
|
TernaryExpression parseTernaryExpression()
|
|
{
|
|
auto node = new TernaryExpression;
|
|
node.orOrExpression = parseOrOrExpression();
|
|
if (tokens[index] == TokenType.ternary)
|
|
{
|
|
++index;
|
|
node.expression = parseExpression();
|
|
expect(TokenType.colon);
|
|
node.ternaryExpression = parseTernaryExpression();
|
|
}
|
|
return node;
|
|
}
|
|
|
|
ThrowStatement parseThrowStatement()
|
|
{
|
|
auto node = new ThrowStatement;
|
|
expect(TokenType.throw_);
|
|
node.expression = parseExpression();
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
TraitsArgument parseTraitsArgument()
|
|
{
|
|
auto node = new TraitsArgument;
|
|
|
|
return node;
|
|
}
|
|
|
|
TraitsExpression parseTraitsExpression()
|
|
{
|
|
auto node = new TraitsExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
TryStatement parseTryStatement()
|
|
{
|
|
auto node = new TryStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
Type parseType()
|
|
{
|
|
auto node = new Type;
|
|
|
|
return node;
|
|
}
|
|
|
|
Type2 parseType2()
|
|
{
|
|
auto node = new Type2;
|
|
|
|
return node;
|
|
}
|
|
|
|
Type3 parseType3()
|
|
{
|
|
auto node = new Type3;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeConstructor parseTypeConstructor()
|
|
{
|
|
auto node = new TypeConstructor;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeConstructors parseTypeConstructors()
|
|
{
|
|
auto node = new TypeConstructors;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeSpecialization parseTypeSpecialization()
|
|
{
|
|
auto node = new TypeSpecialization;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeSuffix parseTypeSuffix()
|
|
{
|
|
auto node = new TypeSuffix;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeidExpression parseTypeidExpression()
|
|
{
|
|
auto node = new TypeidExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
TypeofExpression parseTypeofExpression()
|
|
{
|
|
auto node = new TypeofExpression;
|
|
expect(TokenType.typeof_);
|
|
expect(TokenType.lParen);
|
|
if (tokens[index] == TokenType.return_)
|
|
node.return_ = tokens[index];
|
|
else
|
|
node.expression = parseExpression();
|
|
expect(TokenType.rParen);
|
|
return node;
|
|
}
|
|
|
|
UnaryExpression parseUnaryExpression()
|
|
{
|
|
auto node = new UnaryExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
UnionDeclaration parseUnionDeclaration()
|
|
{
|
|
auto node = new UnionDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
Unittest parseUnittest()
|
|
{
|
|
auto node = new Unittest;
|
|
expect(TokenType.unittest_);
|
|
node.blockStatement = parseBlockStatement();
|
|
return node;
|
|
}
|
|
|
|
VariableDeclaration parseVariableDeclaration()
|
|
{
|
|
auto node = new VariableDeclaration;
|
|
|
|
return node;
|
|
}
|
|
|
|
VersionCondition parseVersionCondition()
|
|
{
|
|
auto node = new VersionCondition;
|
|
expect(TokenType.version_);
|
|
expect(TokenType.lParen);
|
|
node.token = tokens[index];
|
|
expect(TokenType.rParen);
|
|
return node;
|
|
}
|
|
|
|
VersionSpecification parseVersionSpecification()
|
|
{
|
|
auto node = new VersionSpecification;
|
|
expect(TokenType.version_);
|
|
expect(TokenType.assign);
|
|
node.token = tokens[index];
|
|
expect(TokenType.semicolon);
|
|
return node;
|
|
}
|
|
|
|
WhileStatement parseWhileStatement()
|
|
{
|
|
auto node = new WhileStatement;
|
|
|
|
return node;
|
|
}
|
|
|
|
WithStatement parseWithStatement()
|
|
{
|
|
auto node = new WithStatement;
|
|
expect(TokenType.with_);
|
|
expect(TokenType.lParen);
|
|
// magic here
|
|
expect(TokenType.rParen);
|
|
parseNonEmptyStatementNoCaseNoDefault();
|
|
return node;
|
|
}
|
|
|
|
XorExpression parseXorExpression()
|
|
{
|
|
auto node = new XorExpression;
|
|
|
|
return node;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
statementType parseContinueBreakStatement(alias statementType)()
|
|
{
|
|
index++;
|
|
auto c = new statementType;
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.identifier:
|
|
c.identifier = tokens[index++];
|
|
goto case;
|
|
case TokenType.semicolon:
|
|
return c;
|
|
default:
|
|
error("Identifier or semicolon expected");
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
void error(string message)
|
|
{
|
|
import std.stdio;
|
|
stderr.writefln("%s(%d:%d): %s", fileName, tokens[index].line,
|
|
tokens[index].column, message);
|
|
while (index < tokens.length)
|
|
{
|
|
if (tokens[++index].type == TokenType.semicolon)
|
|
break;
|
|
}
|
|
}
|
|
|
|
Token* peekPast(alias O, alias C)()
|
|
in
|
|
{
|
|
assert (tokens[index].type == O);
|
|
}
|
|
body
|
|
{
|
|
int depth = 1;
|
|
auto i = index;
|
|
++i;
|
|
while (index < tokens.length)
|
|
{
|
|
if (tokens[i] == O)
|
|
++depth;
|
|
else if (tokens[i] == C)
|
|
{
|
|
--depth;
|
|
++i;
|
|
if (depth <= 0)
|
|
break;
|
|
}
|
|
++i;
|
|
}
|
|
return depth == 0 ? &tokens[i] : null;
|
|
}
|
|
|
|
Token* peekPastParens()
|
|
{
|
|
return peekPast!(TokenType.lParen, TokenType.rParen)();
|
|
}
|
|
|
|
Token* peekPastBrackets()
|
|
{
|
|
return peekPast!(TokenType.lBracket, TokenType.rBracket)();
|
|
}
|
|
|
|
Token* peekPastBraces()
|
|
{
|
|
return peekPast!(TokenType.lBrace, TokenType.rBrace)();
|
|
}
|
|
|
|
Token* expect(TokenType type)
|
|
{
|
|
if (tokens[index].type == type)
|
|
return &tokens[index++];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
Token* peek()
|
|
{
|
|
return index + 1 < tokens.length ? &tokens[index + 1] : null;
|
|
}
|
|
|
|
bool nextIs(TokenType t)
|
|
{
|
|
return peek() && peek().type == t;
|
|
}
|
|
|
|
bool startsWith(TokenType[] types...)
|
|
{
|
|
for (size_t i = 0; i != types.length; ++i)
|
|
{
|
|
if (tokens[index + i].type != types[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool moreTokens()
|
|
{
|
|
return index < tokens.length;
|
|
}
|
|
|
|
Token[] tokens;
|
|
size_t index;
|
|
string fileName;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto source = cast(ubyte[]) q{import std.stdio;
|
|
import std.ascii: hexDigits;
|
|
import r = std.range;
|
|
import foo, bar;
|
|
import std.stdio : writefln, foo = writef;}c;
|
|
|
|
LexerConfig config;
|
|
auto tokens = source.byToken(config).circularBuffer(4);
|
|
assert (tokens[i] == "import");
|
|
|
|
auto decl = parseImportDeclaration(tokens);
|
|
assert (decl.imports.length == 1);
|
|
assert (decl.imports[0].packageParts == ["std"]);
|
|
assert (decl.imports[0].moduleName == "stdio");
|
|
assert (tokens[i].value == "import", tokens.front.value);
|
|
assert (tokens.peek(3).value == "ascii", tokens.front.value);
|
|
|
|
decl = parseImportDeclaration(tokens);
|
|
assert (decl.imports.length == 1, "%d".format(decl.imports.length));
|
|
assert (decl.imports[0].packageParts == ["std"]);
|
|
assert (decl.imports[0].moduleName == "ascii", decl.imports[0].moduleName);
|
|
assert (decl.imports[0].symbols[0].symbolName == "hexDigits", decl.imports[0].symbols[0].symbolName);
|
|
assert (decl.imports[0].symbols[0].alias_.length == 0);
|
|
|
|
decl = parseImportDeclaration(tokens);
|
|
assert (decl.imports.length == 1, "%s".format(decl.imports.length));
|
|
assert (decl.imports[0].moduleName == "range");
|
|
assert (decl.imports[0].packageParts == ["std"]);
|
|
assert (decl.imports[0].alias_ == "r");
|
|
|
|
decl = parseImportDeclaration(tokens);
|
|
assert (decl.imports.length == 2);
|
|
assert (decl.imports[0].packageParts.length == 0);
|
|
assert (decl.imports[0].moduleName == "foo");
|
|
assert (decl.imports[1].packageParts.length == 0);
|
|
assert (decl.imports[1].moduleName == "bar");
|
|
|
|
decl = parseImportDeclaration(tokens);
|
|
assert (decl.imports.length == 1, "%s".format(decl.imports.length));
|
|
assert (decl.imports[0].packageParts == ["std"]);
|
|
assert (decl.imports[0].moduleName == "stdio");
|
|
assert (decl.imports[0].symbols.length == 2);
|
|
assert (decl.imports[0].symbols[0].symbolName == "writefln");
|
|
assert (decl.imports[0].symbols[1].symbolName == "writef");
|
|
assert (decl.imports[0].symbols[1].alias_ == "foo");
|
|
}
|