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.container;
import std.d.lexer; 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 DeclDef : ASTNode {}
interface AttributeSpecifier : DeclDef {} interface AttributeSpecifier : DeclDef {}
interface EnumDeclaration : DeclDef {} interface EnumDeclaration : DeclDef {}
@ -36,12 +61,14 @@ class Module : ASTNode
{ {
ModuleDeclaration declaration; ModuleDeclaration declaration;
DList!(DeclDef) declDefs; DList!(DeclDef) declDefs;
mixin(DEFAULT_ACCEPT);
} }
class ModuleDeclaration : ASTNode class ModuleDeclaration : ASTNode
{ {
string[] packageName; string[] packageName;
string moduleName; string moduleName;
mixin(DEFAULT_ACCEPT);
} }
@ -55,40 +82,86 @@ struct Import
interface Statement : ASTNode {} interface Statement : ASTNode {}
class EmptyStatement : Statement, NoScopeStatement {} class EmptyStatement : Statement, NoScopeStatement
{
mixin(DEFAULT_ACCEPT);
}
interface NoScopeNonEmptyStatement : ASTNode {} interface NoScopeNonEmptyStatement : ASTNode {}
interface NoScopeStatement : ASTNode {} interface NoScopeStatement : ASTNode {}
interface NonEmptyStatement : NoScopeNonEmptyStatement, NoScopeStatement, Statement {} interface NonEmptyStatement : NoScopeNonEmptyStatement, NoScopeStatement, Statement {}
interface NoScopeBlockStatement : Statement {} interface NonEmptyOrScopeBlockStatement : Statement {} //BUG: The standard does not say that NonEmptyOrScopeBlockStatement is a statement
interface NonEmptyOrScopeBlockStatement : ASTNode {}
interface ScopeBlockStatement : NonEmptyOrScopeBlockStatement {} interface ScopeBlockStatement : NonEmptyOrScopeBlockStatement {}
interface NonEmptyStatementNoCaseNoDefault : NonEmptyStatement {} interface NonEmptyStatementNoCaseNoDefault : NonEmptyStatement {}
class CaseStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class DefaultStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class CaseRangeStatement : NonEmptyStatement
{
mixin(DEFAULT_ACCEPT);
}
class LabeledStatement : NonEmptyStatementNoCaseNoDefault class LabeledStatement : NonEmptyStatementNoCaseNoDefault
{ {
string label; string label;
NoScopeStatement statement; NoScopeStatement statement;
mixin(DEFAULT_ACCEPT);
} }
interface ExpressionStatement : NonEmptyStatementNoCaseNoDefault {} interface ExpressionStatement : NonEmptyStatementNoCaseNoDefault {}
interface DeclarationStatement : NonEmptyStatementNoCaseNoDefault {} interface DeclarationStatement : NonEmptyStatementNoCaseNoDefault {}
/+ class BlockStatement : NoScopeNonEmptyStatement, ScopeBlockStatement, NoScopeStatement
{
Statement[] statements;
mixin(DEFAULT_ACCEPT);
}
/** /**
* $(LINK2 http://dlang.org/statement.html#IfStatement) * $(LINK2 http://dlang.org/statement.html#IfStatement)
*/ */
class IfStatement : NonEmptyStatementNoCaseNoDefault 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) * $(LINK http://dlang.org/statement.html#ContinueStatement)
@ -96,6 +169,7 @@ class FinalSwitchStatement : NonEmptyStatementNoCaseNoDefault {}
class ContinueStatement : NonEmptyStatementNoCaseNoDefault class ContinueStatement : NonEmptyStatementNoCaseNoDefault
{ {
string identifier; string identifier;
mixin(DEFAULT_ACCEPT);
} }
/** /**
@ -104,8 +178,14 @@ class ContinueStatement : NonEmptyStatementNoCaseNoDefault
class BreakStatement : NonEmptyStatementNoCaseNoDefault class BreakStatement : NonEmptyStatementNoCaseNoDefault
{ {
string identifier; string identifier;
mixin(DEFAULT_ACCEPT);
} }
class ReturnStatement : NonEmptyStatementNoCaseNoDefault {}
class ReturnStatement : NonEmptyStatementNoCaseNoDefault
{
mixin(DEFAULT_ACCEPT);
}
class GotoStatement : NonEmptyStatementNoCaseNoDefault class GotoStatement : NonEmptyStatementNoCaseNoDefault
{ {
enum GotoType enum GotoType
@ -123,19 +203,54 @@ class GotoStatement : NonEmptyStatementNoCaseNoDefault
} }
GotoType type; GotoType type;
mixin(DEFAULT_ACCEPT);
} }
class WithStatement : NonEmptyStatementNoCaseNoDefault {} class WithStatement : NonEmptyStatementNoCaseNoDefault {}
class SynchronizedStatement : NonEmptyStatementNoCaseNoDefault {} class SynchronizedStatement : NonEmptyStatementNoCaseNoDefault
class TryStatement : NonEmptyStatementNoCaseNoDefault {} {
class ScopeGuardStatement : NonEmptyStatementNoCaseNoDefault {} mixin(DEFAULT_ACCEPT);
class ThrowStatement : NonEmptyStatementNoCaseNoDefault {} }
class AsmStatement : NonEmptyStatementNoCaseNoDefault {} class TryStatement : NonEmptyStatementNoCaseNoDefault
class PragmaStatement : NonEmptyStatementNoCaseNoDefault {} {
class MixinStatement : NonEmptyStatementNoCaseNoDefault {} mixin(DEFAULT_ACCEPT);
class ForeachRangeStatement : NonEmptyStatementNoCaseNoDefault {} }
class ConditionalStatement : NonEmptyStatementNoCaseNoDefault {} class ScopeGuardStatement : NonEmptyStatementNoCaseNoDefault
class StaticAssert : NonEmptyStatementNoCaseNoDefault, DeclDef {} {
class TemplateMixin : NonEmptyStatementNoCaseNoDefault, DeclDef {} 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 class ImportDeclaration : NonEmptyStatementNoCaseNoDefault, DeclDef
{ {
bool isStatic; bool isStatic;
@ -143,16 +258,15 @@ class ImportDeclaration : NonEmptyStatementNoCaseNoDefault, DeclDef
} }
class BlockStatement : NoScopeNonEmptyStatement, ScopeBlockStatement
{
Statement[] statements;
}
interface Expression : ASTNode {} interface Expression : ASTNode {}
class CommaExpression : Expression class CommaExpression : Expression
{ {
AssignExpression left; AssignExpression left;
AssignExpression right; AssignExpression right;
mixin(DEFAULT_ACCEPT);
} }
class AssignExpression class AssignExpression
@ -165,21 +279,23 @@ class AssignExpression
{ {
assert ( assert (
operator == TokenType.assign operator == TokenType.assign
|| operator == TokenType.plusEquals || operator == TokenType.plusEqual
|| operator == TokenType.minusEquals || operator == TokenType.minusEqual
|| operator == TokenType.mulEquals || operator == TokenType.mulEqual
|| operator == TokenType.divEquals || operator == TokenType.divEqual
|| operator == TokenType.modEquals || operator == TokenType.modEqual
|| operator == TokenType.bitAndEquals || operator == TokenType.bitAndEqual
|| operator == TokenType.bitOrEquals || operator == TokenType.bitOrEqual
|| operator == TokenType.xorEquals || operator == TokenType.xorEqual
|| operator == TokenType.catEquals || operator == TokenType.catEqual
|| operator == TokenType.shiftLeftEqual || operator == TokenType.shiftLeftEqual
|| operator == TokenType.shiftRightEqual || operator == TokenType.shiftRightEqual
|| operator == TokenType.unsignedShiftRightEqual || operator == TokenType.unsignedShiftRightEqual
|| operator == TokenType.powEquals || operator == TokenType.powEqual
); );
} }
mixin(DEFAULT_ACCEPT);
} }
interface ConditionalExpression : Expression {} interface ConditionalExpression : Expression {}
@ -191,6 +307,8 @@ class TernaryExpression : ConditionalExpression
Expression middle; Expression middle;
/// Null unless this is a ternary /// Null unless this is a ternary
ConditionalExpression right; ConditionalExpression right;
mixin(DEFAULT_ACCEPT);
} }
interface OrOrExpression : ConditionalExpression {} interface OrOrExpression : ConditionalExpression {}
@ -208,6 +326,7 @@ interface UnaryExpression : MulExpression {}
class ComplementaryExpression : UnaryExpression class ComplementaryExpression : UnaryExpression
{ {
UnaryExpression unary; UnaryExpression unary;
mixin(DEFAULT_ACCEPT);
} }
interface NewExpression : UnaryExpression {} interface NewExpression : UnaryExpression {}
interface DeleteExpression : UnaryExpression {} interface DeleteExpression : UnaryExpression {}
@ -219,21 +338,64 @@ interface PrimaryExpression : Expression {}
class SingleTokenExpression class SingleTokenExpression
{ {
Token token; 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 left;
ShiftExpression right; ShiftExpression right;
TokenType operator; TokenType operator;
mixin(DEFAULT_ACCEPT);
} }
class Parameter : ASTNode class Parameter : ASTNode
{ {
TokenType[] inOut;
string[] inOut;
string type; 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 * 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_; return t >= TokenType.bool_ && t <= TokenType.wchar_;
} }
@ -1887,7 +1887,7 @@ pure nothrow bool isType(const TokenType t)
/** /**
* ditto * ditto
*/ */
pure nothrow bool isType(ref const Token t) pure nothrow bool isBasicType(ref const Token t)
{ {
return isType(t.type); return isType(t.type);
} }
@ -2114,10 +2114,10 @@ enum TokenType: ushort
const_, /// $(D_KEYWORD const) const_, /// $(D_KEYWORD const)
final_, /// $(D_KEYWORD final) final_, /// $(D_KEYWORD final)
gshared, /// $(D_KEYWORD __gshared) gshared, /// $(D_KEYWORD __gshared)
immutable_, // immutable immutable_, /// $(D_KEYWORD immutable)
inout_, // inout inout_, /// $(D_KEYWORD inout)
scope_, /// $(D_KEYWORD scope) scope_, /// $(D_KEYWORD scope)
shared_, // shared shared_, /// $(D_KEYWORD shared)
static_, /// $(D_KEYWORD static) static_, /// $(D_KEYWORD static)
synchronized_, /// $(D_KEYWORD synchronized) synchronized_, /// $(D_KEYWORD synchronized)
@ -2190,7 +2190,7 @@ enum TokenType: ushort
line, /// $(D_KEYWORD ___LINE__) line, /// $(D_KEYWORD ___LINE__)
comment, /// $(D_COMMENT /** comment */) or $(D_COMMENT // comment) or $(D_COMMENT ///comment) comment, /// $(D_COMMENT /** comment */) or $(D_COMMENT // comment) or $(D_COMMENT ///comment)
identifier, /// anything else 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) traits, /// $(D_KEYWORD ___traits)
parameters, /// $(D_KEYWORD ___parameters) parameters, /// $(D_KEYWORD ___parameters)
vector, /// $(D_KEYWORD ___vector) 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; import std.d.ast;
version(unittest) import std.stdio; 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 struct Parser
{ {
public:
Module parseModule() Module parseModule()
{ {
Module m = new Module; Module m = new Module;
@ -34,8 +41,6 @@ public:
return m; return m;
} }
private:
ModuleDeclaration parseModuleDeclaration() ModuleDeclaration parseModuleDeclaration()
in in
{ {
@ -74,46 +79,239 @@ private:
{ {
switch (tokens[index].type) 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: default:
return null; 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()
// { LabeledStatement parseLabeledStatement()
// switch (tokens[index].type) in
// { {
// case TokenType.semicolon: assert (tokens[index].type == TokenType.identifier);
// return new EmptyStatement; }
// case TokenType.lBrace: body
// return parseBlockStatement(); {
// default: auto ls = new LabeledStatement;
// return parseNonEmptyStatement(); 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) void error(string message)
{ {
@ -186,6 +384,16 @@ private:
return peek() && peek().type == 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() bool moreTokens()
{ {
return index < tokens.length; return index < tokens.length;
@ -196,6 +404,57 @@ private:
string fileName; 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 //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) //T parseSingleTokenExpression(TokType, AstType, R)(ref R range)
@ -421,278 +617,15 @@ private:
// return expr; // 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) bool isIdentifierOrBasicType(const TokenType type)
{ {
return isType(type) || type == TokenType.identifier; 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) string parseType(Tokens)(ref Tokens tokens)
{ {
@ -1096,9 +1029,8 @@ body
return decl; return decl;
} }
+/
void main(string[] args) void main(string[] args)
{ {
} }
+/