ast work
This commit is contained in:
parent
41ec752e86
commit
281751e52e
|
@ -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;
|
|
||||||
}
|
|
||||||
+/
|
|
||||||
|
|
||||||
|
|
||||||
+/
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
+/
|
|
||||||
|
|
Loading…
Reference in New Issue