623 lines
21 KiB
D
Executable File
623 lines
21 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() { return null; }
|
|
AliasDeclaration parseAliasDeclaration() { return null; }
|
|
AliasInitializer parseAliasInitializer() { return null; }
|
|
AliasThisDeclaration parseAliasThisDeclaration() { return null; }
|
|
AlignAttribute parseAlignAttribute() { return null; }
|
|
AndAndExpression parseAndAndExpression() { return null; }
|
|
AndExpression parseAndExpression() { return null; }
|
|
ArgumentList parseArgumentList() { return null; }
|
|
Arguments parseArguments() { return null; }
|
|
ArrayInitializer parseArrayInitializer() { return null; }
|
|
ArrayLiteral parseArrayLiteral() { return null; }
|
|
ArrayMemberInitialization parseArrayMemberInitialization() { return null; }
|
|
ArrayMemberInitializations parseArrayMemberInitializations() { return null; }
|
|
AsmAddExp parseAsmAddExp() { return null; }
|
|
AsmAndExp parseAsmAndExp() { return null; }
|
|
AsmBrExp parseAsmBrExp() { return null; }
|
|
AsmEqualExp parseAsmEqualExp() { return null; }
|
|
AsmExp parseAsmExp() { return null; }
|
|
AsmInstruction parseAsmInstruction() { return null; }
|
|
AsmLogAndExp parseAsmLogAndExp() { return null; }
|
|
AsmLogOrExp parseAsmLogOrExp() { return null; }
|
|
AsmMulExp parseAsmMulExp() { return null; }
|
|
AsmOrExp parseAsmOrExp() { return null; }
|
|
AsmPrimaryExp parseAsmPrimaryExp() { return null; }
|
|
AsmRelExp parseAsmRelExp() { return null; }
|
|
AsmShiftExp parseAsmShiftExp() { return null; }
|
|
AsmStatement parseAsmStatement() { return null; }
|
|
AsmTypePrefix parseAsmTypePrefix() { return null; }
|
|
AsmUnaExp parseAsmUnaExp() { return null; }
|
|
AsmXorExp parseAsmXorExp() { return null; }
|
|
AssertExpression parseAssertExpression() { return null; }
|
|
AssertStatement parseAssertStatement() { return null; }
|
|
AssignExpression parseAssignExpression() { return null; }
|
|
AssignStatement parseAssignStatement() { return null; }
|
|
AssocArrayLiteral parseAssocArrayLiteral() { return null; }
|
|
AtAttribute parseAtAttribute() { return null; }
|
|
Attribute parseAttribute() { return null; }
|
|
AttributedDeclaration parseAttributedDeclaration() { return null; }
|
|
AutoDeclaration parseAutoDeclaration() { return null; }
|
|
|
|
BlockStatement parseBlockStatement()
|
|
{
|
|
auto statement = new BlockStatement();
|
|
expect(TokenType.lBrace);
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.rBrace:
|
|
break;
|
|
default:
|
|
statement.statements ~= parseStatement();
|
|
}
|
|
return statement;
|
|
}
|
|
|
|
BodyStatement parseBodyStatement() { return null; }
|
|
|
|
BreakStatement parseBreakStatement()
|
|
{
|
|
expect(TokenType.break_);
|
|
return parseContinueBreakStatement!(BreakStatement)();
|
|
}
|
|
|
|
BuiltinType parseBuiltinType() { return null; }
|
|
CaseRangeStatement parseCaseRangeStatement() { return null; }
|
|
CaseStatement parseCaseStatement() { return null; }
|
|
CastExpression parseCastExpression() { return null; }
|
|
CastQualifier parseCastQualifier() { return null; }
|
|
Catch parseCatch() { return null; }
|
|
Catches parseCatches() { return null; }
|
|
ClassBody parseClassBody() { return null; }
|
|
ClassDeclaration parseClassDeclaration() { return null; }
|
|
CmpExpression parseCmpExpression() { return null; }
|
|
CompileCondition parseCompileCondition() { return null; }
|
|
ConditionalDeclaration parseConditionalDeclaration() { return null; }
|
|
ConditionalStatement parseConditionalStatement() { return null; }
|
|
Constraint parseConstraint() { return null; }
|
|
Constructor parseConstructor() { return null; }
|
|
|
|
ContinueStatement parseContinueStatement()
|
|
{
|
|
expect(TokenType.continue_);
|
|
return parseContinueBreakStatement!(ContinueStatement)();
|
|
}
|
|
|
|
DebugCondition parseDebugCondition() { return null; }
|
|
DebugSpecification parseDebugSpecification() { return null; }
|
|
Declaration parseDeclaration() { return null; }
|
|
DeclarationsAndStatements parseDeclarationsAndStatements() { return null; }
|
|
Declarator parseDeclarator() { return null; }
|
|
DeclaratorSuffix parseDeclaratorSuffix() { return null; }
|
|
DefaultStatement parseDefaultStatement() { return null; }
|
|
DeleteExpression parseDeleteExpression() { return null; }
|
|
DeleteStatement parseDeleteStatement() { return null; }
|
|
Deprecated parseDeprecated() { return null; }
|
|
Destructor parseDestructor() { return null; }
|
|
DoStatement parseDoStatement() { return null; }
|
|
EnumBody parseEnumBody() { return null; }
|
|
EnumDeclaration parseEnumDeclaration() { return null; }
|
|
EnumMember parseEnumMember() { return null; }
|
|
EqualExpression parseEqualExpression() { return null; }
|
|
Expression parseExpression() { return null; }
|
|
FinalSwitchStatement parseFinalSwitchStatement() { return null; }
|
|
Finally parseFinally() { return null; }
|
|
ForStatement parseForStatement() { return null; }
|
|
ForeachRangeStatement parseForeachRangeStatement() { return null; }
|
|
ForeachStatement parseForeachStatement() { return null; }
|
|
ForeachType parseForeachType() { return null; }
|
|
ForeachTypeList parseForeachTypeList() { return null; }
|
|
FunctionAttribute parseFunctionAttribute() { return null; }
|
|
FunctionBody parseFunctionBody() { return null; }
|
|
FunctionCallExpression parseFunctionCallExpression() { return null; }
|
|
FunctionCallStatement parseFunctionCallStatement() { return null; }
|
|
FunctionDeclaration parseFunctionDeclaration() { return null; }
|
|
FunctionLiteralExpression parseFunctionLiteralExpression() { return null; }
|
|
|
|
GotoStatement parseGotoStatement()
|
|
{
|
|
expect(TokenType.goto_);
|
|
auto g = new GotoStatement;
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.identifier:
|
|
g.type = GotoStatement.GotoType.identifier;
|
|
g.identifier = tokens[index++].value;
|
|
break;
|
|
case TokenType.default_:
|
|
index++;
|
|
g.type = GotoStatement.GotoType.default_;
|
|
break;
|
|
case TokenType.case_:
|
|
g.type = GotoStatement.GotoType.case_;
|
|
index++;
|
|
break;
|
|
default:
|
|
error("Expected an identifier, \"default\", or \"case\" following \"goto\"");
|
|
return null;
|
|
}
|
|
return g;
|
|
}
|
|
|
|
IdentifierChain parseIdentifierChain() { return null; }
|
|
IdentifierList parseIdentifierList() { return null; }
|
|
IdentifierOrTemplateChain parseIdentifierOrTemplateChain() { return null; }
|
|
IdentifierOrTemplateInstance parseIdentifierOrTemplateInstance() { return null; }
|
|
IdentityExpression parseIdentityExpression() { return null; }
|
|
IfStatement parseIfStatement() { return null; }
|
|
ImportBind parseImportBind() { return null; }
|
|
ImportBindings parseImportBindings() { return null; }
|
|
|
|
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() { return null; }
|
|
ImportList parseImportList() { return null; }
|
|
InExpression parseInExpression() { return null; }
|
|
InStatement parseInStatement() { return null; }
|
|
Initialize parseInitialize() { return null; }
|
|
Initializer parseInitializer() { return null; }
|
|
InterfaceDeclaration parseInterfaceDeclaration() { return null; }
|
|
Invariant parseInvariant() { return null; }
|
|
IsExpression parseIsExpression() { return null; }
|
|
KeyValuePair parseKeyValuePair() { return null; }
|
|
KeyValuePairs parseKeyValuePairs() { return null; }
|
|
|
|
LabeledStatement parseLabeledStatement()
|
|
in
|
|
{
|
|
assert (tokens[index].type == TokenType.identifier);
|
|
}
|
|
body
|
|
{
|
|
auto ls = new LabeledStatement;
|
|
ls.label = tokens[index++].value;
|
|
ls.statement = parseNoScopeStatement();
|
|
return ls;
|
|
}
|
|
|
|
LambdaExpression parseLambdaExpression() { return null; }
|
|
LastCatch parseLastCatch() { return null; }
|
|
LinkageAttribute parseLinkageAttribute() { return null; }
|
|
MemberFunctionAttribute parseMemberFunctionAttribute() { return null; }
|
|
MixinDeclaration parseMixinDeclaration() { return null; }
|
|
MixinExpression parseMixinExpression() { return null; }
|
|
MixinTemplateName parseMixinTemplateName() { return null; }
|
|
|
|
Module parseModule()
|
|
{
|
|
Module m = new Module;
|
|
while (index < tokens.length)
|
|
{
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.module_:
|
|
if (m.declaration !is null)
|
|
m.declaration = parseModuleDeclaration();
|
|
else
|
|
error("Only one module declaration is allowed per module");
|
|
break;
|
|
default:
|
|
m.declDefs.insert(parseDeclDef());
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
ModuleDeclaration parseModuleDeclaration()
|
|
in
|
|
{
|
|
assert (expect(TokenType.module_));
|
|
}
|
|
body
|
|
{
|
|
ModuleDeclaration declaration = new ModuleDeclaration;
|
|
string recent;
|
|
loop: while (index < tokens.length)
|
|
{
|
|
if (tokens[index].type == TokenType.identifier)
|
|
{
|
|
recent = tokens[index++].value;
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.dot:
|
|
declaration.packageName ~= recent;
|
|
index++;
|
|
break;
|
|
case TokenType.semicolon:
|
|
declaration.moduleName = recent;
|
|
index++;
|
|
break loop;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
error("Identifier expected");
|
|
}
|
|
return declaration;
|
|
}
|
|
|
|
MulExpression parseMulExpression() { return null; }
|
|
NewAnonClassExpression parseNewAnonClassExpression() { return null; }
|
|
NewExpression parseNewExpression() { return null; }
|
|
|
|
NonEmptyStatement parseNonEmptyStatement()
|
|
{
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.case_:
|
|
return parseCaseStatement();
|
|
case TokenType.default_:
|
|
return parseDefaultStatement();
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
NonEmptyStatementNoCaseNoDefault parseNonEmptyStatementNoCaseNoDefault() { return null; }
|
|
NonVoidInitializer parseNonVoidInitializer() { return null; }
|
|
Opcode parseOpcode() { return null; }
|
|
Operand parseOperand() { return null; }
|
|
Operands parseOperands() { return null; }
|
|
OrExpression parseOrExpression() { return null; }
|
|
OrOrExpression parseOrOrExpression() { return null; }
|
|
OutStatement parseOutStatement() { return null; }
|
|
Parameter parseParameter() { return null; }
|
|
ParameterAttribute parseParameterAttribute() { return null; }
|
|
Parameters parseParameters() { return null; }
|
|
PostIncDecExpression parsePostIncDecExpression() { return null; }
|
|
PowExpression parsePowExpression() { return null; }
|
|
PragmaDeclaration parsePragmaDeclaration() { return null; }
|
|
PragmaExpression parsePragmaExpression() { return null; }
|
|
PreIncDecExpression parsePreIncDecExpression() { return null; }
|
|
PrimaryExpression parsePrimaryExpression() { return null; }
|
|
ProtectionAttribute parseProtectionAttribute() { return null; }
|
|
Register parseRegister() { return null; }
|
|
RelExpression parseRelExpression() { return null; }
|
|
ReturnStatement parseReturnStatement() { return null; }
|
|
ScopeGuardStatement parseScopeGuardStatement() { return null; }
|
|
SharedStaticConstructor parseSharedStaticConstructor() { return null; }
|
|
SharedStaticDestructor parseSharedStaticDestructor() { return null; }
|
|
ShiftExpression parseShiftExpression() { return null; }
|
|
SingleImport parseSingleImport() { return null; }
|
|
Statement parseStatement() { return null; }
|
|
StatementNoCaseNoDefault parseStatementNoCaseNoDefault() { return null; }
|
|
StaticAssertDeclaration parseStaticAssertDeclaration() { return null; }
|
|
StaticAssertStatement parseStaticAssertStatement() { return null; }
|
|
StaticConstructor parseStaticConstructor() { return null; }
|
|
StaticDestructor parseStaticDestructor() { return null; }
|
|
StaticIfCondition parseStaticIfCondition() { return null; }
|
|
StorageClass parseStorageClass() { return null; }
|
|
StructBody parseStructBody() { return null; }
|
|
StructDeclaration parseStructDeclaration() { return null; }
|
|
StructInitializer parseStructInitializer() { return null; }
|
|
StructMemberInitializer parseStructMemberInitializer() { return null; }
|
|
StructMemberInitializers parseStructMemberInitializers() { return null; }
|
|
SwitchBody parseSwitchBody() { return null; }
|
|
SwitchStatement parseSwitchStatement() { return null; }
|
|
Symbol parseSymbol() { return null; }
|
|
SynchronizedStatement parseSynchronizedStatement() { return null; }
|
|
TemplateAliasParameter parseTemplateAliasParameter() { return null; }
|
|
TemplateArgument parseTemplateArgument() { return null; }
|
|
TemplateArgumentList parseTemplateArgumentList() { return null; }
|
|
TemplateArguments parseTemplateArguments() { return null; }
|
|
TemplateDeclaration parseTemplateDeclaration() { return null; }
|
|
TemplateInstance parseTemplateInstance() { return null; }
|
|
TemplateMixinStatement parseTemplateMixinStatement() { return null; }
|
|
TemplateParameter parseTemplateParameter() { return null; }
|
|
TemplateParameterList parseTemplateParameterList() { return null; }
|
|
TemplateParameters parseTemplateParameters() { return null; }
|
|
TemplateSingleArgument parseTemplateSingleArgument() { return null; }
|
|
TemplateThisParameter parseTemplateThisParameter() { return null; }
|
|
TemplateTupleParameter parseTemplateTupleParameter() { return null; }
|
|
TemplateTypeParameter parseTemplateTypeParameter() { return null; }
|
|
TemplateValueParameter parseTemplateValueParameter() { return null; }
|
|
TemplateValueParameterDefault parseTemplateValueParameterDefault() { return null; }
|
|
TernaryExpression parseTernaryExpression() { return null; }
|
|
ThrowStatement parseThrowStatement() { return null; }
|
|
TraitsArgument parseTraitsArgument() { return null; }
|
|
TraitsExpression parseTraitsExpression() { return null; }
|
|
TryStatement parseTryStatement() { return null; }
|
|
Type parseType() { return null; }
|
|
Type2 parseType2() { return null; }
|
|
Type3 parseType3() { return null; }
|
|
TypeConstructor parseTypeConstructor() { return null; }
|
|
TypeConstructors parseTypeConstructors() { return null; }
|
|
TypeSpecialization parseTypeSpecialization() { return null; }
|
|
TypeSuffix parseTypeSuffix() { return null; }
|
|
TypeidExpression parseTypeidExpression() { return null; }
|
|
TypeofExpression parseTypeofExpression() { return null; }
|
|
UnaryExpression parseUnaryExpression() { return null; }
|
|
UnionDeclaration parseUnionDeclaration() { return null; }
|
|
Unittest parseUnittest() { return null; }
|
|
VariableDeclaration parseVariableDeclaration() { return null; }
|
|
VersionCondition parseVersionCondition() { return null; }
|
|
VersionSpecification parseVersionSpecification() { return null; }
|
|
WhileStatement parseWhileStatement() { return null; }
|
|
WithStatement parseWithStatement() { return null; }
|
|
XorExpression parseXorExpression() { return null; }
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
statementType parseContinueBreakStatement(alias statementType)()
|
|
{
|
|
index++;
|
|
auto c = new statementType;
|
|
switch (tokens[index].type)
|
|
{
|
|
case TokenType.identifier:
|
|
c.identifier = tokens[index++].value;
|
|
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");
|
|
}
|