This commit is contained in:
Hackerpilot 2013-03-30 22:59:22 -07:00
parent 41ec752e86
commit 281751e52e
5 changed files with 2164 additions and 575 deletions

1642
d.y Normal file

File diff suppressed because it is too large Load Diff

419
std/d/ast.d Normal file → Executable file
View File

@ -9,7 +9,32 @@ module std.d.ast;
import std.container;
import std.d.lexer;
interface ASTNode {}
interface ASTVisitor
{
///
void visit(ASTNode node);
///
void visit(Module node);
///
void visit(ModuleDeclaration node);
///
void visit(CaseStatement node);
///
void visit(DefaultStatement node);
///
void visit(CaseRangeStatement node);
///
void visit(LabeledStatement node);
}
interface ASTNode
{
void accept(ASTVisitor visitor;)
}
immutable string DEFAULT_ACCEPT = q{override void accept(ASTVisitor visitor) { visitor.visit(this); }};
interface DeclDef : ASTNode {}
interface AttributeSpecifier : DeclDef {}
interface EnumDeclaration : DeclDef {}
@ -36,12 +61,14 @@ class Module : ASTNode
{
ModuleDeclaration declaration;
DList!(DeclDef) declDefs;
mixin(DEFAULT_ACCEPT);
}
class ModuleDeclaration : ASTNode
{
string[] packageName;
string moduleName;
mixin(DEFAULT_ACCEPT);
}
@ -55,40 +82,86 @@ struct Import
interface Statement : ASTNode {}
class EmptyStatement : Statement, NoScopeStatement {}
class EmptyStatement : Statement, NoScopeStatement
{
mixin(DEFAULT_ACCEPT);
}
interface NoScopeNonEmptyStatement : ASTNode {}
interface NoScopeStatement : ASTNode {}
interface NonEmptyStatement : NoScopeNonEmptyStatement, NoScopeStatement, Statement {}
interface NoScopeBlockStatement : Statement {}
interface NonEmptyOrScopeBlockStatement : ASTNode {}
interface NonEmptyOrScopeBlockStatement : Statement {} //BUG: The standard does not say that NonEmptyOrScopeBlockStatement is a statement
interface ScopeBlockStatement : NonEmptyOrScopeBlockStatement {}
interface NonEmptyStatementNoCaseNoDefault : NonEmptyStatement {}
class CaseStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class DefaultStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class CaseRangeStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class LabeledStatement : NonEmptyStatementNoCaseNoDefault
{
string label;
NoScopeStatement statement;
mixin(DEFAULT_ACCEPT);
}
interface ExpressionStatement : NonEmptyStatementNoCaseNoDefault {}
interface DeclarationStatement : NonEmptyStatementNoCaseNoDefault {}
/+
class BlockStatement : NoScopeNonEmptyStatement, ScopeBlockStatement, NoScopeStatement
{
Statement[] statements;
mixin(DEFAULT_ACCEPT);
}
/**
* $(LINK2 http://dlang.org/statement.html#IfStatement)
*/
class IfStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class WhileStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class DoStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ForStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ForeachStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class SwitchStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class FinalSwitchStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class WhileStatement : NonEmptyStatementNoCaseNoDefault {}
class DoStatement : NonEmptyStatementNoCaseNoDefault {}
class ForStatement : NonEmptyStatementNoCaseNoDefault {}
class ForeachStatement : NonEmptyStatementNoCaseNoDefault {}
class SwitchStatement : NonEmptyStatementNoCaseNoDefault {}
class FinalSwitchStatement : NonEmptyStatementNoCaseNoDefault {}
/**
* $(LINK http://dlang.org/statement.html#ContinueStatement)
@ -96,6 +169,7 @@ class FinalSwitchStatement : NonEmptyStatementNoCaseNoDefault {}
class ContinueStatement : NonEmptyStatementNoCaseNoDefault
{
string identifier;
mixin(DEFAULT_ACCEPT);
}
/**
@ -104,8 +178,14 @@ class ContinueStatement : NonEmptyStatementNoCaseNoDefault
class BreakStatement : NonEmptyStatementNoCaseNoDefault
{
string identifier;
mixin(DEFAULT_ACCEPT);
}
class ReturnStatement : NonEmptyStatementNoCaseNoDefault {}
class ReturnStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class GotoStatement : NonEmptyStatementNoCaseNoDefault
{
enum GotoType
@ -123,19 +203,54 @@ class GotoStatement : NonEmptyStatementNoCaseNoDefault
}
GotoType type;
mixin(DEFAULT_ACCEPT);
}
class WithStatement : NonEmptyStatementNoCaseNoDefault {}
class SynchronizedStatement : NonEmptyStatementNoCaseNoDefault {}
class TryStatement : NonEmptyStatementNoCaseNoDefault {}
class ScopeGuardStatement : NonEmptyStatementNoCaseNoDefault {}
class ThrowStatement : NonEmptyStatementNoCaseNoDefault {}
class AsmStatement : NonEmptyStatementNoCaseNoDefault {}
class PragmaStatement : NonEmptyStatementNoCaseNoDefault {}
class MixinStatement : NonEmptyStatementNoCaseNoDefault {}
class ForeachRangeStatement : NonEmptyStatementNoCaseNoDefault {}
class ConditionalStatement : NonEmptyStatementNoCaseNoDefault {}
class StaticAssert : NonEmptyStatementNoCaseNoDefault, DeclDef {}
class TemplateMixin : NonEmptyStatementNoCaseNoDefault, DeclDef {}
class SynchronizedStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class TryStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ScopeGuardStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ThrowStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class AsmStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class PragmaStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class MixinStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ForeachRangeStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class ConditionalStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class StaticAssert : NonEmptyStatementNoCaseNoDefault, DeclDef
{
mixin(DEFAULT_ACCEPT);
}
class TemplateMixin : NonEmptyStatementNoCaseNoDefault, DeclDef
{
mixin(DEFAULT_ACCEPT);
}
class ImportDeclaration : NonEmptyStatementNoCaseNoDefault, DeclDef
{
bool isStatic;
@ -143,16 +258,15 @@ class ImportDeclaration : NonEmptyStatementNoCaseNoDefault, DeclDef
}
class BlockStatement : NoScopeNonEmptyStatement, ScopeBlockStatement
{
Statement[] statements;
}
interface Expression : ASTNode {}
class CommaExpression : Expression
{
AssignExpression left;
AssignExpression right;
mixin(DEFAULT_ACCEPT);
}
class AssignExpression
@ -165,21 +279,23 @@ class AssignExpression
{
assert (
operator == TokenType.assign
|| operator == TokenType.plusEquals
|| operator == TokenType.minusEquals
|| operator == TokenType.mulEquals
|| operator == TokenType.divEquals
|| operator == TokenType.modEquals
|| operator == TokenType.bitAndEquals
|| operator == TokenType.bitOrEquals
|| operator == TokenType.xorEquals
|| operator == TokenType.catEquals
|| operator == TokenType.plusEqual
|| operator == TokenType.minusEqual
|| operator == TokenType.mulEqual
|| operator == TokenType.divEqual
|| operator == TokenType.modEqual
|| operator == TokenType.bitAndEqual
|| operator == TokenType.bitOrEqual
|| operator == TokenType.xorEqual
|| operator == TokenType.catEqual
|| operator == TokenType.shiftLeftEqual
|| operator == TokenType.shiftRightEqual
|| operator == TokenType.unsignedShiftRightEqual
|| operator == TokenType.powEquals
|| operator == TokenType.powEqual
);
}
mixin(DEFAULT_ACCEPT);
}
interface ConditionalExpression : Expression {}
@ -191,6 +307,8 @@ class TernaryExpression : ConditionalExpression
Expression middle;
/// Null unless this is a ternary
ConditionalExpression right;
mixin(DEFAULT_ACCEPT);
}
interface OrOrExpression : ConditionalExpression {}
@ -208,6 +326,7 @@ interface UnaryExpression : MulExpression {}
class ComplementaryExpression : UnaryExpression
{
UnaryExpression unary;
mixin(DEFAULT_ACCEPT);
}
interface NewExpression : UnaryExpression {}
interface DeleteExpression : UnaryExpression {}
@ -219,21 +338,64 @@ interface PrimaryExpression : Expression {}
class SingleTokenExpression
{
Token token;
mixin(DEFAULT_ACCEPT);
}
class ThisExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class SuperExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class NullExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class TrueExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class FalseExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class DollarExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class FileExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class LineExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class IntegerExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class FloatExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class CharacterExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class StringExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class IdentifierExpression : SingleTokenExpression
{
mixin(DEFAULT_ACCEPT);
}
class ArrayExpression : PrimaryExpression
{
mixin(DEFAULT_ACCEPT);
}
class ThisExpression : SingleTokenExpression {}
class SuperExpression : SingleTokenExpression {}
class NullExpression : SingleTokenExpression {}
class TrueExpression : SingleTokenExpression {}
class FalseExpression : SingleTokenExpression {}
class DollarExpression : SingleTokenExpression {}
class FileExpression : SingleTokenExpression {}
class LineExpression : SingleTokenExpression {}
class IntegerExpression : SingleTokenExpression {}
class FloatExpression : SingleTokenExpression {}
class CharacterExpression : SingleTokenExpression {}
class StringExpression : SingleTokenExpression {}
class IdentifierExpression : SingleTokenExpression {}
class ArrayExpression : PrimaryExpression {}
@ -244,159 +406,12 @@ class RelExpression : CmpExpression
ShiftExpression left;
ShiftExpression right;
TokenType operator;
mixin(DEFAULT_ACCEPT);
}
class Parameter : ASTNode
{
string[] inOut;
TokenType[] inOut;
string type;
mixin(DEFAULT_ACCEPT);
}
/+
// Copyright Brian Schott (Sir Alaran) 2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module basicast;
import std.d.lexer;
struct Scope
{
size_t begin;
size_t end;
Scope* parent;
}
struct ModuleDeclaration
{
string[] package_;
string name;
}
struct Module
{
ModuleDeclaration moduleDeclaration;
VariableDeclaration[] variables;
FunctionDeclaration[] functions;
Enum[] enums;
Scope*[] scopes;
}
enum DeclDefType : ubyte
{
attributeSpecifier,
importDeclaration,
enumDeclaration,
classDeclaration,
interfaceDeclaration,
aggregateDeclaration,
declaration,
constructor,
destructor,
unitTest,
staticConstructor,
staticDestructor,
sharedStaticConstructor,
sharedStaticDestructor,
conditionalDeclaration,
debugSpecification,
versionSpecification,
staticAssert,
templatedeclaration,
templateMixinDeclaration,
templateMixin,
mixinDeclaration,
semicolon
}
class DeclDef
{
DeclDefType type;
}
struct Enum
{
bool singleValue;
EnumMember[] members;
string baseType;
}
struct AttributeList
{
public:
void set(TokenType attribute)
in
{
assert(isAttribute(attribute));
}
body
{
attributes ~= attribute;
}
const(TokenType)[] get()
{
return attributes[];
}
private:
TokenType[] attributes;
}
struct Parameter
{
string name;
string type;
string def;
}
struct FunctionDeclaration
{
AttributeList attributes;
Parameter[] ctParameters;
Parameter[] rtParameters;
string returnType;
string name;
uint line;
}
struct VariableDeclaration
{
AttributeList attributes;
string name;
string type;
uint line;
}
struct Import
{
struct ImportSymbol
{
string symbolName;
string alias_;
}
string alias_;
string moduleName;
string[] packageParts;
ImportSymbol[] symbols;
}
class ImportDeclaration : DeclDef
{
Import[] imports;
}
class Inherits : DeclDef
{
//FunctionDeclaration[] functions;
}
+/
+/

0
std/d/entities.d Normal file → Executable file
View File

12
std/d/lexer.d Normal file → Executable file
View File

@ -1879,7 +1879,7 @@ pure nothrow bool isKeyword(ref const Token t)
/**
* Returns: true if the token is a built-in type
*/
pure nothrow bool isType(const TokenType t)
pure nothrow bool isBasicType(const TokenType t)
{
return t >= TokenType.bool_ && t <= TokenType.wchar_;
}
@ -1887,7 +1887,7 @@ pure nothrow bool isType(const TokenType t)
/**
* ditto
*/
pure nothrow bool isType(ref const Token t)
pure nothrow bool isBasicType(ref const Token t)
{
return isType(t.type);
}
@ -2114,10 +2114,10 @@ enum TokenType: ushort
const_, /// $(D_KEYWORD const)
final_, /// $(D_KEYWORD final)
gshared, /// $(D_KEYWORD __gshared)
immutable_, // immutable
inout_, // inout
immutable_, /// $(D_KEYWORD immutable)
inout_, /// $(D_KEYWORD inout)
scope_, /// $(D_KEYWORD scope)
shared_, // shared
shared_, /// $(D_KEYWORD shared)
static_, /// $(D_KEYWORD static)
synchronized_, /// $(D_KEYWORD synchronized)
@ -2190,7 +2190,7 @@ enum TokenType: ushort
line, /// $(D_KEYWORD ___LINE__)
comment, /// $(D_COMMENT /** comment */) or $(D_COMMENT // comment) or $(D_COMMENT ///comment)
identifier, /// anything else
scriptLine, // Line at the beginning of source file that starts from #!
scriptLine, /// Line at the beginning of source file that starts from #!
traits, /// $(D_KEYWORD ___traits)
parameters, /// $(D_KEYWORD ___parameters)
vector, /// $(D_KEYWORD ___vector)

666
std/d/parser.d Normal file → Executable file
View File

@ -10,10 +10,17 @@ 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
{
public:
Module parseModule()
{
Module m = new Module;
@ -34,8 +41,6 @@ public:
return m;
}
private:
ModuleDeclaration parseModuleDeclaration()
in
{
@ -74,46 +79,239 @@ private:
{
switch (tokens[index].type)
{
// case TokenType.identifier:
// if (nextIs(TokenType.colon))
// return parseLabeledStatement();
// break;
// case TokenType.this_:
// return parseConstructor();
// case TokenType.tilde:
// if (nextIs(TokenType.this_))
// return parseDestructor();
// break;
default:
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;
// }
// NoScopeStatement parseNoScopeStatement()
// {
// switch (tokens[index].type)
// {
// case TokenType.semicolon:
// return new EmptyStatement;
// case TokenType.lBrace:
// return parseBlockStatement();
// default:
// return parseNonEmptyStatement();
// }
// }
LabeledStatement parseLabeledStatement()
in
{
assert (tokens[index].type == TokenType.identifier);
}
body
{
auto ls = new LabeledStatement;
ls.label = tokens[index++].value;
ls.statement = parseNoScopeStatement();
return ls;
}
NoScopeStatement parseNoScopeStatement()
{
switch (tokens[index].type)
{
case TokenType.semicolon:
return new EmptyStatement;
case TokenType.lBrace:
return parseBlockStatement();
default:
return parseNonEmptyStatement();
}
}
NonEmptyStatement parseNonEmptyStatement()
{
switch (tokens[index].type)
{
case TokenType.case_:
return parseCaseStatement();
case TokenType.default_:
return parseDefaultStatement();
default:
return null;
}
}
CaseStatement parseCaseStatement()
{
return null;
}
DefaultStatement parseDefaultStatement()
{
return null;
}
Statement parseStatement()
{
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;
}
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;
}
ContinueStatement parseContinueStatement()
{
expect(TokenType.continue_);
return parseContinueBreakStatement!(ContinueStatement)();
}
BreakStatement parseBreakStatement()
{
expect(TokenType.break_);
return parseContinueBreakStatement!(BreakStatement)();
}
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;
}
}
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;
}
void error(string message)
{
@ -186,6 +384,16 @@ private:
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;
@ -196,6 +404,57 @@ private:
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");
}
//
//unittest
//{
@ -320,70 +579,7 @@ private:
// }
//}
//
//GotoStatement parseGotoStatement(Token[] tokens)
//in
//{
// assert (tokens[i] == TokenType.goto_);
//}
//body
//{
// tokens.popFront();
// auto g = new GotoExpression;
// switch (tokens[i].type)
// {
// case TokenType.identifier:
// g.type = GotoStatement.GotoType.identifier;
// g.identifier = tokens.moveFront().value;
// break;
// case TokenType.default_:
// tokens.popFront();
// g.type = GotoStatement.GotoType.break_;
// case TokenType.case_:
// g.type = GotoStatement.GotoType.case_;
// tokens.popFront();
// default:
// error(tokens, "Expected an identifier, \"default\", or \"case\" following \"goto\"");
// return null;
// }
//}
//
//ContinueStatement parseContinueStatement(Token[] tokens)
//in
//{
// assert (tokens[i] == TokenType.continue_);
//}
//body
//{
// return parseContinueBreakStatement!(R, ContinueStatement)(tokens);
//}
//
//BreakStatement parseBreakStatement(Token[] tokens)
//in
//{
// assert (tokens[i] == TokenType.break_);
//}
//body
//{
// return parseBreakStatement!(R, BreakStatement)(tokens);
//}
//
//statementType parseContinueBreakStatement(R, alias statementType)(ref R tokens)
//{
// tokens.popFront();
// auto c = new statementType;
// switch (tokens[i].type)
// {
// case TokenType.identifier:
// c.identifier = tokens.moveFront().value;
// goto case;
// case TokenType.semicolon:
// return c;
// default:
// error(tokens, "Identifier or semicolon expected");
// return null;
// }
//
//}
//
//
//T parseSingleTokenExpression(TokType, AstType, R)(ref R range)
@ -421,278 +617,15 @@ private:
// return expr;
//}
//void main(string[] args) {}
/+
// Copyright Brian Schott (Sir Alaran) 2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module parser;
import std.d.lexer;
import std.range;
import basicast;
version (unittest) import std.stdio;
version (unittest) import std.string;
void skipPastSemicolon(Tokens)(ref Tokens tokens)
{
while (!tokens.empty)
{
if (tokens[i].type == TokenType.semicolon)
{
tokens.popFront();
return;
}
else
tokens.popFront();
}
}
void skipDelimited(Tokens, alias O, alias C)(ref Tokens tokens)
in
{
assert (tokens[i].type == O);
}
body
{
tokens.popFront();
int depth = 1;
while (!tokens.empty)
{
switch (tokens[i].type)
{
case C:
--depth;
if (depth > 0)
goto default;
tokens.popFront();
return;
case O:
++depth;
goto default;
default:
tokens.popFront();
break;
}
}
}
void skipBraces(Tokens)(ref Tokens tokens)
{
return skipDelimited!(Tokens, TokenType.lBrace, TokenType.rBrace)(tokens);
}
void skipParens(Tokens)(ref Tokens tokens)
{
return skipDelimited!(Tokens, TokenType.lParen, TokenType.rParen)(tokens);
}
void skipBrackets(Tokens)(ref Tokens tokens)
{
return skipDelimited!(Tokens, TokenType.lBracket, TokenType.rBracket)(tokens);
}
string delimiterContent(Tokens, alias O, alias C)(ref Tokens tokens)
{
tokens.popFront();
int depth = 1;
auto app = appender!(char[])();
loop: while (!tokens.empty)
{
switch (tokens[i].type)
{
case C:
--depth;
if (depth > 0)
goto default;
tokens.popFront();
break loop;
case O:
++depth;
goto default;
default:
app.put(tokens.moveFront().value);
break;
}
}
return cast(string) app.data;
}
string bracketContent(Tokens)(ref Tokens tokens)
{
return "[" ~ delimiterContent!(Tokens, TokenType.lBracket, TokenType.rBracket)(tokens) ~ "]";
}
string parenContent(Tokens)(ref Tokens tokens)
{
return "(" ~ delimiterContent!(Tokens, TokenType.lParen, TokenType.rParen)(tokens) ~ ")";
}
string braceContent(Tokens)(ref Tokens tokens)
{
return "{" ~ delimiterContent!(Tokens, TokenType.lBrace, TokenType.rBrace)(tokens) ~ "}";
}
bool isIdentifierOrBasicType(const TokenType type)
{
return isType(type) || type == TokenType.identifier;
}
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;
}
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");
}
string parseType(Tokens)(ref Tokens tokens)
{
@ -1096,9 +1029,8 @@ body
return decl;
}
+/
void main(string[] args)
{
}
+/