Mercurial > projects > dil
changeset 325:540ec3753263
- Moved some source files to src/dil/.
author | aziz |
---|---|
date | Tue, 21 Aug 2007 16:28:05 +0000 |
parents | c1820da1ca53 |
children | 4a7359b88c11 |
files | trunk/src/Declarations.d trunk/src/Expressions.d trunk/src/HtmlEntities.d trunk/src/Identifier.d trunk/src/Information.d trunk/src/Keywords.d trunk/src/Lexer.d trunk/src/Messages.d trunk/src/Parser.d trunk/src/Settings.d trunk/src/Statements.d trunk/src/SyntaxTree.d trunk/src/Token.d trunk/src/Types.d trunk/src/dil/Declarations.d trunk/src/dil/Expressions.d trunk/src/dil/HtmlEntities.d trunk/src/dil/Identifier.d trunk/src/dil/Information.d trunk/src/dil/Keywords.d trunk/src/dil/Lexer.d trunk/src/dil/Messages.d trunk/src/dil/Parser.d trunk/src/dil/Settings.d trunk/src/dil/Statements.d trunk/src/dil/SyntaxTree.d trunk/src/dil/Token.d trunk/src/dil/Types.d |
diffstat | 28 files changed, 9639 insertions(+), 9639 deletions(-) [+] |
line wrap: on
line diff
--- a/trunk/src/Declarations.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,526 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Declarations; -import SyntaxTree; -import Expressions; -import Types; -import Statements; -import Token; - -abstract class Declaration : Node -{ - bool hasBody; - this(bool hasBody) - { - super(NodeCategory.Declaration); - this.hasBody = hasBody; - } -} - -class Declarations : Declaration -{ - this() - { - super(true); - mixin(set_kind); - } - - void opCatAssign(Declaration d) - { - this.children ~= d; - } - - void opCatAssign(Declarations ds) - { - this.children ~= ds.children; - } -} - -class EmptyDeclaration : Declaration -{ - this() - { - super(false); - mixin(set_kind); - } -} - -class IllegalDeclaration : Declaration -{ - Token* token; - this(Token* token) - { - super(false); - mixin(set_kind); - this.token = token; - } -} - -alias Token*[] ModuleName; // Identifier(.Identifier)* - -class ModuleDeclaration : Declaration -{ - ModuleName moduleName; // module name sits at end of array - this(ModuleName moduleName) - { - super(false); - mixin(set_kind); - this.moduleName = moduleName; - } -} - -class ImportDeclaration : Declaration -{ - ModuleName[] moduleNames; - Token*[] moduleAliases; - Token*[] bindNames; - Token*[] bindAliases; - this(ModuleName[] moduleNames, Token*[] moduleAliases, Token*[] bindNames, Token*[] bindAliases) - { - super(false); - mixin(set_kind); - this.moduleNames = moduleNames; - this.moduleAliases = moduleAliases; - this.bindNames = bindNames; - this.bindAliases = bindAliases; - } -} - -class AliasDeclaration : Declaration -{ - Declaration decl; - this(Declaration decl) - { - super(false); - mixin(set_kind); - this.children = [decl]; - this.decl = decl; - } -} - -class TypedefDeclaration : Declaration -{ - Declaration decl; - this(Declaration decl) - { - super(false); - mixin(set_kind); - this.children = [decl]; - this.decl = decl; - } -} - -class EnumDeclaration : Declaration -{ - Token* name; - Type baseType; - Token*[] members; - Expression[] values; - this(Token* name, Type baseType, Token*[] members, Expression[] values, bool hasBody) - { - super(hasBody); - mixin(set_kind); - if (baseType) - this.children = [baseType]; - foreach(value; values) - if (value) - this.children ~= value; - this.name = name; - this.baseType = baseType; - this.members = members; - this.values = values; - } -} - -class ClassDeclaration : Declaration -{ - Token* name; - TemplateParameters tparams; - BaseClass[] bases; - Declarations decls; - this(Token* name, TemplateParameters tparams, BaseClass[] bases, Declarations decls, bool hasBody) - { - super(hasBody); - mixin(set_kind); - if (tparams) - this.children = [tparams]; - if (bases.length) - this.children ~= bases; - this.children ~= decls; - - this.name = name; - this.tparams = tparams; - this.bases = bases; - this.decls = decls; - } -} - -class InterfaceDeclaration : Declaration -{ - Token* name; - TemplateParameters tparams; - BaseClass[] bases; - Declarations decls; - this(Token* name, TemplateParameters tparams, BaseClass[] bases, Declarations decls, bool hasBody) - { - super(hasBody); - mixin(set_kind); - if (tparams) - this.children = [tparams]; - if (bases.length) - this.children ~= bases; - this.children ~= decls; - - this.name = name; - this.tparams = tparams; - this.bases = bases; - this.decls = decls; - } -} - -class StructDeclaration : Declaration -{ - Token* name; - TemplateParameters tparams; - Declarations decls; - this(Token* name, TemplateParameters tparams, Declarations decls, bool hasBody) - { - super(hasBody); - mixin(set_kind); - if (tparams) - this.children = [tparams]; - this.children ~= decls; - - this.name = name; - this.tparams = tparams; - this.decls = decls; - } -} - -class UnionDeclaration : Declaration -{ - Token* name; - TemplateParameters tparams; - Declarations decls; - this(Token* name, TemplateParameters tparams, Declarations decls, bool hasBody) - { - super(hasBody); - mixin(set_kind); - if (tparams) - this.children = [tparams]; - this.children ~= decls; - - this.name = name; - this.tparams = tparams; - this.decls = decls; - } -} - -class ConstructorDeclaration : Declaration -{ - Parameters parameters; - FunctionBody funcBody; - this(Parameters parameters, FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [cast(Node)parameters, funcBody]; - this.parameters = parameters; - this.funcBody = funcBody; - } -} - -class StaticConstructorDeclaration : Declaration -{ - FunctionBody funcBody; - this(FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [funcBody]; - this.funcBody = funcBody; - } -} - -class DestructorDeclaration : Declaration -{ - FunctionBody funcBody; - this(FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [funcBody]; - this.funcBody = funcBody; - } -} - -class StaticDestructorDeclaration : Declaration -{ - FunctionBody funcBody; - this(FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [funcBody]; - this.funcBody = funcBody; - } -} - -class FunctionDeclaration : Declaration -{ - Type returnType; - Token* funcName; - TemplateParameters tparams; - Parameters params; - FunctionBody funcBody; - this(Type returnType, Token* funcName, TemplateParameters tparams, Parameters params, FunctionBody funcBody) - { - assert(returnType !is null); - super(funcBody.funcBody !is null); - mixin(set_kind); - this.children = [returnType]; - if (tparams) - this.children ~= tparams; - this.children ~= [cast(Node)params, funcBody]; - this.returnType = returnType; - this.funcName = funcName; - this.tparams = tparams; - this.params = params; - this.funcBody = funcBody; - } -} - -class VariableDeclaration : Declaration -{ - Type type; - Token*[] idents; - Expression[] values; - this(Type type, Token*[] idents, Expression[] values) - { - super(false); - mixin(set_kind); - if (type) - this.children = [type]; - foreach(value; values) - if (value) - this.children ~= value; - this.type = type; - this.idents = idents; - this.values = values; - } -} - -class InvariantDeclaration : Declaration -{ - FunctionBody funcBody; - this(FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [funcBody]; - this.funcBody = funcBody; - } -} - -class UnittestDeclaration : Declaration -{ - FunctionBody funcBody; - this(FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [funcBody]; - this.funcBody = funcBody; - } -} - -class DebugDeclaration : Declaration -{ - Token* spec; - Token* cond; - Declaration decls, elseDecls; - - this(Token* spec, Token* cond, Declaration decls, Declaration elseDecls) - { - super(true /+decls.length != 0+/); - mixin(set_kind); - if (decls) - this.children = [decls]; - if (elseDecls) - this.children ~= elseDecls; - this.spec = spec; - this.cond = cond; - this.decls = decls; - this.elseDecls = elseDecls; - } -} - -class VersionDeclaration : Declaration -{ - Token* spec; - Token* cond; - Declaration decls, elseDecls; - - this(Token* spec, Token* cond, Declaration decls, Declaration elseDecls) - { - super(true /+decls.length != 0+/); - mixin(set_kind); - if (decls) - this.children = [decls]; - if (elseDecls) - this.children ~= elseDecls; - this.spec = spec; - this.cond = cond; - this.decls = decls; - this.elseDecls = elseDecls; - } -} - -class StaticIfDeclaration : Declaration -{ - Expression condition; - Declaration ifDecls, elseDecls; - this(Expression condition, Declaration ifDecls, Declaration elseDecls) - { - super(true); - mixin(set_kind); - this.children = [cast(Node)condition, ifDecls, elseDecls]; - this.condition = condition; - this.ifDecls = ifDecls; - this.elseDecls = elseDecls; - } -} - -class StaticAssertDeclaration : Declaration -{ - Expression condition, message; - this(Expression condition, Expression message) - { - super(true); - mixin(set_kind); - this.children = [condition]; - if (message) - this.children ~= message; - this.condition = condition; - this.message = message; - } -} - -class TemplateDeclaration : Declaration -{ - Token* name; - TemplateParameters tparams; - Declarations decls; - this(Token* name, TemplateParameters tparams, Declarations decls) - { - super(true); - mixin(set_kind); - this.children = [cast(Node)tparams, decls]; - this.name = name; - this.tparams = tparams; - this.decls = decls; - } -} - -class NewDeclaration : Declaration -{ - Parameters parameters; - FunctionBody funcBody; - this(Parameters parameters, FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [cast(Node)parameters, funcBody]; - this.parameters = parameters; - this.funcBody = funcBody; - } -} - -class DeleteDeclaration : Declaration -{ - Parameters parameters; - FunctionBody funcBody; - this(Parameters parameters, FunctionBody funcBody) - { - super(true); - mixin(set_kind); - this.children = [cast(Node)parameters, funcBody]; - this.parameters = parameters; - this.funcBody = funcBody; - } -} - -class AttributeDeclaration : Declaration -{ - TOK attribute; - Declaration decls; - this(TOK attribute, Declaration decls) - { - super(true); - mixin(set_kind); - this.children = [decls]; - this.attribute = attribute; - this.decls = decls; - } -} - -class ExternDeclaration : AttributeDeclaration -{ - Linkage linkage; - this(Linkage linkage, Declaration decls) - { - super(TOK.Extern, decls); - mixin(set_kind); - this.linkage = linkage; - } -} - -class AlignDeclaration : AttributeDeclaration -{ - int size; - this(int size, Declaration decls) - { - super(TOK.Align, decls); - mixin(set_kind); - this.size = size; - } -} - -class PragmaDeclaration : AttributeDeclaration -{ - Token* ident; - Expression[] args; - this(Token* ident, Expression[] args, Declaration decls) - { - super(TOK.Pragma, decls); - mixin(set_kind); - if (args.length) - this.children ~= args; - this.ident = ident; - this.args = args; - } -} - -class MixinDeclaration : Declaration -{ - Expression[] templateIdents; - Token* mixinIdent; - Expression argument; // mixin ( AssignExpression ) - this(Expression[] templateIdents, Token* mixinIdent) - { - super(false); - mixin(set_kind); - this.children = templateIdents; - this.templateIdents = templateIdents; - this.mixinIdent = mixinIdent; - } - this(Expression argument) - { - super(false); - mixin(set_kind); - this.children = [argument]; - this.argument = argument; - } -}
--- a/trunk/src/Expressions.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,988 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Expressions; -import SyntaxTree; -import Token; -import Types; -import Declarations; -import Statements; - -abstract class Expression : Node -{ - this() - { - super(NodeCategory.Expression); - } -} - -class EmptyExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -abstract class BinaryExpression : Expression -{ - Expression left, right; - Token* tok; - this(Expression left, Expression right, Token* tok) - { - this.children = [left, right]; - this.left = left; - this.right = right; - this.tok = tok; - } -} - -class CondExpression : BinaryExpression -{ - Expression condition; - this(Expression condition, Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - this.children ~= [condition]; - this.condition = condition; - } -} - -class CommaExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class OrOrExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class AndAndExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class OrExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class XorExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class AndExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -abstract class CmpExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - } -} - -class EqualExpression : CmpExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class IdentityExpression : CmpExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class RelExpression : CmpExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class InExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class LShiftExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class RShiftExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class URShiftExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class PlusExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class MinusExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class CatExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class MulExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class DivExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class ModExpression : BinaryExpression -{ - this(Expression left, Expression right, Token* tok) - { - super(left, right, tok); - mixin(set_kind); - } -} - -class AssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class LShiftAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class RShiftAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class URShiftAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class OrAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class AndAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class PlusAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class MinusAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class DivAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class MulAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class ModAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class XorAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} -class CatAssignExpression : BinaryExpression -{ - this(Expression left, Expression right) - { - super(left, right, null); - mixin(set_kind); - } -} - -abstract class UnaryExpression : Expression -{ - Expression e; - this(Expression e) - { - this.children ~= e; - this.e = e; - } -} - -class AddressExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class PreIncrExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class PreDecrExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class PostIncrExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class PostDecrExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class DerefExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class SignExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class NotExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class CompExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} -/+ -class DotIdExpression : UnaryExpression -{ - string ident; - this(Expression e, string ident) - { - super(e); - this.ident = ident; - } -} -+/ -/+ -class DotTemplateInstanceExpression : UnaryExpression -{ - string ident; - TemplateArguments targs; - this(Expression e, string ident, TemplateArguments targs) - { - super(e); - this.ident = ident; - this.targs = targs; - } -} -+/ -class PostDotListExpression : UnaryExpression -{ - DotListExpression dotList; - this(Expression e, DotListExpression dotList) - { - super(e); - mixin(set_kind); - this.children ~= [dotList]; - this.dotList = dotList; - } -} - -class CallExpression : UnaryExpression -{ - Expression[] args; - this(Expression e, Expression[] args) - { - super(e); - mixin(set_kind); - this.children ~= args; - this.args = args; - } -} - -class NewExpression : /*Unary*/Expression -{ - Expression[] newArgs; - Type type; - Expression[] ctorArgs; - this(/*Expression e, */Expression[] newArgs, Type type, Expression[] ctorArgs) - { - /*super(e);*/ - mixin(set_kind); - if (newArgs.length) - this.children ~= newArgs; - this.children ~= type; - if (ctorArgs.length) - this.children ~= ctorArgs; - this.newArgs = newArgs; - this.type = type; - this.ctorArgs = ctorArgs; - } -} - -class NewAnonClassExpression : /*Unary*/Expression -{ - Expression[] newArgs; - BaseClass[] bases; - Expression[] ctorArgs; - Declarations decls; - this(/*Expression e, */Expression[] newArgs, BaseClass[] bases, Expression[] ctorArgs, Declarations decls) - { - /*super(e);*/ - mixin(set_kind); - if (newArgs.length) - this.children ~= newArgs; - if (bases.length) - this.children ~= bases; - if (ctorArgs.length) - this.children ~= ctorArgs; - this.children ~= decls; - - this.newArgs = newArgs; - this.bases = bases; - this.ctorArgs = ctorArgs; - this.decls = decls; - } -} - -class DeleteExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class CastExpression : UnaryExpression -{ - Type type; - this(Expression e, Type type) - { - this.children = [type]; - super(e); - mixin(set_kind); - this.type = type; - } -} - -class IndexExpression : UnaryExpression -{ - Expression[] args; - this(Expression e, Expression[] args) - { - super(e); - mixin(set_kind); - this.children ~= args; - this.args = args; - } -} - -class SliceExpression : UnaryExpression -{ - Expression left, right; - this(Expression e, Expression left, Expression right) - { - super(e); - mixin(set_kind); - this.children ~= [left, right]; - this.left = left; - this.right = right; - } -} - -/* -class PrimaryExpression -{ - -} -*/ - -class IdentifierExpression : Expression -{ - Token* identifier; - this(Token* identifier) - { - mixin(set_kind); - this.identifier = identifier; - } -} - -class SpecialTokenExpression : Expression -{ - Token* special; - this(Token* special) - { - mixin(set_kind); - this.special = special; - } -} - -/* -class IdentifierListExpression : Expression -{ - Expression[] identList; - this(Expression[] identList) - { - this.identList = identList; - } -} -*/ -class DotListExpression : Expression -{ - Expression[] items; - this(Expression[] items) - { - mixin(set_kind); - this.children = items; - this.items = items; - } -} - -class TemplateInstanceExpression : Expression -{ - Token* ident; - TemplateArguments targs; - this(Token* ident, TemplateArguments targs) - { - mixin(set_kind); - this.children = [targs]; - this.ident = ident; - this.targs = targs; - } -} - -class ThisExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class SuperExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class NullExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class DollarExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class BoolExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class IntNumberExpression : Expression -{ - TOK type; - ulong number; - this(TOK type, ulong number) - { - mixin(set_kind); - this.number = number; - this.type = type; - } -} - -class RealNumberExpression : Expression -{ - TOK type; - real number; - this(TOK type, real number) - { - mixin(set_kind); - this.number = number; - this.type = type; - } -} - -class CharLiteralExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class StringLiteralsExpression : Expression -{ - Token*[] strings; - this(Token*[] strings) - { - mixin(set_kind); - this.strings = strings; - } - - string getString() - { - char[] buffer; - foreach (strTok; strings) - { - buffer ~= strTok.str[0..$-1]; - } - return buffer; - } -} - -class ArrayLiteralExpression : Expression -{ - Expression[] values; - this(Expression[] values) - { - mixin(set_kind); - this.children = values; - this.values = values; - } -} - -class AssocArrayLiteralExpression : Expression -{ - Expression[] keys, values; - this(Expression[] keys, Expression[] values) - { - assert(keys.length == values.length); - mixin(set_kind); - foreach (i, key; keys) - this.children ~= [key, values[i]]; - this.keys = keys; - this.values = values; - } -} - -class AssertExpression : Expression -{ - Expression expr, msg; - this(Expression expr, Expression msg) - { - mixin(set_kind); - this.children = [expr]; - if (msg) - this.children ~= msg; - this.expr = expr; - this.msg = msg; - } -} - -class MixinExpression : Expression -{ - Expression expr; - this(Expression expr) - { - mixin(set_kind); - this.children = [expr]; - this.expr = expr; - } -} - -class ImportExpression : Expression -{ - Expression expr; - this(Expression expr) - { - mixin(set_kind); - this.children = [expr]; - this.expr = expr; - } -} - -class TypeofExpression : Expression -{ - Type type; - this(Type type) - { - mixin(set_kind); - this.children = [type]; - this.type = type; - } -} - -class TypeDotIdExpression : Expression -{ - Type type; - Token* ident; - this(Type type, Token* ident) - { - mixin(set_kind); - this.children = [type]; - this.type = type; - this.ident = ident; - } -} - -class TypeidExpression : Expression -{ - Type type; - this(Type type) - { - mixin(set_kind); - this.children = [type]; - this.type = type; - } -} - -class IsExpression : Expression -{ - Type type; - Token* ident; - Token* opTok, specTok; - Type specType; - this(Type type, Token* ident, Token* opTok, Token* specTok, Type specType) - { - mixin(set_kind); - this.children = [type]; - if (specType) - this.children ~= specType; - this.type = type; - this.ident = ident; - this.opTok = opTok; - this.specTok = specTok; - this.specType = specType; - } -} - -class FunctionLiteralExpression : Expression -{ - Type returnType; - Parameters parameters; - FunctionBody funcBody; - - this() - { - mixin(set_kind); - if (returnType) - this.children ~= returnType; - if (parameters) - this.children ~= parameters; - this.children ~= funcBody; - } - - this(Type returnType, Parameters parameters, FunctionBody funcBody) - { - this.returnType = returnType; - this.parameters = parameters; - this.funcBody = funcBody; - this(); - } - - this(FunctionBody funcBody) - { - this.funcBody = funcBody; - this(); - } -} - -version(D2) -{ -class TraitsExpression : Expression -{ - Token* ident; - TemplateArguments targs; - this(typeof(ident) ident, typeof(targs) targs) - { - mixin(set_kind); - this.children = [targs]; - this.ident = ident; - this.targs = targs; - } -} -} - -class VoidInitializer : Expression -{ - this() - { - mixin(set_kind); - } -} - -class ArrayInitializer : Expression -{ - Expression[] keys; - Expression[] values; - this(Expression[] keys, Expression[] values) - { - assert(keys.length == values.length); - mixin(set_kind); - foreach (i, key; keys) - { - if (key) - this.children ~= key; - if (values[i]) - this.children ~= values[i]; - } - this.keys = keys; - this.values = values; - } -} - -class StructInitializer : Expression -{ - Token*[] idents; - Expression[] values; - this(Token*[] idents, Expression[] values) - { - mixin(set_kind); - this.children = values; - this.idents = idents; - this.values = values; - } -} - -class AsmTypeExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class AsmOffsetExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class AsmSegExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class AsmPostBracketExpression : UnaryExpression -{ - this(Expression e) - { - super(e); - mixin(set_kind); - } -} - -class AsmBracketExpression : Expression -{ - Expression e; - this(Expression e) - { - mixin(set_kind); - this.children = [e]; - this.e = e; - } -} - -class AsmLocalSizeExpression : Expression -{ - this() - { - mixin(set_kind); - } -} - -class AsmRegisterExpression : Expression -{ - Token* register; - Token* number; // ST(0) - ST(7) - this(Token* register, Token* number = null) - { - mixin(set_kind); - this.register = register; - this.number = number; - } -}
--- a/trunk/src/HtmlEntities.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module HtmlEntities; - -private const dchar[char[]] entities_table; - -static this() -{ - entities_table = [ - "Aacute"[] : '\u00C1', - "aacute" : '\u00E1', - "Acirc" : '\u00C2', - "acirc" : '\u00E2', - "acute" : '\u00B4', - "AElig" : '\u00C6', - "aelig" : '\u00E6', - "Agrave" : '\u00C0', - "agrave" : '\u00E0', - "alefsym" : '\u2135', - "Alpha" : '\u0391', - "alpha" : '\u03B1', - "amp" : '\u0026', - "and" : '\u2227', - "ang" : '\u2220', - "Aring" : '\u00C5', - "aring" : '\u00E5', - "asymp" : '\u2248', - "Atilde" : '\u00C3', - "atilde" : '\u00E3', - "Auml" : '\u00C4', - "auml" : '\u00E4', - "bdquo" : '\u201E', - "Beta" : '\u0392', - "beta" : '\u03B2', - "brvbar" : '\u00A6', - "bull" : '\u2022', - "cap" : '\u2229', - "Ccedil" : '\u00C7', - "ccedil" : '\u00E7', - "cedil" : '\u00B8', - "cent" : '\u00A2', - "Chi" : '\u03A7', - "chi" : '\u03C7', - "circ" : '\u02C6', - "clubs" : '\u2663', - "cong" : '\u2245', - "copy" : '\u00A9', - "crarr" : '\u21B5', - "cup" : '\u222A', - "curren" : '\u00A4', - "Dagger" : '\u2021', - "dagger" : '\u2020', - "dArr" : '\u21D3', - "darr" : '\u2193', - "deg" : '\u00B0', - "Delta" : '\u0394', - "delta" : '\u03B4', - "diams" : '\u2666', - "divide" : '\u00F7', - "Eacute" : '\u00C9', - "eacute" : '\u00E9', - "Ecirc" : '\u00CA', - "ecirc" : '\u00EA', - "Egrave" : '\u00C8', - "egrave" : '\u00E8', - "empty" : '\u2205', - "emsp" : '\u2003', - "ensp" : '\u2002', - "Epsilon" : '\u0395', - "epsilon" : '\u03B5', - "equiv" : '\u2261', - "Eta" : '\u0397', - "eta" : '\u03B7', - "ETH" : '\u00D0', - "eth" : '\u00F0', - "Euml" : '\u00CB', - "euml" : '\u00EB', - "euro" : '\u20AC', - "exist" : '\u2203', - "fnof" : '\u0192', - "forall" : '\u2200', - "frac12" : '\u00BD', - "frac14" : '\u00BC', - "frac34" : '\u00BE', - "frasl" : '\u2044', - "Gamma" : '\u0393', - "gamma" : '\u03B3', - "ge" : '\u2265', - "gt" : '\u003E', - "hArr" : '\u21D4', - "harr" : '\u2194', - "hearts" : '\u2665', - "hellip" : '\u2026', - "Iacute" : '\u00CD', - "iacute" : '\u00ED', - "Icirc" : '\u00CE', - "icirc" : '\u00EE', - "iexcl" : '\u00A1', - "Igrave" : '\u00CC', - "igrave" : '\u00EC', - "image" : '\u2111', - "infin" : '\u221E', - "int" : '\u222B', - "Iota" : '\u0399', - "iota" : '\u03B9', - "iquest" : '\u00BF', - "isin" : '\u2208', - "Iuml" : '\u00CF', - "iuml" : '\u00EF', - "Kappa" : '\u039A', - "kappa" : '\u03BA', - "Lambda" : '\u039B', - "lambda" : '\u03BB', - "lang" : '\u2329', - "laquo" : '\u00AB', - "lArr" : '\u21D0', - "larr" : '\u2190', - "lceil" : '\u2308', - "ldquo" : '\u201C', - "le" : '\u2264', - "lfloor" : '\u230A', - "lowast" : '\u2217', - "loz" : '\u25CA', - "lrm" : '\u200E', - "lsaquo" : '\u2039', - "lsquo" : '\u2018', - "lt" : '\u003C', - "macr" : '\u00AF', - "mdash" : '\u2014', - "micro" : '\u00B5', - "middot" : '\u00B7', - "minus" : '\u2212', - "Mu" : '\u039C', - "mu" : '\u03BC', - "nabla" : '\u2207', - "nbsp" : '\u00A0', - "ndash" : '\u2013', - "ne" : '\u2260', - "ni" : '\u220B', - "not" : '\u00AC', - "notin" : '\u2209', - "nsub" : '\u2284', - "Ntilde" : '\u00D1', - "ntilde" : '\u00F1', - "Nu" : '\u039D', - "nu" : '\u03BD', - "Oacute" : '\u00D3', - "oacute" : '\u00F3', - "Ocirc" : '\u00D4', - "ocirc" : '\u00F4', - "OElig" : '\u0152', - "oelig" : '\u0153', - "Ograve" : '\u00D2', - "ograve" : '\u00F2', - "oline" : '\u203E', - "Omega" : '\u03A9', - "omega" : '\u03C9', - "Omicron" : '\u039F', - "omicron" : '\u03BF', - "oplus" : '\u2295', - "or" : '\u2228', - "ordf" : '\u00AA', - "ordm" : '\u00BA', - "Oslash" : '\u00D8', - "oslash" : '\u00F8', - "Otilde" : '\u00D5', - "otilde" : '\u00F5', - "otimes" : '\u2297', - "Ouml" : '\u00D6', - "ouml" : '\u00F6', - "para" : '\u00B6', - "part" : '\u2202', - "permil" : '\u2030', - "perp" : '\u22A5', - "Phi" : '\u03A6', - "phi" : '\u03C6', - "Pi" : '\u03A0', - "pi" : '\u03C0', - "piv" : '\u03D6', - "plusmn" : '\u00B1', - "pound" : '\u00A3', - "Prime" : '\u2033', - "prime" : '\u2032', - "prod" : '\u220F', - "prop" : '\u221D', - "Psi" : '\u03A8', - "psi" : '\u03C8', - "quot" : '\u0022', - "radic" : '\u221A', - "rang" : '\u232A', - "raquo" : '\u00BB', - "rArr" : '\u21D2', - "rarr" : '\u2192', - "rceil" : '\u2309', - "rdquo" : '\u201D', - "real" : '\u211C', - "reg" : '\u00AE', - "rfloor" : '\u230B', - "Rho" : '\u03A1', - "rho" : '\u03C1', - "rlm" : '\u200F', - "rsaquo" : '\u203A', - "rsquo" : '\u2019', - "sbquo" : '\u201A', - "Scaron" : '\u0160', - "scaron" : '\u0161', - "sdot" : '\u22C5', - "sect" : '\u00A7', - "shy" : '\u00AD', - "Sigma" : '\u03A3', - "sigma" : '\u03C3', - "sigmaf" : '\u03C2', - "sim" : '\u223C', - "spades" : '\u2660', - "sub" : '\u2282', - "sube" : '\u2286', - "sum" : '\u2211', - "sup" : '\u2283', - "sup1" : '\u00B9', - "sup2" : '\u00B2', - "sup3" : '\u00B3', - "supe" : '\u2287', - "szlig" : '\u00DF', - "Tau" : '\u03A4', - "tau" : '\u03C4', - "there4" : '\u2234', - "Theta" : '\u0398', - "theta" : '\u03B8', - "thetasym" : '\u03D1', - "thinsp" : '\u2009', - "THORN" : '\u00DE', - "thorn" : '\u00FE', - "tilde" : '\u02DC', - "times" : '\u00D7', - "trade" : '\u2122', - "Uacute" : '\u00DA', - "uacute" : '\u00FA', - "uArr" : '\u21D1', - "uarr" : '\u2191', - "Ucirc" : '\u00DB', - "ucirc" : '\u00FB', - "Ugrave" : '\u00D9', - "ugrave" : '\u00F9', - "uml" : '\u00A8', - "upsih" : '\u03D2', - "Upsilon" : '\u03A5', - "upsilon" : '\u03C5', - "Uuml" : '\u00DC', - "uuml" : '\u00FC', - "weierp" : '\u2118', - "Xi" : '\u039E', - "xi" : '\u03BE', - "Yacute" : '\u00DD', - "yacute" : '\u00FD', - "yen" : '\u00A5', - "Yuml" : '\u0178', - "yuml" : '\u00FF', - "Zeta" : '\u0396', - "zeta" : '\u03B6', - "zwj" : '\u200D', - "zwnj" : '\u200C' - ]; -} - -/++ - Converts a named HTML entity into its equivalent Unicode codepoint. - Returns 0xFFFF if entity doesn't exist. -+/ -dchar entity2Unicode(char[] entity) -{ - auto d = entity in entities_table; - if (d) - return *d; - return 0xFFFF; -} \ No newline at end of file
--- a/trunk/src/Identifier.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Identifier; -import Token; - -struct Identifier -{ - TOK type; - string str; - - static Identifier opCall(TOK type, string str) - { - Identifier i; - i.type = type; - i.str = str; - return i; - } - - uint toHash() - { - uint hash; - foreach(c; str) { - hash *= 9; - hash += c; - } - return hash; - } -}
--- a/trunk/src/Information.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Information; -import Messages; -import std.stdarg; - -enum InfoType -{ - Lexer, - Parser, - Semantic -} - -class Information -{ - MID id; - InfoType type; - uint loc; - string[] arguments; - - this(InfoType type, MID id, uint loc, string[] arguments) - { - this.id = id; - this.type = type; - this.loc = loc; - this.arguments = arguments; - } - - string getMsg() - { - return format_args(GetMsg(id), arguments); - } -}
--- a/trunk/src/Keywords.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Keywords; -import Token; -import Identifier; - -static const Identifier[] keywords = [ - {TOK.Abstract, "abstract"}, - {TOK.Alias, "alias"}, - {TOK.Align, "align"}, - {TOK.Asm, "asm"}, - {TOK.Assert, "assert"}, - {TOK.Auto, "auto"}, - {TOK.Body, "body"}, - {TOK.Bool, "bool"}, - {TOK.Break, "break"}, - {TOK.Byte, "byte"}, - {TOK.Case, "case"}, - {TOK.Cast, "cast"}, - {TOK.Catch, "catch"}, - {TOK.Cdouble, "cdouble"}, - {TOK.Cent, "cent"}, - {TOK.Cfloat, "cfloat"}, - {TOK.Char, "char"}, - {TOK.Class, "class"}, - {TOK.Const, "const"}, - {TOK.Continue, "continue"}, - {TOK.Creal, "creal"}, - {TOK.Dchar, "dchar"}, - {TOK.Debug, "debug"}, - {TOK.Default, "default"}, - {TOK.Delegate, "delegate"}, - {TOK.Delete, "delete"}, - {TOK.Deprecated, "deprecated"}, - {TOK.Do, "do"}, - {TOK.Double, "double"}, - {TOK.Else, "else"}, - {TOK.Enum, "enum"}, - {TOK.Export, "export"}, - {TOK.Extern, "extern"}, - {TOK.False, "false"}, - {TOK.Final, "final"}, - {TOK.Finally, "finally"}, - {TOK.Float, "float"}, - {TOK.For, "for"}, - {TOK.Foreach, "foreach"}, - {TOK.Foreach_reverse, "foreach_reverse"}, - {TOK.Function, "function"}, - {TOK.Goto, "goto"}, - {TOK.Idouble, "idouble"}, - {TOK.If, "if"}, - {TOK.Ifloat, "ifloat"}, - {TOK.Import, "import"}, - {TOK.In, "in"}, - {TOK.Inout, "inout"}, - {TOK.Int, "int"}, - {TOK.Interface, "interface"}, - {TOK.Invariant, "invariant"}, - {TOK.Ireal, "ireal"}, - {TOK.Is, "is"}, - {TOK.Lazy, "lazy"}, - {TOK.Long, "long"}, - {TOK.Macro, "macro"}, // D2.0 - {TOK.Mixin, "mixin"}, - {TOK.Module, "module"}, - {TOK.New, "new"}, - {TOK.Null, "null"}, - {TOK.Out, "out"}, - {TOK.Override, "override"}, - {TOK.Package, "package"}, - {TOK.Pragma, "pragma"}, - {TOK.Private, "private"}, - {TOK.Protected, "protected"}, - {TOK.Public, "public"}, - {TOK.Real, "real"}, - {TOK.Ref, "ref"}, - {TOK.Return, "return"}, - {TOK.Scope, "scope"}, - {TOK.Short, "short"}, - {TOK.Static, "static"}, - {TOK.Struct, "struct"}, - {TOK.Super, "super"}, - {TOK.Switch, "switch"}, - {TOK.Synchronized, "synchronized"}, - {TOK.Template, "template"}, - {TOK.This, "this"}, - {TOK.Throw, "throw"}, - {TOK.Traits, "__traits"}, // D2.0 - {TOK.True, "true"}, - {TOK.Try, "try"}, - {TOK.Typedef, "typedef"}, - {TOK.Typeid, "typeid"}, - {TOK.Typeof, "typeof"}, - {TOK.Ubyte, "ubyte"}, - {TOK.Ucent, "ucent"}, - {TOK.Uint, "uint"}, - {TOK.Ulong, "ulong"}, - {TOK.Union, "union"}, - {TOK.Unittest, "unittest"}, - {TOK.Ushort, "ushort"}, - {TOK.Version, "version"}, - {TOK.Void, "void"}, - {TOK.Volatile, "volatile"}, - {TOK.Wchar, "wchar"}, - {TOK.While, "while"}, - {TOK.With, "with"}, - // Special tokens: - {TOK.Special, "__FILE__"}, - {TOK.Special, "__LINE__"}, - {TOK.Special, "__DATE__"}, - {TOK.Special, "__TIME__"}, - {TOK.Special, "__TIMESTAMP__"}, - {TOK.Special, "__VENDOR__"}, - {TOK.Special, "__VERSION__"}, -];
--- a/trunk/src/Lexer.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1773 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Lexer; -import Token; -import Information; -import Keywords; -import Identifier; -import Messages; -import HtmlEntities; -import std.stdio; -import std.utf; -import std.uni; -import std.c.stdlib; -import std.string; - -const char[3] LS = \u2028; -const char[3] PS = \u2029; - -const dchar LSd = 0x2028; -const dchar PSd = 0x2029; - -const uint _Z_ = 26; /// Control+Z - -class Lexer -{ - Token* head; /// The head of the doubly linked token list. - Token* token; /// Points to the current token in the token list. - string text; - char* p; /// Points to the current character in the source text. - char* end; /// Points one character past the end of the source text. - - uint loc = 1; /// line of code - - char[] fileName; - - Information[] errors; - -// bool reportErrors; - - Identifier[string] idtable; - - this(string text, string fileName) - { - this.fileName = fileName; - - this.text = text; - if (text[$-1] != 0) - { - this.text.length = this.text.length + 1; - this.text[$-1] = 0; - } - - this.p = this.text.ptr; - this.end = this.p + this.text.length; -// this.reportErrors = true; - loadKeywords(); - - this.head = new Token; - this.head.type = TOK.HEAD; - this.token = this.head; - scanShebang(); - } - - void scanShebang() - { - if (*p == '#' && p[1] == '!') - { - Token* t = new Token; - t.start = p; - t.type = TOK.Shebang; - ++p; - while (1) - { - switch (*++p) - { - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - ++loc; - if (p[-1] == '\r') - t.end = p-1; - else - t.end = p; - break; - case LS[0]: - t.end = p; - if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) - { - ++p; ++p; - ++loc; - } - break; - case 0, _Z_: - t.end = p; - break; - default: - continue; - } - break; // Exit loop. - } - this.head.next = t; - t.prev = this.head; - } - } - - public void scan(out Token t) - in - { - assert(text.ptr <= p && p < end); - } - out - { - assert(text.ptr <= t.start && t.start < end); - assert(text.ptr < t.end && t.end <= end, std.string.format(t.type)); - } - body - { - uint c = *p; - - while (1) - { - t.start = p; - - if (c == 0 || c == _Z_) - { - assert(*p == 0 || *p == _Z_); - t.type = TOK.EOF; - t.end = p; - assert(t.start == t.end); - return; - } - - if (c == '\n') - { - c = *++p; - ++loc; - continue; - } - else if (c == '\r') - { - c = *++p; - if (c != '\n') - ++loc; - continue; - } - else if (c == LS[0] && p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) - { - p += 3; - c = *p; - continue; - } - - if (isidbeg(c)) - { - if (c == 'r' && p[1] == '"' && ++p) - return scanRawStringLiteral(t); - if (c == 'x' && p[1] == '"') - return scanHexStringLiteral(t); - Lidentifier: - do - { c = *++p; } - while (isident(c) || c & 128 && isUniAlpha(decodeUTF8())) - - t.end = p; - - string str = t.srcText; - Identifier* id = str in idtable; - - if (!id) - { - idtable[str] = Identifier.Identifier(TOK.Identifier, str); - id = str in idtable; - } - assert(id); - t.type = id.type; - return; - } - - if (isdigit(c)) - return scanNumber(t); - - if (c == '/') - { - c = *++p; - switch(c) - { - case '=': - ++p; - t.type = TOK.DivAssign; - t.end = p; - return; - case '+': - uint level = 1; - while (1) - { - c = *++p; - LswitchNC: // only jumped to from default case of next switch(c) - switch (c) - { - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - ++loc; - continue; - case 0, _Z_: - error(MID.UnterminatedNestedComment); - goto LreturnNC; - default: - } - - c <<= 8; - c |= *++p; - switch (c) - { - case 0x2F2B: // /+ - ++level; - continue; - case 0x2B2F: // +/ - if (--level == 0) - { - ++p; - LreturnNC: - t.type = TOK.Comment; - t.end = p; - return; - } - continue; - case 0xE280: // LS[0..1] || PS[0..1] - if (p[1] == LS[2] || p[1] == PS[2]) - { - ++loc; - ++p; - } - continue; - default: - c &= char.max; - goto LswitchNC; - } - } - case '*': - while (1) - { - c = *++p; - LswitchBC: // only jumped to from default case of next switch(c) - switch (c) - { - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - ++loc; - continue; - case 0, _Z_: - error(MID.UnterminatedBlockComment); - goto LreturnBC; - default: - } - - c <<= 8; - c |= *++p; - switch (c) - { - case 0x2A2F: // */ - ++p; - LreturnBC: - t.type = TOK.Comment; - t.end = p; - return; - case 0xE280: // LS[0..1] || PS[0..1] - if (p[1] == LS[2] || p[1] == PS[2]) - { - ++loc; - ++p; - } - continue; - default: - c &= char.max; - goto LswitchBC; - } - } - assert(0); - case '/': - while (1) - { - c = *++p; - switch (c) - { - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - case 0, _Z_: - break; - case LS[0]: - if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) - break; - continue; - default: - continue; - } - t.type = TOK.Comment; - t.end = p; - return; - } - default: - t.type = TOK.Div; - t.end = p; - return; - } - } - - switch (c) - { - case '\'': - return scanCharacterLiteral(t); - case '`': - return scanRawStringLiteral(t); - case '"': - return scanNormalStringLiteral(t); - case '\\': - char[] buffer; - do - { - ++p; - c = scanEscapeSequence(); - if (c < 128) - buffer ~= c; - else - encodeUTF8(buffer, c); - } while (*p == '\\') - buffer ~= 0; - t.type = TOK.String; - t.str = buffer; - t.end = p; - return; - case '>': /* > >= >> >>= >>> >>>= */ - c = *++p; - switch (c) - { - case '=': - t.type = TOK.GreaterEqual; - goto Lcommon; - case '>': - if (p[1] == '>') - { - ++p; - if (p[1] == '=') - { ++p; - t.type = TOK.URShiftAssign; - } - else - t.type = TOK.URShift; - } - else if (p[1] == '=') - { - ++p; - t.type = TOK.RShiftAssign; - } - else - t.type = TOK.RShift; - goto Lcommon; - default: - t.type = TOK.Greater; - goto Lcommon2; - } - assert(0); - case '<': /* < <= <> <>= << <<= */ - c = *++p; - switch (c) - { - case '=': - t.type = TOK.LessEqual; - goto Lcommon; - case '<': - if (p[1] == '=') { - ++p; - t.type = TOK.LShiftAssign; - } - else - t.type = TOK.LShift; - goto Lcommon; - case '>': - if (p[1] == '=') { - ++p; - t.type = TOK.LorEorG; - } - else - t.type = TOK.LorG; - goto Lcommon; - default: - t.type = TOK.Less; - goto Lcommon2; - } - assert(0); - case '!': /* ! !< !> !<= !>= !<> !<>= */ - c = *++p; - switch (c) - { - case '<': - c = *++p; - if (c == '>') - { - if (p[1] == '=') { - ++p; - t.type = TOK.Unordered; - } - else - t.type = TOK.UorE; - } - else if (c == '=') - { - t.type = TOK.UorG; - } - else { - t.type = TOK.UorGorE; - goto Lcommon2; - } - goto Lcommon; - case '>': - if (p[1] == '=') - { - ++p; - t.type = TOK.UorL; - } - else - t.type = TOK.UorLorE; - goto Lcommon; - case '=': - t.type = TOK.NotEqual; - goto Lcommon; - default: - t.type = TOK.Not; - goto Lcommon2; - } - assert(0); - case '.': /* . .[0-9] .. ... */ - if (p[1] == '.') - { - ++p; - if (p[1] == '.') { - ++p; - t.type = TOK.Ellipses; - } - else - t.type = TOK.Slice; - } - else if (isdigit(p[1])) - { - return scanReal(t); - } - else - t.type = TOK.Dot; - goto Lcommon; - case '|': /* | || |= */ - c = *++p; - if (c == '=') - t.type = TOK.OrAssign; - else if (c == '|') - t.type = TOK.OrLogical; - else { - t.type = TOK.OrBinary; - goto Lcommon2; - } - goto Lcommon; - case '&': /* & && &= */ - c = *++p; - if (c == '=') - t.type = TOK.AndAssign; - else if (c == '&') - t.type = TOK.AndLogical; - else { - t.type = TOK.AndBinary; - goto Lcommon2; - } - goto Lcommon; - case '+': /* + ++ += */ - c = *++p; - if (c == '=') - t.type = TOK.PlusAssign; - else if (c == '+') - t.type = TOK.PlusPlus; - else { - t.type = TOK.Plus; - goto Lcommon2; - } - goto Lcommon; - case '-': /* - -- -= */ - c = *++p; - if (c == '=') - t.type = TOK.MinusAssign; - else if (c == '-') - t.type = TOK.MinusMinus; - else { - t.type = TOK.Minus; - goto Lcommon2; - } - goto Lcommon; - case '=': /* = == */ - if (p[1] == '=') { - ++p; - t.type = TOK.Equal; - } - else - t.type = TOK.Assign; - goto Lcommon; - case '~': /* ~ ~= */ - if (p[1] == '=') { - ++p; - t.type = TOK.CatAssign; - } - else - t.type = TOK.Tilde; - goto Lcommon; - case '*': /* * *= */ - if (p[1] == '=') { - ++p; - t.type = TOK.MulAssign; - } - else - t.type = TOK.Mul; - goto Lcommon; - case '^': /* ^ ^= */ - if (p[1] == '=') { - ++p; - t.type = TOK.XorAssign; - } - else - t.type = TOK.Xor; - goto Lcommon; - case '%': /* % %= */ - if (p[1] == '=') { - ++p; - t.type = TOK.ModAssign; - } - else - t.type = TOK.Mod; - goto Lcommon; - // Single character tokens: - case '(': - t.type = TOK.LParen; - goto Lcommon; - case ')': - t.type = TOK.RParen; - goto Lcommon; - case '[': - t.type = TOK.LBracket; - goto Lcommon; - case ']': - t.type = TOK.RBracket; - goto Lcommon; - case '{': - t.type = TOK.LBrace; - goto Lcommon; - case '}': - t.type = TOK.RBrace; - goto Lcommon; - case ':': - t.type = TOK.Colon; - goto Lcommon; - case ';': - t.type = TOK.Semicolon; - goto Lcommon; - case '?': - t.type = TOK.Question; - goto Lcommon; - case ',': - t.type = TOK.Comma; - goto Lcommon; - case '$': - t.type = TOK.Dollar; - Lcommon: - ++p; - Lcommon2: - t.end = p; - return; - case '#': - return scanSpecialToken(t); - default: - } - - if (c & 128 && isUniAlpha(decodeUTF8())) - goto Lidentifier; - c = *++p; - } - } - - void scanNormalStringLiteral(ref Token t) - { - assert(*p == '"'); - ++p; - char[] buffer; - t.type = TOK.String; - while (1) - { - switch (*p) - { - case '"': - ++p; - Lreturn: - buffer ~= 0; - t.str = buffer; - t.pf = scanPostfix(); - t.end = p; - return; - case '\\': - ++p; - dchar d = scanEscapeSequence(); - if (d < 128) - buffer ~= d; - else - encodeUTF8(buffer, d); - continue; - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - ++p; - ++loc; - buffer ~= '\n'; // Convert EndOfLine to \n. - continue; - case 0, _Z_: - error(MID.UnterminatedString); - goto Lreturn; - default: - if (*p & 128) - { -// char* begin = p; - dchar d = decodeUTF8(); - if (d == LSd || d == PSd) - goto case '\n'; - - // We don't copy per pointer because we might include - // invalid, skipped utf-8 sequences. See decodeUTF8(). -// ++p; -// buffer ~= begin[0 .. p - begin]; - ++p; - encodeUTF8(buffer, d); - continue; - } - // Copy ASCII character. - buffer ~= *p++; - } - } - assert(0); - } - - void scanCharacterLiteral(ref Token t) - { - assert(*p == '\''); - MID id = MID.UnterminatedCharacterLiteral; - ++p; - TOK type = TOK.CharLiteral; - switch (*p) - { - case '\\': - ++p; - switch (*p) - { - case 'u': - type = TOK.WCharLiteral; break; - case 'U': - type = TOK.DCharLiteral; break; - default: - } - t.dchar_ = scanEscapeSequence(); - break; - case '\'': - ++p; - id = MID.EmptyCharacterLiteral; - case '\n', '\r', 0, _Z_: - goto Lerr; - default: - uint c = *p; - if (c & 128) - { - c = decodeUTF8(); - if (c == LSd || c == PSd) - goto Lerr; - if (c <= 0xFFFF) - type = TOK.WCharLiteral; - else - type = TOK.DCharLiteral; - } - t.dchar_ = c; - ++p; - } - - if (*p == '\'') - ++p; - else - Lerr: - error(id); - t.type = type; - t.end = p; - } - - char scanPostfix() - { - switch (*p) - { - case 'c': - case 'w': - case 'd': - return *p++; - default: - return 0; - } - assert(0); - } - - void scanRawStringLiteral(ref Token t) - { - uint delim = *p; - assert(delim == '`' || delim == '"' && p[-1] == 'r'); - t.type = TOK.String; - char[] buffer; - uint c; - while (1) - { - c = *++p; - switch (c) - { - case '\r': - if (p[1] == '\n') - ++p; - c = '\n'; // Convert '\r' and '\r\n' to '\n' - case '\n': - ++loc; - break; - case '`': - case '"': - if (c == delim) - { - ++p; - t.pf = scanPostfix(); - Lreturn: - t.str = buffer ~ '\0'; - t.end = p; - return; - } - break; - case LS[0]: - if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) - { - c = '\n'; - ++p; ++p; - ++loc; - } - break; - case 0, _Z_: - if (delim == 'r') - error(MID.UnterminatedRawString); - else - error(MID.UnterminatedBackQuoteString); - goto Lreturn; - default: - } - buffer ~= c; // copy character to buffer - } - assert(0); - } - - void scanHexStringLiteral(ref Token t) - { - assert(p[0] == 'x' && p[1] == '"'); - t.type = TOK.String; - - uint c; - ubyte[] buffer; - ubyte h; // hex number - uint n; // number of hex digits - - ++p; - while (1) - { - c = *++p; - switch (c) - { - case '"': - ++p; - if (n & 1) - error(MID.OddNumberOfDigitsInHexString); - t.pf = scanPostfix(); - Lreturn: - buffer ~= 0; - t.str = cast(string) buffer; - t.end = p; - return; - case '\r': - if (p[1] == '\n') - ++p; - case '\n': - ++loc; - continue; - default: - if (ishexad(c)) - { - if (c <= '9') - c -= '0'; - else if (c <= 'F') - c -= 'A' - 10; - else - c -= 'a' - 10; - - if (n & 1) - { - h <<= 4; - h |= c; - buffer ~= h; - } - else - h = cast(ubyte)c; - ++n; - continue; - } - else if (isspace(c)) - continue; - - if (c >= 128) - { - c = decodeUTF8(); - if (c == LSd || c == PSd) - { - ++p; ++p; - ++loc; - continue; - } - } - else if (c == 0 || c == _Z_) - { - error(MID.UnterminatedHexString); - t.pf = 0; - goto Lreturn; - } - error(MID.NonHexCharInHexString, cast(dchar)c); - } - } - assert(0); - } - - dchar scanEscapeSequence() - { - uint c = char2ev(*p); - if (c) - { - ++p; - return c; - } - uint digits = 2; - - switch (*p) - { - case 'x': - c = 0; - while (1) - { - ++p; - if (ishexad(*p)) - { - c *= 16; - if (*p <= '9') - c += *p - '0'; - else if (*p <= 'F') - c += *p - 'A' + 10; - else - c += *p - 'a' + 10; - - if (!--digits) - { - ++p; - break; - } - } - else - { - error(MID.InsufficientHexDigits); - break; - } - } - if (!isValidDchar(c)) - error(MID.InvalidUnicodeCharacter); - break; - case 'u': - digits = 4; - goto case 'x'; - case 'U': - digits = 8; - goto case 'x'; - default: - if (isoctal(*p)) - { - c = 0; - c += *p - '0'; - ++p; - if (!isoctal(*p)) - return c; - c *= 8; - c += *p - '0'; - ++p; - if (!isoctal(*p)) - return c; - c *= 8; - c += *p - '0'; - ++p; - } - else if(*p == '&') - { - if (isalpha(*++p)) - { - auto begin = p; - while (isalnum(*++p)) - {} - - if (*p == ';') - { - c = entity2Unicode(begin[0..p - begin]); - ++p; - if (c == 0xFFFF) - error(MID.UndefinedHTMLEntity, (begin-1)[0..p-(begin-1)]); - } - else - error(MID.UnterminatedHTMLEntity); - } - else - error(MID.InvalidBeginHTMLEntity); - } - else - error(MID.UndefinedEscapeSequence); - } - - return c; - } - - /* - IntegerLiteral:= (Dec|Hex|Bin|Oct)Suffix? - Dec:= (0|[1-9][0-9_]*) - Hex:= 0[xX] HexDigits - Bin:= 0[bB][01_]+ - Oct:= 0[0-7_]+ - Suffix:= (L[uU]?|[uU]L?) - HexDigits:= [0-9a-zA-Z_]+ - - Invalid: "0b_", "0x_", "._" - */ - void scanNumber(ref Token t) - { - ulong ulong_; - bool overflow; - bool isDecimal; - size_t digits; - - if (*p != '0') - goto LscanInteger; - ++p; // skip zero - // check for xX bB ... - switch (*p) - { - case 'x','X': - goto LscanHex; - case 'b','B': - goto LscanBin; - case 'L': - if (p[1] == 'i') - goto LscanReal; - case '.': - if (p[1] == '.') - break; - case 'i','f','F', 'e', 'E': // Imaginary and float literal suffix - goto LscanReal; - default: - if (*p == '_' || isoctal(*p)) - goto LscanOct; - } - - // Number 0 - assert(p[-1] == '0'); - assert(ulong_ == 0); - isDecimal = true; - goto Lfinalize; - - LscanInteger: - assert(*p != 0 && isdigit(*p)); - isDecimal = true; - goto Lenter_loop_int; - while (1) - { - if (*++p == '_') - continue; - if (!isdigit(*p)) - break; - Lenter_loop_int: - if (ulong_ < ulong.max/10 || (ulong_ == ulong.max/10 && *p <= '5')) - { - ulong_ *= 10; - ulong_ += *p - '0'; - continue; - } - // Overflow: skip following digits. - overflow = true; - while (isdigit(*++p)) {} - break; - } - - // The number could be a float, so check overflow below. - switch (*p) - { - case '.': - if (p[1] != '.') - goto LscanReal; - break; - case 'L': - if (p[1] != 'i') - break; - case 'i', 'f', 'F', 'e', 'E': - goto LscanReal; - default: - } - - if (overflow) - error(MID.OverflowDecimalNumber); - - assert((isdigit(p[-1]) || p[-1] == '_') && !isdigit(*p) && *p != '_'); - goto Lfinalize; - - LscanHex: - assert(digits == 0); - assert(*p == 'x'); - while (1) - { - if (*++p == '_') - continue; - if (!ishexad(*p)) - break; - ++digits; - ulong_ *= 16; - if (*p <= '9') - ulong_ += *p - '0'; - else if (*p <= 'F') - ulong_ += *p - 'A' + 10; - else - ulong_ += *p - 'a' + 10; - } - - switch (*p) - { - case '.': - if (p[1] != '.') - goto LscanHexReal; - break; - case 'L': - if (p[1] != 'i') - break; - case 'i', 'p', 'P': - goto LscanHexReal; - default: - } - if (digits == 0) - error(MID.NoDigitsInHexNumber); - else if (digits > 16) - { - // Overflow: skip following digits. - error(MID.OverflowHexNumber); - while (ishexad(*++p)) {} - } - goto Lfinalize; - LscanHexReal: - return scanHexReal(t); - - LscanBin: - assert(digits == 0); - assert(*p == 'b'); - while (1) - { - if (*++p == '0') - { - ++digits; - ulong_ *= 2; - } - if (*p == '1') - { - ++digits; - ulong_ *= 2; - ulong_ += *p - '0'; - } - if (*p == '_') - continue; - break; - } - - if (digits == 0) - error(MID.NoDigitsInBinNumber); - - if (digits > 64) - error(MID.OverflowBinaryNumber); - assert((p[-1] == '0' || p[-1] == '1' || p[-1] == '_') && !(*p == '0' || *p == '1' || *p == '_')); - goto Lfinalize; - - LscanOct: - assert(*p == '_' || isoctal(*p)); - if (*p != '_') - goto Lenter_loop_oct; - while (1) - { - if (*++p == '_') - continue; - if (!isoctal(*p)) - break; - Lenter_loop_oct: - if (ulong_ < ulong.max/2 || (ulong_ == ulong.max/2 && *p <= '1')) - { - ulong_ *= 8; - ulong_ += *p - '0'; - ++p; - continue; - } - // Overflow: skip following digits. - overflow = true; - while (isdigit(*++p)) {} - break; - } - - bool hasDecimalDigits; - if (isdigit(*p)) - { - hasDecimalDigits = true; - while (isdigit(*++p)) {} - } - - // The number could be a float, so check errors below. - switch (*p) - { - case '.': - if (p[1] != '.') - goto LscanReal; - break; - case 'L': - if (p[1] != 'i') - break; - case 'i', 'f', 'F', 'e', 'E': - goto LscanReal; - default: - } - - if (hasDecimalDigits) - error(MID.OctalNumberHasDecimals); - if (overflow) - error(MID.OverflowOctalNumber); -// goto Lfinalize; - - Lfinalize: - enum Suffix - { - None = 0, - Unsigned = 1, - Long = 2 - } - - Suffix suffix; - while (1) - { - switch (*p) - { - case 'L': - if (suffix & Suffix.Long) - break; - suffix |= Suffix.Long; - ++p; - continue; - case 'u', 'U': - if (suffix & Suffix.Unsigned) - break; - suffix |= Suffix.Unsigned; - ++p; - continue; - default: - break; - } - break; - } - - switch (suffix) - { - case Suffix.None: - if (ulong_ & 0x8000000000000000) - { - if (isDecimal) - error(MID.OverflowDecimalSign); - t.type = TOK.Uint64; - } - else if (ulong_ & 0xFFFFFFFF00000000) - t.type = TOK.Int64; - else if (ulong_ & 0x80000000) - t.type = isDecimal ? TOK.Int64 : TOK.Uint32; - else - t.type = TOK.Int32; - break; - case Suffix.Unsigned: - if (ulong_ & 0xFFFFFFFF00000000) - t.type = TOK.Uint64; - else - t.type = TOK.Uint32; - break; - case Suffix.Long: - if (ulong_ & 0x8000000000000000) - { - if (isDecimal) - error(MID.OverflowDecimalSign); - t.type = TOK.Uint64; - } - else - t.type = TOK.Int64; - break; - case Suffix.Unsigned | Suffix.Long: - t.type = TOK.Uint64; - break; - default: - assert(0); - } - t.ulong_ = ulong_; - t.end = p; - return; - LscanReal: - scanReal(t); - return; - } - - /* - FloatLiteral:= Float[fFL]?i? - Float:= DecFloat | HexFloat - DecFloat:= ([0-9][0-9_]*[.][0-9_]*DecExponent?) | [.][0-9][0-9_]*DecExponent? | [0-9][0-9_]*DecExponent - DecExponent:= [eE][+-]?[0-9][0-9_]* - HexFloat:= 0[xX](HexDigits[.]HexDigits | [.][0-9a-zA-Z]HexDigits? | HexDigits)HexExponent - HexExponent:= [pP][+-]?[0-9][0-9_]* - */ - void scanReal(ref Token t) - { - if (*p == '.') - // This function was called by scan() or scanNumber(). - while (isdigit(*++p) || *p == '_') {} - else - { - // This function was called by scanNumber(). - debug switch (*p) - { - case 'L': - if (p[1] != 'i') - assert(0); - case 'i', 'f', 'F', 'e', 'E': break; - default: assert(0); - } - } - - // Scan exponent. - if (*p == 'e' || *p == 'E') - { - ++p; - if (*p == '-' || *p == '+') - ++p; - if (!isdigit(*p)) - error(MID.FloatExponentDigitExpected); - else - while (isdigit(*++p) || *p == '_') {} - } - - // Copy string to buffer ignoring underscores. - char[] buffer; - char* end = p; - p = t.start; - do - { - if (*p == '_') - { - ++p; - continue; - } - buffer ~= *p; - ++p; - } while (p != end) - buffer ~= 0; - finalizeFloat(t, buffer); - } - - void scanHexReal(ref Token t) - { - assert(*p == '.' || *p == 'i' || *p == 'p' || *p == 'P' || (*p == 'L' && p[1] == 'i')); - MID mid; - if (*p == '.') - while (ishexad(*++p) || *p == '_') {} - if (*p != 'p' && *p != 'P') - { - mid = MID.HexFloatExponentRequired; - goto Lerr; - } - // Copy mantissa to a buffer ignoring underscores. - char* end = p; - p = t.start; - char[] buffer; - do - { - if (*p == '_') - { - ++p; - continue; - } - buffer ~= *p; - ++p; - } while (p != end) - - assert(p == end && (*p == 'p' || *p == 'P')); - // Scan and copy the exponent. - buffer ~= 'p'; - size_t bufflen = buffer.length; - while (1) - { - if (*++p == '_') - continue; - if (isdigit(*p)) - buffer ~= *p; - else - break; - } - // When the buffer length hasn't changed, no digits were copied. - if (bufflen == buffer.length) { - mid = MID.HexFloatMissingExpDigits; - goto Lerr; - } - buffer ~= 0; // Terminate for C functions. - finalizeFloat(t, buffer); - return; - Lerr: - t.type = TOK.Float32; - t.end = p; - error(mid); - } - - void finalizeFloat(ref Token t, string buffer) - { - // Float number is well-formed. Check suffixes and do conversion. - switch (*p) - { - case 'f', 'F': - t.type = TOK.Float32; - t.float_ = strtof(buffer.ptr, null); - ++p; - break; - case 'L': - t.type = TOK.Float80; - t.real_ = strtold(buffer.ptr, null); - ++p; - break; - default: - t.type = TOK.Float64; - t.double_ = strtod(buffer.ptr, null); - break; - } - if (*p == 'i') - { - ++p; - t.type += 3; // Switch to imaginary counterpart. - } - if (getErrno == ERANGE) - error(MID.OverflowFloatNumber); - t.end = p; - } - - /// Scan special token: #line Integer [Filespec] EndOfLine - void scanSpecialToken(ref Token t) - { - assert(*p == '#'); - - t.type = TOK.HashLine; - - MID mid; - - ++p; - if (p[0] != 'l' || p[1] != 'i' || p[2] != 'n' || p[3] != 'e') - { - mid = MID.ExpectedNumberAfterSTLine; - goto Lerr; - } - p += 3; - - enum State - { Number, Filespec, End } - - State state; - - Loop: - while (1) - { - switch (*++p) - { - case '\r': - if (p[1] == '\n') - ++p; - case '\n', 0, _Z_: - break Loop; - case LS[0]: - if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) - { - ++p; ++p; - break Loop; - } - goto default; - default: - if (isspace(*p)) - continue; - if (state == State.Number) - { - if (!isdigit(*p)) - { - mid = MID.ExpectedNumberAfterSTLine; - goto Lerr; - } - t.line_num = new Token; - scan(*t.line_num); - --p; - state = State.Filespec; - } - else if (state == State.Filespec) - { - if (*p != '"') - { - mid = MID.ExpectedFilespec; - goto Lerr; - } - t.line_filespec = new Token; - t.line_filespec.start = p; - t.line_filespec.type = TOK.Filespec; - while (1) - { - switch (*++p) - { - case '"': - break; - case LS[0]: - if (!(p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2]))) - goto default; - case '\r', '\n', 0, _Z_: - mid = MID.UnterminatedFilespec; - t.line_filespec.end = p; - goto Lerr; - default: - if (*p & 128) - decodeUTF8(); - continue; - } - break; // Exit loop. - } - auto start = t.line_filespec.start +1; // +1 skips '"' - t.line_filespec.str = start[0 .. p - start]; - t.line_filespec.end = p + 1; - state = State.End; - } - else/+ if (state == State.End)+/ - { - mid = MID.UnterminatedSpecialToken; - goto Lerr; - } - } - } - - if (state == State.Number) - { - mid = MID.ExpectedNumberAfterSTLine; - goto Lerr; - } - - this.loc = t.line_num.uint_ - 1; - if (t.line_filespec) - this.fileName = t.line_filespec.str; - t.end = p; - - return; - Lerr: - t.end = p; - error(mid); - } - - dchar decodeUTF8() - { - assert(*p & 128, "check for ASCII char before calling decodeUTF8()."); - size_t idx; - dchar d; - try - { - d = std.utf.decode(p[0 .. end-p], idx); - p += idx -1; - } - catch (UtfException e) - { - error(MID.InvalidUTF8Sequence); - // Skip to next valid utf-8 sequence - while (UTF8stride[*++p] != 0xFF) {} - --p; - } - return d; - } - - void loadKeywords() - { - foreach(k; keywords) - idtable[k.str] = k; - } -/+ - struct State - { - Lexer lexer; - Token token; - char* scanPointer; - int loc; - string fileName; - size_t errorLen; - static State opCall(Lexer lx) - { - State s; - s.lexer = lx; - s.token = lx.token; - s.scanPointer = lx.p; - s.loc = lx.loc; - s.fileName = lx.fileName; - s.errorLen = lx.errors.length; - return s; - } - void restore() - { - lexer.p = scanPointer; - lexer.token = token; - lexer.loc = loc; - lexer.fileName = fileName; - lexer.errors = lexer.errors[0..errorLen]; - } - } - - State getState() - { - return State(this); - } -+/ - - private void scanNext(ref Token* t) - { - assert(t !is null); - if (t.next) - t = t.next; - else if (t.type != TOK.EOF) - { - Token* new_t = new Token; - scan(*new_t); - new_t.prev = t; - t.next = new_t; - t = new_t; - } - } - - void peek(ref Token* t) - { - scanNext(t); - } - - TOK nextToken() - { - scanNext(this.token); - return this.token.type; - } - - void error(MID id, ...) - { -// if (reportErrors) - errors ~= new Information(InfoType.Lexer, id, loc, arguments(_arguments, _argptr)); - } - - unittest - { - string sourceText = "unittest { }"; - auto lx = new Lexer(sourceText, null); - - Token next; - lx.peek(next); - assert(next == TOK.Unittest); - lx.peek(next); - assert(next == TOK.LBrace); - lx.peek(next); - assert(next == TOK.RBrace); - lx.peek(next); - assert(next == TOK.EOF); - writefln("end of peek() unittest"); - } - - Token* getTokens() - { - while (nextToken() != TOK.EOF) - {} - return head; - } - - private void encodeUTF8(inout char[] str, dchar d) - { - char[6] b; - assert(d > 0x7F, "check for ASCII char before calling encodeUTF8()."); - if (d < 0x800) - { - b[0] = 0xC0 | (d >> 6); - b[1] = 0x80 | (d & 0x3F); - str ~= b[0..2]; - } - else if (d < 0x10000) - { - b[0] = 0xE0 | (d >> 12); - b[1] = 0x80 | ((d >> 6) & 0x3F); - b[2] = 0x80 | (d & 0x3F); - str ~= b[0..3]; - } - else if (d < 0x200000) - { - b[0] = 0xF0 | (d >> 18); - b[1] = 0x80 | ((d >> 12) & 0x3F); - b[2] = 0x80 | ((d >> 6) & 0x3F); - b[3] = 0x80 | (d & 0x3F); - str ~= b[0..4]; - } - else if (d < 0x4000000) - { - b[0] = 0xF8 | (d >> 24); - b[1] = 0x80 | ((d >> 18) & 0x3F); - b[2] = 0x80 | ((d >> 12) & 0x3F); - b[3] = 0x80 | ((d >> 6) & 0x3F); - b[4] = 0x80 | (d & 0x3F); - str ~= b[0..5]; - } - else if (d < 0x80000000) - { - b[0] = 0xFC | (d >> 30); - b[1] = 0x80 | ((d >> 24) & 0x3F); - b[2] = 0x80 | ((d >> 18) & 0x3F); - b[3] = 0x80 | ((d >> 12) & 0x3F); - b[4] = 0x80 | ((d >> 6) & 0x3F); - b[5] = 0x80 | (d & 0x3F); - str ~= b[0..6]; - } - else - error(MID.InvalidUnicodeCharacter); - } -} - -unittest -{ - string[] toks = [ - ">", ">=", ">>", ">>=", ">>>", ">>>=", "<", "<=", "<>", - "<>=", "<<", "<<=", "!", "!<", "!>", "!<=", "!>=", "!<>", - "!<>=", ".", "..", "...", "&", "&&", "&=", "+", "++", - "+=", "-", "--", "-=", "=", "==", "~", "~=", "*", - "*=", "/", "/=", "^", "^=", "%", "%=", "(", ")", - "[", "]", "{", "}", ":", ";", "?", ",", "$" - ]; - - char[] src; - - foreach (op; toks) - src ~= op ~ " "; - - auto lx = new Lexer(src, ""); - auto tokens = lx.getTokens(); - - tokens = tokens[0..$-1]; // exclude TOK.EOF - - assert(tokens.length == toks.length ); - - foreach (i, t; tokens) - assert(t.srcText == toks[i], std.string.format("Lexed '%s' but expected '%s'", t.srcText, toks[i])); -} - -unittest -{ - // Numbers unittest - // 0L 0ULi 0_L 0_UL 0x0U 0x0p2 0_Fi 0_e2 0_F 0_i - // 0u 0U 0uL 0UL 0L 0LU 0Lu - // 0Li 0f 0F 0fi 0Fi 0i - // 0b_1_LU 0b1000u - // 0x232Lu -} - -/// ASCII character properties table. -static const int ptable[256] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0,32,32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -32, 0, 0x2200, 0, 0, 0, 0, 0x2700, 0, 0, 0, 0, 0, 0, 0, 0, - 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 0, 0, 0, 0, 0, 0x3f00, - 0,12,12,12,12,12,12, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0x5c00, 0, 0,16, - 0, 0x70c, 0x80c,12,12,12, 0xc0c, 8, 8, 8, 8, 8, 8, 8, 0xa08, 8, - 8, 8, 0xd08, 8, 0x908, 8, 0xb08, 8, 8, 8, 8, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -]; - -enum CProperty -{ - Octal = 1, - Digit = 1<<1, - Hex = 1<<2, - Alpha = 1<<3, - Underscore = 1<<4, - Whitespace = 1<<5 -} - -const uint EVMask = 0xFF00; // Bit mask for escape value - -private alias CProperty CP; -int isoctal(char c) { return ptable[c] & CP.Octal; } -int isdigit(char c) { return ptable[c] & CP.Digit; } -int ishexad(char c) { return ptable[c] & CP.Hex; } -int isalpha(char c) { return ptable[c] & CP.Alpha; } -int isalnum(char c) { return ptable[c] & (CP.Alpha | CP.Digit); } -int isidbeg(char c) { return ptable[c] & (CP.Alpha | CP.Underscore); } -int isident(char c) { return ptable[c] & (CP.Alpha | CP.Underscore | CP.Digit); } -int isspace(char c) { return ptable[c] & CP.Whitespace; } -int char2ev(char c) { return ptable[c] >> 8; /*(ptable[c] & EVMask) >> 8;*/ } - -version(gen_ptable) -static this() -{ - alias ptable p; - // Initialize character properties table. - for (int i; i < p.length; ++i) - { - p[i] = 0; - if ('0' <= i && i <= '7') - p[i] |= CP.Octal; - if ('0' <= i && i <= '9') - p[i] |= CP.Digit; - if (isdigit(i) || 'a' <= i && i <= 'f' || 'A' <= i && i <= 'F') - p[i] |= CP.Hex; - if ('a' <= i && i <= 'z' || 'A' <= i && i <= 'Z') - p[i] |= CP.Alpha; - if (i == '_') - p[i] |= CP.Underscore; - if (i == ' ' || i == '\t' || i == '\v' || i == '\f') - p[i] |= CP.Whitespace; - } - // Store escape sequence values in second byte. - assert(CProperty.max <= ubyte.max, "character property flags and escape value byte overlap."); - p['\''] |= 39 << 8; - p['"'] |= 34 << 8; - p['?'] |= 63 << 8; - p['\\'] |= 92 << 8; - p['a'] |= 7 << 8; - p['b'] |= 8 << 8; - p['f'] |= 12 << 8; - p['n'] |= 10 << 8; - p['r'] |= 13 << 8; - p['t'] |= 9 << 8; - p['v'] |= 11 << 8; - // Print a formatted array literal. - char[] array = "[\n"; - for (int i; i < p.length; ++i) - { - int c = p[i]; - array ~= std.string.format(c>255?" 0x%x,":"%2d,", c, ((i+1) % 16) ? "":"\n"); - } - array[$-2..$] = "\n]"; - writefln(array); -}
--- a/trunk/src/Messages.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Messages; -import Settings; -import std.stdarg; - -/// Index into table of compiler messages. -enum MID -{ - // Lexer messages: - InvalidUnicodeCharacter, - InvalidUTF8Sequence, - // '' - UnterminatedCharacterLiteral, - EmptyCharacterLiteral, - // #line - ExpectedIdentifierSTLine, - ExpectedNumberAfterSTLine, - ExpectedFilespec, - UnterminatedFilespec, - UnterminatedSpecialToken, - // "" - UnterminatedString, - // x"" - NonHexCharInHexString, - OddNumberOfDigitsInHexString, - UnterminatedHexString, - // /* */ /+ +/ - UnterminatedBlockComment, - UnterminatedNestedComment, - // `` r"" - UnterminatedRawString, - UnterminatedBackQuoteString, - // \x \u \U - UndefinedEscapeSequence, - InsufficientHexDigits, - // \&[a-zA-Z][a-zA-Z0-9]+; - UndefinedHTMLEntity, - UnterminatedHTMLEntity, - InvalidBeginHTMLEntity, - // integer overflows - OverflowDecimalSign, - OverflowDecimalNumber, - OverflowHexNumber, - OverflowBinaryNumber, - OverflowOctalNumber, - OverflowFloatNumber, - OctalNumberHasDecimals, - NoDigitsInHexNumber, - NoDigitsInBinNumber, - HexFloatExponentRequired, - HexFloatMissingExpDigits, - FloatExponentDigitExpected, - - // Parser messages: - ExpectedButFound, - RedundantStorageClass, - - // Help messages: - HelpMain, -} - -string GetMsg(MID mid) -{ - assert(mid < GlobalSettings.messages.length); - return GlobalSettings.messages[mid]; -} - -char[] format(MID mid, ...) -{ - auto args = arguments(_arguments, _argptr); - return format_args(GetMsg(mid), args); -} - -char[] format(char[] format_str, ...) -{ - auto args = arguments(_arguments, _argptr); - return format_args(format_str, args); -} - -char[] format_args(char[] format_str, char[][] args) -{ - char[] result = format_str; - - foreach (i, arg; args) - result = std.string.replace(result, std.string.format("{%s}", i+1), arg); - - return result; -} - -char[][] arguments(TypeInfo[] tinfos, void* argptr) -{ - char[][] args; - foreach (ti; tinfos) - { - if (ti == typeid(char[])) - args ~= va_arg!(char[])(argptr); - else if (ti == typeid(int)) - args ~= std.string.format(va_arg!(int)(argptr)); - else if (ti == typeid(dchar)) - args ~= std.string.format(va_arg!(dchar)(argptr)); - else - assert(0, "argument type not supported yet."); - } - return args; -}
--- a/trunk/src/Parser.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4193 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Parser; -import Lexer; -import SyntaxTree; -import Token; -import Messages; -import Information; -import Declarations; -import Statements; -import Expressions; -import Types; -import std.stdio; - -private alias TOK T; - -class Parser -{ - Lexer lx; - Token* token; /// Current non-whitespace token. - Token* prevToken; /// Previous non-whitespace token. - - Information[] errors; - - this(char[] srcText, string fileName) - { - lx = new Lexer(srcText, fileName); - } - - debug char* prev; - - void start() - { - debug prev = lx.text.ptr; - nT(); - prevToken = token; - } - - void nT() - { - prevToken = token; - do - { - lx.nextToken(); - token = lx.token; - -debug if (!trying) -{ - writef("\33[32m%s\33[0m", token.type); - writef("%s", prev[0 .. token.end - prev]); - prev = token.end; -} - } while (token.isWhitespace) // Skip whitespace - } - - void skipToOnePast(TOK tok) - { - for (; token.type != tok && token.type != T.EOF; nT()) - {} - nT(); - } - - int trying; - int errorCount; - - ReturnType try_(ReturnType)(lazy ReturnType parseMethod, out bool success) - { -debug writef("\33[31mtry_\33[0m"); - ++trying; -// auto len = errors.length; - auto oldToken = token; - auto oldPrevToken = prevToken; - auto oldCount = errorCount; -// auto lexerState = lx.getState(); - auto result = parseMethod(); - // If the length of the array changed we know an error occurred. - if (errorCount != oldCount) - { -// lexerState.restore(); // Restore state of the Lexer object. -// errors = errors[0..len]; // Remove errors that were added when parseMethod() was called. - token = oldToken; - prevToken = oldPrevToken; - lx.token = oldToken; - errorCount = oldCount; - success = false; - } - else - success = true; - --trying; -debug writef("\33[34m%s\33[0m", success); - return result; - } - - Class set(Class)(Class node, Token* begin) - { - node.setTokens(begin, this.prevToken); - return node; - } - - TOK peekNext() - { - Token* next = token; - do - lx.peek(next); - while (next.isWhitespace) // Skip whitespace - return next.type; - } - - /++++++++++++++++++++++++++++++ - + Declaration parsing methods + - ++++++++++++++++++++++++++++++/ - - Declarations parseModule() - { - auto decls = new Declarations; - - if (token.type == T.Module) - { - auto begin = token; - ModuleName moduleName; - do - { - nT(); - moduleName ~= requireId(); - } while (token.type == T.Dot) - require(T.Semicolon); - decls ~= set(new ModuleDeclaration(moduleName), begin); - } - decls ~= parseDeclarationDefinitions(); - return decls; - } - - Declarations parseDeclarationDefinitions() - { - auto decls = new Declarations; - while (token.type != T.EOF) - decls ~= parseDeclarationDefinition(); - return decls; - } - - /* - DeclDefsBlock: - { } - { DeclDefs } - */ - Declarations parseDeclarationDefinitionsBlock() - { - auto decls = new Declarations; - require(T.LBrace); - while (token.type != T.RBrace && token.type != T.EOF) - decls ~= parseDeclarationDefinition(); - require(T.RBrace); - return decls; - } - - Declaration parseDeclarationDefinition() - { - auto begin = token; - Declaration decl; - switch (token.type) - { - case T.Align, - T.Pragma, - // Protection attributes - T.Export, - T.Private, - T.Package, - T.Protected, - T.Public: - decl = parseAttributeSpecifier(); - break; - // Storage classes - case T.Extern, - T.Deprecated, - T.Override, - T.Abstract, - T.Synchronized, - //T.Static, - T.Final, - T.Const, - //T.Invariant, // D 2.0 - T.Auto, - T.Scope: - case_StaticAttribute: - case_InvariantAttribute: // D 2.0 - decl = parseStorageAttribute(); - break; - case T.Alias: - nT(); - // TODO: parse StorageClasses? - decl = new AliasDeclaration(parseDeclaration()); - break; - case T.Typedef: - nT(); - // TODO: parse StorageClasses? - decl = new TypedefDeclaration(parseDeclaration()); - break; - case T.Static: - switch (peekNext()) - { - case T.Import: - goto case T.Import; - case T.This: - decl = parseStaticConstructorDeclaration(); - break; - case T.Tilde: - decl = parseStaticDestructorDeclaration(); - break; - case T.If: - decl = parseStaticIfDeclaration(); - break; - case T.Assert: - decl = parseStaticAssertDeclaration(); - break; - default: - goto case_StaticAttribute; - } - break; - case T.Import: - decl = parseImportDeclaration(); - break; - case T.Enum: - decl = parseEnumDeclaration(); - break; - case T.Class: - decl = parseClassDeclaration(); - break; - case T.Interface: - decl = parseInterfaceDeclaration(); - break; - case T.Struct, T.Union: - decl = parseAggregateDeclaration(); - break; - case T.This: - decl = parseConstructorDeclaration(); - break; - case T.Tilde: - decl = parseDestructorDeclaration(); - break; - case T.Invariant: - version(D2) - { - auto next = token; - lx.peek(next); - if (next.type == T.LParen) - { - lx.peek(next); - if (next.type != T.RParen) - goto case_Declaration; - } - else - goto case_InvariantAttribute; - } - decl = parseInvariantDeclaration(); - break; - case T.Unittest: - decl = parseUnittestDeclaration(); - break; - case T.Debug: - decl = parseDebugDeclaration(); - break; - case T.Version: - decl = parseVersionDeclaration(); - break; - case T.Template: - decl = parseTemplateDeclaration(); - break; - case T.New: - decl = parseNewDeclaration(); - break; - case T.Delete: - decl = parseDeleteDeclaration(); - break; - case T.Mixin: - decl = parseMixin!(MixinDeclaration)(); - break; - case T.Semicolon: - nT(); - decl = new EmptyDeclaration(); - break; - // Declaration - case T.Identifier, T.Dot, T.Typeof: - // BasicType - case T.Char, T.Wchar, T.Dchar, T.Bool, - T.Byte, T.Ubyte, T.Short, T.Ushort, - T.Int, T.Uint, T.Long, T.Ulong, - T.Float, T.Double, T.Real, - T.Ifloat, T.Idouble, T.Ireal, - T.Cfloat, T.Cdouble, T.Creal, T.Void: - case_Declaration: - decl = parseDeclaration(); - break; - /+case T.Module: - // TODO: Error: module is optional and can appear only once at the top of the source file. - break;+/ - default: - error(MID.ExpectedButFound, "Declaration", token.srcText); - decl = new IllegalDeclaration(token); - nT(); - } -// writef("§%s§", decl.classinfo.name); - set(decl, begin); - return decl; - } - - /* - DeclarationsBlock: - : DeclDefs - { } - { DeclDefs } - DeclDef - */ - Declaration parseDeclarationsBlock() - { - Declaration d; - switch (token.type) - { - case T.LBrace: - d = parseDeclarationDefinitionsBlock(); - break; - case T.Colon: - nT(); - auto decls = new Declarations; - while (token.type != T.RBrace && token.type != T.EOF) - decls ~= parseDeclarationDefinition(); - d = decls; - break; - default: - d = parseDeclarationDefinition(); - } - return d; - } - - Declaration parseDeclaration(StorageClass stc = StorageClass.None) - { - Type type; - Token* ident; - - // Check for AutoDeclaration - if (stc != StorageClass.None && - token.type == T.Identifier && - peekNext() == T.Assign) - { - ident = token; - nT(); - } - else - { - type = parseType(); - ident = requireId(); - // Type FunctionName ( ParameterList ) FunctionBody - if (token.type == T.LParen) - { - // It's a function declaration - TemplateParameters tparams; - if (tokenAfterParenIs(T.LParen)) - { - // ( TemplateParameterList ) ( ParameterList ) - tparams = parseTemplateParameterList(); - } - - auto params = parseParameterList(); - // ReturnType FunctionName ( ParameterList ) - auto funcBody = parseFunctionBody(); - return new FunctionDeclaration(type, ident, tparams, params, funcBody); - } - type = parseDeclaratorSuffix(type); - } - - // It's a variable declaration. - Token*[] idents = [ident]; - Expression[] values; - goto LenterLoop; // We've already parsed an identifier. Jump to if statement and check for initializer. - while (token.type == T.Comma) - { - nT(); - idents ~= requireId(); - LenterLoop: - if (token.type == T.Assign) - { - nT(); - values ~= parseInitializer(); - } - else - values ~= null; - } - require(T.Semicolon); - return new VariableDeclaration(type, idents, values); - } - - Expression parseInitializer() - { - if (token.type == T.Void) - { - auto begin = token; - auto next = peekNext(); - if (next == T.Comma || next == T.Semicolon) - { - nT(); - return set(new VoidInitializer(), begin); - } - } - return parseNonVoidInitializer(); - } - - Expression parseNonVoidInitializer() - { - auto begin = token; - Expression init; - switch (token.type) - { - case T.LBracket: - // ArrayInitializer: - // [ ] - // [ ArrayMemberInitializations ] - Expression[] keys; - Expression[] values; - - nT(); - while (token.type != T.RBracket) - { - auto e = parseNonVoidInitializer(); - if (token.type == T.Colon) - { - nT(); - keys ~= e; - values ~= parseNonVoidInitializer(); - } - else - { - keys ~= null; - values ~= e; - } - - if (token.type != T.Comma) - break; - nT(); - } - require(T.RBracket); - init = new ArrayInitializer(keys, values); - break; - case T.LBrace: - // StructInitializer: - // { } - // { StructMemberInitializers } - Expression parseStructInitializer() - { - Token*[] idents; - Expression[] values; - - nT(); - while (token.type != T.RBrace) - { - if (token.type == T.Identifier) - { - // Peek for colon to see if this is a member identifier. - if (peekNext() == T.Colon) - { - idents ~= token; - nT(); - nT(); - } - } - // NonVoidInitializer - values ~= parseNonVoidInitializer(); - - if (token.type != T.Comma) - break; - nT(); - } - require(T.RBrace); - return new StructInitializer(idents, values); - } - - bool success; - auto si = try_(parseStructInitializer(), success); - if (success) - { - init = si; - break; - } - assert(token.type == T.LBrace); - //goto default; - default: - init = parseAssignExpression(); - } - set(init, begin); - return init; - } - - FunctionBody parseFunctionBody() - { - auto begin = token; - auto func = new FunctionBody; - while (1) - { - switch (token.type) - { - case T.LBrace: - func.funcBody = parseStatements(); - break; - case T.Semicolon: - nT(); - break; - case T.In: - //if (func.inBody) - // TODO: issue error msg. - nT(); - func.inBody = parseStatements(); - continue; - case T.Out: - //if (func.outBody) - // TODO: issue error msg. - nT(); - if (token.type == T.LParen) - { - nT(); - func.outIdent = requireId(); - require(T.RParen); - } - func.outBody = parseStatements(); - continue; - case T.Body: - nT(); - goto case T.LBrace; - default: - error(MID.ExpectedButFound, "FunctionBody", token.srcText); - } - break; // exit while loop - } - set(func, begin); - func.finishConstruction(); - return func; - } - - Declaration parseStorageAttribute() - { - StorageClass stc, tmp; - - void addStorageClass() - { - if (stc & tmp) - { - error(MID.RedundantStorageClass, token.srcText); - } - else - stc |= tmp; - } - - Declaration parse() - { - Declaration decl; - switch (token.type) - { - case T.Extern: - tmp = StorageClass.Extern; - addStorageClass(); - nT(); - Linkage linkage; - if (token.type == T.LParen) - { - nT(); - auto ident = requireId(); - switch (ident ? ident.identifier : null) - { - case "C": - if (token.type == T.PlusPlus) - { - nT(); - linkage = Linkage.Cpp; - break; - } - linkage = Linkage.C; - break; - case "D": - linkage = Linkage.D; - break; - case "Windows": - linkage = Linkage.Windows; - break; - case "Pascal": - linkage = Linkage.Pascal; - break; - case "System": - linkage = Linkage.System; - break; - default: - // TODO: issue error msg. Unrecognized LinkageType. - } - require(T.RParen); - } - decl = new ExternDeclaration(linkage, parse()); - break; - case T.Override: - tmp = StorageClass.Override; - goto Lcommon; - case T.Deprecated: - tmp = StorageClass.Deprecated; - goto Lcommon; - case T.Abstract: - tmp = StorageClass.Abstract; - goto Lcommon; - case T.Synchronized: - tmp = StorageClass.Synchronized; - goto Lcommon; - case T.Static: - tmp = StorageClass.Static; - goto Lcommon; - case T.Final: - tmp = StorageClass.Final; - goto Lcommon; - case T.Const: - version(D2) - { - if (peekNext() == T.LParen) - goto case_Declaration; - } - tmp = StorageClass.Const; - goto Lcommon; - version(D2) - { - case T.Invariant: // D 2.0 - if (peekNext() == T.LParen) - goto case_Declaration; - tmp = StorageClass.Invariant; - goto Lcommon; - } - case T.Auto: - tmp = StorageClass.Auto; - goto Lcommon; - case T.Scope: - tmp = StorageClass.Scope; - goto Lcommon; - Lcommon: - addStorageClass(); - auto tok = token.type; - nT(); - decl = new AttributeDeclaration(tok, parse()); - break; - case T.Identifier: - case_Declaration: - // This could be a normal Declaration or an AutoDeclaration - decl = parseDeclaration(stc); - break; - default: - decl = parseDeclarationsBlock(); - } - return decl; - } - return parse(); - } - - Token* parseAlignAttribute() - { - assert(token.type == T.Align); - nT(); // Skip align keyword. - Token* tok; - if (token.type == T.LParen) - { - nT(); - if (token.type == T.Int32) - { - tok = token; - nT(); - } - else - expected(T.Int32); - require(T.RParen); - } - return tok; - } - - Declaration parseAttributeSpecifier() - { - Declaration decl; - - switch (token.type) - { - case T.Align: - int size = -1; - auto intTok = parseAlignAttribute(); - if (intTok) - size = intTok.int_; - decl = new AlignDeclaration(size, parseDeclarationsBlock()); - break; - case T.Pragma: - // Pragma: - // pragma ( Identifier ) - // pragma ( Identifier , ExpressionList ) - // ExpressionList: - // AssignExpression - // AssignExpression , ExpressionList - nT(); - Token* ident; - Expression[] args; - Declaration decls; - - require(T.LParen); - ident = requireId(); - - if (token.type == T.Comma) - { - // Parse at least one argument. - nT(); - args ~= parseAssignExpression(); - } - - if (token.type == T.Comma) - args ~= parseArguments(T.RParen); - else - require(T.RParen); - - if (token.type == T.Semicolon) - { - nT(); - decls = new EmptyDeclaration(); - } - else - decls = parseDeclarationsBlock(); - - decl = new PragmaDeclaration(ident, args, decls); - break; - // Protection attributes - case T.Private: - case T.Package: - case T.Protected: - case T.Public: - case T.Export: - auto tok = token.type; - nT(); - decl = new AttributeDeclaration(tok, parseDeclarationsBlock()); - break; - default: - assert(0); - } - return decl; - } - - Declaration parseImportDeclaration() - { - assert(token.type == T.Import || token.type == T.Static); - - bool isStatic; - - if (token.type == T.Static) - { - isStatic = true; - nT(); - } - - ModuleName[] moduleNames; - Token*[] moduleAliases; - Token*[] bindNames; - Token*[] bindAliases; - - nT(); // Skip import keyword. - while (1) - { - ModuleName moduleName; - Token* moduleAlias; - - moduleAlias = requireId(); - - // AliasName = ModuleName - if (token.type == T.Assign) - { - nT(); - moduleName ~= requireId(); - } - else // import Identifier [^=] - { - moduleName ~= moduleAlias; - moduleAlias = null; - } - - // Identifier(.Identifier)* - while (token.type == T.Dot) - { - nT(); - moduleName ~= requireId(); - } - - // Push identifiers. - moduleNames ~= moduleName; - moduleAliases ~= moduleAlias; - - if (token.type == T.Colon) - break; - if (token.type != T.Comma) - break; - nT(); - } - - if (token.type == T.Colon) - { - // BindAlias = BindName(, BindAlias = BindName)*; - // BindName(, BindName)*; - Token* bindName, bindAlias; - do - { - nT(); - bindAlias = requireId(); - - if (token.type == T.Assign) - { - nT(); - bindName = requireId(); - } - else - { - bindName = bindAlias; - bindAlias = null; - } - - // Push identifiers. - bindNames ~= bindName; - bindAliases ~= bindAlias; - } while (token.type == T.Comma) - } - - require(T.Semicolon); - - return new ImportDeclaration(moduleNames, moduleAliases, bindNames, bindAliases); - } - - Declaration parseEnumDeclaration() - { - assert(token.type == T.Enum); - - Token* enumName; - Type baseType; - Token*[] members; - Expression[] values; - bool hasBody; - - nT(); // Skip enum keyword. - - if (token.type == T.Identifier) - { - enumName = token; - nT(); - } - - if (token.type == T.Colon) - { - nT(); - baseType = parseBasicType(); - } - - if (token.type == T.Semicolon) - { - if (enumName is null) - expected(T.Identifier); - nT(); - } - else if (token.type == T.LBrace) - { - hasBody = true; - nT(); - do - { - members ~= requireId(); - - if (token.type == T.Assign) - { - nT(); - values ~= parseAssignExpression(); - } - else - values ~= null; - - if (token.type == T.Comma) - nT(); - else if (token.type != T.RBrace) - { - expected(T.RBrace); - break; - } - } while (token.type != T.RBrace) - nT(); - } - else - error(MID.ExpectedButFound, "enum declaration", token.srcText); - - return new EnumDeclaration(enumName, baseType, members, values, hasBody); - } - - Declaration parseClassDeclaration() - { - assert(token.type == T.Class); - - Token* className; - TemplateParameters tparams; - BaseClass[] bases; - Declarations decls; - bool hasBody; - - nT(); // Skip class keyword. - className = requireId(); - - if (token.type == T.LParen) - { - tparams = parseTemplateParameterList(); - } - - if (token.type == T.Colon) - bases = parseBaseClasses(); - - if (token.type == T.Semicolon) - { - //if (bases.length != 0) - // TODO: Error: bases classes are not allowed in forward declarations. - nT(); - } - else if (token.type == T.LBrace) - { - hasBody = true; - // TODO: think about setting a member status variable to a flag InClassBody... this way we can check for DeclDefs that are illegal in class bodies in the parsing phase. - decls = parseDeclarationDefinitionsBlock(); - } - else - expected(T.LBrace); // TODO: better error msg - - return new ClassDeclaration(className, tparams, bases, decls, hasBody); - } - - BaseClass[] parseBaseClasses(bool colonLeadsOff = true) - { - if (colonLeadsOff) - { - assert(token.type == T.Colon); - nT(); // Skip colon - } - - BaseClass[] bases; - - while (1) - { - Protection prot = Protection.Public; - switch (token.type) - { - case T.Identifier, T.Dot, T.Typeof: goto LparseBasicType; - case T.Private: prot = Protection.Private; break; - case T.Protected: prot = Protection.Protected; break; - case T.Package: prot = Protection.Package; break; - case T.Public: /*prot = Protection.Public;*/ break; - default: - // TODO: issue error msg - return bases; - } - nT(); // Skip protection attribute. - LparseBasicType: - auto type = parseBasicType(); - //if (type.tid != TID.DotList) - // TODO: issue error msg. base classes can only be one or more identifiers or template instances separated by dots. - bases ~= new BaseClass(prot, type); - if (token.type != T.Comma) - break; - } - return bases; - } - - Declaration parseInterfaceDeclaration() - { - assert(token.type == T.Interface); - - Token* name; - TemplateParameters tparams; - BaseClass[] bases; - Declarations decls; - bool hasBody; - - nT(); // Skip interface keyword. - name = requireId(); - - if (token.type == T.LParen) - { - tparams = parseTemplateParameterList(); - } - - if (token.type == T.Colon) - bases = parseBaseClasses(); - - if (token.type == T.Semicolon) - { - //if (bases.length != 0) - // TODO: error: base classes are not allowed in forward declarations. - nT(); - } - else if (token.type == T.LBrace) - { - hasBody = true; - decls = parseDeclarationDefinitionsBlock(); - } - else - expected(T.LBrace); // TODO: better error msg - - return new InterfaceDeclaration(name, tparams, bases, decls, hasBody); - } - - Declaration parseAggregateDeclaration() - { - assert(token.type == T.Struct || token.type == T.Union); - - TOK tok = token.type; - - Token* name; - TemplateParameters tparams; - Declarations decls; - bool hasBody; - - nT(); // Skip struct or union keyword. - // name is optional. - if (token.type == T.Identifier) - { - name = token; - nT(); - if (token.type == T.LParen) - { - tparams = parseTemplateParameterList(); - } - } - - if (token.type == T.Semicolon) - { - //if (name.length == 0) - // TODO: error: forward declarations must have a name. - nT(); - } - else if (token.type == T.LBrace) - { - hasBody = true; - decls = parseDeclarationDefinitionsBlock(); - } - else - expected(T.LBrace); // TODO: better error msg - - if (tok == T.Struct) - return new StructDeclaration(name, tparams, decls, hasBody); - else - return new UnionDeclaration(name, tparams, decls, hasBody); - } - - Declaration parseConstructorDeclaration() - { - assert(token.type == T.This); - nT(); // Skip 'this' keyword. - auto parameters = parseParameterList(); - auto funcBody = parseFunctionBody(); - return new ConstructorDeclaration(parameters, funcBody); - } - - Declaration parseDestructorDeclaration() - { - assert(token.type == T.Tilde); - nT(); // Skip ~ - require(T.This); - require(T.LParen); - require(T.RParen); - auto funcBody = parseFunctionBody(); - return new DestructorDeclaration(funcBody); - } - - Declaration parseStaticConstructorDeclaration() - { - assert(token.type == T.Static); - nT(); // Skip static keyword. - nT(); // Skip 'this' keyword. - require(T.LParen); - require(T.RParen); - auto funcBody = parseFunctionBody(); - return new StaticConstructorDeclaration(funcBody); - } - - Declaration parseStaticDestructorDeclaration() - { - assert(token.type == T.Static); - nT(); // Skip static keyword. - nT(); // Skip ~ - require(T.This); - require(T.LParen); - require(T.RParen); - auto funcBody = parseFunctionBody(); - return new StaticDestructorDeclaration(funcBody); - } - - Declaration parseInvariantDeclaration() - { - assert(token.type == T.Invariant); - nT(); // Skip invariant keyword. - // Optional () for getting ready porting to D 2.0 - if (token.type == T.LParen) - requireNext(T.RParen); - auto funcBody = parseFunctionBody(); - return new InvariantDeclaration(funcBody); - } - - Declaration parseUnittestDeclaration() - { - assert(token.type == T.Unittest); - - nT(); // Skip unittest keyword. - auto funcBody = parseFunctionBody(); - return new UnittestDeclaration(funcBody); - } - - Declaration parseDebugDeclaration() - { - assert(token.type == T.Debug); - - nT(); // Skip debug keyword. - - Token* spec; // debug = Integer ; - // debug = Identifier ; - Token* cond; // debug ( Integer ) - // debug ( Identifier ) - Declaration decls, elseDecls; - - void parseIdentOrInt(ref Token* tok) - { - nT(); - if (token.type == T.Int32 || - token.type == T.Identifier) - { - tok = token; - nT(); - } - else - expected(T.Identifier); // TODO: better error msg - } - - if (token.type == T.Assign) - { - parseIdentOrInt(spec); - require(T.Semicolon); - } - else - { - // Condition: - // Integer - // Identifier - // ( Condition ) - if (token.type == T.LParen) - { - parseIdentOrInt(cond); - require(T.RParen); - } - - // debug DeclarationsBlock - // debug ( Condition ) DeclarationsBlock - decls = parseDeclarationsBlock(); - - // else DeclarationsBlock - if (token.type == T.Else) - { - nT(); - //if (token.type == T.Colon) - // TODO: avoid "else:"? - elseDecls = parseDeclarationsBlock(); - } - } - - return new DebugDeclaration(spec, cond, decls, elseDecls); - } - - Declaration parseVersionDeclaration() - { - assert(token.type == T.Version); - - nT(); // Skip version keyword. - - Token* spec; // version = Integer ; - // version = Identifier ; - Token* cond; // version ( Integer ) - // version ( Identifier ) - Declaration decls, elseDecls; - - void parseIdentOrInt(ref Token* tok) - { - if (token.type == T.Int32 || - token.type == T.Identifier) - { - tok = token; - nT(); - } - else - expected(T.Identifier); // TODO: better error msg - } - - if (token.type == T.Assign) - { - nT(); - parseIdentOrInt(spec); - require(T.Semicolon); - } - else - { - // Condition: - // Integer - // Identifier - - // ( Condition ) - require(T.LParen); - parseIdentOrInt(cond); - require(T.RParen); - - // version ( Condition ) DeclarationsBlock - decls = parseDeclarationsBlock(); - - // else DeclarationsBlock - if (token.type == T.Else) - { - nT(); - //if (token.type == T.Colon) - // TODO: avoid "else:"? - elseDecls = parseDeclarationsBlock(); - } - } - - return new VersionDeclaration(spec, cond, decls, elseDecls); - } - - Declaration parseStaticIfDeclaration() - { - assert(token.type == T.Static); - - nT(); // Skip static keyword. - nT(); // Skip if keyword. - - Expression condition; - Declaration ifDecls, elseDecls; - - require(T.LParen); - condition = parseAssignExpression(); - require(T.RParen); - - if (token.type != T.Colon) - ifDecls = parseDeclarationsBlock(); - else - expected(T.LBrace); // TODO: better error msg - - if (token.type == T.Else) - { - nT(); - if (token.type != T.Colon) - elseDecls = parseDeclarationsBlock(); - else - expected(T.LBrace); // TODO: better error msg - } - - return new StaticIfDeclaration(condition, ifDecls, elseDecls); - } - - Declaration parseStaticAssertDeclaration() - { - assert(token.type == T.Static); - - nT(); // Skip static keyword. - nT(); // Skip assert keyword. - - Expression condition, message; - - require(T.LParen); - - condition = parseAssignExpression(); - - if (token.type == T.Comma) - { - nT(); - message = parseAssignExpression(); - } - - require(T.RParen); - require(T.Semicolon); - - return new StaticAssertDeclaration(condition, message); - } - - Declaration parseTemplateDeclaration() - { - assert(token.type == T.Template); - nT(); // Skip template keyword. - auto templateName = requireId(); - auto templateParams = parseTemplateParameterList(); - auto decls = parseDeclarationDefinitionsBlock(); - return new TemplateDeclaration(templateName, templateParams, decls); - } - - Declaration parseNewDeclaration() - { - assert(token.type == T.New); - nT(); // Skip new keyword. - auto parameters = parseParameterList(); - auto funcBody = parseFunctionBody(); - return new NewDeclaration(parameters, funcBody); - } - - Declaration parseDeleteDeclaration() - { - assert(token.type == T.Delete); - nT(); // Skip delete keyword. - auto parameters = parseParameterList(); - // TODO: only one parameter of type void* allowed. Check in parsing or semantic phase? - auto funcBody = parseFunctionBody(); - return new DeleteDeclaration(parameters, funcBody); - } - - /+ - DotListExpression: - . DotListItems - DotListItems - Typeof - Typeof . DotListItems - DotListItems: - DotListItem - DotListItem . DotListItems - DotListItem: - Identifier - TemplateInstance - NewExpression - TemplateInstance: - Identifier !( TemplateArguments ) - +/ - DotListExpression parseDotListExpression() - { - assert(token.type == T.Identifier || token.type == T.Dot || token.type == T.Typeof); - Expression[] identList; - if (token.type == T.Dot) - { - identList ~= new IdentifierExpression(token); - nT(); - } - else if (token.type == T.Typeof) - { - requireNext(T.LParen); - auto type = new TypeofType(parseExpression()); - require(T.RParen); - identList ~= new TypeofExpression(type); - if (token.type != T.Dot) - goto Lreturn; - nT(); - } - - while (1) - { - auto begin2 = token; - auto ident = requireId(); - Expression e; - if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) - { - nT(); // Skip !. - e = set(new TemplateInstanceExpression(ident, parseTemplateArguments()), begin2); - } - else // Identifier - e = set(new IdentifierExpression(ident), begin2); - - identList ~= e; - - LnewExpressionLoop: - if (token.type != T.Dot) - break; - nT(); // Skip dot. - - if (token.type == T.New) - { - identList ~= parseNewExpression(); - goto LnewExpressionLoop; - } - } - - Lreturn: - return new DotListExpression(identList); - } - - /+ - DotListType: - . TypeItems - TypeItems - Typeof - Typeof . TypeItems - TypeItems: - TypeItem - TypeItem . TypeItems - TypeItem: - Identifier - TemplateInstance - TemplateInstance: - Identifier !( TemplateArguments ) - +/ - DotListType parseDotListType() - { - Type[] identList; - if (token.type == T.Dot) - { - identList ~= new IdentifierType(token); - nT(); - } - else if (token.type == T.Typeof) - { - requireNext(T.LParen); - identList ~= new TypeofType(parseExpression()); - require(T.RParen); - if (token.type != T.Dot) - goto Lreturn; - nT(); - } - - while (1) - { - auto begin2 = token; - auto ident = requireId(); - // NB.: Currently Types can't be followed by "!=" so we don't need to peek for "(" when parsing TemplateInstances. - if (token.type == T.Not/+ && peekNext() == T.LParen+/) // Identifier !( TemplateArguments ) - { - nT(); // Skip !. - identList ~= set(new TemplateInstanceType(ident, parseTemplateArguments()), begin2); - } - else // Identifier - identList ~= set(new IdentifierType(ident), begin2); - - if (token.type != T.Dot) - break; - nT(); - } - Lreturn: - return new DotListType(identList); - } - - /* - TemplateMixin: - mixin ( AssignExpression ) ; - mixin TemplateIdentifier ; - mixin TemplateIdentifier MixinIdentifier ; - mixin TemplateIdentifier !( TemplateArguments ) ; - mixin TemplateIdentifier !( TemplateArguments ) MixinIdentifier ; - */ - Class parseMixin(Class)() - { - assert(token.type == T.Mixin); - auto begin = token; - nT(); // Skip mixin keyword. - - static if (is(Class == MixinDeclaration)) - { - if (token.type == T.LParen) - { - // TODO: What about mixin(...).ident;? - nT(); - auto e = parseAssignExpression(); - require(T.RParen); - require(T.Semicolon); - return new MixinDeclaration(e); - } - } - - Expression[] templateIdent; - Token* mixinIdent; - - // This code is similar to parseDotListType(). - if (token.type == T.Dot) - { - templateIdent ~= new IdentifierExpression(token); - nT(); - } - - while (1) - { - auto ident = requireId(); - Expression e; - if (token.type == T.Not) // Identifier !( TemplateArguments ) - { - // No need to peek for T.LParen. This must be a template instance. - nT(); - e = new TemplateInstanceExpression(ident, parseTemplateArguments()); - } - else // Identifier - e = new IdentifierExpression(ident); - - templateIdent ~= e; - - if (token.type != T.Dot) - break; - nT(); - } - - if (token.type == T.Identifier) - { - mixinIdent = token; - nT(); - } - - require(T.Semicolon); - - return new Class(templateIdent, mixinIdent); - } - - /+++++++++++++++++++++++++++++ - + Statement parsing methods + - +++++++++++++++++++++++++++++/ - - Statements parseStatements() - { - auto begin = token; - require(T.LBrace); - auto statements = new Statements(); - while (token.type != T.RBrace && token.type != T.EOF) - statements ~= parseStatement(); - require(T.RBrace); - return set(statements, begin); - } - - Statement parseStatement() - { -// writefln("°parseStatement:(%d)token='%s'°", lx.loc, token.srcText); - auto begin = token; - Statement s; - Declaration d; - switch (token.type) - { - case T.Align: - int size = -1; - auto intTok = parseAlignAttribute(); - if (intTok) - size = intTok.int_; - // Restrict align attribute to structs in parsing phase. - Declaration structDecl; - if (token.type == T.Struct) - structDecl = parseAggregateDeclaration(); - else - expected(T.Struct); - d = new AlignDeclaration(size, structDecl ? structDecl : new Declarations); - goto case_DeclarationStatement; -/+ Not applicable for statements. -// T.Private, -// T.Package, -// T.Protected, -// T.Public, -// T.Export, -// T.Deprecated, -// T.Override, -// T.Abstract, -+/ - case T.Extern, - T.Final, - T.Const, - T.Auto: - //T.Scope - //T.Static - case_parseAttribute: - s = parseAttributeStatement(); - return s; - case T.Identifier: - if (peekNext() == T.Colon) - { - auto ident = token; - nT(); // Skip Identifier - nT(); // Skip : - s = new LabeledStatement(ident, parseNoScopeOrEmptyStatement()); - break; - } - goto case T.Dot; - case T.Dot, T.Typeof: - bool success; - d = try_(parseDeclaration(), success); - if (success) - goto case_DeclarationStatement; // Declaration - else - goto default; // Expression - // BasicType - case T.Char, T.Wchar, T.Dchar, T.Bool, - T.Byte, T.Ubyte, T.Short, T.Ushort, - T.Int, T.Uint, T.Long, T.Ulong, - T.Float, T.Double, T.Real, - T.Ifloat, T.Idouble, T.Ireal, - T.Cfloat, T.Cdouble, T.Creal, T.Void: - case_parseDeclaration: - d = parseDeclaration(); - goto case_DeclarationStatement; - case T.If: - s = parseIfStatement(); - break; - case T.While: - s = parseWhileStatement(); - break; - case T.Do: - s = parseDoWhileStatement(); - break; - case T.For: - s = parseForStatement(); - break; - case T.Foreach, T.Foreach_reverse: - s = parseForeachStatement(); - break; - case T.Switch: - s = parseSwitchStatement(); - break; - case T.Case: - s = parseCaseStatement(); - break; - case T.Default: - s = parseDefaultStatement(); - break; - case T.Continue: - s = parseContinueStatement(); - break; - case T.Break: - s = parseBreakStatement(); - break; - case T.Return: - s = parseReturnStatement(); - break; - case T.Goto: - s = parseGotoStatement(); - break; - case T.With: - s = parseWithStatement(); - break; - case T.Synchronized: - s = parseSynchronizedStatement(); - break; - case T.Try: - s = parseTryStatement(); - break; - case T.Throw: - s = parseThrowStatement(); - break; - case T.Scope: - if (peekNext() != T.LParen) - goto case_parseAttribute; - s = parseScopeGuardStatement(); - break; - case T.Volatile: - s = parseVolatileStatement(); - break; - case T.Asm: - s = parseAsmStatement(); - break; - case T.Pragma: - s = parsePragmaStatement(); - break; - case T.Mixin: - if (peekNext() == T.LParen) - goto default; // Parse as expression. - s = parseMixin!(MixinStatement)(); - break; - case T.Static: - switch (peekNext()) - { - case T.If: - s = parseStaticIfStatement(); - break; - case T.Assert: - s = parseStaticAssertStatement(); - break; - default: - goto case_parseAttribute; - } - break; - case T.Debug: - s = parseDebugStatement(); - break; - case T.Version: - s = parseVersionStatement(); - break; - // DeclDef - case T.Alias, T.Typedef: - d = parseDeclarationDefinition(); - goto case_DeclarationStatement; - case T.Enum: - d = parseEnumDeclaration(); - goto case_DeclarationStatement; - case T.Class: - d = parseClassDeclaration(); - goto case_DeclarationStatement; - case T.Interface: - d = parseInterfaceDeclaration(); - goto case_DeclarationStatement; - case T.Struct, T.Union: - d = parseAggregateDeclaration(); - goto case_DeclarationStatement; - case_DeclarationStatement: - set(d, begin); - s = new DeclarationStatement(d); - break; - case T.LBrace: - s = parseScopeStatement(); - break; - case T.Semicolon: - nT(); - s = new EmptyStatement(); - break; - default: - bool success; - auto expression = try_(parseExpression(), success); -// writefln("parseExpression()=", failed?"failed":"success"); - if (success) - { - require(T.Semicolon); - s = new ExpressionStatement(expression); - } - else - { - error(MID.ExpectedButFound, "Statement", token.srcText); - s = new IllegalStatement(token); - nT(); - } - } - assert(s !is null); -// writef("§%s§", s.classinfo.name); - set(s, begin); - return s; - } - - /+ - ScopeStatement: - NoScopeStatement - +/ - Statement parseScopeStatement() - { - return new ScopeStatement(parseNoScopeStatement()); - } - - /+ - NoScopeStatement: - NonEmptyStatement - BlockStatement - BlockStatement: - { } - { StatementList } - +/ - Statement parseNoScopeStatement() - { - Statement s; - if (token.type == T.LBrace) - { - nT(); - auto ss = new Statements(); - while (token.type != T.RBrace && token.type != T.EOF) - ss ~= parseStatement(); - require(T.RBrace); - s = ss; - } - else if (token.type == T.Semicolon) - { - error(MID.ExpectedButFound, "non-empty statement", ";"); - s = new EmptyStatement(); - nT(); - } - else - s = parseStatement(); - return s; - } - - /+ - NoScopeOrEmptyStatement: - ; - NoScopeStatement - +/ - Statement parseNoScopeOrEmptyStatement() - { - if (token.type == T.Semicolon) - { - nT(); - return new EmptyStatement(); - } - else - return parseNoScopeStatement(); - } - - Statement parseAttributeStatement() - { - StorageClass stc, tmp; - - void addStorageClass() - { - if (stc & tmp) - { - error(MID.RedundantStorageClass, token.srcText); - } - else - stc |= tmp; - } - - Statement parse() - { - auto begin = token; - Statement s; - switch (token.type) - { - case T.Extern: - tmp = StorageClass.Extern; - addStorageClass(); - nT(); - Linkage linkage; - if (token.type == T.LParen) - { - nT(); - auto ident = requireId(); - switch (ident ? ident.identifier : null) - { - case "C": - if (token.type == T.PlusPlus) - { - nT(); - linkage = Linkage.Cpp; - break; - } - linkage = Linkage.C; - break; - case "D": - linkage = Linkage.D; - break; - case "Windows": - linkage = Linkage.Windows; - break; - case "Pascal": - linkage = Linkage.Pascal; - break; - case "System": - linkage = Linkage.System; - break; - default: - // TODO: issue error msg. Unrecognized LinkageType. - } - require(T.RParen); - } - s = new ExternStatement(linkage, parse()); - break; - case T.Static: - tmp = StorageClass.Static; - goto Lcommon; - case T.Final: - tmp = StorageClass.Final; - goto Lcommon; - case T.Const: - version(D2) - { - if (peekNext() == T.LParen) - goto case_Declaration; - } - tmp = StorageClass.Const; - goto Lcommon; - version(D2) - { - case T.Invariant: // D 2.0 - if (peekNext() == T.LParen) - goto case_Declaration; - tmp = StorageClass.Invariant; - goto Lcommon; - } - case T.Auto: - tmp = StorageClass.Auto; - goto Lcommon; - case T.Scope: - tmp = StorageClass.Scope; - goto Lcommon; - Lcommon: - addStorageClass(); - auto tok = token.type; - nT(); - s = new AttributeStatement(tok, parse()); - break; - // TODO: allow "scope class", "abstract scope class" in function bodies? - //case T.Class: - default: - case_Declaration: - s = new DeclarationStatement(parseDeclaration(stc)); - } - set(s, begin); - return s; - } - return parse(); - } - - Statement parseIfStatement() - { - assert(token.type == T.If); - nT(); - - Statement variable; - Expression condition; - Statement ifBody, elseBody; - - require(T.LParen); - - Token* ident; - // auto Identifier = Expression - if (token.type == T.Auto) - { - auto a = new AttributeStatement(token.type, null); - nT(); - ident = requireId(); - require(T.Assign); - auto init = parseExpression(); - a.statement = new DeclarationStatement(new VariableDeclaration(null, [ident], [init])); - variable = a; - } - else - { - // Declarator = Expression - Type parseDeclaratorAssign() - { - auto type = parseDeclarator(ident); - require(T.Assign); - return type; - } - bool success; - auto type = try_(parseDeclaratorAssign(), success); - if (success) - { - auto init = parseExpression(); - variable = new DeclarationStatement(new VariableDeclaration(type, [ident], [init])); - } - else - condition = parseExpression(); - } - require(T.RParen); - ifBody = parseScopeStatement(); - if (token.type == T.Else) - { - nT(); - elseBody = parseScopeStatement(); - } - return new IfStatement(variable, condition, ifBody, elseBody); - } - - Statement parseWhileStatement() - { - assert(token.type == T.While); - nT(); - require(T.LParen); - auto condition = parseExpression(); - require(T.RParen); - return new WhileStatement(condition, parseScopeStatement()); - } - - Statement parseDoWhileStatement() - { - assert(token.type == T.Do); - nT(); - auto doBody = parseScopeStatement(); - require(T.While); - require(T.LParen); - auto condition = parseExpression(); - require(T.RParen); - return new DoWhileStatement(condition, doBody); - } - - Statement parseForStatement() - { - assert(token.type == T.For); - nT(); - require(T.LParen); - - Statement init, forBody; - Expression condition, increment; - - if (token.type != T.Semicolon) - init = parseNoScopeStatement(); - else - nT(); // Skip ; - if (token.type != T.Semicolon) - condition = parseExpression(); - require(T.Semicolon); - if (token.type != T.RParen) - increment = parseExpression(); - require(T.RParen); - forBody = parseScopeStatement(); - return new ForStatement(init, condition, increment, forBody); - } - - Statement parseForeachStatement() - { - assert(token.type == T.Foreach || token.type == T.Foreach_reverse); - TOK tok = token.type; - nT(); - - auto params = new Parameters; - Expression e; // Aggregate or LwrExpression - - require(T.LParen); - while (1) - { - auto paramBegin = token; - Token* stcTok; - Type type; - Token* ident; - - switch (token.type) - { - case T.Ref, T.Inout: - stcTok = token; - nT(); - // fall through - case T.Identifier: - auto next = peekNext(); - if (next == T.Comma || next == T.Semicolon || next == T.RParen) - { - ident = token; - nT(); - break; - } - // fall through - default: - type = parseDeclarator(ident); - } - - params ~= set(new Parameter(stcTok, type, ident, null), paramBegin); - - if (token.type != T.Comma) - break; - nT(); - } - require(T.Semicolon); - e = parseExpression(); - version(D2) - { //Foreach (ForeachType; LwrExpression .. UprExpression ) ScopeStatement - if (token.type == T.Slice) - { - // if (params.length != 1) - // error(MID.XYZ); // TODO: issue error msg - nT(); - auto upper = parseExpression(); - require(T.RParen); - auto forBody = parseScopeStatement(); - return new ForeachRangeStatement(tok, params, e, upper, forBody); - } - } - // Foreach (ForeachTypeList; Aggregate) ScopeStatement - require(T.RParen); - auto forBody = parseScopeStatement(); - return new ForeachStatement(tok, params, e, forBody); - } - - Statement parseSwitchStatement() - { - assert(token.type == T.Switch); - nT(); - - require(T.LParen); - auto condition = parseExpression(); - require(T.RParen); - auto switchBody = parseScopeStatement(); - return new SwitchStatement(condition, switchBody); - } - - Statement parseCaseDefaultBody() - { - // This function is similar to parseNoScopeStatement() - auto s = new Statements(); - while (token.type != T.Case && - token.type != T.Default && - token.type != T.RBrace && - token.type != T.EOF) - s ~= parseStatement(); - return new ScopeStatement(s); - } - - Statement parseCaseStatement() - { - assert(token.type == T.Case); - // T.Case skipped in do-while. - Expression[] values; - do - { - nT(); - values ~= parseAssignExpression(); - } while (token.type == T.Comma) - require(T.Colon); - - auto caseBody = parseCaseDefaultBody(); - return new CaseStatement(values, caseBody); - } - - Statement parseDefaultStatement() - { - assert(token.type == T.Default); - nT(); - require(T.Colon); - return new DefaultStatement(parseCaseDefaultBody()); - } - - Statement parseContinueStatement() - { - assert(token.type == T.Continue); - nT(); - Token* ident; - if (token.type == T.Identifier) - { - ident = token; - nT(); - } - require(T.Semicolon); - return new ContinueStatement(ident); - } - - Statement parseBreakStatement() - { - assert(token.type == T.Break); - nT(); - Token* ident; - if (token.type == T.Identifier) - { - ident = token; - nT(); - } - require(T.Semicolon); - return new BreakStatement(ident); - } - - Statement parseReturnStatement() - { - assert(token.type == T.Return); - nT(); - Expression expr; - if (token.type != T.Semicolon) - expr = parseExpression(); - require(T.Semicolon); - return new ReturnStatement(expr); - } - - Statement parseGotoStatement() - { - assert(token.type == T.Goto); - nT(); - Token* ident; - Expression caseExpr; - switch (token.type) - { - case T.Case: - nT(); - if (token.type == T.Semicolon) - break; - caseExpr = parseExpression(); - break; - case T.Default: - nT(); - break; - default: - ident = requireId(); - } - require(T.Semicolon); - return new GotoStatement(ident, caseExpr); - } - - Statement parseWithStatement() - { - assert(token.type == T.With); - nT(); - require(T.LParen); - auto expr = parseExpression(); - require(T.RParen); - return new WithStatement(expr, parseScopeStatement()); - } - - Statement parseSynchronizedStatement() - { - assert(token.type == T.Synchronized); - nT(); - Expression expr; - - if (token.type == T.LParen) - { - nT(); - expr = parseExpression(); - require(T.RParen); - } - return new SynchronizedStatement(expr, parseScopeStatement()); - } - - Statement parseTryStatement() - { - assert(token.type == T.Try); - nT(); - - auto tryBody = parseScopeStatement(); - CatchBody[] catchBodies; - FinallyBody finBody; - - while (token.type == T.Catch) - { - nT(); - Parameter param; - if (token.type == T.LParen) - { - nT(); - Token* ident; - auto type = parseDeclarator(ident); - param = new Parameter(null, type, ident, null); - require(T.RParen); - } - catchBodies ~= new CatchBody(param, parseNoScopeStatement()); - if (param is null) - break; // This is a LastCatch - } - - if (token.type == T.Finally) - { - nT(); - finBody = new FinallyBody(parseNoScopeStatement()); - } - - if (catchBodies.length == 0 || finBody is null) - { - // TODO: issue error msg. - } - - return new TryStatement(tryBody, catchBodies, finBody); - } - - Statement parseThrowStatement() - { - assert(token.type == T.Throw); - nT(); - auto expr = parseExpression(); - require(T.Semicolon); - return new ThrowStatement(expr); - } - - Statement parseScopeGuardStatement() - { - assert(token.type == T.Scope); - nT(); - assert(token.type == T.LParen); - nT(); - - Token* condition = requireId(); - if (condition) - switch (condition.identifier) - { - case "exit": - case "success": - case "failure": - break; - default: - // TODO: issue error msg. - } - require(T.RParen); - Statement scopeBody; - if (token.type == T.LBrace) - scopeBody = parseScopeStatement(); - else - scopeBody = parseNoScopeStatement(); - return new ScopeGuardStatement(condition, scopeBody); - } - - Statement parseVolatileStatement() - { - assert(token.type == T.Volatile); - nT(); - Statement volatileBody; - if (token.type == T.Semicolon) - nT(); - else if (token.type == T.LBrace) - volatileBody = parseScopeStatement(); - else - volatileBody = parseStatement(); - return new VolatileStatement(volatileBody); - } - - Statement parsePragmaStatement() - { - assert(token.type == T.Pragma); - nT(); - - Token* ident; - Expression[] args; - Statement pragmaBody; - - require(T.LParen); - ident = requireId(); - - if (token.type == T.Comma) - { - // Parse at least one argument. - nT(); - args ~= parseAssignExpression(); - } - - if (token.type == T.Comma) - args ~= parseArguments(T.RParen); - else - require(T.RParen); - - pragmaBody = parseNoScopeOrEmptyStatement(); - - return new PragmaStatement(ident, args, pragmaBody); - } - - Statement parseStaticIfStatement() - { - assert(token.type == T.Static); - nT(); - assert(token.type == T.If); - nT(); - Expression condition; - Statement ifBody, elseBody; - - require(T.LParen); - condition = parseExpression(); - require(T.RParen); - ifBody = parseNoScopeStatement(); - if (token.type == T.Else) - { - nT(); - elseBody = parseNoScopeStatement(); - } - return new StaticIfStatement(condition, ifBody, elseBody); - } - - Statement parseStaticAssertStatement() - { - assert(token.type == T.Static); - nT(); - assert(token.type == T.Assert); - nT(); - Expression condition, message; - require(T.LParen); - condition = parseAssignExpression(); - if (token.type == T.Comma) - { - nT(); - message = parseAssignExpression(); - } - require(T.RParen); - require(T.Semicolon); - return new StaticAssertStatement(condition, message); - } - - Statement parseDebugStatement() - { - assert(token.type == T.Debug); - nT(); // Skip debug keyword. - - Token* cond; // debug ( Integer ) - // debug ( Identifier ) - Statement debugBody, elseBody; - - void parseIdentOrInt(ref Token* tok) - { - nT(); - if (token.type == T.Int32 || - token.type == T.Identifier) - { - tok = token; - nT(); - } - else - expected(T.Identifier); // TODO: better error msg - } - -// if (token.type == T.Assign) -// { -// parseIdentOrInt(identSpec, levelSpec); -// require(T.Semicolon); -// } -// else - { - // Condition: - // Integer - // Identifier - - // ( Condition ) - if (token.type == T.LParen) - { - parseIdentOrInt(cond); - require(T.RParen); - } - - // debug Statement - // debug ( Condition ) Statement - debugBody = parseNoScopeStatement(); - - // else Statement - if (token.type == T.Else) - { - // debug without condition and else body makes no sense - //if (levelCond == -1 && identCond.length == 0) - // TODO: issue error msg - nT(); - elseBody = parseNoScopeStatement(); - } - } - - return new DebugStatement(cond, debugBody, elseBody); - } - - Statement parseVersionStatement() - { - assert(token.type == T.Version); - - nT(); // Skip version keyword. - - Token* cond; // version ( Integer ) - // version ( Identifier ) - Statement versionBody, elseBody; - - void parseIdentOrInt(ref Token* tok) - { - if (token.type == T.Int32 || - token.type == T.Identifier) - { - tok = token; - nT(); - } - else - expected(T.Identifier); // TODO: better error msg - } - -// if (token.type == T.Assign) -// { -// parseIdentOrInt(identSpec, levelSpec); -// require(T.Semicolon); -// } -// else - { - // Condition: - // Integer - // Identifier - - // ( Condition ) - require(T.LParen); - parseIdentOrInt(cond); - require(T.RParen); - - // version ( Condition ) Statement - versionBody = parseNoScopeStatement(); - - // else Statement - if (token.type == T.Else) - { - nT(); - elseBody = parseNoScopeStatement(); - } - } - - return new VersionStatement(cond, versionBody, elseBody); - } - - /+++++++++++++++++++++++++++++ - + Assembler parsing methods + - +++++++++++++++++++++++++++++/ - - Statement parseAsmStatement() - { - assert(token.type == T.Asm); - nT(); // Skip asm keyword. - require(T.LBrace); - auto ss = new Statements; - while (token.type != T.RBrace && token.type != T.EOF) - ss ~= parseAsmInstruction(); - require(T.RBrace); - return new AsmStatement(ss); - } - - Statement parseAsmInstruction() - { - auto begin = token; - Statement s; - switch (token.type) - { - case T.Identifier: - auto ident = token; - auto next = peekNext(); - if (next == T.Colon) - { - // Identifier : AsmInstruction - nT(); // Skip Identifier - nT(); // Skip : - s = new LabeledStatement(ident, parseAsmInstruction()); - break; - } - - // Opcode ; - // Opcode Operands ; - // Opcode - // Identifier - Expression[] es; - if (next != T.Semicolon) - { - while (1) - { - es ~= parseAsmExpression(); - if (token.type != T.Comma) - break; - nT(); - } - } - require(T.Semicolon); - s = new AsmInstruction(ident, es); - break; - case T.Semicolon: - s = new EmptyStatement(); - nT(); - break; - default: - error(MID.ExpectedButFound, "AsmStatement", token.srcText); - s = new IllegalAsmInstruction(token); - nT(); - } - set(s, begin); - return s; - } - - Expression parseAsmExpression() - { - auto begin = token; - auto e = parseOrOrExpression(); - if (token.type == T.Question) - { - auto tok = token; - nT(); - auto iftrue = parseAsmExpression(); - require(T.Colon); - auto iffalse = parseAsmExpression(); - e = new CondExpression(e, iftrue, iffalse, tok); - set(e, begin); - } - // TODO: create AsmExpression that contains e? - return e; - } - - Expression parseAsmOrOrExpression() - { - auto begin = token; - alias parseAsmAndAndExpression parseNext; - auto e = parseNext(); - while (token.type == T.OrLogical) - { - auto tok = token; - nT(); - e = new OrOrExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAsmAndAndExpression() - { - auto begin = token; - alias parseAsmOrExpression parseNext; - auto e = parseNext(); - while (token.type == T.AndLogical) - { - auto tok = token; - nT(); - e = new AndAndExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAsmOrExpression() - { - auto begin = token; - alias parseAsmXorExpression parseNext; - auto e = parseNext(); - while (token.type == T.OrBinary) - { - auto tok = token; - nT(); - e = new OrExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAsmXorExpression() - { - alias parseAsmAndExpression parseNext; - auto begin = token; - auto e = parseNext(); - while (token.type == T.Xor) - { - auto tok = token; - nT(); - e = new XorExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAsmAndExpression() - { - alias parseAsmCmpExpression parseNext; - auto begin = token; - auto e = parseNext(); - while (token.type == T.AndBinary) - { - auto tok = token; - nT(); - e = new AndExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAsmCmpExpression() - { - alias parseAsmShiftExpression parseNext; - auto begin = token; - auto e = parseNext(); - - auto operator = token; - switch (operator.type) - { - case T.Equal, T.NotEqual: - nT(); - e = new EqualExpression(e, parseNext(), operator); - break; - case T.LessEqual, T.Less, T.GreaterEqual, T.Greater: - nT(); - e = new RelExpression(e, parseNext(), operator); - break; - default: - return e; - } - set(e, begin); - return e; - } - - Expression parseAsmShiftExpression() - { - alias parseAsmAddExpression parseNext; - auto begin = token; - auto e = parseNext(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.LShift: nT(); e = new LShiftExpression(e, parseNext(), operator); break; - case T.RShift: nT(); e = new RShiftExpression(e, parseNext(), operator); break; - case T.URShift: nT(); e = new URShiftExpression(e, parseNext(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseAsmAddExpression() - { - alias parseAsmMulExpression parseNext; - auto begin = token; - auto e = parseNext(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.Plus: nT(); e = new PlusExpression(e, parseNext(), operator); break; - case T.Minus: nT(); e = new MinusExpression(e, parseNext(), operator); break; - // Not allowed in asm - //case T.Tilde: nT(); e = new CatExpression(e, parseNext(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseAsmMulExpression() - { - alias parseAsmPostExpression parseNext; - auto begin = token; - auto e = parseNext(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.Mul: nT(); e = new MulExpression(e, parseNext(), operator); break; - case T.Div: nT(); e = new DivExpression(e, parseNext(), operator); break; - case T.Mod: nT(); e = new ModExpression(e, parseNext(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseAsmPostExpression() - { - auto begin = token; - auto e = parseAsmUnaryExpression(); - while (token.type == T.RBracket) - { - nT(); - e = parseAsmExpression(); - e = new AsmPostBracketExpression(e); - require(T.RBracket); - set(e, begin); - } - return e; - } - - Expression parseAsmUnaryExpression() - { - auto begin = token; - Expression e; - switch (token.type) - { - case T.Identifier: - switch (token.identifier) - { - case "near", "far", "byte", "short", "int", - "word", "dword", "float", "double", "real": - nT(); - if (token.type == T.Identifier && token.identifier == "ptr") - nT(); - else - error(MID.ExpectedButFound, "ptr", token.srcText); - e = new AsmTypeExpression(parseAsmUnaryExpression()); - break; - case "offset": - nT(); - e = new AsmOffsetExpression(parseAsmUnaryExpression()); - break; - case "seg": - nT(); - e = new AsmSegExpression(parseAsmUnaryExpression()); - break; - default: - } - goto default; - case T.Minus: - case T.Plus: - nT(); - e = new SignExpression(parseAsmUnaryExpression()); - break; - case T.Not: - nT(); - e = new NotExpression(parseAsmUnaryExpression()); - break; - case T.Tilde: - nT(); - e = new CompExpression(parseAsmUnaryExpression()); - default: - e = parseAsmPrimaryExpression(); - return e; - } - set(e, begin); - return e; - } - - Expression parseAsmPrimaryExpression() - { - auto begin = token; - Expression e; - switch (token.type) - { - case T.Int32, T.Int64, T.Uint32, T.Uint64: - e = new IntNumberExpression(token.type, token.ulong_); - nT(); - break; - case T.Float32, T.Float64, T.Float80, - T.Imaginary32, T.Imaginary64, T.Imaginary80: - e = new RealNumberExpression(token.type, token.real_); - nT(); - break; - case T.Dollar: - e = new DollarExpression(); - nT(); - break; - case T.LBracket: - // [ AsmExpression ] - nT(); - e = parseAsmExpression(); - require(T.RBracket); - e = new AsmBracketExpression(e); - break; - case T.Identifier: - switch (token.identifier) - { - // __LOCAL_SIZE - case "__LOCAL_SIZE": - e = new AsmLocalSizeExpression(); - nT(); - break; - // Register - case "ST": - auto register = token; - nT(); - // (1) - (7) - Token* number; - if (token.type == T.LParen) - { - nT(); - if (token.type == T.Int32) - { - number = token; - nT(); - } - else - expected(T.Int32); - require(T.RParen); - } - e = new AsmRegisterExpression(register, number); - break; - case "AL", "AH", "AX", "EAX", - "BL", "BH", "BX", "EBX", - "CL", "CH", "CX", "ECX", - "DL", "DH", "DX", "EDX", - "BP", "EBP", - "SP", "ESP", - "DI", "EDI", - "SI", "ESI", - "ES", "CS", "SS", "DS", "GS", "FS", - "CR0", "CR2", "CR3", "CR4", - "DR0", "DR1", "DR2", "DR3", "DR6", "DR7", - "TR3", "TR4", "TR5", "TR6", "TR7", - "MM0", "MM1", "MM2", "MM3", "MM4", "MM5", "MM6", "MM7", - "XMM0", "XMM1", "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7": - e = new AsmRegisterExpression(token); - nT(); - break; - default: - // DotIdentifier - auto begin2 = token; - Expression[] identList; - goto LenterLoop; - while (token.type == T.Dot) - { - nT(); - begin2 = token; - auto ident = requireId(); - LenterLoop: - e = new IdentifierExpression(token); - nT(); - set(e, begin2); - identList ~= e; - } - e = new DotListExpression(identList); - } - break; - default: - error(MID.ExpectedButFound, "Expression", token.srcText); - e = new EmptyExpression(); - break; - } - set(e, begin); - return e; - } - - /+++++++++++++++++++++++++++++ - + Expression parsing methods + - +++++++++++++++++++++++++++++/ - - Expression parseExpression() - { - auto begin = token; - auto e = parseAssignExpression(); - while (token.type == T.Comma) - { - auto comma = token; - nT(); - e = new CommaExpression(e, parseAssignExpression(), comma); - set(e, begin); - } -// if (!trying) -// writef("§%s§", e.classinfo.name); - return e; - } - - Expression parseAssignExpression() - { - auto begin = token; - auto e = parseCondExpression(); - while (1) - { - switch (token.type) - { - case T.Assign: - nT(); e = new AssignExpression(e, parseAssignExpression()); - break; - case T.LShiftAssign: - nT(); e = new LShiftAssignExpression(e, parseAssignExpression()); - break; - case T.RShiftAssign: - nT(); e = new RShiftAssignExpression(e, parseAssignExpression()); - break; - case T.URShiftAssign: - nT(); e = new URShiftAssignExpression(e, parseAssignExpression()); - break; - case T.OrAssign: - nT(); e = new OrAssignExpression(e, parseAssignExpression()); - break; - case T.AndAssign: - nT(); e = new AndAssignExpression(e, parseAssignExpression()); - break; - case T.PlusAssign: - nT(); e = new PlusAssignExpression(e, parseAssignExpression()); - break; - case T.MinusAssign: - nT(); e = new MinusAssignExpression(e, parseAssignExpression()); - break; - case T.DivAssign: - nT(); e = new DivAssignExpression(e, parseAssignExpression()); - break; - case T.MulAssign: - nT(); e = new MulAssignExpression(e, parseAssignExpression()); - break; - case T.ModAssign: - nT(); e = new ModAssignExpression(e, parseAssignExpression()); - break; - case T.XorAssign: - nT(); e = new XorAssignExpression(e, parseAssignExpression()); - break; - case T.CatAssign: - nT(); e = new CatAssignExpression(e, parseAssignExpression()); - break; - default: - return e; - } - set(e, begin); - } - return e; - } - - Expression parseCondExpression() - { - auto begin = token; - auto e = parseOrOrExpression(); - if (token.type == T.Question) - { - auto tok = token; - nT(); - auto iftrue = parseExpression(); - require(T.Colon); - auto iffalse = parseCondExpression(); - e = new CondExpression(e, iftrue, iffalse, tok); - set(e, begin); - } - return e; - } - - Expression parseOrOrExpression() - { - auto begin = token; - alias parseAndAndExpression parseNext; - auto e = parseNext(); - while (token.type == T.OrLogical) - { - auto tok = token; - nT(); - e = new OrOrExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAndAndExpression() - { - auto begin = token; - alias parseOrExpression parseNext; - auto e = parseNext(); - while (token.type == T.AndLogical) - { - auto tok = token; - nT(); - e = new AndAndExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseOrExpression() - { - auto begin = token; - alias parseXorExpression parseNext; - auto e = parseNext(); - while (token.type == T.OrBinary) - { - auto tok = token; - nT(); - e = new OrExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseXorExpression() - { - auto begin = token; - alias parseAndExpression parseNext; - auto e = parseNext(); - while (token.type == T.Xor) - { - auto tok = token; - nT(); - e = new XorExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseAndExpression() - { - auto begin = token; - alias parseCmpExpression parseNext; - auto e = parseNext(); - while (token.type == T.AndBinary) - { - auto tok = token; - nT(); - e = new AndExpression(e, parseNext(), tok); - set(e, begin); - } - return e; - } - - Expression parseCmpExpression() - { - auto begin = token; - auto e = parseShiftExpression(); - - auto operator = token; - switch (operator.type) - { - case T.Equal, T.NotEqual: - nT(); - e = new EqualExpression(e, parseShiftExpression(), operator); - break; - case T.Not: - if (peekNext() != T.Is) - break; - nT(); - // fall through - case T.Is: - nT(); - e = new IdentityExpression(e, parseShiftExpression(), operator); - break; - case T.LessEqual, T.Less, T.GreaterEqual, T.Greater, - T.Unordered, T.UorE, T.UorG, T.UorGorE, - T.UorL, T.UorLorE, T.LorEorG, T.LorG: - nT(); - e = new RelExpression(e, parseShiftExpression(), operator); - break; - case T.In: - nT(); - e = new InExpression(e, parseShiftExpression(), operator); - break; - default: - return e; - } - set(e, begin); - return e; - } - - Expression parseShiftExpression() - { - auto begin = token; - auto e = parseAddExpression(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.LShift: nT(); e = new LShiftExpression(e, parseAddExpression(), operator); break; - case T.RShift: nT(); e = new RShiftExpression(e, parseAddExpression(), operator); break; - case T.URShift: nT(); e = new URShiftExpression(e, parseAddExpression(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseAddExpression() - { - auto begin = token; - auto e = parseMulExpression(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.Plus: nT(); e = new PlusExpression(e, parseMulExpression(), operator); break; - case T.Minus: nT(); e = new MinusExpression(e, parseMulExpression(), operator); break; - case T.Tilde: nT(); e = new CatExpression(e, parseMulExpression(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseMulExpression() - { - auto begin = token; - auto e = parseUnaryExpression(); - while (1) - { - auto operator = token; - switch (operator.type) - { - case T.Mul: nT(); e = new MulExpression(e, parseUnaryExpression(), operator); break; - case T.Div: nT(); e = new DivExpression(e, parseUnaryExpression(), operator); break; - case T.Mod: nT(); e = new ModExpression(e, parseUnaryExpression(), operator); break; - default: - return e; - } - set(e, begin); - } - assert(0); - } - - Expression parseUnaryExpression() - { - auto begin = token; - Expression e; - switch (token.type) - { - case T.AndBinary: - nT(); - e = new AddressExpression(parseUnaryExpression()); - break; - case T.PlusPlus: - nT(); - e = new PreIncrExpression(parseUnaryExpression()); - break; - case T.MinusMinus: - nT(); - e = new PreDecrExpression(parseUnaryExpression()); - break; - case T.Mul: - nT(); - e = new DerefExpression(parseUnaryExpression()); - break; - case T.Minus: - case T.Plus: - nT(); - e = new SignExpression(parseUnaryExpression()); - break; - case T.Not: - nT(); - e = new NotExpression(parseUnaryExpression()); - break; - case T.Tilde: - nT(); - e = new CompExpression(parseUnaryExpression()); - break; - case T.New: - e = parseNewExpression(); - return e; - case T.Delete: - nT(); - e = new DeleteExpression(parseUnaryExpression()); - break; - case T.Cast: - requireNext(T.LParen); - Type type; - switch (token.type) - { - version(D2) - { - auto begin2 = token; - case T.Const: - type = new ConstType(null); - goto case_break; - case T.Invariant: - type = new InvariantType(null); - case_break: - nT(); - set(type, begin2); - break; - } - default: - type = parseType(); - } - require(T.RParen); - e = new CastExpression(parseUnaryExpression(), type); - break; - case T.LParen: - // ( Type ) . Identifier - Type parseType_() - { - nT(); - auto type = parseType(); - require(T.RParen); - require(T.Dot); - return type; - } - bool success; - auto type = try_(parseType_(), success); - if (success) - { - auto ident = requireId(); - e = new TypeDotIdExpression(type, ident); - break; - } - goto default; - default: - e = parsePostExpression(parsePrimaryExpression()); - return e; - } - assert(e !is null); - set(e, begin); - return e; - } - - Expression parsePostExpression(Expression e) - { - typeof(token) begin; - while (1) - { - begin = token; - switch (token.type) - { -/* -// Commented out because parseDotListExpression() handles this. - case T.Dot: - nT(); - if (token.type == T.Identifier) - { - string ident = token.identifier; - nT(); - if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) - { - nT(); // Skip !. - e = new DotTemplateInstanceExpression(e, ident, parseTemplateArguments()); - } - else - { - e = new DotIdExpression(e, ident); - nT(); - } - } - else if (token.type == T.New) - e = parseNewExpression(e); - else - expected(T.Identifier); - continue; -*/ - case T.Dot: - e = new PostDotListExpression(e, parseDotListExpression()); - goto Lset; - case T.PlusPlus: - e = new PostIncrExpression(e); - break; - case T.MinusMinus: - e = new PostDecrExpression(e); - break; - case T.LParen: - e = new CallExpression(e, parseArguments(T.RParen)); - goto Lset; - case T.LBracket: - // parse Slice- and IndexExpression - nT(); - if (token.type == T.RBracket) - { - e = new SliceExpression(e, null, null); - break; - } - - Expression[] es = [parseAssignExpression()]; - - if (token.type == T.Slice) - { - nT(); - e = new SliceExpression(e, es[0], parseAssignExpression()); - require(T.RBracket); - goto Lset; - } - else if (token.type == T.Comma) - { - es ~= parseArguments(T.RBracket); - } - else - require(T.RBracket); - - e = new IndexExpression(e, es); - goto Lset; - default: - return e; - } - nT(); - Lset: - set(e, begin); - } - assert(0); - } - - Expression parsePrimaryExpression() - { - auto begin = token; - Expression e; - switch (token.type) - { -/* -// Commented out because parseDotListExpression() handles this. - case T.Identifier: - string ident = token.identifier; - nT(); - if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) - { - nT(); // Skip !. - e = new TemplateInstanceExpression(ident, parseTemplateArguments()); - } - else - e = new IdentifierExpression(ident); - break; - case T.Dot: - nT(); - e = new IdentifierExpression("."); - break; -*/ - case T.Identifier, T.Dot, T.Typeof: - e = parseDotListExpression(); - break; - case T.This: - nT(); - e = new ThisExpression(); - break; - case T.Super: - nT(); - e = new SuperExpression(); - break; - case T.Null: - nT(); - e = new NullExpression(); - break; - case T.True, T.False: - nT(); - e = new BoolExpression(); - break; - case T.Dollar: - nT(); - e = new DollarExpression(); - break; - case T.Int32, T.Int64, T.Uint32, T.Uint64: - e = new IntNumberExpression(token.type, token.ulong_); - nT(); - break; - case T.Float32, T.Float64, T.Float80, - T.Imaginary32, T.Imaginary64, T.Imaginary80: - e = new RealNumberExpression(token.type, token.real_); - nT(); - break; - case T.CharLiteral, T.WCharLiteral, T.DCharLiteral: - nT(); - e = new CharLiteralExpression(); - break; - case T.String: - Token*[] stringLiterals; - do - { - stringLiterals ~= token; - nT(); - } while (token.type == T.String) - e = new StringLiteralsExpression(stringLiterals); - break; - case T.LBracket: - Expression[] values; - - nT(); - if (token.type != T.RBracket) - { - e = parseAssignExpression(); - if (token.type == T.Colon) - goto LparseAssocArray; - else if (token.type == T.Comma) - values = [e] ~ parseArguments(T.RBracket); - else - require(T.RBracket); - } - else - nT(); - - e = new ArrayLiteralExpression(values); - break; - - LparseAssocArray: - Expression[] keys; - - keys ~= e; - nT(); // Skip colon. - goto LenterLoop; - - while (1) - { - keys ~= parseAssignExpression(); - require(T.Colon); - LenterLoop: - values ~= parseAssignExpression(); - if (token.type != T.Comma) - break; - nT(); - } - require(T.RBracket); - e = new AssocArrayLiteralExpression(keys, values); - break; - case T.LBrace: - // DelegateLiteral := { Statements } - auto funcBody = parseFunctionBody(); - e = new FunctionLiteralExpression(funcBody); - break; - case T.Function, T.Delegate: - // FunctionLiteral := (function|delegate) Type? '(' ArgumentList ')' '{' Statements '}' - nT(); // Skip function|delegate token. - Type returnType; - Parameters parameters; - if (token.type != T.LBrace) - { - if (token.type != T.LParen) // Optional return type - returnType = parseType(); - parameters = parseParameterList(); - } - auto funcBody = parseFunctionBody(); - e = new FunctionLiteralExpression(returnType, parameters, funcBody); - break; - case T.Assert: - Expression msg; - requireNext(T.LParen); - e = parseAssignExpression(); - if (token.type == T.Comma) - { - nT(); - msg = parseAssignExpression(); - } - require(T.RParen); - e = new AssertExpression(e, msg); - break; - case T.Mixin: - requireNext(T.LParen); - e = parseAssignExpression(); - require(T.RParen); - e = new MixinExpression(e); - break; - case T.Import: - requireNext(T.LParen); - e = parseAssignExpression(); - require(T.RParen); - e = new ImportExpression(e); - break; - case T.Typeid: - requireNext(T.LParen); - auto type = parseType(); - require(T.RParen); - e = new TypeidExpression(type); - break; -/* -// Commented out because parseDotListExpression() handles this. - case T.Typeof: - requireNext(T.LParen); - auto type = new TypeofType(parseExpression()); - require(T.RParen); - if (token.type == T.Dot) - { // typeof ( Expression ) . Identifier - nT(); - string ident = requireIdentifier; - e = new TypeDotIdExpression(type, ident); - } - else // typeof ( Expression ) - e = new TypeofExpression(type); - break; -*/ - case T.Is: - requireNext(T.LParen); - - Type type, specType; - Token* ident; // optional Identifier - Token* opTok, specTok; - - type = parseDeclarator(ident, true); - - switch (token.type) - { - case T.Colon, T.Equal: - opTok = token; - nT(); - switch (token.type) - { - case T.Typedef, - T.Struct, - T.Union, - T.Class, - T.Interface, - T.Enum, - T.Function, - T.Delegate, - T.Super, - T.Return: - specTok = token; - nT(); - break; - default: - specType = parseType(); - } - default: - } - require(T.RParen); - e = new IsExpression(type, ident, opTok, specTok, specType); - break; - case T.LParen: - if (tokenAfterParenIs(T.LBrace)) - { - auto parameters = parseParameterList(); - // ( ParameterList ) FunctionBody - auto funcBody = parseFunctionBody(); - e = new FunctionLiteralExpression(null, parameters, funcBody); - } - else - { - // ( Expression ) - nT(); - e = parseExpression(); - require(T.RParen); - // TODO: create ParenExpression? - } - break; - // BasicType . Identifier - case T.Char, T.Wchar, T.Dchar, T.Bool, - T.Byte, T.Ubyte, T.Short, T.Ushort, - T.Int, T.Uint, T.Long, T.Ulong, - T.Float, T.Double, T.Real, - T.Ifloat, T.Idouble, T.Ireal, - T.Cfloat, T.Cdouble, T.Creal, T.Void: - auto type = new IntegralType(token.type); - nT(); - set(type, begin); - require(T.Dot); - auto ident = requireId(); - - e = new TypeDotIdExpression(type, ident); - break; - version(D2) - { - case T.Traits: - nT(); - require(T.LParen); - auto id = requireId(); - TemplateArguments args; - if (token.type == T.Comma) - { - args = parseTemplateArguments2(); - } - else - require(T.RParen); - e = new TraitsExpression(id, args); - break; - } - case T.Special: - e = new SpecialTokenExpression(token); - nT(); - break; - default: - // TODO: issue error msg. - error(MID.ExpectedButFound, "Expression", token.srcText); - e = new EmptyExpression(); - } - set(e, begin); - return e; - } - - Expression parseNewExpression(/*Expression e*/) - { - auto begin = token; - assert(token.type == T.New); - nT(); // Skip new keyword. - - Expression[] newArguments; - Expression[] ctorArguments; - - if (token.type == T.LParen) - newArguments = parseArguments(T.RParen); - - // NewAnonClassExpression: - // new (ArgumentList)opt class (ArgumentList)opt SuperClassopt InterfaceClassesopt ClassBody - if (token.type == T.Class) - { - nT(); - if (token.type == T.LParen) - ctorArguments = parseArguments(T.RParen); - - BaseClass[] bases = token.type != T.LBrace ? parseBaseClasses(false) : null ; - - auto decls = parseDeclarationDefinitionsBlock(); - return set(new NewAnonClassExpression(/*e, */newArguments, bases, ctorArguments, decls), begin); - } - - // NewExpression: - // NewArguments Type [ AssignExpression ] - // NewArguments Type ( ArgumentList ) - // NewArguments Type - auto type = parseType(); - - if (token.type == T.LParen) - ctorArguments = parseArguments(T.RParen); - - return set(new NewExpression(/*e, */newArguments, type, ctorArguments), begin); - } - - Type parseType() - { - return parseBasicType2(parseBasicType()); - } - - Type parseBasicType() - { - auto begin = token; - Type t; -// IdentifierType tident; - - switch (token.type) - { - case T.Char, T.Wchar, T.Dchar, T.Bool, - T.Byte, T.Ubyte, T.Short, T.Ushort, - T.Int, T.Uint, T.Long, T.Ulong, - T.Float, T.Double, T.Real, - T.Ifloat, T.Idouble, T.Ireal, - T.Cfloat, T.Cdouble, T.Creal, T.Void: - t = new IntegralType(token.type); - nT(); - set(t, begin); - break; - case T.Identifier, T.Typeof, T.Dot: - t = parseDotListType(); - break; - version(D2) - { - case T.Const: - // const ( Type ) - nT(); - require(T.LParen); - t = parseType(); - require(T.RParen); - t = new ConstType(t); - set(t, begin); - break; - case T.Invariant: - // invariant ( Type ) - nT(); - require(T.LParen); - t = parseType(); - require(T.RParen); - t = new InvariantType(t); - set(t, begin); - break; - } - default: - // TODO: issue error msg. - error(MID.ExpectedButFound, "BasicType", token.srcText); - t = new UndefinedType(); - nT(); - set(t, begin); - } - return t; - } - - Type parseBasicType2(Type t) - { - typeof(token) begin; - while (1) - { - begin = token; - switch (token.type) - { - case T.Mul: - t = new PointerType(t); - nT(); - break; - case T.LBracket: - t = parseArrayType(t); - continue; - case T.Function, T.Delegate: - TOK tok = token.type; - nT(); - auto parameters = parseParameterList(); - if (tok == T.Function) - t = new FunctionType(t, parameters); - else - t = new DelegateType(t, parameters); - break; - default: - return t; - } - set(t, begin); - } - assert(0); - } - - bool tokenAfterParenIs(TOK tok) - { - // We count nested parentheses tokens because template types may appear inside parameter lists; e.g. (int x, Foo!(int) y). - assert(token.type == T.LParen); - Token* next = token; - uint level = 1; - while (1) - { - lx.peek(next); - switch (next.type) - { - case T.RParen: - if (--level == 0) - { // Closing parentheses found. - lx.peek(next); - break; - } - continue; - case T.LParen: - ++level; - continue; - case T.EOF: - break; - default: - continue; - } - break; - } - - return next.type == tok; - } - - Type parseDeclaratorSuffix(Type t) - { - switch (token.type) - { - case T.LBracket: - // Type Identifier ArrayType - // ArrayType := [] or [Type] or [Expression..Expression] - do - t = parseArrayType(t); - while (token.type == T.LBracket) - break; -/+ // parsed in parseDeclaration() - case T.LParen: - TemplateParameters tparams; - if (tokenAfterParenIs(T.LParen)) - { - // ( TemplateParameterList ) ( ParameterList ) - tparams = parseTemplateParameterList(); - } - - auto params = parseParameterList(); - // ReturnType FunctionName ( ParameterList ) - t = new FunctionType(t, params, tparams); - break; -+/ - default: - break; - } - return t; - } - - Type parseArrayType(Type t) - { - assert(token.type == T.LBracket); - auto begin = token; - nT(); - if (token.type == T.RBracket) - { - t = new ArrayType(t); - nT(); - } - else - { - bool success; - auto assocType = try_(parseType(), success); - if (success) - t = new ArrayType(t, assocType); - else - { - Expression e = parseExpression(), e2; - if (token.type == T.Slice) - { - nT(); - e2 = parseExpression(); - } - t = new ArrayType(t, e, e2); - } - require(T.RBracket); - } - set(t, begin); - return t; - } - - Type parseDeclarator(ref Token* ident, bool identOptional = false) - { - auto t = parseType(); - - if (token.type == T.Identifier) - { - ident = token; - nT(); - t = parseDeclaratorSuffix(t); - } - else if (!identOptional) - expected(T.Identifier); - - return t; - } - - Expression[] parseArguments(TOK terminator) - { - assert(token.type == T.LParen || token.type == T.LBracket || token.type == T.Comma); - assert(terminator == T.RParen || terminator == T.RBracket); - Expression[] args; - - nT(); - if (token.type == terminator) - { - nT(); - return null; - } - - goto LenterLoop; - do - { - nT(); - LenterLoop: - args ~= parseAssignExpression(); - } while (token.type == T.Comma) - - require(terminator); - return args; - } - - Parameters parseParameterList() - out(params) - { - if (params.length > 1) - foreach (param; params.items[0..$-1]) - { - if (param.isVariadic()) - assert(0, "variadic arguments can only appear at the end of the parameter list."); - } - } - body - { - auto begin = token; - require(T.LParen); - - auto params = new Parameters(); - - if (token.type == T.RParen) - { - nT(); - return set(params, begin); - } - - while (1) - { - auto paramBegin = token; - Token* stcTok; - StorageClass stc, tmp; - - if (token.type == T.Ellipses) - { - nT(); - params ~= set(new Parameter(null, null, null, null), paramBegin); - break; // Exit loop. - } - - Lstc_loop: - switch (token.type) - { - version(D2) - { - case T.Invariant: // D2.0 - if (peekNext() == T.LParen) - goto default; - tmp = StorageClass.Invariant; - goto Lcommon; - case T.Const: // D2.0 - if (peekNext() == T.LParen) - goto default; - tmp = StorageClass.Const; - goto Lcommon; - case T.Final: // D2.0 - tmp = StorageClass.Final; - goto Lcommon; - case T.Scope: // D2.0 - tmp = StorageClass.Scope; - goto Lcommon; - case T.Static: // D2.0 - tmp = StorageClass.Static; - goto Lcommon; - case T.In: - tmp = StorageClass.In; - goto Lcommon; - case T.Out: - tmp = StorageClass.Out; - goto Lcommon; - case T.Inout, T.Ref: - tmp = StorageClass.Ref; - goto Lcommon; - case T.Lazy: - tmp = StorageClass.Lazy; - goto Lcommon; - Lcommon: - if (stc & tmp) - error(MID.RedundantStorageClass, token.srcText); - else - stc |= tmp; - nT(); - goto Lstc_loop; - } - else // else body of version(D2) - { - case T.In, T.Out, T.Inout, T.Ref, T.Lazy: - stcTok = token; - nT(); - goto default; - } - default: - version(D2) - { - if (stc != StorageClass.None) - stcTok = begin; - } - Token* ident; - auto type = parseDeclarator(ident, true); - - Expression assignExpr; - if (token.type == T.Assign) - { - nT(); - assignExpr = parseAssignExpression(); - } - - if (token.type == T.Ellipses) - { - auto p = set(new Parameter(stcTok, type, ident, assignExpr), paramBegin); - p.stc |= StorageClass.Variadic; - params ~= p; - nT(); - break; // Exit loop. - } - - params ~= set(new Parameter(stcTok, type, ident, assignExpr), paramBegin); - - if (token.type != T.Comma) - break; // Exit loop. - nT(); - continue; - } - break; // Exit loop. - } - require(T.RParen); - return set(params, begin); - } - - TemplateArguments parseTemplateArguments() - { - auto begin = token; - auto args = new TemplateArguments; - - require(T.LParen); - if (token.type != T.RParen) - { - while (1) - { - bool success; - auto typeArgument = try_(parseType(), success); - if (success) - { - // TemplateArgument: - // Type - // Symbol - args ~= typeArgument; - } - else - { - // TemplateArgument: - // AssignExpression - args ~= parseAssignExpression(); - } - if (token.type != T.Comma) - break; // Exit loop. - nT(); - } - } - require(T.RParen); - set(args, begin); - return args; - } -version(D2) -{ - TemplateArguments parseTemplateArguments2() - { - assert(token.type == T.Comma); - nT(); - auto begin = token; - auto args = new TemplateArguments; - - if (token.type != T.RParen) - { - while (1) - { - bool success; - auto typeArgument = try_(parseType(), success); - if (success) - { - // TemplateArgument: - // Type - // Symbol - args ~= typeArgument; - } - else - { - // TemplateArgument: - // AssignExpression - args ~= parseAssignExpression(); - } - if (token.type != T.Comma) - break; // Exit loop. - nT(); - } - } - else - error(MID.ExpectedButFound, "Type/Expression", ")"); - require(T.RParen); - set(args, begin); - return args; - } -} // version(D2) - TemplateParameters parseTemplateParameterList() - { - auto begin = token; - auto tparams = new TemplateParameters; - - require(T.LParen); - if (token.type == T.RParen) - return tparams; - - while (1) - { - auto paramBegin = token; - TP tp; - Token* ident; - Type valueType; - Type specType, defType; - Expression specValue, defValue; - - switch (token.type) - { - case T.Alias: - // TemplateAliasParameter: - // alias Identifier - tp = TP.Alias; - nT(); // Skip alias keyword. - ident = requireId(); - // : SpecializationType - if (token.type == T.Colon) - { - nT(); - specType = parseType(); - } - // = DefaultType - if (token.type == T.Assign) - { - nT(); - defType = parseType(); - } - break; - case T.Identifier: - ident = token; - switch (peekNext()) - { - case T.Ellipses: - // TemplateTupleParameter: - // Identifier ... - tp = TP.Tuple; - nT(); // Skip Identifier. - nT(); // Skip Ellipses. - // if (token.type == T.Comma) - // error(); // TODO: issue error msg for variadic param not being last. - break; - case T.Comma, T.RParen, T.Colon, T.Assign: - // TemplateTypeParameter: - // Identifier - tp = TP.Type; - nT(); // Skip Identifier. - // : SpecializationType - if (token.type == T.Colon) - { - nT(); - specType = parseType(); - } - // = DefaultType - if (token.type == T.Assign) - { - nT(); - defType = parseType(); - } - break; - default: - // TemplateValueParameter: - // Declarator - ident = null; - goto LTemplateValueParameter; - } - break; - default: - LTemplateValueParameter: - // TemplateValueParameter: - // Declarator - tp = TP.Value; - valueType = parseDeclarator(ident); - // : SpecializationValue - if (token.type == T.Colon) - { - nT(); - specValue = parseCondExpression(); - } - // = DefaultValue - if (token.type == T.Assign) - { - nT(); - defValue = parseCondExpression(); - } - } - - tparams ~= set(new TemplateParameter(tp, valueType, ident, specType, defType, specValue, defValue), paramBegin); - - if (token.type != T.Comma) - break; - nT(); - } - require(T.RParen); - set(tparams, begin); - return tparams; - } - - void expected(TOK tok) - { - if (token.type != tok) - error(MID.ExpectedButFound, Token.Token.toString(tok), token.srcText); - } - - void require(TOK tok) - { - if (token.type == tok) - nT(); - else - error(MID.ExpectedButFound, Token.Token.toString(tok), token.srcText); - } - - void requireNext(TOK tok) - { - nT(); - require(tok); - } - - string requireIdentifier() - { - string identifier; - if (token.type == T.Identifier) - { - identifier = token.identifier; - nT(); - } - else - error(MID.ExpectedButFound, "Identifier", token.srcText); - return identifier; - } - - Token* requireId() - { - if (token.type == T.Identifier) - { - auto id = token; - nT(); - return id; - } - else - error(MID.ExpectedButFound, "Identifier", token.srcText); - return null; - } - - void error(MID id, ...) - { - if (trying) - { - ++errorCount; - return; - } - -// if (errors.length == 10) -// return; - errors ~= new Information(InfoType.Parser, id, lx.loc, arguments(_arguments, _argptr)); -// writefln("(%d)P: ", lx.loc, errors[$-1].getMsg); - } -}
--- a/trunk/src/Settings.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Settings; -import Messages; -import Parser, SyntaxTree, Declarations, Expressions; -import std.metastrings; - -version(D2) -{ - const VERSION_MAJOR = 2; - const VERSION_MINOR = 0; -} -else -{ - const VERSION_MAJOR = 1; - const VERSION_MINOR = 0; -} -const string VERSION = Format!("%s.%s", VERSION_MAJOR, VERSION_MINOR); - -const COMPILED_WITH = __VENDOR__; -const COMPILED_VERSION = Format!("%s.%s", __VERSION__/1000, __VERSION__%1000); -const COMPILED_DATE = __TIMESTAMP__; - -const usageHighlight = "highlight (hl) file.d"; - -struct GlobalSettings -{ -static: - string language; /// Language of messages catalogue to load. - string[] messages; /// Table of localized compiler messages. - void load() - { - auto fileName = "config.d"[]; - auto sourceText = cast(char[]) std.file.read(fileName); - auto parser = new Parser(sourceText, fileName); - parser.start(); - auto root = parser.parseModule(); - - if (parser.errors.length || parser.lx.errors.length) - { - throw new Exception("There are errors in " ~ fileName ~ "."); - } - - foreach (decl; root.children) - { - auto v = Cast!(VariableDeclaration)(decl); - if (v && v.idents[0].srcText == "language") - { - auto e = v.values[0]; - if (!e) - throw new Exception("language variable has no value set."); - auto val = Cast!(StringLiteralsExpression)(e); - if (val) - { - GlobalSettings.language = val.getString(); - break; - } - } - } - - // Load messages - if (GlobalSettings.language.length) - { - fileName = "lang_" ~ GlobalSettings.language ~ ".d"; - sourceText = cast(char[]) std.file.read(fileName); - parser = new Parser(sourceText, fileName); - parser.start(); - root = parser.parseModule(); - - if (parser.errors.length || parser.lx.errors.length) - { - throw new Exception("There are errors in "~fileName~"."); - } - - char[][] messages; - foreach (decl; root.children) - { - auto v = Cast!(VariableDeclaration)(decl); - if (v && v.idents[0].srcText == "messages") - { - auto e = v.values[0]; - if (!e) - throw new Exception("messages variable in "~fileName~" has no value set."); - if (auto array = Cast!(ArrayInitializer)(e)) - { - foreach (value; array.values) - { - if (auto str = Cast!(StringLiteralsExpression)(value)) - messages ~= str.getString(); - } - } - else - throw new Exception("messages variable is set to "~e.classinfo.name~" instead of an ArrayInitializer."); - } - } - if (messages.length != MID.max+1) - throw new Exception(std.string.format("messages table in %s must exactly have %d entries, but %s were found.", fileName, MID.max, messages.length)); - GlobalSettings.messages = messages; - } - } - -}
--- a/trunk/src/Statements.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,567 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Statements; -import SyntaxTree; -import Expressions; -import Declarations; -import Types; -import Token; - -abstract class Statement : Node -{ - this() - { - super(NodeCategory.Statement); - } -} - -class Statements : Statement -{ - this() - { - mixin(set_kind); - } - - void opCatAssign(Statement s) - { - this.children ~= s; - } -} - -class IllegalStatement : Statement -{ - Token* tok; - this(Token* tok) - { - mixin(set_kind); - this.tok = tok; - } -} - -class EmptyStatement : Statement -{ - this() - { - mixin(set_kind); - } -} - -class FunctionBody : Node -{ - Statement funcBody, inBody, outBody; - Token* outIdent; - this() - { - super(NodeCategory.Other); - mixin(set_kind); - } - - void finishConstruction() - { - if (funcBody) - this.children ~= funcBody; - if (inBody) - this.children ~= inBody; - if (outBody) - this.children ~= outBody; - } -} - -class ScopeStatement : Statement -{ - Statement s; - this(Statement s) - { - mixin(set_kind); - this.children = [s]; - this.s = s; - } -} - -class LabeledStatement : Statement -{ - Token* label; - Statement s; - this(Token* label, Statement s) - { - mixin(set_kind); - this.children = [s]; - this.label = label; - this.s = s; - } -} - -class ExpressionStatement : Statement -{ - Expression expression; - this(Expression expression) - { - mixin(set_kind); - this.children = [expression]; - this.expression = expression; - } -} - -class DeclarationStatement : Statement -{ - Declaration declaration; - this(Declaration declaration) - { - mixin(set_kind); - this.children = [declaration]; - this.declaration = declaration; - } -} - -class IfStatement : Statement -{ - Statement variable; // AutoDeclaration or VariableDeclaration - Expression condition; - Statement ifBody; - Statement elseBody; - this(Statement variable, Expression condition, Statement ifBody, Statement elseBody) - { - mixin(set_kind); - if (variable) - this.children ~= variable; - else - this.children ~= condition; - this.children ~= ifBody; - if (elseBody) - this.children ~= elseBody; - this.variable = variable; - this.condition = condition; - this.ifBody = ifBody; - this.elseBody = elseBody; - } -} - -class WhileStatement : Statement -{ - Expression condition; - Statement whileBody; - this(Expression condition, Statement whileBody) - { - mixin(set_kind); - this.children = [cast(Node)condition, whileBody]; - this.condition = condition; - this.whileBody = whileBody; - } -} - -class DoWhileStatement : Statement -{ - Expression condition; - Statement doBody; - this(Expression condition, Statement doBody) - { - mixin(set_kind); - this.children = [cast(Node)condition, doBody]; - this.condition = condition; - this.doBody = doBody; - } -} - -class ForStatement : Statement -{ - Statement init; - Expression condition, increment; - Statement forBody; - - this(Statement init, Expression condition, Expression increment, Statement forBody) - { - mixin(set_kind); - if (init) - this.children ~= init; - if (condition) - this.children ~= condition; - if (increment) - this.children ~= increment; - this.children ~= forBody; - this.init = init; - this.condition = condition; - this.increment = increment; - this.forBody = forBody; - } -} - -class ForeachStatement : Statement -{ - TOK tok; - Parameters params; - Expression aggregate; - Statement forBody; - - this(TOK tok, Parameters params, Expression aggregate, Statement forBody) - { - mixin(set_kind); - this.children = [cast(Node)params, aggregate, forBody]; - this.tok = tok; - this.params = params; - this.aggregate = aggregate; - this.forBody = forBody; - } -} - -version(D2) -{ -class ForeachRangeStatement : Statement -{ - TOK tok; - Parameters params; - Expression lower, upper; - Statement forBody; - - this(TOK tok, Parameters params, Expression lower, Expression upper, Statement forBody) - { - mixin(set_kind); - this.children = [cast(Node)params, lower, upper, forBody]; - this.tok = tok; - this.params = params; - this.lower = lower; - this.upper = upper; - this.forBody = forBody; - } -} -} - -class SwitchStatement : Statement -{ - Expression condition; - Statement switchBody; - - this(Expression condition, Statement switchBody) - { - mixin(set_kind); - this.children = [cast(Node)condition, switchBody]; - this.condition = condition; - this.switchBody = switchBody; - } -} - -class CaseStatement : Statement -{ - Expression[] values; - Statement caseBody; - - this(Expression[] values, Statement caseBody) - { - mixin(set_kind); - this.children = cast(Node[])values ~ [caseBody]; - this.values = values; - this.caseBody = caseBody; - } -} - -class DefaultStatement : Statement -{ - Statement defaultBody; - this(Statement defaultBody) - { - mixin(set_kind); - this.children = [defaultBody]; - this.defaultBody = defaultBody; - } -} - -class ContinueStatement : Statement -{ - Token* ident; - this(Token* ident) - { - mixin(set_kind); - this.ident = ident; - } -} - -class BreakStatement : Statement -{ - Token* ident; - this(Token* ident) - { - mixin(set_kind); - this.ident = ident; - } -} - -class ReturnStatement : Statement -{ - Expression expr; - this(Expression expr) - { - mixin(set_kind); - if (expr) - this.children = [expr]; - this.expr = expr; - } -} - -class GotoStatement : Statement -{ - Token* ident; - Expression caseExpr; - this(Token* ident, Expression caseExpr) - { - mixin(set_kind); - if (caseExpr) - this.children = [caseExpr]; - this.ident = ident; - this.caseExpr = caseExpr; - } -} - -class WithStatement : Statement -{ - Expression expr; - Statement withBody; - this(Expression expr, Statement withBody) - { - mixin(set_kind); - this.children = [cast(Node)expr, withBody]; - this.expr = expr; - this.withBody = withBody; - } -} - -class SynchronizedStatement : Statement -{ - Expression expr; - Statement syncBody; - this(Expression expr, Statement withBody) - { - mixin(set_kind); - this.children = [cast(Node)expr, syncBody]; - this.expr = expr; - this.syncBody = syncBody; - } -} - -class TryStatement : Statement -{ - Statement tryBody; - CatchBody[] catchBodies; - FinallyBody finallyBody; - this(Statement tryBody, CatchBody[] catchBodies, FinallyBody finallyBody) - { - mixin(set_kind); - this.children = [tryBody]; - if (catchBodies.length) - this.children ~= catchBodies; - if (finallyBody) - this.children ~= finallyBody; - this.tryBody = tryBody; - this.catchBodies = catchBodies; - this.finallyBody = finallyBody; - } -} - -class CatchBody : Statement -{ - Parameter param; - Statement catchBody; - this(Parameter param, Statement catchBody) - { - mixin(set_kind); - this.children = [cast(Node)param, catchBody]; - this.param = param; - this.catchBody = catchBody; - } -} - -class FinallyBody : Statement -{ - Statement finallyBody; - this(Statement finallyBody) - { - mixin(set_kind); - this.children = [finallyBody]; - this.finallyBody = finallyBody; - } -} - -class ScopeGuardStatement : Statement -{ - Token* condition; - Statement scopeBody; - this(Token* condition, Statement scopeBody) - { - mixin(set_kind); - this.children = [scopeBody]; - this.condition = condition; - this.scopeBody = scopeBody; - } -} - -class ThrowStatement : Statement -{ - Expression expr; - this(Expression expr) - { - mixin(set_kind); - this.children = [expr]; - this.expr = expr; - } -} - -class VolatileStatement : Statement -{ - Statement volatileBody; - this(Statement volatileBody) - { - mixin(set_kind); - if (volatileBody) - this.children = [volatileBody]; - this.volatileBody = volatileBody; - } -} - -class AsmStatement : Statement -{ - Statements statements; - this(Statements statements) - { - mixin(set_kind); - this.children = [statements]; - this.statements = statements; - } -} - -class AsmInstruction : Statement -{ - Token* ident; - Expression[] operands; - this(Token* ident, Expression[] operands) - { - mixin(set_kind); - this.children = operands; - this.ident = ident; - this.operands = operands; - } -} - -class IllegalAsmInstruction : IllegalStatement -{ - this(Token* token) - { - super(token); - mixin(set_kind); - } -} - -class PragmaStatement : Statement -{ - Token* ident; - Expression[] args; - Statement pragmaBody; - this(Token* ident, Expression[] args, Statement pragmaBody) - { - mixin(set_kind); - if (args.length) - this.children = args; - this.children ~= pragmaBody; - this.ident = ident; - this.args = args; - this.pragmaBody = pragmaBody; - } -} - -class MixinStatement : Statement -{ - Expression[] templateIdents; - Token* mixinIdent; - this(Expression[] templateIdents, Token* mixinIdent) - { - mixin(set_kind); - this.children = templateIdents; - this.templateIdents = templateIdents; - this.mixinIdent = mixinIdent; - } -} - -class StaticIfStatement : Statement -{ - Expression condition; - Statement ifBody, elseBody; - this(Expression condition, Statement ifBody, Statement elseBody) - { - mixin(set_kind); - this.children = [cast(Node)condition, ifBody]; - if (elseBody) - this.children ~= elseBody; - this.condition = condition; - this.ifBody = ifBody; - this.elseBody = elseBody; - } -} - -class StaticAssertStatement : Statement -{ - Expression condition, message; - this(Expression condition, Expression message) - { - mixin(set_kind); - this.children = [condition]; - if (message) - this.children ~= message; - this.condition = condition; - this.message = message; - } -} - -class DebugStatement : Statement -{ - Token* cond; - Statement debugBody, elseBody; - this(Token* cond, Statement debugBody, Statement elseBody) - { - mixin(set_kind); - this.children = [debugBody]; - if (elseBody) - this.children ~= elseBody; - this.cond = cond; - this.debugBody = debugBody; - this.elseBody = elseBody; - } -} - -class VersionStatement : Statement -{ - Token* cond; - Statement versionBody, elseBody; - this(Token* cond, Statement versionBody, Statement elseBody) - { - mixin(set_kind); - this.children = [versionBody]; - if (elseBody) - this.children ~= [elseBody]; - this.cond = cond; - this.versionBody = versionBody; - this.elseBody = elseBody; - } -} - -class AttributeStatement : Statement -{ - TOK tok; - Statement statement; - this(TOK tok, Statement statement) - { - mixin(set_kind); - this.children = [statement]; - this.tok = tok; - this.statement = statement; - } -} - -class ExternStatement : AttributeStatement -{ - Linkage linkage; - this(Linkage linkage, Statement statement) - { - super(TOK.Extern, statement); - mixin(set_kind); - this.linkage = linkage; - } -}
--- a/trunk/src/SyntaxTree.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module SyntaxTree; -import Token; - -enum NodeCategory -{ - Declaration, - Statement, - Expression, - Type, - Other -} - -enum NodeKind -{ - // Declarations: - Declarations, - EmptyDeclaration, - IllegalDeclaration, - ModuleDeclaration, - ImportDeclaration, - AliasDeclaration, - TypedefDeclaration, - EnumDeclaration, - ClassDeclaration, - InterfaceDeclaration, - StructDeclaration, - UnionDeclaration, - ConstructorDeclaration, - StaticConstructorDeclaration, - DestructorDeclaration, - StaticDestructorDeclaration, - FunctionDeclaration, - VariableDeclaration, - InvariantDeclaration, - UnittestDeclaration, - DebugDeclaration, - VersionDeclaration, - StaticIfDeclaration, - StaticAssertDeclaration, - TemplateDeclaration, - NewDeclaration, - DeleteDeclaration, - AttributeDeclaration, - ExternDeclaration, - AlignDeclaration, - PragmaDeclaration, - MixinDeclaration, - - // Statements: - Statements, - IllegalStatement, - EmptyStatement, - ScopeStatement, - LabeledStatement, - ExpressionStatement, - DeclarationStatement, - IfStatement, - ConditionalStatement, - WhileStatement, - DoWhileStatement, - ForStatement, - ForeachStatement, - ForeachRangeStatement, // D2.0 - SwitchStatement, - CaseStatement, - DefaultStatement, - ContinueStatement, - BreakStatement, - ReturnStatement, - GotoStatement, - WithStatement, - SynchronizedStatement, - TryStatement, - CatchBody, - FinallyBody, - ScopeGuardStatement, - ThrowStatement, - VolatileStatement, - AsmStatement, - AsmInstruction, - IllegalAsmInstruction, - PragmaStatement, - MixinStatement, - StaticIfStatement, - StaticAssertStatement, - DebugStatement, - VersionStatement, - AttributeStatement, - ExternStatement, - - // Expressions: - EmptyExpression, - BinaryExpression, - CondExpression, - CommaExpression, - OrOrExpression, - AndAndExpression, - OrExpression, - XorExpression, - AndExpression, - CmpExpression, - EqualExpression, - IdentityExpression, - RelExpression, - InExpression, - LShiftExpression, - RShiftExpression, - URShiftExpression, - PlusExpression, - MinusExpression, - CatExpression, - MulExpression, - DivExpression, - ModExpression, - AssignExpression, - LShiftAssignExpression, - RShiftAssignExpression, - URShiftAssignExpression, - OrAssignExpression, - AndAssignExpression, - PlusAssignExpression, - MinusAssignExpression, - DivAssignExpression, - MulAssignExpression, - ModAssignExpression, - XorAssignExpression, - CatAssignExpression, - UnaryExpression, - AddressExpression, - PreIncrExpression, - PreDecrExpression, - PostIncrExpression, - PostDecrExpression, - DerefExpression, - SignExpression, - NotExpression, - CompExpression, - PostDotListExpression, - CallExpression, - NewExpression, - NewAnonClassExpression, - DeleteExpression, - CastExpression, - IndexExpression, - SliceExpression, - PrimaryExpressio, - IdentifierExpression, - SpecialTokenExpression, - DotListExpression, - TemplateInstanceExpression, - ThisExpression, - SuperExpression, - NullExpression, - DollarExpression, - BoolExpression, - IntNumberExpression, - RealNumberExpression, - CharLiteralExpression, - StringLiteralsExpression, - ArrayLiteralExpression, - AssocArrayLiteralExpression, - AssertExpression, - MixinExpression, - ImportExpression, - TypeofExpression, - TypeDotIdExpression, - TypeidExpression, - IsExpression, - FunctionLiteralExpression, - TraitsExpression, // D2.0 - VoidInitializer, - ArrayInitializer, - StructInitializer, - AsmTypeExpression, - AsmOffsetExpression, - AsmSegExpression, - AsmPostBracketExpression, - AsmBracketExpression, - AsmLocalSizeExpression, - AsmRegisterExpression, - - // Types: - IntegralType, - UndefinedType, - DotListType, - IdentifierType, - TypeofType, - TemplateInstanceType, - PointerType, - ArrayType, - FunctionType, - DelegateType, - ConstType, // D2.0 - InvariantType, // D2.0 - - // Other: - FunctionBody, - Parameter, - Parameters, - BaseClass, - TemplateParameter, - TemplateParameters, - TemplateArguments, -} - -/// This string is mixed into the constructor of a class that inherits from Node. -const string set_kind = `this.kind = mixin("NodeKind." ~ typeof(this).stringof);`; - -Class Cast(Class)(Node n) -{ - assert(n !is null); - if (n.kind == mixin("NodeKind." ~ typeof(Class).stringof)) - return cast(Class)cast(void*)n; - return null; -} - -class Node -{ - NodeCategory category; - NodeKind kind; - Node[] children; - Token* begin, end; - - this(NodeCategory category) - { - this.category = category; - } - - void setTokens(Token* begin, Token* end) - { - this.begin = begin; - this.end = end; - } -}
--- a/trunk/src/Token.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Token; -import std.c.stdlib : malloc, free; -import std.outofmemory; - -struct Position -{ - size_t loc; - size_t col; -} - -enum TOK : ushort -{ - Invalid, - - /// Flag for whitespace tokens that must be ignored in the parsing phase. - Whitespace = 0x8000, - Comment = 1 | Whitespace, - Shebang = 2 | Whitespace, - HashLine = 3 | Whitespace, - Filespec = 4 | Whitespace, - - Identifier = 5, - String, - Special, - CharLiteral, WCharLiteral, DCharLiteral, - - // Numbers - Int32, Int64, Uint32, Uint64, - // Floating point number scanner relies on this order. (FloatXY + 3 == ImaginaryXY) - Float32, Float64, Float80, - Imaginary32, Imaginary64, Imaginary80, - - - // Brackets - LParen, - RParen, - LBracket, - RBracket, - LBrace, - RBrace, - - Dot, Slice, Ellipses, - - // Floating point number operators - Unordered, - UorE, - UorG, - UorGorE, - UorL, - UorLorE, - LorEorG, - LorG, - - // Normal operators - Assign, Equal, NotEqual, Not, - LessEqual, Less, - GreaterEqual, Greater, - LShiftAssign, LShift, - RShiftAssign,RShift, - URShiftAssign, URShift, - OrAssign, OrLogical, OrBinary, - AndAssign, AndLogical, AndBinary, - PlusAssign, PlusPlus, Plus, - MinusAssign, MinusMinus, Minus, - DivAssign, Div, - MulAssign, Mul, - ModAssign, Mod, - XorAssign, Xor, - CatAssign, Catenate, - Tilde, - Identity, NotIdentity, - - Colon, - Semicolon, - Question, - Comma, - Dollar, - - /* Keywords: - NB.: Token.isKeyword() depends on this list being contiguous. - */ - Abstract,Alias,Align,Asm,Assert,Auto,Body, - Bool,Break,Byte,Case,Cast,Catch,Cdouble, - Cent,Cfloat,Char,Class,Const,Continue,Creal, - Dchar,Debug,Default,Delegate,Delete,Deprecated,Do, - Double,Else,Enum,Export,Extern,False,Final, - Finally,Float,For,Foreach,Foreach_reverse,Function,Goto, - Idouble,If,Ifloat,Import,In,Inout,Int, - Interface,Invariant,Ireal,Is,Lazy,Long,Macro/+D2.0+/, - Mixin,Module,New,Null,Out,Override,Package, - Pragma,Private,Protected,Public,Real,Ref/+D2.0+/,Return, - Scope,Short,Static,Struct,Super,Switch,Synchronized, - Template,This,Throw,Traits/+D2.0+/,True,Try,Typedef,Typeid, - Typeof,Ubyte,Ucent,Uint,Ulong,Union,Unittest, - Ushort,Version,Void,Volatile,Wchar,While,With, - - HEAD, // start of linked list - EOF -} - -alias TOK.Abstract KeywordsBegin; -alias TOK.With KeywordsEnd; - -struct Token -{ - TOK type; -// Position pos; - - Token* next, prev; - - char* start; - char* end; - - union - { - struct - { - Token* line_num; // #line number - Token* line_filespec; // #line number filespec - } - struct - { - string str; - char pf; - } - dchar dchar_; - long long_; - ulong ulong_; - int int_; - uint uint_; - float float_; - double double_; - real real_; - } - - alias srcText identifier; - - string srcText() - { - assert(start && end); - return start[0 .. end - start]; - } - - static string toString(TOK tok) - { - return tokToString[tok]; - } - - bool isKeyword() - { - return KeywordsBegin <= type && type <= KeywordsEnd; - } - - bool isWhitespace() - { - return !!(type & TOK.Whitespace); - } - - int opEquals(TOK type2) - { - return type == type2; - } - - new(size_t size) - { - void* p = malloc(size); - if (p is null) - throw new OutOfMemoryException(); - *cast(Token*)p = Token.init; - return p; - } - - delete(void* p) - { - free(p); - } -} - -string[] tokToString = [ - "Invalid", - - "Comment", - "#! /shebang/", - "#line", - - "Identifier", - "String", - "Special", - "CharLiteral", "WCharLiteral", "DCharLiteral", - - "Int32", "Int64", "Uint32", "Uint64", - "Float32", "Float64", "Float80", - "Imaginary32", "Imaginary64", "Imaginary80", - - "(", - ")", - "[", - "]", - "{", - "}", - - ".", "..", "...", - - "Unordered", - "UorE", - "UorG", - "UorGorE", - "UorL", - "UorLorE", - "LorEorG", - "LorG", - - "=", "==", "!=", "!", - "<=", "<", - ">=", ">", - "<<=", "<<", - ">>=",">>", - ">>>=", ">>>", - "|=", "||", "|", - "&=", "&&", "&", - "+=", "++", "+", - "-=", "--", "-", - "/=", "/", - "*=", "*", - "%=", "%", - "^=", "^", - "~=", "~", - "~", - "is", "!is", - - ":", - ";", - "?", - ",", - "$", - - "abstract","alias","align","asm","assert","auto","body", - "bool","break","byte","case","cast","catch","cdouble", - "cent","cfloat","char","class","const","continue","creal", - "dchar","debug","default","delegate","delete","deprecated","do", - "double","else","enum","export","extern","false","final", - "finally","float","for","foreach","foreach_reverse","function","goto", - "idouble","if","ifloat","import","in","inout","int", - "interface","invariant","ireal","is","lazy","long","macro", - "mixin","module","new","null","out","override","package", - "pragma","private","protected","public","real","ref","return", - "scope","short","static","struct","super","switch","synchronized", - "template","this","throw","true","try","typedef","typeid", - "typeof","ubyte","ucent","uint","ulong","union","unittest", - "ushort","version","void","volatile","wchar","while","with", - - "EOF" -];
--- a/trunk/src/Types.d Tue Aug 21 16:18:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,426 +0,0 @@ -/++ - Author: Aziz Köksal - License: GPL3 -+/ -module Types; -import SyntaxTree; -import Token; -import Expressions; - -enum Linkage -{ - Invalid, - C, - Cpp, - D, - Windows, - Pascal, - System -} - -enum StorageClass -{ - None = 0, - Abstract = 1, - Auto = 1<<2, - Const = 1<<3, - Deprecated = 1<<4, - Extern = 1<<5, - Final = 1<<6, - Invariant = 1<<7, - Override = 1<<8, - Scope = 1<<9, - Static = 1<<10, - Synchronized = 1<<11, - In = 1<<12, - Out = 1<<13, - Ref = 1<<14, - Lazy = 1<<15, - Variadic = 1<<16, -} - -class Parameter : Node -{ - StorageClass stc; - Token* stcTok; - Type type; - Token* ident; - Expression assignExpr; - - this(Token* stcTok, Type type, Token* ident, Expression assignExpr) - { - super(NodeCategory.Other); - mixin(set_kind); - if (type) // type can be null when param in foreach statement - this.children = [type]; - if (assignExpr) - this.children ~= assignExpr; - - StorageClass stc; - if (stcTok !is null) - { - // NB: In D 2.0 StorageClass.In means final/scope/const - switch (stcTok.type) - { - // TODO: D 2.0 invariant/const/final/scope - case TOK.In: stc = StorageClass.In; break; - case TOK.Out: stc = StorageClass.Out; break; - case TOK.Inout: - case TOK.Ref: stc = StorageClass.Ref; break; - case TOK.Lazy: stc = StorageClass.Lazy; break; - case TOK.Ellipses: - stc = StorageClass.Variadic; - default: - } - } - - this.stc = stc; - this.stcTok = stcTok; - this.type = type; - this.ident = ident; - this.assignExpr = assignExpr; - } - - bool isVariadic() - { - return !!(stc & StorageClass.Variadic); - } - - bool isOnlyVariadic() - { - return stc == StorageClass.Variadic; - } -} - -class Parameters : Node -{ - this() - { - super(NodeCategory.Other); - mixin(set_kind); - } - - bool hasVariadic() - { - if (children.length != 0) - return items[$-1].isVariadic(); - return false; - } - - void opCatAssign(Parameter param) - { children ~= param; } - - Parameter[] items() - { return cast(Parameter[])children; } - - size_t length() - { return children.length; } -} - - -enum Protection -{ - None, - Private = 1, - Protected = 1<<1, - Package = 1<<2, - Public = 1<<3, - Export = 1<<4 -} - -class BaseClass : Node -{ - Protection prot; - Type type; - this(Protection prot, Type type) - { - super(NodeCategory.Other); - mixin(set_kind); - this.children = [type]; - this.prot = prot; - this.type = type; - } -} - -enum TP -{ - Type, - Value, - Alias, - Tuple -} - -class TemplateParameter : Node -{ - TP tp; - Type valueType; - Token* ident; - Type specType, defType; - Expression specValue, defValue; - this(TP tp, Type valueType, Token* ident, Type specType, Type defType, Expression specValue, Expression defValue) - { - super(NodeCategory.Other); - mixin(set_kind); - if (valueType) - this.children ~= valueType; - if (specType) - this.children ~= specType; - if (defType) - this.children ~= defType; - if (specValue) - this.children ~= specValue; - if (defValue) - this.children ~= defValue; - this.tp = tp; - this.valueType = valueType; - this.ident = ident; - this.specType = specType; - this.defType = defType; - this.specValue = specValue; - this.defValue = defValue; - } -} - -class TemplateParameters : Node -{ - this() - { - super(NodeCategory.Other); - mixin(set_kind); - } - - void opCatAssign(TemplateParameter parameter) - { - this.children ~= parameter; - } - - TemplateParameter[] items() - { - return cast(TemplateParameter[])children; - } -} - -class TemplateArguments : Node -{ - this() - { - super(NodeCategory.Other); - mixin(set_kind); - } - - void opCatAssign(Node argument) - { - this.children ~= argument; - } -} - -enum TID -{ - Void = TOK.Void, - Char = TOK.Char, - Wchar = TOK.Wchar, - Dchar = TOK.Dchar, - Bool = TOK.Bool, - Byte = TOK.Byte, - Ubyte = TOK.Ubyte, - Short = TOK.Short, - Ushort = TOK.Ushort, - Int = TOK.Int, - Uint = TOK.Uint, - Long = TOK.Long, - Ulong = TOK.Ulong, - Float = TOK.Float, - Double = TOK.Double, - Real = TOK.Real, - Ifloat = TOK.Ifloat, - Idouble = TOK.Idouble, - Ireal = TOK.Ireal, - Cfloat = TOK.Cfloat, - Cdouble = TOK.Cdouble, - Creal = TOK.Creal, - - Undefined, - Function, - Delegate, - Pointer, - Array, - DotList, - Identifier, - Typeof, - TemplateInstance, - Const, // D2 - Invariant, // D2 -} - -abstract class Type : Node -{ - TID tid; - Type next; - - this(TID tid) - { - this(tid, null); - } - - this(TID tid, Type next) - { - super(NodeCategory.Type); - if (next) - this.children ~= next; - this.tid = tid; - this.next = next; - } -} - -class IntegralType : Type -{ - this(TOK tok) - { - super(cast(TID)tok); - mixin(set_kind); - } -} - -class UndefinedType : Type -{ - this() - { - super(TID.Undefined); - mixin(set_kind); - } -} - -class DotListType : Type -{ - Type[] dotList; - this(Type[] dotList) - { - super(TID.DotList); - mixin(set_kind); - this.children ~= dotList; - this.dotList = dotList; - } -} - -class IdentifierType : Type -{ - Token* ident; - this(Token* ident) - { - super(TID.Identifier); - mixin(set_kind); - this.ident = ident; - } -} - -class TypeofType : Type -{ - Expression e; - this(Expression e) - { - super(TID.Typeof); - mixin(set_kind); - this.children ~= e; - this.e = e; - } -} - -class TemplateInstanceType : Type -{ - Token* ident; - TemplateArguments targs; - this(Token* ident, TemplateArguments targs) - { - super(TID.TemplateInstance); - mixin(set_kind); - this.children ~= targs; - this.ident = ident; - this.targs = targs; - } -} - -class PointerType : Type -{ - this(Type t) - { - super(TID.Pointer, t); - mixin(set_kind); - } -} - -class ArrayType : Type -{ - Expression e, e2; - Type assocType; - this(Type t) - { - super(TID.Array, t); - mixin(set_kind); - } - this(Type t, Expression e, Expression e2) - { - this.children = [e]; - if (e2) - this.children ~= e2; - this.e = e; - this.e2 = e2; - this(t); - } - this(Type t, Type assocType) - { - this.children = [assocType]; - this.assocType = assocType; - this(t); - } -} - -class FunctionType : Type -{ - Type returnType; - Parameters parameters; - this(Type returnType, Parameters parameters) - { - super(TID.Function); - mixin(set_kind); - this.children = [cast(Node)returnType, parameters]; - this.returnType = returnType; - this.parameters = parameters; - } -} - -class DelegateType : Type -{ - Type returnType; - Parameters parameters; - this(Type returnType, Parameters parameters) - { - super(TID.Delegate); - mixin(set_kind); - this.children = [cast(Node)returnType, parameters]; - this.returnType = returnType; - this.parameters = parameters; - } -} - -version(D2) -{ -class ConstType : Type -{ - this(Type t) - { - // If t is null: cast(const) - super(TID.Const, t); - mixin(set_kind); - } -} - -class InvariantType : Type -{ - this(Type t) - { - // If t is null: cast(invariant) - super(TID.Invariant, t); - mixin(set_kind); - } -} -} // version(D2)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Declarations.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,526 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Declarations; +import SyntaxTree; +import Expressions; +import Types; +import Statements; +import Token; + +abstract class Declaration : Node +{ + bool hasBody; + this(bool hasBody) + { + super(NodeCategory.Declaration); + this.hasBody = hasBody; + } +} + +class Declarations : Declaration +{ + this() + { + super(true); + mixin(set_kind); + } + + void opCatAssign(Declaration d) + { + this.children ~= d; + } + + void opCatAssign(Declarations ds) + { + this.children ~= ds.children; + } +} + +class EmptyDeclaration : Declaration +{ + this() + { + super(false); + mixin(set_kind); + } +} + +class IllegalDeclaration : Declaration +{ + Token* token; + this(Token* token) + { + super(false); + mixin(set_kind); + this.token = token; + } +} + +alias Token*[] ModuleName; // Identifier(.Identifier)* + +class ModuleDeclaration : Declaration +{ + ModuleName moduleName; // module name sits at end of array + this(ModuleName moduleName) + { + super(false); + mixin(set_kind); + this.moduleName = moduleName; + } +} + +class ImportDeclaration : Declaration +{ + ModuleName[] moduleNames; + Token*[] moduleAliases; + Token*[] bindNames; + Token*[] bindAliases; + this(ModuleName[] moduleNames, Token*[] moduleAliases, Token*[] bindNames, Token*[] bindAliases) + { + super(false); + mixin(set_kind); + this.moduleNames = moduleNames; + this.moduleAliases = moduleAliases; + this.bindNames = bindNames; + this.bindAliases = bindAliases; + } +} + +class AliasDeclaration : Declaration +{ + Declaration decl; + this(Declaration decl) + { + super(false); + mixin(set_kind); + this.children = [decl]; + this.decl = decl; + } +} + +class TypedefDeclaration : Declaration +{ + Declaration decl; + this(Declaration decl) + { + super(false); + mixin(set_kind); + this.children = [decl]; + this.decl = decl; + } +} + +class EnumDeclaration : Declaration +{ + Token* name; + Type baseType; + Token*[] members; + Expression[] values; + this(Token* name, Type baseType, Token*[] members, Expression[] values, bool hasBody) + { + super(hasBody); + mixin(set_kind); + if (baseType) + this.children = [baseType]; + foreach(value; values) + if (value) + this.children ~= value; + this.name = name; + this.baseType = baseType; + this.members = members; + this.values = values; + } +} + +class ClassDeclaration : Declaration +{ + Token* name; + TemplateParameters tparams; + BaseClass[] bases; + Declarations decls; + this(Token* name, TemplateParameters tparams, BaseClass[] bases, Declarations decls, bool hasBody) + { + super(hasBody); + mixin(set_kind); + if (tparams) + this.children = [tparams]; + if (bases.length) + this.children ~= bases; + this.children ~= decls; + + this.name = name; + this.tparams = tparams; + this.bases = bases; + this.decls = decls; + } +} + +class InterfaceDeclaration : Declaration +{ + Token* name; + TemplateParameters tparams; + BaseClass[] bases; + Declarations decls; + this(Token* name, TemplateParameters tparams, BaseClass[] bases, Declarations decls, bool hasBody) + { + super(hasBody); + mixin(set_kind); + if (tparams) + this.children = [tparams]; + if (bases.length) + this.children ~= bases; + this.children ~= decls; + + this.name = name; + this.tparams = tparams; + this.bases = bases; + this.decls = decls; + } +} + +class StructDeclaration : Declaration +{ + Token* name; + TemplateParameters tparams; + Declarations decls; + this(Token* name, TemplateParameters tparams, Declarations decls, bool hasBody) + { + super(hasBody); + mixin(set_kind); + if (tparams) + this.children = [tparams]; + this.children ~= decls; + + this.name = name; + this.tparams = tparams; + this.decls = decls; + } +} + +class UnionDeclaration : Declaration +{ + Token* name; + TemplateParameters tparams; + Declarations decls; + this(Token* name, TemplateParameters tparams, Declarations decls, bool hasBody) + { + super(hasBody); + mixin(set_kind); + if (tparams) + this.children = [tparams]; + this.children ~= decls; + + this.name = name; + this.tparams = tparams; + this.decls = decls; + } +} + +class ConstructorDeclaration : Declaration +{ + Parameters parameters; + FunctionBody funcBody; + this(Parameters parameters, FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [cast(Node)parameters, funcBody]; + this.parameters = parameters; + this.funcBody = funcBody; + } +} + +class StaticConstructorDeclaration : Declaration +{ + FunctionBody funcBody; + this(FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [funcBody]; + this.funcBody = funcBody; + } +} + +class DestructorDeclaration : Declaration +{ + FunctionBody funcBody; + this(FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [funcBody]; + this.funcBody = funcBody; + } +} + +class StaticDestructorDeclaration : Declaration +{ + FunctionBody funcBody; + this(FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [funcBody]; + this.funcBody = funcBody; + } +} + +class FunctionDeclaration : Declaration +{ + Type returnType; + Token* funcName; + TemplateParameters tparams; + Parameters params; + FunctionBody funcBody; + this(Type returnType, Token* funcName, TemplateParameters tparams, Parameters params, FunctionBody funcBody) + { + assert(returnType !is null); + super(funcBody.funcBody !is null); + mixin(set_kind); + this.children = [returnType]; + if (tparams) + this.children ~= tparams; + this.children ~= [cast(Node)params, funcBody]; + this.returnType = returnType; + this.funcName = funcName; + this.tparams = tparams; + this.params = params; + this.funcBody = funcBody; + } +} + +class VariableDeclaration : Declaration +{ + Type type; + Token*[] idents; + Expression[] values; + this(Type type, Token*[] idents, Expression[] values) + { + super(false); + mixin(set_kind); + if (type) + this.children = [type]; + foreach(value; values) + if (value) + this.children ~= value; + this.type = type; + this.idents = idents; + this.values = values; + } +} + +class InvariantDeclaration : Declaration +{ + FunctionBody funcBody; + this(FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [funcBody]; + this.funcBody = funcBody; + } +} + +class UnittestDeclaration : Declaration +{ + FunctionBody funcBody; + this(FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [funcBody]; + this.funcBody = funcBody; + } +} + +class DebugDeclaration : Declaration +{ + Token* spec; + Token* cond; + Declaration decls, elseDecls; + + this(Token* spec, Token* cond, Declaration decls, Declaration elseDecls) + { + super(true /+decls.length != 0+/); + mixin(set_kind); + if (decls) + this.children = [decls]; + if (elseDecls) + this.children ~= elseDecls; + this.spec = spec; + this.cond = cond; + this.decls = decls; + this.elseDecls = elseDecls; + } +} + +class VersionDeclaration : Declaration +{ + Token* spec; + Token* cond; + Declaration decls, elseDecls; + + this(Token* spec, Token* cond, Declaration decls, Declaration elseDecls) + { + super(true /+decls.length != 0+/); + mixin(set_kind); + if (decls) + this.children = [decls]; + if (elseDecls) + this.children ~= elseDecls; + this.spec = spec; + this.cond = cond; + this.decls = decls; + this.elseDecls = elseDecls; + } +} + +class StaticIfDeclaration : Declaration +{ + Expression condition; + Declaration ifDecls, elseDecls; + this(Expression condition, Declaration ifDecls, Declaration elseDecls) + { + super(true); + mixin(set_kind); + this.children = [cast(Node)condition, ifDecls, elseDecls]; + this.condition = condition; + this.ifDecls = ifDecls; + this.elseDecls = elseDecls; + } +} + +class StaticAssertDeclaration : Declaration +{ + Expression condition, message; + this(Expression condition, Expression message) + { + super(true); + mixin(set_kind); + this.children = [condition]; + if (message) + this.children ~= message; + this.condition = condition; + this.message = message; + } +} + +class TemplateDeclaration : Declaration +{ + Token* name; + TemplateParameters tparams; + Declarations decls; + this(Token* name, TemplateParameters tparams, Declarations decls) + { + super(true); + mixin(set_kind); + this.children = [cast(Node)tparams, decls]; + this.name = name; + this.tparams = tparams; + this.decls = decls; + } +} + +class NewDeclaration : Declaration +{ + Parameters parameters; + FunctionBody funcBody; + this(Parameters parameters, FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [cast(Node)parameters, funcBody]; + this.parameters = parameters; + this.funcBody = funcBody; + } +} + +class DeleteDeclaration : Declaration +{ + Parameters parameters; + FunctionBody funcBody; + this(Parameters parameters, FunctionBody funcBody) + { + super(true); + mixin(set_kind); + this.children = [cast(Node)parameters, funcBody]; + this.parameters = parameters; + this.funcBody = funcBody; + } +} + +class AttributeDeclaration : Declaration +{ + TOK attribute; + Declaration decls; + this(TOK attribute, Declaration decls) + { + super(true); + mixin(set_kind); + this.children = [decls]; + this.attribute = attribute; + this.decls = decls; + } +} + +class ExternDeclaration : AttributeDeclaration +{ + Linkage linkage; + this(Linkage linkage, Declaration decls) + { + super(TOK.Extern, decls); + mixin(set_kind); + this.linkage = linkage; + } +} + +class AlignDeclaration : AttributeDeclaration +{ + int size; + this(int size, Declaration decls) + { + super(TOK.Align, decls); + mixin(set_kind); + this.size = size; + } +} + +class PragmaDeclaration : AttributeDeclaration +{ + Token* ident; + Expression[] args; + this(Token* ident, Expression[] args, Declaration decls) + { + super(TOK.Pragma, decls); + mixin(set_kind); + if (args.length) + this.children ~= args; + this.ident = ident; + this.args = args; + } +} + +class MixinDeclaration : Declaration +{ + Expression[] templateIdents; + Token* mixinIdent; + Expression argument; // mixin ( AssignExpression ) + this(Expression[] templateIdents, Token* mixinIdent) + { + super(false); + mixin(set_kind); + this.children = templateIdents; + this.templateIdents = templateIdents; + this.mixinIdent = mixinIdent; + } + this(Expression argument) + { + super(false); + mixin(set_kind); + this.children = [argument]; + this.argument = argument; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Expressions.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,988 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Expressions; +import SyntaxTree; +import Token; +import Types; +import Declarations; +import Statements; + +abstract class Expression : Node +{ + this() + { + super(NodeCategory.Expression); + } +} + +class EmptyExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +abstract class BinaryExpression : Expression +{ + Expression left, right; + Token* tok; + this(Expression left, Expression right, Token* tok) + { + this.children = [left, right]; + this.left = left; + this.right = right; + this.tok = tok; + } +} + +class CondExpression : BinaryExpression +{ + Expression condition; + this(Expression condition, Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + this.children ~= [condition]; + this.condition = condition; + } +} + +class CommaExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class OrOrExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class AndAndExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class OrExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class XorExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class AndExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +abstract class CmpExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + } +} + +class EqualExpression : CmpExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class IdentityExpression : CmpExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class RelExpression : CmpExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class InExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class LShiftExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class RShiftExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class URShiftExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class PlusExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class MinusExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class CatExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class MulExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class DivExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class ModExpression : BinaryExpression +{ + this(Expression left, Expression right, Token* tok) + { + super(left, right, tok); + mixin(set_kind); + } +} + +class AssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class LShiftAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class RShiftAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class URShiftAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class OrAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class AndAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class PlusAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class MinusAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class DivAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class MulAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class ModAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class XorAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} +class CatAssignExpression : BinaryExpression +{ + this(Expression left, Expression right) + { + super(left, right, null); + mixin(set_kind); + } +} + +abstract class UnaryExpression : Expression +{ + Expression e; + this(Expression e) + { + this.children ~= e; + this.e = e; + } +} + +class AddressExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class PreIncrExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class PreDecrExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class PostIncrExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class PostDecrExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class DerefExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class SignExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class NotExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class CompExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} +/+ +class DotIdExpression : UnaryExpression +{ + string ident; + this(Expression e, string ident) + { + super(e); + this.ident = ident; + } +} ++/ +/+ +class DotTemplateInstanceExpression : UnaryExpression +{ + string ident; + TemplateArguments targs; + this(Expression e, string ident, TemplateArguments targs) + { + super(e); + this.ident = ident; + this.targs = targs; + } +} ++/ +class PostDotListExpression : UnaryExpression +{ + DotListExpression dotList; + this(Expression e, DotListExpression dotList) + { + super(e); + mixin(set_kind); + this.children ~= [dotList]; + this.dotList = dotList; + } +} + +class CallExpression : UnaryExpression +{ + Expression[] args; + this(Expression e, Expression[] args) + { + super(e); + mixin(set_kind); + this.children ~= args; + this.args = args; + } +} + +class NewExpression : /*Unary*/Expression +{ + Expression[] newArgs; + Type type; + Expression[] ctorArgs; + this(/*Expression e, */Expression[] newArgs, Type type, Expression[] ctorArgs) + { + /*super(e);*/ + mixin(set_kind); + if (newArgs.length) + this.children ~= newArgs; + this.children ~= type; + if (ctorArgs.length) + this.children ~= ctorArgs; + this.newArgs = newArgs; + this.type = type; + this.ctorArgs = ctorArgs; + } +} + +class NewAnonClassExpression : /*Unary*/Expression +{ + Expression[] newArgs; + BaseClass[] bases; + Expression[] ctorArgs; + Declarations decls; + this(/*Expression e, */Expression[] newArgs, BaseClass[] bases, Expression[] ctorArgs, Declarations decls) + { + /*super(e);*/ + mixin(set_kind); + if (newArgs.length) + this.children ~= newArgs; + if (bases.length) + this.children ~= bases; + if (ctorArgs.length) + this.children ~= ctorArgs; + this.children ~= decls; + + this.newArgs = newArgs; + this.bases = bases; + this.ctorArgs = ctorArgs; + this.decls = decls; + } +} + +class DeleteExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class CastExpression : UnaryExpression +{ + Type type; + this(Expression e, Type type) + { + this.children = [type]; + super(e); + mixin(set_kind); + this.type = type; + } +} + +class IndexExpression : UnaryExpression +{ + Expression[] args; + this(Expression e, Expression[] args) + { + super(e); + mixin(set_kind); + this.children ~= args; + this.args = args; + } +} + +class SliceExpression : UnaryExpression +{ + Expression left, right; + this(Expression e, Expression left, Expression right) + { + super(e); + mixin(set_kind); + this.children ~= [left, right]; + this.left = left; + this.right = right; + } +} + +/* +class PrimaryExpression +{ + +} +*/ + +class IdentifierExpression : Expression +{ + Token* identifier; + this(Token* identifier) + { + mixin(set_kind); + this.identifier = identifier; + } +} + +class SpecialTokenExpression : Expression +{ + Token* special; + this(Token* special) + { + mixin(set_kind); + this.special = special; + } +} + +/* +class IdentifierListExpression : Expression +{ + Expression[] identList; + this(Expression[] identList) + { + this.identList = identList; + } +} +*/ +class DotListExpression : Expression +{ + Expression[] items; + this(Expression[] items) + { + mixin(set_kind); + this.children = items; + this.items = items; + } +} + +class TemplateInstanceExpression : Expression +{ + Token* ident; + TemplateArguments targs; + this(Token* ident, TemplateArguments targs) + { + mixin(set_kind); + this.children = [targs]; + this.ident = ident; + this.targs = targs; + } +} + +class ThisExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class SuperExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class NullExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class DollarExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class BoolExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class IntNumberExpression : Expression +{ + TOK type; + ulong number; + this(TOK type, ulong number) + { + mixin(set_kind); + this.number = number; + this.type = type; + } +} + +class RealNumberExpression : Expression +{ + TOK type; + real number; + this(TOK type, real number) + { + mixin(set_kind); + this.number = number; + this.type = type; + } +} + +class CharLiteralExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class StringLiteralsExpression : Expression +{ + Token*[] strings; + this(Token*[] strings) + { + mixin(set_kind); + this.strings = strings; + } + + string getString() + { + char[] buffer; + foreach (strTok; strings) + { + buffer ~= strTok.str[0..$-1]; + } + return buffer; + } +} + +class ArrayLiteralExpression : Expression +{ + Expression[] values; + this(Expression[] values) + { + mixin(set_kind); + this.children = values; + this.values = values; + } +} + +class AssocArrayLiteralExpression : Expression +{ + Expression[] keys, values; + this(Expression[] keys, Expression[] values) + { + assert(keys.length == values.length); + mixin(set_kind); + foreach (i, key; keys) + this.children ~= [key, values[i]]; + this.keys = keys; + this.values = values; + } +} + +class AssertExpression : Expression +{ + Expression expr, msg; + this(Expression expr, Expression msg) + { + mixin(set_kind); + this.children = [expr]; + if (msg) + this.children ~= msg; + this.expr = expr; + this.msg = msg; + } +} + +class MixinExpression : Expression +{ + Expression expr; + this(Expression expr) + { + mixin(set_kind); + this.children = [expr]; + this.expr = expr; + } +} + +class ImportExpression : Expression +{ + Expression expr; + this(Expression expr) + { + mixin(set_kind); + this.children = [expr]; + this.expr = expr; + } +} + +class TypeofExpression : Expression +{ + Type type; + this(Type type) + { + mixin(set_kind); + this.children = [type]; + this.type = type; + } +} + +class TypeDotIdExpression : Expression +{ + Type type; + Token* ident; + this(Type type, Token* ident) + { + mixin(set_kind); + this.children = [type]; + this.type = type; + this.ident = ident; + } +} + +class TypeidExpression : Expression +{ + Type type; + this(Type type) + { + mixin(set_kind); + this.children = [type]; + this.type = type; + } +} + +class IsExpression : Expression +{ + Type type; + Token* ident; + Token* opTok, specTok; + Type specType; + this(Type type, Token* ident, Token* opTok, Token* specTok, Type specType) + { + mixin(set_kind); + this.children = [type]; + if (specType) + this.children ~= specType; + this.type = type; + this.ident = ident; + this.opTok = opTok; + this.specTok = specTok; + this.specType = specType; + } +} + +class FunctionLiteralExpression : Expression +{ + Type returnType; + Parameters parameters; + FunctionBody funcBody; + + this() + { + mixin(set_kind); + if (returnType) + this.children ~= returnType; + if (parameters) + this.children ~= parameters; + this.children ~= funcBody; + } + + this(Type returnType, Parameters parameters, FunctionBody funcBody) + { + this.returnType = returnType; + this.parameters = parameters; + this.funcBody = funcBody; + this(); + } + + this(FunctionBody funcBody) + { + this.funcBody = funcBody; + this(); + } +} + +version(D2) +{ +class TraitsExpression : Expression +{ + Token* ident; + TemplateArguments targs; + this(typeof(ident) ident, typeof(targs) targs) + { + mixin(set_kind); + this.children = [targs]; + this.ident = ident; + this.targs = targs; + } +} +} + +class VoidInitializer : Expression +{ + this() + { + mixin(set_kind); + } +} + +class ArrayInitializer : Expression +{ + Expression[] keys; + Expression[] values; + this(Expression[] keys, Expression[] values) + { + assert(keys.length == values.length); + mixin(set_kind); + foreach (i, key; keys) + { + if (key) + this.children ~= key; + if (values[i]) + this.children ~= values[i]; + } + this.keys = keys; + this.values = values; + } +} + +class StructInitializer : Expression +{ + Token*[] idents; + Expression[] values; + this(Token*[] idents, Expression[] values) + { + mixin(set_kind); + this.children = values; + this.idents = idents; + this.values = values; + } +} + +class AsmTypeExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class AsmOffsetExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class AsmSegExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class AsmPostBracketExpression : UnaryExpression +{ + this(Expression e) + { + super(e); + mixin(set_kind); + } +} + +class AsmBracketExpression : Expression +{ + Expression e; + this(Expression e) + { + mixin(set_kind); + this.children = [e]; + this.e = e; + } +} + +class AsmLocalSizeExpression : Expression +{ + this() + { + mixin(set_kind); + } +} + +class AsmRegisterExpression : Expression +{ + Token* register; + Token* number; // ST(0) - ST(7) + this(Token* register, Token* number = null) + { + mixin(set_kind); + this.register = register; + this.number = number; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/HtmlEntities.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,277 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module HtmlEntities; + +private const dchar[char[]] entities_table; + +static this() +{ + entities_table = [ + "Aacute"[] : '\u00C1', + "aacute" : '\u00E1', + "Acirc" : '\u00C2', + "acirc" : '\u00E2', + "acute" : '\u00B4', + "AElig" : '\u00C6', + "aelig" : '\u00E6', + "Agrave" : '\u00C0', + "agrave" : '\u00E0', + "alefsym" : '\u2135', + "Alpha" : '\u0391', + "alpha" : '\u03B1', + "amp" : '\u0026', + "and" : '\u2227', + "ang" : '\u2220', + "Aring" : '\u00C5', + "aring" : '\u00E5', + "asymp" : '\u2248', + "Atilde" : '\u00C3', + "atilde" : '\u00E3', + "Auml" : '\u00C4', + "auml" : '\u00E4', + "bdquo" : '\u201E', + "Beta" : '\u0392', + "beta" : '\u03B2', + "brvbar" : '\u00A6', + "bull" : '\u2022', + "cap" : '\u2229', + "Ccedil" : '\u00C7', + "ccedil" : '\u00E7', + "cedil" : '\u00B8', + "cent" : '\u00A2', + "Chi" : '\u03A7', + "chi" : '\u03C7', + "circ" : '\u02C6', + "clubs" : '\u2663', + "cong" : '\u2245', + "copy" : '\u00A9', + "crarr" : '\u21B5', + "cup" : '\u222A', + "curren" : '\u00A4', + "Dagger" : '\u2021', + "dagger" : '\u2020', + "dArr" : '\u21D3', + "darr" : '\u2193', + "deg" : '\u00B0', + "Delta" : '\u0394', + "delta" : '\u03B4', + "diams" : '\u2666', + "divide" : '\u00F7', + "Eacute" : '\u00C9', + "eacute" : '\u00E9', + "Ecirc" : '\u00CA', + "ecirc" : '\u00EA', + "Egrave" : '\u00C8', + "egrave" : '\u00E8', + "empty" : '\u2205', + "emsp" : '\u2003', + "ensp" : '\u2002', + "Epsilon" : '\u0395', + "epsilon" : '\u03B5', + "equiv" : '\u2261', + "Eta" : '\u0397', + "eta" : '\u03B7', + "ETH" : '\u00D0', + "eth" : '\u00F0', + "Euml" : '\u00CB', + "euml" : '\u00EB', + "euro" : '\u20AC', + "exist" : '\u2203', + "fnof" : '\u0192', + "forall" : '\u2200', + "frac12" : '\u00BD', + "frac14" : '\u00BC', + "frac34" : '\u00BE', + "frasl" : '\u2044', + "Gamma" : '\u0393', + "gamma" : '\u03B3', + "ge" : '\u2265', + "gt" : '\u003E', + "hArr" : '\u21D4', + "harr" : '\u2194', + "hearts" : '\u2665', + "hellip" : '\u2026', + "Iacute" : '\u00CD', + "iacute" : '\u00ED', + "Icirc" : '\u00CE', + "icirc" : '\u00EE', + "iexcl" : '\u00A1', + "Igrave" : '\u00CC', + "igrave" : '\u00EC', + "image" : '\u2111', + "infin" : '\u221E', + "int" : '\u222B', + "Iota" : '\u0399', + "iota" : '\u03B9', + "iquest" : '\u00BF', + "isin" : '\u2208', + "Iuml" : '\u00CF', + "iuml" : '\u00EF', + "Kappa" : '\u039A', + "kappa" : '\u03BA', + "Lambda" : '\u039B', + "lambda" : '\u03BB', + "lang" : '\u2329', + "laquo" : '\u00AB', + "lArr" : '\u21D0', + "larr" : '\u2190', + "lceil" : '\u2308', + "ldquo" : '\u201C', + "le" : '\u2264', + "lfloor" : '\u230A', + "lowast" : '\u2217', + "loz" : '\u25CA', + "lrm" : '\u200E', + "lsaquo" : '\u2039', + "lsquo" : '\u2018', + "lt" : '\u003C', + "macr" : '\u00AF', + "mdash" : '\u2014', + "micro" : '\u00B5', + "middot" : '\u00B7', + "minus" : '\u2212', + "Mu" : '\u039C', + "mu" : '\u03BC', + "nabla" : '\u2207', + "nbsp" : '\u00A0', + "ndash" : '\u2013', + "ne" : '\u2260', + "ni" : '\u220B', + "not" : '\u00AC', + "notin" : '\u2209', + "nsub" : '\u2284', + "Ntilde" : '\u00D1', + "ntilde" : '\u00F1', + "Nu" : '\u039D', + "nu" : '\u03BD', + "Oacute" : '\u00D3', + "oacute" : '\u00F3', + "Ocirc" : '\u00D4', + "ocirc" : '\u00F4', + "OElig" : '\u0152', + "oelig" : '\u0153', + "Ograve" : '\u00D2', + "ograve" : '\u00F2', + "oline" : '\u203E', + "Omega" : '\u03A9', + "omega" : '\u03C9', + "Omicron" : '\u039F', + "omicron" : '\u03BF', + "oplus" : '\u2295', + "or" : '\u2228', + "ordf" : '\u00AA', + "ordm" : '\u00BA', + "Oslash" : '\u00D8', + "oslash" : '\u00F8', + "Otilde" : '\u00D5', + "otilde" : '\u00F5', + "otimes" : '\u2297', + "Ouml" : '\u00D6', + "ouml" : '\u00F6', + "para" : '\u00B6', + "part" : '\u2202', + "permil" : '\u2030', + "perp" : '\u22A5', + "Phi" : '\u03A6', + "phi" : '\u03C6', + "Pi" : '\u03A0', + "pi" : '\u03C0', + "piv" : '\u03D6', + "plusmn" : '\u00B1', + "pound" : '\u00A3', + "Prime" : '\u2033', + "prime" : '\u2032', + "prod" : '\u220F', + "prop" : '\u221D', + "Psi" : '\u03A8', + "psi" : '\u03C8', + "quot" : '\u0022', + "radic" : '\u221A', + "rang" : '\u232A', + "raquo" : '\u00BB', + "rArr" : '\u21D2', + "rarr" : '\u2192', + "rceil" : '\u2309', + "rdquo" : '\u201D', + "real" : '\u211C', + "reg" : '\u00AE', + "rfloor" : '\u230B', + "Rho" : '\u03A1', + "rho" : '\u03C1', + "rlm" : '\u200F', + "rsaquo" : '\u203A', + "rsquo" : '\u2019', + "sbquo" : '\u201A', + "Scaron" : '\u0160', + "scaron" : '\u0161', + "sdot" : '\u22C5', + "sect" : '\u00A7', + "shy" : '\u00AD', + "Sigma" : '\u03A3', + "sigma" : '\u03C3', + "sigmaf" : '\u03C2', + "sim" : '\u223C', + "spades" : '\u2660', + "sub" : '\u2282', + "sube" : '\u2286', + "sum" : '\u2211', + "sup" : '\u2283', + "sup1" : '\u00B9', + "sup2" : '\u00B2', + "sup3" : '\u00B3', + "supe" : '\u2287', + "szlig" : '\u00DF', + "Tau" : '\u03A4', + "tau" : '\u03C4', + "there4" : '\u2234', + "Theta" : '\u0398', + "theta" : '\u03B8', + "thetasym" : '\u03D1', + "thinsp" : '\u2009', + "THORN" : '\u00DE', + "thorn" : '\u00FE', + "tilde" : '\u02DC', + "times" : '\u00D7', + "trade" : '\u2122', + "Uacute" : '\u00DA', + "uacute" : '\u00FA', + "uArr" : '\u21D1', + "uarr" : '\u2191', + "Ucirc" : '\u00DB', + "ucirc" : '\u00FB', + "Ugrave" : '\u00D9', + "ugrave" : '\u00F9', + "uml" : '\u00A8', + "upsih" : '\u03D2', + "Upsilon" : '\u03A5', + "upsilon" : '\u03C5', + "Uuml" : '\u00DC', + "uuml" : '\u00FC', + "weierp" : '\u2118', + "Xi" : '\u039E', + "xi" : '\u03BE', + "Yacute" : '\u00DD', + "yacute" : '\u00FD', + "yen" : '\u00A5', + "Yuml" : '\u0178', + "yuml" : '\u00FF', + "Zeta" : '\u0396', + "zeta" : '\u03B6', + "zwj" : '\u200D', + "zwnj" : '\u200C' + ]; +} + +/++ + Converts a named HTML entity into its equivalent Unicode codepoint. + Returns 0xFFFF if entity doesn't exist. ++/ +dchar entity2Unicode(char[] entity) +{ + auto d = entity in entities_table; + if (d) + return *d; + return 0xFFFF; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Identifier.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,30 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Identifier; +import Token; + +struct Identifier +{ + TOK type; + string str; + + static Identifier opCall(TOK type, string str) + { + Identifier i; + i.type = type; + i.str = str; + return i; + } + + uint toHash() + { + uint hash; + foreach(c; str) { + hash *= 9; + hash += c; + } + return hash; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Information.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,35 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Information; +import Messages; +import std.stdarg; + +enum InfoType +{ + Lexer, + Parser, + Semantic +} + +class Information +{ + MID id; + InfoType type; + uint loc; + string[] arguments; + + this(InfoType type, MID id, uint loc, string[] arguments) + { + this.id = id; + this.type = type; + this.loc = loc; + this.arguments = arguments; + } + + string getMsg() + { + return format_args(GetMsg(id), arguments); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Keywords.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,117 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Keywords; +import Token; +import Identifier; + +static const Identifier[] keywords = [ + {TOK.Abstract, "abstract"}, + {TOK.Alias, "alias"}, + {TOK.Align, "align"}, + {TOK.Asm, "asm"}, + {TOK.Assert, "assert"}, + {TOK.Auto, "auto"}, + {TOK.Body, "body"}, + {TOK.Bool, "bool"}, + {TOK.Break, "break"}, + {TOK.Byte, "byte"}, + {TOK.Case, "case"}, + {TOK.Cast, "cast"}, + {TOK.Catch, "catch"}, + {TOK.Cdouble, "cdouble"}, + {TOK.Cent, "cent"}, + {TOK.Cfloat, "cfloat"}, + {TOK.Char, "char"}, + {TOK.Class, "class"}, + {TOK.Const, "const"}, + {TOK.Continue, "continue"}, + {TOK.Creal, "creal"}, + {TOK.Dchar, "dchar"}, + {TOK.Debug, "debug"}, + {TOK.Default, "default"}, + {TOK.Delegate, "delegate"}, + {TOK.Delete, "delete"}, + {TOK.Deprecated, "deprecated"}, + {TOK.Do, "do"}, + {TOK.Double, "double"}, + {TOK.Else, "else"}, + {TOK.Enum, "enum"}, + {TOK.Export, "export"}, + {TOK.Extern, "extern"}, + {TOK.False, "false"}, + {TOK.Final, "final"}, + {TOK.Finally, "finally"}, + {TOK.Float, "float"}, + {TOK.For, "for"}, + {TOK.Foreach, "foreach"}, + {TOK.Foreach_reverse, "foreach_reverse"}, + {TOK.Function, "function"}, + {TOK.Goto, "goto"}, + {TOK.Idouble, "idouble"}, + {TOK.If, "if"}, + {TOK.Ifloat, "ifloat"}, + {TOK.Import, "import"}, + {TOK.In, "in"}, + {TOK.Inout, "inout"}, + {TOK.Int, "int"}, + {TOK.Interface, "interface"}, + {TOK.Invariant, "invariant"}, + {TOK.Ireal, "ireal"}, + {TOK.Is, "is"}, + {TOK.Lazy, "lazy"}, + {TOK.Long, "long"}, + {TOK.Macro, "macro"}, // D2.0 + {TOK.Mixin, "mixin"}, + {TOK.Module, "module"}, + {TOK.New, "new"}, + {TOK.Null, "null"}, + {TOK.Out, "out"}, + {TOK.Override, "override"}, + {TOK.Package, "package"}, + {TOK.Pragma, "pragma"}, + {TOK.Private, "private"}, + {TOK.Protected, "protected"}, + {TOK.Public, "public"}, + {TOK.Real, "real"}, + {TOK.Ref, "ref"}, + {TOK.Return, "return"}, + {TOK.Scope, "scope"}, + {TOK.Short, "short"}, + {TOK.Static, "static"}, + {TOK.Struct, "struct"}, + {TOK.Super, "super"}, + {TOK.Switch, "switch"}, + {TOK.Synchronized, "synchronized"}, + {TOK.Template, "template"}, + {TOK.This, "this"}, + {TOK.Throw, "throw"}, + {TOK.Traits, "__traits"}, // D2.0 + {TOK.True, "true"}, + {TOK.Try, "try"}, + {TOK.Typedef, "typedef"}, + {TOK.Typeid, "typeid"}, + {TOK.Typeof, "typeof"}, + {TOK.Ubyte, "ubyte"}, + {TOK.Ucent, "ucent"}, + {TOK.Uint, "uint"}, + {TOK.Ulong, "ulong"}, + {TOK.Union, "union"}, + {TOK.Unittest, "unittest"}, + {TOK.Ushort, "ushort"}, + {TOK.Version, "version"}, + {TOK.Void, "void"}, + {TOK.Volatile, "volatile"}, + {TOK.Wchar, "wchar"}, + {TOK.While, "while"}, + {TOK.With, "with"}, + // Special tokens: + {TOK.Special, "__FILE__"}, + {TOK.Special, "__LINE__"}, + {TOK.Special, "__DATE__"}, + {TOK.Special, "__TIME__"}, + {TOK.Special, "__TIMESTAMP__"}, + {TOK.Special, "__VENDOR__"}, + {TOK.Special, "__VERSION__"}, +];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Lexer.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,1773 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Lexer; +import Token; +import Information; +import Keywords; +import Identifier; +import Messages; +import HtmlEntities; +import std.stdio; +import std.utf; +import std.uni; +import std.c.stdlib; +import std.string; + +const char[3] LS = \u2028; +const char[3] PS = \u2029; + +const dchar LSd = 0x2028; +const dchar PSd = 0x2029; + +const uint _Z_ = 26; /// Control+Z + +class Lexer +{ + Token* head; /// The head of the doubly linked token list. + Token* token; /// Points to the current token in the token list. + string text; + char* p; /// Points to the current character in the source text. + char* end; /// Points one character past the end of the source text. + + uint loc = 1; /// line of code + + char[] fileName; + + Information[] errors; + +// bool reportErrors; + + Identifier[string] idtable; + + this(string text, string fileName) + { + this.fileName = fileName; + + this.text = text; + if (text[$-1] != 0) + { + this.text.length = this.text.length + 1; + this.text[$-1] = 0; + } + + this.p = this.text.ptr; + this.end = this.p + this.text.length; +// this.reportErrors = true; + loadKeywords(); + + this.head = new Token; + this.head.type = TOK.HEAD; + this.token = this.head; + scanShebang(); + } + + void scanShebang() + { + if (*p == '#' && p[1] == '!') + { + Token* t = new Token; + t.start = p; + t.type = TOK.Shebang; + ++p; + while (1) + { + switch (*++p) + { + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + ++loc; + if (p[-1] == '\r') + t.end = p-1; + else + t.end = p; + break; + case LS[0]: + t.end = p; + if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) + { + ++p; ++p; + ++loc; + } + break; + case 0, _Z_: + t.end = p; + break; + default: + continue; + } + break; // Exit loop. + } + this.head.next = t; + t.prev = this.head; + } + } + + public void scan(out Token t) + in + { + assert(text.ptr <= p && p < end); + } + out + { + assert(text.ptr <= t.start && t.start < end); + assert(text.ptr < t.end && t.end <= end, std.string.format(t.type)); + } + body + { + uint c = *p; + + while (1) + { + t.start = p; + + if (c == 0 || c == _Z_) + { + assert(*p == 0 || *p == _Z_); + t.type = TOK.EOF; + t.end = p; + assert(t.start == t.end); + return; + } + + if (c == '\n') + { + c = *++p; + ++loc; + continue; + } + else if (c == '\r') + { + c = *++p; + if (c != '\n') + ++loc; + continue; + } + else if (c == LS[0] && p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) + { + p += 3; + c = *p; + continue; + } + + if (isidbeg(c)) + { + if (c == 'r' && p[1] == '"' && ++p) + return scanRawStringLiteral(t); + if (c == 'x' && p[1] == '"') + return scanHexStringLiteral(t); + Lidentifier: + do + { c = *++p; } + while (isident(c) || c & 128 && isUniAlpha(decodeUTF8())) + + t.end = p; + + string str = t.srcText; + Identifier* id = str in idtable; + + if (!id) + { + idtable[str] = Identifier.Identifier(TOK.Identifier, str); + id = str in idtable; + } + assert(id); + t.type = id.type; + return; + } + + if (isdigit(c)) + return scanNumber(t); + + if (c == '/') + { + c = *++p; + switch(c) + { + case '=': + ++p; + t.type = TOK.DivAssign; + t.end = p; + return; + case '+': + uint level = 1; + while (1) + { + c = *++p; + LswitchNC: // only jumped to from default case of next switch(c) + switch (c) + { + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + ++loc; + continue; + case 0, _Z_: + error(MID.UnterminatedNestedComment); + goto LreturnNC; + default: + } + + c <<= 8; + c |= *++p; + switch (c) + { + case 0x2F2B: // /+ + ++level; + continue; + case 0x2B2F: // +/ + if (--level == 0) + { + ++p; + LreturnNC: + t.type = TOK.Comment; + t.end = p; + return; + } + continue; + case 0xE280: // LS[0..1] || PS[0..1] + if (p[1] == LS[2] || p[1] == PS[2]) + { + ++loc; + ++p; + } + continue; + default: + c &= char.max; + goto LswitchNC; + } + } + case '*': + while (1) + { + c = *++p; + LswitchBC: // only jumped to from default case of next switch(c) + switch (c) + { + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + ++loc; + continue; + case 0, _Z_: + error(MID.UnterminatedBlockComment); + goto LreturnBC; + default: + } + + c <<= 8; + c |= *++p; + switch (c) + { + case 0x2A2F: // */ + ++p; + LreturnBC: + t.type = TOK.Comment; + t.end = p; + return; + case 0xE280: // LS[0..1] || PS[0..1] + if (p[1] == LS[2] || p[1] == PS[2]) + { + ++loc; + ++p; + } + continue; + default: + c &= char.max; + goto LswitchBC; + } + } + assert(0); + case '/': + while (1) + { + c = *++p; + switch (c) + { + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + case 0, _Z_: + break; + case LS[0]: + if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) + break; + continue; + default: + continue; + } + t.type = TOK.Comment; + t.end = p; + return; + } + default: + t.type = TOK.Div; + t.end = p; + return; + } + } + + switch (c) + { + case '\'': + return scanCharacterLiteral(t); + case '`': + return scanRawStringLiteral(t); + case '"': + return scanNormalStringLiteral(t); + case '\\': + char[] buffer; + do + { + ++p; + c = scanEscapeSequence(); + if (c < 128) + buffer ~= c; + else + encodeUTF8(buffer, c); + } while (*p == '\\') + buffer ~= 0; + t.type = TOK.String; + t.str = buffer; + t.end = p; + return; + case '>': /* > >= >> >>= >>> >>>= */ + c = *++p; + switch (c) + { + case '=': + t.type = TOK.GreaterEqual; + goto Lcommon; + case '>': + if (p[1] == '>') + { + ++p; + if (p[1] == '=') + { ++p; + t.type = TOK.URShiftAssign; + } + else + t.type = TOK.URShift; + } + else if (p[1] == '=') + { + ++p; + t.type = TOK.RShiftAssign; + } + else + t.type = TOK.RShift; + goto Lcommon; + default: + t.type = TOK.Greater; + goto Lcommon2; + } + assert(0); + case '<': /* < <= <> <>= << <<= */ + c = *++p; + switch (c) + { + case '=': + t.type = TOK.LessEqual; + goto Lcommon; + case '<': + if (p[1] == '=') { + ++p; + t.type = TOK.LShiftAssign; + } + else + t.type = TOK.LShift; + goto Lcommon; + case '>': + if (p[1] == '=') { + ++p; + t.type = TOK.LorEorG; + } + else + t.type = TOK.LorG; + goto Lcommon; + default: + t.type = TOK.Less; + goto Lcommon2; + } + assert(0); + case '!': /* ! !< !> !<= !>= !<> !<>= */ + c = *++p; + switch (c) + { + case '<': + c = *++p; + if (c == '>') + { + if (p[1] == '=') { + ++p; + t.type = TOK.Unordered; + } + else + t.type = TOK.UorE; + } + else if (c == '=') + { + t.type = TOK.UorG; + } + else { + t.type = TOK.UorGorE; + goto Lcommon2; + } + goto Lcommon; + case '>': + if (p[1] == '=') + { + ++p; + t.type = TOK.UorL; + } + else + t.type = TOK.UorLorE; + goto Lcommon; + case '=': + t.type = TOK.NotEqual; + goto Lcommon; + default: + t.type = TOK.Not; + goto Lcommon2; + } + assert(0); + case '.': /* . .[0-9] .. ... */ + if (p[1] == '.') + { + ++p; + if (p[1] == '.') { + ++p; + t.type = TOK.Ellipses; + } + else + t.type = TOK.Slice; + } + else if (isdigit(p[1])) + { + return scanReal(t); + } + else + t.type = TOK.Dot; + goto Lcommon; + case '|': /* | || |= */ + c = *++p; + if (c == '=') + t.type = TOK.OrAssign; + else if (c == '|') + t.type = TOK.OrLogical; + else { + t.type = TOK.OrBinary; + goto Lcommon2; + } + goto Lcommon; + case '&': /* & && &= */ + c = *++p; + if (c == '=') + t.type = TOK.AndAssign; + else if (c == '&') + t.type = TOK.AndLogical; + else { + t.type = TOK.AndBinary; + goto Lcommon2; + } + goto Lcommon; + case '+': /* + ++ += */ + c = *++p; + if (c == '=') + t.type = TOK.PlusAssign; + else if (c == '+') + t.type = TOK.PlusPlus; + else { + t.type = TOK.Plus; + goto Lcommon2; + } + goto Lcommon; + case '-': /* - -- -= */ + c = *++p; + if (c == '=') + t.type = TOK.MinusAssign; + else if (c == '-') + t.type = TOK.MinusMinus; + else { + t.type = TOK.Minus; + goto Lcommon2; + } + goto Lcommon; + case '=': /* = == */ + if (p[1] == '=') { + ++p; + t.type = TOK.Equal; + } + else + t.type = TOK.Assign; + goto Lcommon; + case '~': /* ~ ~= */ + if (p[1] == '=') { + ++p; + t.type = TOK.CatAssign; + } + else + t.type = TOK.Tilde; + goto Lcommon; + case '*': /* * *= */ + if (p[1] == '=') { + ++p; + t.type = TOK.MulAssign; + } + else + t.type = TOK.Mul; + goto Lcommon; + case '^': /* ^ ^= */ + if (p[1] == '=') { + ++p; + t.type = TOK.XorAssign; + } + else + t.type = TOK.Xor; + goto Lcommon; + case '%': /* % %= */ + if (p[1] == '=') { + ++p; + t.type = TOK.ModAssign; + } + else + t.type = TOK.Mod; + goto Lcommon; + // Single character tokens: + case '(': + t.type = TOK.LParen; + goto Lcommon; + case ')': + t.type = TOK.RParen; + goto Lcommon; + case '[': + t.type = TOK.LBracket; + goto Lcommon; + case ']': + t.type = TOK.RBracket; + goto Lcommon; + case '{': + t.type = TOK.LBrace; + goto Lcommon; + case '}': + t.type = TOK.RBrace; + goto Lcommon; + case ':': + t.type = TOK.Colon; + goto Lcommon; + case ';': + t.type = TOK.Semicolon; + goto Lcommon; + case '?': + t.type = TOK.Question; + goto Lcommon; + case ',': + t.type = TOK.Comma; + goto Lcommon; + case '$': + t.type = TOK.Dollar; + Lcommon: + ++p; + Lcommon2: + t.end = p; + return; + case '#': + return scanSpecialToken(t); + default: + } + + if (c & 128 && isUniAlpha(decodeUTF8())) + goto Lidentifier; + c = *++p; + } + } + + void scanNormalStringLiteral(ref Token t) + { + assert(*p == '"'); + ++p; + char[] buffer; + t.type = TOK.String; + while (1) + { + switch (*p) + { + case '"': + ++p; + Lreturn: + buffer ~= 0; + t.str = buffer; + t.pf = scanPostfix(); + t.end = p; + return; + case '\\': + ++p; + dchar d = scanEscapeSequence(); + if (d < 128) + buffer ~= d; + else + encodeUTF8(buffer, d); + continue; + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + ++p; + ++loc; + buffer ~= '\n'; // Convert EndOfLine to \n. + continue; + case 0, _Z_: + error(MID.UnterminatedString); + goto Lreturn; + default: + if (*p & 128) + { +// char* begin = p; + dchar d = decodeUTF8(); + if (d == LSd || d == PSd) + goto case '\n'; + + // We don't copy per pointer because we might include + // invalid, skipped utf-8 sequences. See decodeUTF8(). +// ++p; +// buffer ~= begin[0 .. p - begin]; + ++p; + encodeUTF8(buffer, d); + continue; + } + // Copy ASCII character. + buffer ~= *p++; + } + } + assert(0); + } + + void scanCharacterLiteral(ref Token t) + { + assert(*p == '\''); + MID id = MID.UnterminatedCharacterLiteral; + ++p; + TOK type = TOK.CharLiteral; + switch (*p) + { + case '\\': + ++p; + switch (*p) + { + case 'u': + type = TOK.WCharLiteral; break; + case 'U': + type = TOK.DCharLiteral; break; + default: + } + t.dchar_ = scanEscapeSequence(); + break; + case '\'': + ++p; + id = MID.EmptyCharacterLiteral; + case '\n', '\r', 0, _Z_: + goto Lerr; + default: + uint c = *p; + if (c & 128) + { + c = decodeUTF8(); + if (c == LSd || c == PSd) + goto Lerr; + if (c <= 0xFFFF) + type = TOK.WCharLiteral; + else + type = TOK.DCharLiteral; + } + t.dchar_ = c; + ++p; + } + + if (*p == '\'') + ++p; + else + Lerr: + error(id); + t.type = type; + t.end = p; + } + + char scanPostfix() + { + switch (*p) + { + case 'c': + case 'w': + case 'd': + return *p++; + default: + return 0; + } + assert(0); + } + + void scanRawStringLiteral(ref Token t) + { + uint delim = *p; + assert(delim == '`' || delim == '"' && p[-1] == 'r'); + t.type = TOK.String; + char[] buffer; + uint c; + while (1) + { + c = *++p; + switch (c) + { + case '\r': + if (p[1] == '\n') + ++p; + c = '\n'; // Convert '\r' and '\r\n' to '\n' + case '\n': + ++loc; + break; + case '`': + case '"': + if (c == delim) + { + ++p; + t.pf = scanPostfix(); + Lreturn: + t.str = buffer ~ '\0'; + t.end = p; + return; + } + break; + case LS[0]: + if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) + { + c = '\n'; + ++p; ++p; + ++loc; + } + break; + case 0, _Z_: + if (delim == 'r') + error(MID.UnterminatedRawString); + else + error(MID.UnterminatedBackQuoteString); + goto Lreturn; + default: + } + buffer ~= c; // copy character to buffer + } + assert(0); + } + + void scanHexStringLiteral(ref Token t) + { + assert(p[0] == 'x' && p[1] == '"'); + t.type = TOK.String; + + uint c; + ubyte[] buffer; + ubyte h; // hex number + uint n; // number of hex digits + + ++p; + while (1) + { + c = *++p; + switch (c) + { + case '"': + ++p; + if (n & 1) + error(MID.OddNumberOfDigitsInHexString); + t.pf = scanPostfix(); + Lreturn: + buffer ~= 0; + t.str = cast(string) buffer; + t.end = p; + return; + case '\r': + if (p[1] == '\n') + ++p; + case '\n': + ++loc; + continue; + default: + if (ishexad(c)) + { + if (c <= '9') + c -= '0'; + else if (c <= 'F') + c -= 'A' - 10; + else + c -= 'a' - 10; + + if (n & 1) + { + h <<= 4; + h |= c; + buffer ~= h; + } + else + h = cast(ubyte)c; + ++n; + continue; + } + else if (isspace(c)) + continue; + + if (c >= 128) + { + c = decodeUTF8(); + if (c == LSd || c == PSd) + { + ++p; ++p; + ++loc; + continue; + } + } + else if (c == 0 || c == _Z_) + { + error(MID.UnterminatedHexString); + t.pf = 0; + goto Lreturn; + } + error(MID.NonHexCharInHexString, cast(dchar)c); + } + } + assert(0); + } + + dchar scanEscapeSequence() + { + uint c = char2ev(*p); + if (c) + { + ++p; + return c; + } + uint digits = 2; + + switch (*p) + { + case 'x': + c = 0; + while (1) + { + ++p; + if (ishexad(*p)) + { + c *= 16; + if (*p <= '9') + c += *p - '0'; + else if (*p <= 'F') + c += *p - 'A' + 10; + else + c += *p - 'a' + 10; + + if (!--digits) + { + ++p; + break; + } + } + else + { + error(MID.InsufficientHexDigits); + break; + } + } + if (!isValidDchar(c)) + error(MID.InvalidUnicodeCharacter); + break; + case 'u': + digits = 4; + goto case 'x'; + case 'U': + digits = 8; + goto case 'x'; + default: + if (isoctal(*p)) + { + c = 0; + c += *p - '0'; + ++p; + if (!isoctal(*p)) + return c; + c *= 8; + c += *p - '0'; + ++p; + if (!isoctal(*p)) + return c; + c *= 8; + c += *p - '0'; + ++p; + } + else if(*p == '&') + { + if (isalpha(*++p)) + { + auto begin = p; + while (isalnum(*++p)) + {} + + if (*p == ';') + { + c = entity2Unicode(begin[0..p - begin]); + ++p; + if (c == 0xFFFF) + error(MID.UndefinedHTMLEntity, (begin-1)[0..p-(begin-1)]); + } + else + error(MID.UnterminatedHTMLEntity); + } + else + error(MID.InvalidBeginHTMLEntity); + } + else + error(MID.UndefinedEscapeSequence); + } + + return c; + } + + /* + IntegerLiteral:= (Dec|Hex|Bin|Oct)Suffix? + Dec:= (0|[1-9][0-9_]*) + Hex:= 0[xX] HexDigits + Bin:= 0[bB][01_]+ + Oct:= 0[0-7_]+ + Suffix:= (L[uU]?|[uU]L?) + HexDigits:= [0-9a-zA-Z_]+ + + Invalid: "0b_", "0x_", "._" + */ + void scanNumber(ref Token t) + { + ulong ulong_; + bool overflow; + bool isDecimal; + size_t digits; + + if (*p != '0') + goto LscanInteger; + ++p; // skip zero + // check for xX bB ... + switch (*p) + { + case 'x','X': + goto LscanHex; + case 'b','B': + goto LscanBin; + case 'L': + if (p[1] == 'i') + goto LscanReal; + case '.': + if (p[1] == '.') + break; + case 'i','f','F', 'e', 'E': // Imaginary and float literal suffix + goto LscanReal; + default: + if (*p == '_' || isoctal(*p)) + goto LscanOct; + } + + // Number 0 + assert(p[-1] == '0'); + assert(ulong_ == 0); + isDecimal = true; + goto Lfinalize; + + LscanInteger: + assert(*p != 0 && isdigit(*p)); + isDecimal = true; + goto Lenter_loop_int; + while (1) + { + if (*++p == '_') + continue; + if (!isdigit(*p)) + break; + Lenter_loop_int: + if (ulong_ < ulong.max/10 || (ulong_ == ulong.max/10 && *p <= '5')) + { + ulong_ *= 10; + ulong_ += *p - '0'; + continue; + } + // Overflow: skip following digits. + overflow = true; + while (isdigit(*++p)) {} + break; + } + + // The number could be a float, so check overflow below. + switch (*p) + { + case '.': + if (p[1] != '.') + goto LscanReal; + break; + case 'L': + if (p[1] != 'i') + break; + case 'i', 'f', 'F', 'e', 'E': + goto LscanReal; + default: + } + + if (overflow) + error(MID.OverflowDecimalNumber); + + assert((isdigit(p[-1]) || p[-1] == '_') && !isdigit(*p) && *p != '_'); + goto Lfinalize; + + LscanHex: + assert(digits == 0); + assert(*p == 'x'); + while (1) + { + if (*++p == '_') + continue; + if (!ishexad(*p)) + break; + ++digits; + ulong_ *= 16; + if (*p <= '9') + ulong_ += *p - '0'; + else if (*p <= 'F') + ulong_ += *p - 'A' + 10; + else + ulong_ += *p - 'a' + 10; + } + + switch (*p) + { + case '.': + if (p[1] != '.') + goto LscanHexReal; + break; + case 'L': + if (p[1] != 'i') + break; + case 'i', 'p', 'P': + goto LscanHexReal; + default: + } + if (digits == 0) + error(MID.NoDigitsInHexNumber); + else if (digits > 16) + { + // Overflow: skip following digits. + error(MID.OverflowHexNumber); + while (ishexad(*++p)) {} + } + goto Lfinalize; + LscanHexReal: + return scanHexReal(t); + + LscanBin: + assert(digits == 0); + assert(*p == 'b'); + while (1) + { + if (*++p == '0') + { + ++digits; + ulong_ *= 2; + } + if (*p == '1') + { + ++digits; + ulong_ *= 2; + ulong_ += *p - '0'; + } + if (*p == '_') + continue; + break; + } + + if (digits == 0) + error(MID.NoDigitsInBinNumber); + + if (digits > 64) + error(MID.OverflowBinaryNumber); + assert((p[-1] == '0' || p[-1] == '1' || p[-1] == '_') && !(*p == '0' || *p == '1' || *p == '_')); + goto Lfinalize; + + LscanOct: + assert(*p == '_' || isoctal(*p)); + if (*p != '_') + goto Lenter_loop_oct; + while (1) + { + if (*++p == '_') + continue; + if (!isoctal(*p)) + break; + Lenter_loop_oct: + if (ulong_ < ulong.max/2 || (ulong_ == ulong.max/2 && *p <= '1')) + { + ulong_ *= 8; + ulong_ += *p - '0'; + ++p; + continue; + } + // Overflow: skip following digits. + overflow = true; + while (isdigit(*++p)) {} + break; + } + + bool hasDecimalDigits; + if (isdigit(*p)) + { + hasDecimalDigits = true; + while (isdigit(*++p)) {} + } + + // The number could be a float, so check errors below. + switch (*p) + { + case '.': + if (p[1] != '.') + goto LscanReal; + break; + case 'L': + if (p[1] != 'i') + break; + case 'i', 'f', 'F', 'e', 'E': + goto LscanReal; + default: + } + + if (hasDecimalDigits) + error(MID.OctalNumberHasDecimals); + if (overflow) + error(MID.OverflowOctalNumber); +// goto Lfinalize; + + Lfinalize: + enum Suffix + { + None = 0, + Unsigned = 1, + Long = 2 + } + + Suffix suffix; + while (1) + { + switch (*p) + { + case 'L': + if (suffix & Suffix.Long) + break; + suffix |= Suffix.Long; + ++p; + continue; + case 'u', 'U': + if (suffix & Suffix.Unsigned) + break; + suffix |= Suffix.Unsigned; + ++p; + continue; + default: + break; + } + break; + } + + switch (suffix) + { + case Suffix.None: + if (ulong_ & 0x8000000000000000) + { + if (isDecimal) + error(MID.OverflowDecimalSign); + t.type = TOK.Uint64; + } + else if (ulong_ & 0xFFFFFFFF00000000) + t.type = TOK.Int64; + else if (ulong_ & 0x80000000) + t.type = isDecimal ? TOK.Int64 : TOK.Uint32; + else + t.type = TOK.Int32; + break; + case Suffix.Unsigned: + if (ulong_ & 0xFFFFFFFF00000000) + t.type = TOK.Uint64; + else + t.type = TOK.Uint32; + break; + case Suffix.Long: + if (ulong_ & 0x8000000000000000) + { + if (isDecimal) + error(MID.OverflowDecimalSign); + t.type = TOK.Uint64; + } + else + t.type = TOK.Int64; + break; + case Suffix.Unsigned | Suffix.Long: + t.type = TOK.Uint64; + break; + default: + assert(0); + } + t.ulong_ = ulong_; + t.end = p; + return; + LscanReal: + scanReal(t); + return; + } + + /* + FloatLiteral:= Float[fFL]?i? + Float:= DecFloat | HexFloat + DecFloat:= ([0-9][0-9_]*[.][0-9_]*DecExponent?) | [.][0-9][0-9_]*DecExponent? | [0-9][0-9_]*DecExponent + DecExponent:= [eE][+-]?[0-9][0-9_]* + HexFloat:= 0[xX](HexDigits[.]HexDigits | [.][0-9a-zA-Z]HexDigits? | HexDigits)HexExponent + HexExponent:= [pP][+-]?[0-9][0-9_]* + */ + void scanReal(ref Token t) + { + if (*p == '.') + // This function was called by scan() or scanNumber(). + while (isdigit(*++p) || *p == '_') {} + else + { + // This function was called by scanNumber(). + debug switch (*p) + { + case 'L': + if (p[1] != 'i') + assert(0); + case 'i', 'f', 'F', 'e', 'E': break; + default: assert(0); + } + } + + // Scan exponent. + if (*p == 'e' || *p == 'E') + { + ++p; + if (*p == '-' || *p == '+') + ++p; + if (!isdigit(*p)) + error(MID.FloatExponentDigitExpected); + else + while (isdigit(*++p) || *p == '_') {} + } + + // Copy string to buffer ignoring underscores. + char[] buffer; + char* end = p; + p = t.start; + do + { + if (*p == '_') + { + ++p; + continue; + } + buffer ~= *p; + ++p; + } while (p != end) + buffer ~= 0; + finalizeFloat(t, buffer); + } + + void scanHexReal(ref Token t) + { + assert(*p == '.' || *p == 'i' || *p == 'p' || *p == 'P' || (*p == 'L' && p[1] == 'i')); + MID mid; + if (*p == '.') + while (ishexad(*++p) || *p == '_') {} + if (*p != 'p' && *p != 'P') + { + mid = MID.HexFloatExponentRequired; + goto Lerr; + } + // Copy mantissa to a buffer ignoring underscores. + char* end = p; + p = t.start; + char[] buffer; + do + { + if (*p == '_') + { + ++p; + continue; + } + buffer ~= *p; + ++p; + } while (p != end) + + assert(p == end && (*p == 'p' || *p == 'P')); + // Scan and copy the exponent. + buffer ~= 'p'; + size_t bufflen = buffer.length; + while (1) + { + if (*++p == '_') + continue; + if (isdigit(*p)) + buffer ~= *p; + else + break; + } + // When the buffer length hasn't changed, no digits were copied. + if (bufflen == buffer.length) { + mid = MID.HexFloatMissingExpDigits; + goto Lerr; + } + buffer ~= 0; // Terminate for C functions. + finalizeFloat(t, buffer); + return; + Lerr: + t.type = TOK.Float32; + t.end = p; + error(mid); + } + + void finalizeFloat(ref Token t, string buffer) + { + // Float number is well-formed. Check suffixes and do conversion. + switch (*p) + { + case 'f', 'F': + t.type = TOK.Float32; + t.float_ = strtof(buffer.ptr, null); + ++p; + break; + case 'L': + t.type = TOK.Float80; + t.real_ = strtold(buffer.ptr, null); + ++p; + break; + default: + t.type = TOK.Float64; + t.double_ = strtod(buffer.ptr, null); + break; + } + if (*p == 'i') + { + ++p; + t.type += 3; // Switch to imaginary counterpart. + } + if (getErrno == ERANGE) + error(MID.OverflowFloatNumber); + t.end = p; + } + + /// Scan special token: #line Integer [Filespec] EndOfLine + void scanSpecialToken(ref Token t) + { + assert(*p == '#'); + + t.type = TOK.HashLine; + + MID mid; + + ++p; + if (p[0] != 'l' || p[1] != 'i' || p[2] != 'n' || p[3] != 'e') + { + mid = MID.ExpectedNumberAfterSTLine; + goto Lerr; + } + p += 3; + + enum State + { Number, Filespec, End } + + State state; + + Loop: + while (1) + { + switch (*++p) + { + case '\r': + if (p[1] == '\n') + ++p; + case '\n', 0, _Z_: + break Loop; + case LS[0]: + if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2])) + { + ++p; ++p; + break Loop; + } + goto default; + default: + if (isspace(*p)) + continue; + if (state == State.Number) + { + if (!isdigit(*p)) + { + mid = MID.ExpectedNumberAfterSTLine; + goto Lerr; + } + t.line_num = new Token; + scan(*t.line_num); + --p; + state = State.Filespec; + } + else if (state == State.Filespec) + { + if (*p != '"') + { + mid = MID.ExpectedFilespec; + goto Lerr; + } + t.line_filespec = new Token; + t.line_filespec.start = p; + t.line_filespec.type = TOK.Filespec; + while (1) + { + switch (*++p) + { + case '"': + break; + case LS[0]: + if (!(p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2]))) + goto default; + case '\r', '\n', 0, _Z_: + mid = MID.UnterminatedFilespec; + t.line_filespec.end = p; + goto Lerr; + default: + if (*p & 128) + decodeUTF8(); + continue; + } + break; // Exit loop. + } + auto start = t.line_filespec.start +1; // +1 skips '"' + t.line_filespec.str = start[0 .. p - start]; + t.line_filespec.end = p + 1; + state = State.End; + } + else/+ if (state == State.End)+/ + { + mid = MID.UnterminatedSpecialToken; + goto Lerr; + } + } + } + + if (state == State.Number) + { + mid = MID.ExpectedNumberAfterSTLine; + goto Lerr; + } + + this.loc = t.line_num.uint_ - 1; + if (t.line_filespec) + this.fileName = t.line_filespec.str; + t.end = p; + + return; + Lerr: + t.end = p; + error(mid); + } + + dchar decodeUTF8() + { + assert(*p & 128, "check for ASCII char before calling decodeUTF8()."); + size_t idx; + dchar d; + try + { + d = std.utf.decode(p[0 .. end-p], idx); + p += idx -1; + } + catch (UtfException e) + { + error(MID.InvalidUTF8Sequence); + // Skip to next valid utf-8 sequence + while (UTF8stride[*++p] != 0xFF) {} + --p; + } + return d; + } + + void loadKeywords() + { + foreach(k; keywords) + idtable[k.str] = k; + } +/+ + struct State + { + Lexer lexer; + Token token; + char* scanPointer; + int loc; + string fileName; + size_t errorLen; + static State opCall(Lexer lx) + { + State s; + s.lexer = lx; + s.token = lx.token; + s.scanPointer = lx.p; + s.loc = lx.loc; + s.fileName = lx.fileName; + s.errorLen = lx.errors.length; + return s; + } + void restore() + { + lexer.p = scanPointer; + lexer.token = token; + lexer.loc = loc; + lexer.fileName = fileName; + lexer.errors = lexer.errors[0..errorLen]; + } + } + + State getState() + { + return State(this); + } ++/ + + private void scanNext(ref Token* t) + { + assert(t !is null); + if (t.next) + t = t.next; + else if (t.type != TOK.EOF) + { + Token* new_t = new Token; + scan(*new_t); + new_t.prev = t; + t.next = new_t; + t = new_t; + } + } + + void peek(ref Token* t) + { + scanNext(t); + } + + TOK nextToken() + { + scanNext(this.token); + return this.token.type; + } + + void error(MID id, ...) + { +// if (reportErrors) + errors ~= new Information(InfoType.Lexer, id, loc, arguments(_arguments, _argptr)); + } + + unittest + { + string sourceText = "unittest { }"; + auto lx = new Lexer(sourceText, null); + + Token next; + lx.peek(next); + assert(next == TOK.Unittest); + lx.peek(next); + assert(next == TOK.LBrace); + lx.peek(next); + assert(next == TOK.RBrace); + lx.peek(next); + assert(next == TOK.EOF); + writefln("end of peek() unittest"); + } + + Token* getTokens() + { + while (nextToken() != TOK.EOF) + {} + return head; + } + + private void encodeUTF8(inout char[] str, dchar d) + { + char[6] b; + assert(d > 0x7F, "check for ASCII char before calling encodeUTF8()."); + if (d < 0x800) + { + b[0] = 0xC0 | (d >> 6); + b[1] = 0x80 | (d & 0x3F); + str ~= b[0..2]; + } + else if (d < 0x10000) + { + b[0] = 0xE0 | (d >> 12); + b[1] = 0x80 | ((d >> 6) & 0x3F); + b[2] = 0x80 | (d & 0x3F); + str ~= b[0..3]; + } + else if (d < 0x200000) + { + b[0] = 0xF0 | (d >> 18); + b[1] = 0x80 | ((d >> 12) & 0x3F); + b[2] = 0x80 | ((d >> 6) & 0x3F); + b[3] = 0x80 | (d & 0x3F); + str ~= b[0..4]; + } + else if (d < 0x4000000) + { + b[0] = 0xF8 | (d >> 24); + b[1] = 0x80 | ((d >> 18) & 0x3F); + b[2] = 0x80 | ((d >> 12) & 0x3F); + b[3] = 0x80 | ((d >> 6) & 0x3F); + b[4] = 0x80 | (d & 0x3F); + str ~= b[0..5]; + } + else if (d < 0x80000000) + { + b[0] = 0xFC | (d >> 30); + b[1] = 0x80 | ((d >> 24) & 0x3F); + b[2] = 0x80 | ((d >> 18) & 0x3F); + b[3] = 0x80 | ((d >> 12) & 0x3F); + b[4] = 0x80 | ((d >> 6) & 0x3F); + b[5] = 0x80 | (d & 0x3F); + str ~= b[0..6]; + } + else + error(MID.InvalidUnicodeCharacter); + } +} + +unittest +{ + string[] toks = [ + ">", ">=", ">>", ">>=", ">>>", ">>>=", "<", "<=", "<>", + "<>=", "<<", "<<=", "!", "!<", "!>", "!<=", "!>=", "!<>", + "!<>=", ".", "..", "...", "&", "&&", "&=", "+", "++", + "+=", "-", "--", "-=", "=", "==", "~", "~=", "*", + "*=", "/", "/=", "^", "^=", "%", "%=", "(", ")", + "[", "]", "{", "}", ":", ";", "?", ",", "$" + ]; + + char[] src; + + foreach (op; toks) + src ~= op ~ " "; + + auto lx = new Lexer(src, ""); + auto tokens = lx.getTokens(); + + tokens = tokens[0..$-1]; // exclude TOK.EOF + + assert(tokens.length == toks.length ); + + foreach (i, t; tokens) + assert(t.srcText == toks[i], std.string.format("Lexed '%s' but expected '%s'", t.srcText, toks[i])); +} + +unittest +{ + // Numbers unittest + // 0L 0ULi 0_L 0_UL 0x0U 0x0p2 0_Fi 0_e2 0_F 0_i + // 0u 0U 0uL 0UL 0L 0LU 0Lu + // 0Li 0f 0F 0fi 0Fi 0i + // 0b_1_LU 0b1000u + // 0x232Lu +} + +/// ASCII character properties table. +static const int ptable[256] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0,32,32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +32, 0, 0x2200, 0, 0, 0, 0, 0x2700, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 0, 0, 0, 0, 0, 0x3f00, + 0,12,12,12,12,12,12, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0x5c00, 0, 0,16, + 0, 0x70c, 0x80c,12,12,12, 0xc0c, 8, 8, 8, 8, 8, 8, 8, 0xa08, 8, + 8, 8, 0xd08, 8, 0x908, 8, 0xb08, 8, 8, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +]; + +enum CProperty +{ + Octal = 1, + Digit = 1<<1, + Hex = 1<<2, + Alpha = 1<<3, + Underscore = 1<<4, + Whitespace = 1<<5 +} + +const uint EVMask = 0xFF00; // Bit mask for escape value + +private alias CProperty CP; +int isoctal(char c) { return ptable[c] & CP.Octal; } +int isdigit(char c) { return ptable[c] & CP.Digit; } +int ishexad(char c) { return ptable[c] & CP.Hex; } +int isalpha(char c) { return ptable[c] & CP.Alpha; } +int isalnum(char c) { return ptable[c] & (CP.Alpha | CP.Digit); } +int isidbeg(char c) { return ptable[c] & (CP.Alpha | CP.Underscore); } +int isident(char c) { return ptable[c] & (CP.Alpha | CP.Underscore | CP.Digit); } +int isspace(char c) { return ptable[c] & CP.Whitespace; } +int char2ev(char c) { return ptable[c] >> 8; /*(ptable[c] & EVMask) >> 8;*/ } + +version(gen_ptable) +static this() +{ + alias ptable p; + // Initialize character properties table. + for (int i; i < p.length; ++i) + { + p[i] = 0; + if ('0' <= i && i <= '7') + p[i] |= CP.Octal; + if ('0' <= i && i <= '9') + p[i] |= CP.Digit; + if (isdigit(i) || 'a' <= i && i <= 'f' || 'A' <= i && i <= 'F') + p[i] |= CP.Hex; + if ('a' <= i && i <= 'z' || 'A' <= i && i <= 'Z') + p[i] |= CP.Alpha; + if (i == '_') + p[i] |= CP.Underscore; + if (i == ' ' || i == '\t' || i == '\v' || i == '\f') + p[i] |= CP.Whitespace; + } + // Store escape sequence values in second byte. + assert(CProperty.max <= ubyte.max, "character property flags and escape value byte overlap."); + p['\''] |= 39 << 8; + p['"'] |= 34 << 8; + p['?'] |= 63 << 8; + p['\\'] |= 92 << 8; + p['a'] |= 7 << 8; + p['b'] |= 8 << 8; + p['f'] |= 12 << 8; + p['n'] |= 10 << 8; + p['r'] |= 13 << 8; + p['t'] |= 9 << 8; + p['v'] |= 11 << 8; + // Print a formatted array literal. + char[] array = "[\n"; + for (int i; i < p.length; ++i) + { + int c = p[i]; + array ~= std.string.format(c>255?" 0x%x,":"%2d,", c, ((i+1) % 16) ? "":"\n"); + } + array[$-2..$] = "\n]"; + writefln(array); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Messages.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,108 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Messages; +import Settings; +import std.stdarg; + +/// Index into table of compiler messages. +enum MID +{ + // Lexer messages: + InvalidUnicodeCharacter, + InvalidUTF8Sequence, + // '' + UnterminatedCharacterLiteral, + EmptyCharacterLiteral, + // #line + ExpectedIdentifierSTLine, + ExpectedNumberAfterSTLine, + ExpectedFilespec, + UnterminatedFilespec, + UnterminatedSpecialToken, + // "" + UnterminatedString, + // x"" + NonHexCharInHexString, + OddNumberOfDigitsInHexString, + UnterminatedHexString, + // /* */ /+ +/ + UnterminatedBlockComment, + UnterminatedNestedComment, + // `` r"" + UnterminatedRawString, + UnterminatedBackQuoteString, + // \x \u \U + UndefinedEscapeSequence, + InsufficientHexDigits, + // \&[a-zA-Z][a-zA-Z0-9]+; + UndefinedHTMLEntity, + UnterminatedHTMLEntity, + InvalidBeginHTMLEntity, + // integer overflows + OverflowDecimalSign, + OverflowDecimalNumber, + OverflowHexNumber, + OverflowBinaryNumber, + OverflowOctalNumber, + OverflowFloatNumber, + OctalNumberHasDecimals, + NoDigitsInHexNumber, + NoDigitsInBinNumber, + HexFloatExponentRequired, + HexFloatMissingExpDigits, + FloatExponentDigitExpected, + + // Parser messages: + ExpectedButFound, + RedundantStorageClass, + + // Help messages: + HelpMain, +} + +string GetMsg(MID mid) +{ + assert(mid < GlobalSettings.messages.length); + return GlobalSettings.messages[mid]; +} + +char[] format(MID mid, ...) +{ + auto args = arguments(_arguments, _argptr); + return format_args(GetMsg(mid), args); +} + +char[] format(char[] format_str, ...) +{ + auto args = arguments(_arguments, _argptr); + return format_args(format_str, args); +} + +char[] format_args(char[] format_str, char[][] args) +{ + char[] result = format_str; + + foreach (i, arg; args) + result = std.string.replace(result, std.string.format("{%s}", i+1), arg); + + return result; +} + +char[][] arguments(TypeInfo[] tinfos, void* argptr) +{ + char[][] args; + foreach (ti; tinfos) + { + if (ti == typeid(char[])) + args ~= va_arg!(char[])(argptr); + else if (ti == typeid(int)) + args ~= std.string.format(va_arg!(int)(argptr)); + else if (ti == typeid(dchar)) + args ~= std.string.format(va_arg!(dchar)(argptr)); + else + assert(0, "argument type not supported yet."); + } + return args; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Parser.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,4193 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Parser; +import Lexer; +import SyntaxTree; +import Token; +import Messages; +import Information; +import Declarations; +import Statements; +import Expressions; +import Types; +import std.stdio; + +private alias TOK T; + +class Parser +{ + Lexer lx; + Token* token; /// Current non-whitespace token. + Token* prevToken; /// Previous non-whitespace token. + + Information[] errors; + + this(char[] srcText, string fileName) + { + lx = new Lexer(srcText, fileName); + } + + debug char* prev; + + void start() + { + debug prev = lx.text.ptr; + nT(); + prevToken = token; + } + + void nT() + { + prevToken = token; + do + { + lx.nextToken(); + token = lx.token; + +debug if (!trying) +{ + writef("\33[32m%s\33[0m", token.type); + writef("%s", prev[0 .. token.end - prev]); + prev = token.end; +} + } while (token.isWhitespace) // Skip whitespace + } + + void skipToOnePast(TOK tok) + { + for (; token.type != tok && token.type != T.EOF; nT()) + {} + nT(); + } + + int trying; + int errorCount; + + ReturnType try_(ReturnType)(lazy ReturnType parseMethod, out bool success) + { +debug writef("\33[31mtry_\33[0m"); + ++trying; +// auto len = errors.length; + auto oldToken = token; + auto oldPrevToken = prevToken; + auto oldCount = errorCount; +// auto lexerState = lx.getState(); + auto result = parseMethod(); + // If the length of the array changed we know an error occurred. + if (errorCount != oldCount) + { +// lexerState.restore(); // Restore state of the Lexer object. +// errors = errors[0..len]; // Remove errors that were added when parseMethod() was called. + token = oldToken; + prevToken = oldPrevToken; + lx.token = oldToken; + errorCount = oldCount; + success = false; + } + else + success = true; + --trying; +debug writef("\33[34m%s\33[0m", success); + return result; + } + + Class set(Class)(Class node, Token* begin) + { + node.setTokens(begin, this.prevToken); + return node; + } + + TOK peekNext() + { + Token* next = token; + do + lx.peek(next); + while (next.isWhitespace) // Skip whitespace + return next.type; + } + + /++++++++++++++++++++++++++++++ + + Declaration parsing methods + + ++++++++++++++++++++++++++++++/ + + Declarations parseModule() + { + auto decls = new Declarations; + + if (token.type == T.Module) + { + auto begin = token; + ModuleName moduleName; + do + { + nT(); + moduleName ~= requireId(); + } while (token.type == T.Dot) + require(T.Semicolon); + decls ~= set(new ModuleDeclaration(moduleName), begin); + } + decls ~= parseDeclarationDefinitions(); + return decls; + } + + Declarations parseDeclarationDefinitions() + { + auto decls = new Declarations; + while (token.type != T.EOF) + decls ~= parseDeclarationDefinition(); + return decls; + } + + /* + DeclDefsBlock: + { } + { DeclDefs } + */ + Declarations parseDeclarationDefinitionsBlock() + { + auto decls = new Declarations; + require(T.LBrace); + while (token.type != T.RBrace && token.type != T.EOF) + decls ~= parseDeclarationDefinition(); + require(T.RBrace); + return decls; + } + + Declaration parseDeclarationDefinition() + { + auto begin = token; + Declaration decl; + switch (token.type) + { + case T.Align, + T.Pragma, + // Protection attributes + T.Export, + T.Private, + T.Package, + T.Protected, + T.Public: + decl = parseAttributeSpecifier(); + break; + // Storage classes + case T.Extern, + T.Deprecated, + T.Override, + T.Abstract, + T.Synchronized, + //T.Static, + T.Final, + T.Const, + //T.Invariant, // D 2.0 + T.Auto, + T.Scope: + case_StaticAttribute: + case_InvariantAttribute: // D 2.0 + decl = parseStorageAttribute(); + break; + case T.Alias: + nT(); + // TODO: parse StorageClasses? + decl = new AliasDeclaration(parseDeclaration()); + break; + case T.Typedef: + nT(); + // TODO: parse StorageClasses? + decl = new TypedefDeclaration(parseDeclaration()); + break; + case T.Static: + switch (peekNext()) + { + case T.Import: + goto case T.Import; + case T.This: + decl = parseStaticConstructorDeclaration(); + break; + case T.Tilde: + decl = parseStaticDestructorDeclaration(); + break; + case T.If: + decl = parseStaticIfDeclaration(); + break; + case T.Assert: + decl = parseStaticAssertDeclaration(); + break; + default: + goto case_StaticAttribute; + } + break; + case T.Import: + decl = parseImportDeclaration(); + break; + case T.Enum: + decl = parseEnumDeclaration(); + break; + case T.Class: + decl = parseClassDeclaration(); + break; + case T.Interface: + decl = parseInterfaceDeclaration(); + break; + case T.Struct, T.Union: + decl = parseAggregateDeclaration(); + break; + case T.This: + decl = parseConstructorDeclaration(); + break; + case T.Tilde: + decl = parseDestructorDeclaration(); + break; + case T.Invariant: + version(D2) + { + auto next = token; + lx.peek(next); + if (next.type == T.LParen) + { + lx.peek(next); + if (next.type != T.RParen) + goto case_Declaration; + } + else + goto case_InvariantAttribute; + } + decl = parseInvariantDeclaration(); + break; + case T.Unittest: + decl = parseUnittestDeclaration(); + break; + case T.Debug: + decl = parseDebugDeclaration(); + break; + case T.Version: + decl = parseVersionDeclaration(); + break; + case T.Template: + decl = parseTemplateDeclaration(); + break; + case T.New: + decl = parseNewDeclaration(); + break; + case T.Delete: + decl = parseDeleteDeclaration(); + break; + case T.Mixin: + decl = parseMixin!(MixinDeclaration)(); + break; + case T.Semicolon: + nT(); + decl = new EmptyDeclaration(); + break; + // Declaration + case T.Identifier, T.Dot, T.Typeof: + // BasicType + case T.Char, T.Wchar, T.Dchar, T.Bool, + T.Byte, T.Ubyte, T.Short, T.Ushort, + T.Int, T.Uint, T.Long, T.Ulong, + T.Float, T.Double, T.Real, + T.Ifloat, T.Idouble, T.Ireal, + T.Cfloat, T.Cdouble, T.Creal, T.Void: + case_Declaration: + decl = parseDeclaration(); + break; + /+case T.Module: + // TODO: Error: module is optional and can appear only once at the top of the source file. + break;+/ + default: + error(MID.ExpectedButFound, "Declaration", token.srcText); + decl = new IllegalDeclaration(token); + nT(); + } +// writef("§%s§", decl.classinfo.name); + set(decl, begin); + return decl; + } + + /* + DeclarationsBlock: + : DeclDefs + { } + { DeclDefs } + DeclDef + */ + Declaration parseDeclarationsBlock() + { + Declaration d; + switch (token.type) + { + case T.LBrace: + d = parseDeclarationDefinitionsBlock(); + break; + case T.Colon: + nT(); + auto decls = new Declarations; + while (token.type != T.RBrace && token.type != T.EOF) + decls ~= parseDeclarationDefinition(); + d = decls; + break; + default: + d = parseDeclarationDefinition(); + } + return d; + } + + Declaration parseDeclaration(StorageClass stc = StorageClass.None) + { + Type type; + Token* ident; + + // Check for AutoDeclaration + if (stc != StorageClass.None && + token.type == T.Identifier && + peekNext() == T.Assign) + { + ident = token; + nT(); + } + else + { + type = parseType(); + ident = requireId(); + // Type FunctionName ( ParameterList ) FunctionBody + if (token.type == T.LParen) + { + // It's a function declaration + TemplateParameters tparams; + if (tokenAfterParenIs(T.LParen)) + { + // ( TemplateParameterList ) ( ParameterList ) + tparams = parseTemplateParameterList(); + } + + auto params = parseParameterList(); + // ReturnType FunctionName ( ParameterList ) + auto funcBody = parseFunctionBody(); + return new FunctionDeclaration(type, ident, tparams, params, funcBody); + } + type = parseDeclaratorSuffix(type); + } + + // It's a variable declaration. + Token*[] idents = [ident]; + Expression[] values; + goto LenterLoop; // We've already parsed an identifier. Jump to if statement and check for initializer. + while (token.type == T.Comma) + { + nT(); + idents ~= requireId(); + LenterLoop: + if (token.type == T.Assign) + { + nT(); + values ~= parseInitializer(); + } + else + values ~= null; + } + require(T.Semicolon); + return new VariableDeclaration(type, idents, values); + } + + Expression parseInitializer() + { + if (token.type == T.Void) + { + auto begin = token; + auto next = peekNext(); + if (next == T.Comma || next == T.Semicolon) + { + nT(); + return set(new VoidInitializer(), begin); + } + } + return parseNonVoidInitializer(); + } + + Expression parseNonVoidInitializer() + { + auto begin = token; + Expression init; + switch (token.type) + { + case T.LBracket: + // ArrayInitializer: + // [ ] + // [ ArrayMemberInitializations ] + Expression[] keys; + Expression[] values; + + nT(); + while (token.type != T.RBracket) + { + auto e = parseNonVoidInitializer(); + if (token.type == T.Colon) + { + nT(); + keys ~= e; + values ~= parseNonVoidInitializer(); + } + else + { + keys ~= null; + values ~= e; + } + + if (token.type != T.Comma) + break; + nT(); + } + require(T.RBracket); + init = new ArrayInitializer(keys, values); + break; + case T.LBrace: + // StructInitializer: + // { } + // { StructMemberInitializers } + Expression parseStructInitializer() + { + Token*[] idents; + Expression[] values; + + nT(); + while (token.type != T.RBrace) + { + if (token.type == T.Identifier) + { + // Peek for colon to see if this is a member identifier. + if (peekNext() == T.Colon) + { + idents ~= token; + nT(); + nT(); + } + } + // NonVoidInitializer + values ~= parseNonVoidInitializer(); + + if (token.type != T.Comma) + break; + nT(); + } + require(T.RBrace); + return new StructInitializer(idents, values); + } + + bool success; + auto si = try_(parseStructInitializer(), success); + if (success) + { + init = si; + break; + } + assert(token.type == T.LBrace); + //goto default; + default: + init = parseAssignExpression(); + } + set(init, begin); + return init; + } + + FunctionBody parseFunctionBody() + { + auto begin = token; + auto func = new FunctionBody; + while (1) + { + switch (token.type) + { + case T.LBrace: + func.funcBody = parseStatements(); + break; + case T.Semicolon: + nT(); + break; + case T.In: + //if (func.inBody) + // TODO: issue error msg. + nT(); + func.inBody = parseStatements(); + continue; + case T.Out: + //if (func.outBody) + // TODO: issue error msg. + nT(); + if (token.type == T.LParen) + { + nT(); + func.outIdent = requireId(); + require(T.RParen); + } + func.outBody = parseStatements(); + continue; + case T.Body: + nT(); + goto case T.LBrace; + default: + error(MID.ExpectedButFound, "FunctionBody", token.srcText); + } + break; // exit while loop + } + set(func, begin); + func.finishConstruction(); + return func; + } + + Declaration parseStorageAttribute() + { + StorageClass stc, tmp; + + void addStorageClass() + { + if (stc & tmp) + { + error(MID.RedundantStorageClass, token.srcText); + } + else + stc |= tmp; + } + + Declaration parse() + { + Declaration decl; + switch (token.type) + { + case T.Extern: + tmp = StorageClass.Extern; + addStorageClass(); + nT(); + Linkage linkage; + if (token.type == T.LParen) + { + nT(); + auto ident = requireId(); + switch (ident ? ident.identifier : null) + { + case "C": + if (token.type == T.PlusPlus) + { + nT(); + linkage = Linkage.Cpp; + break; + } + linkage = Linkage.C; + break; + case "D": + linkage = Linkage.D; + break; + case "Windows": + linkage = Linkage.Windows; + break; + case "Pascal": + linkage = Linkage.Pascal; + break; + case "System": + linkage = Linkage.System; + break; + default: + // TODO: issue error msg. Unrecognized LinkageType. + } + require(T.RParen); + } + decl = new ExternDeclaration(linkage, parse()); + break; + case T.Override: + tmp = StorageClass.Override; + goto Lcommon; + case T.Deprecated: + tmp = StorageClass.Deprecated; + goto Lcommon; + case T.Abstract: + tmp = StorageClass.Abstract; + goto Lcommon; + case T.Synchronized: + tmp = StorageClass.Synchronized; + goto Lcommon; + case T.Static: + tmp = StorageClass.Static; + goto Lcommon; + case T.Final: + tmp = StorageClass.Final; + goto Lcommon; + case T.Const: + version(D2) + { + if (peekNext() == T.LParen) + goto case_Declaration; + } + tmp = StorageClass.Const; + goto Lcommon; + version(D2) + { + case T.Invariant: // D 2.0 + if (peekNext() == T.LParen) + goto case_Declaration; + tmp = StorageClass.Invariant; + goto Lcommon; + } + case T.Auto: + tmp = StorageClass.Auto; + goto Lcommon; + case T.Scope: + tmp = StorageClass.Scope; + goto Lcommon; + Lcommon: + addStorageClass(); + auto tok = token.type; + nT(); + decl = new AttributeDeclaration(tok, parse()); + break; + case T.Identifier: + case_Declaration: + // This could be a normal Declaration or an AutoDeclaration + decl = parseDeclaration(stc); + break; + default: + decl = parseDeclarationsBlock(); + } + return decl; + } + return parse(); + } + + Token* parseAlignAttribute() + { + assert(token.type == T.Align); + nT(); // Skip align keyword. + Token* tok; + if (token.type == T.LParen) + { + nT(); + if (token.type == T.Int32) + { + tok = token; + nT(); + } + else + expected(T.Int32); + require(T.RParen); + } + return tok; + } + + Declaration parseAttributeSpecifier() + { + Declaration decl; + + switch (token.type) + { + case T.Align: + int size = -1; + auto intTok = parseAlignAttribute(); + if (intTok) + size = intTok.int_; + decl = new AlignDeclaration(size, parseDeclarationsBlock()); + break; + case T.Pragma: + // Pragma: + // pragma ( Identifier ) + // pragma ( Identifier , ExpressionList ) + // ExpressionList: + // AssignExpression + // AssignExpression , ExpressionList + nT(); + Token* ident; + Expression[] args; + Declaration decls; + + require(T.LParen); + ident = requireId(); + + if (token.type == T.Comma) + { + // Parse at least one argument. + nT(); + args ~= parseAssignExpression(); + } + + if (token.type == T.Comma) + args ~= parseArguments(T.RParen); + else + require(T.RParen); + + if (token.type == T.Semicolon) + { + nT(); + decls = new EmptyDeclaration(); + } + else + decls = parseDeclarationsBlock(); + + decl = new PragmaDeclaration(ident, args, decls); + break; + // Protection attributes + case T.Private: + case T.Package: + case T.Protected: + case T.Public: + case T.Export: + auto tok = token.type; + nT(); + decl = new AttributeDeclaration(tok, parseDeclarationsBlock()); + break; + default: + assert(0); + } + return decl; + } + + Declaration parseImportDeclaration() + { + assert(token.type == T.Import || token.type == T.Static); + + bool isStatic; + + if (token.type == T.Static) + { + isStatic = true; + nT(); + } + + ModuleName[] moduleNames; + Token*[] moduleAliases; + Token*[] bindNames; + Token*[] bindAliases; + + nT(); // Skip import keyword. + while (1) + { + ModuleName moduleName; + Token* moduleAlias; + + moduleAlias = requireId(); + + // AliasName = ModuleName + if (token.type == T.Assign) + { + nT(); + moduleName ~= requireId(); + } + else // import Identifier [^=] + { + moduleName ~= moduleAlias; + moduleAlias = null; + } + + // Identifier(.Identifier)* + while (token.type == T.Dot) + { + nT(); + moduleName ~= requireId(); + } + + // Push identifiers. + moduleNames ~= moduleName; + moduleAliases ~= moduleAlias; + + if (token.type == T.Colon) + break; + if (token.type != T.Comma) + break; + nT(); + } + + if (token.type == T.Colon) + { + // BindAlias = BindName(, BindAlias = BindName)*; + // BindName(, BindName)*; + Token* bindName, bindAlias; + do + { + nT(); + bindAlias = requireId(); + + if (token.type == T.Assign) + { + nT(); + bindName = requireId(); + } + else + { + bindName = bindAlias; + bindAlias = null; + } + + // Push identifiers. + bindNames ~= bindName; + bindAliases ~= bindAlias; + } while (token.type == T.Comma) + } + + require(T.Semicolon); + + return new ImportDeclaration(moduleNames, moduleAliases, bindNames, bindAliases); + } + + Declaration parseEnumDeclaration() + { + assert(token.type == T.Enum); + + Token* enumName; + Type baseType; + Token*[] members; + Expression[] values; + bool hasBody; + + nT(); // Skip enum keyword. + + if (token.type == T.Identifier) + { + enumName = token; + nT(); + } + + if (token.type == T.Colon) + { + nT(); + baseType = parseBasicType(); + } + + if (token.type == T.Semicolon) + { + if (enumName is null) + expected(T.Identifier); + nT(); + } + else if (token.type == T.LBrace) + { + hasBody = true; + nT(); + do + { + members ~= requireId(); + + if (token.type == T.Assign) + { + nT(); + values ~= parseAssignExpression(); + } + else + values ~= null; + + if (token.type == T.Comma) + nT(); + else if (token.type != T.RBrace) + { + expected(T.RBrace); + break; + } + } while (token.type != T.RBrace) + nT(); + } + else + error(MID.ExpectedButFound, "enum declaration", token.srcText); + + return new EnumDeclaration(enumName, baseType, members, values, hasBody); + } + + Declaration parseClassDeclaration() + { + assert(token.type == T.Class); + + Token* className; + TemplateParameters tparams; + BaseClass[] bases; + Declarations decls; + bool hasBody; + + nT(); // Skip class keyword. + className = requireId(); + + if (token.type == T.LParen) + { + tparams = parseTemplateParameterList(); + } + + if (token.type == T.Colon) + bases = parseBaseClasses(); + + if (token.type == T.Semicolon) + { + //if (bases.length != 0) + // TODO: Error: bases classes are not allowed in forward declarations. + nT(); + } + else if (token.type == T.LBrace) + { + hasBody = true; + // TODO: think about setting a member status variable to a flag InClassBody... this way we can check for DeclDefs that are illegal in class bodies in the parsing phase. + decls = parseDeclarationDefinitionsBlock(); + } + else + expected(T.LBrace); // TODO: better error msg + + return new ClassDeclaration(className, tparams, bases, decls, hasBody); + } + + BaseClass[] parseBaseClasses(bool colonLeadsOff = true) + { + if (colonLeadsOff) + { + assert(token.type == T.Colon); + nT(); // Skip colon + } + + BaseClass[] bases; + + while (1) + { + Protection prot = Protection.Public; + switch (token.type) + { + case T.Identifier, T.Dot, T.Typeof: goto LparseBasicType; + case T.Private: prot = Protection.Private; break; + case T.Protected: prot = Protection.Protected; break; + case T.Package: prot = Protection.Package; break; + case T.Public: /*prot = Protection.Public;*/ break; + default: + // TODO: issue error msg + return bases; + } + nT(); // Skip protection attribute. + LparseBasicType: + auto type = parseBasicType(); + //if (type.tid != TID.DotList) + // TODO: issue error msg. base classes can only be one or more identifiers or template instances separated by dots. + bases ~= new BaseClass(prot, type); + if (token.type != T.Comma) + break; + } + return bases; + } + + Declaration parseInterfaceDeclaration() + { + assert(token.type == T.Interface); + + Token* name; + TemplateParameters tparams; + BaseClass[] bases; + Declarations decls; + bool hasBody; + + nT(); // Skip interface keyword. + name = requireId(); + + if (token.type == T.LParen) + { + tparams = parseTemplateParameterList(); + } + + if (token.type == T.Colon) + bases = parseBaseClasses(); + + if (token.type == T.Semicolon) + { + //if (bases.length != 0) + // TODO: error: base classes are not allowed in forward declarations. + nT(); + } + else if (token.type == T.LBrace) + { + hasBody = true; + decls = parseDeclarationDefinitionsBlock(); + } + else + expected(T.LBrace); // TODO: better error msg + + return new InterfaceDeclaration(name, tparams, bases, decls, hasBody); + } + + Declaration parseAggregateDeclaration() + { + assert(token.type == T.Struct || token.type == T.Union); + + TOK tok = token.type; + + Token* name; + TemplateParameters tparams; + Declarations decls; + bool hasBody; + + nT(); // Skip struct or union keyword. + // name is optional. + if (token.type == T.Identifier) + { + name = token; + nT(); + if (token.type == T.LParen) + { + tparams = parseTemplateParameterList(); + } + } + + if (token.type == T.Semicolon) + { + //if (name.length == 0) + // TODO: error: forward declarations must have a name. + nT(); + } + else if (token.type == T.LBrace) + { + hasBody = true; + decls = parseDeclarationDefinitionsBlock(); + } + else + expected(T.LBrace); // TODO: better error msg + + if (tok == T.Struct) + return new StructDeclaration(name, tparams, decls, hasBody); + else + return new UnionDeclaration(name, tparams, decls, hasBody); + } + + Declaration parseConstructorDeclaration() + { + assert(token.type == T.This); + nT(); // Skip 'this' keyword. + auto parameters = parseParameterList(); + auto funcBody = parseFunctionBody(); + return new ConstructorDeclaration(parameters, funcBody); + } + + Declaration parseDestructorDeclaration() + { + assert(token.type == T.Tilde); + nT(); // Skip ~ + require(T.This); + require(T.LParen); + require(T.RParen); + auto funcBody = parseFunctionBody(); + return new DestructorDeclaration(funcBody); + } + + Declaration parseStaticConstructorDeclaration() + { + assert(token.type == T.Static); + nT(); // Skip static keyword. + nT(); // Skip 'this' keyword. + require(T.LParen); + require(T.RParen); + auto funcBody = parseFunctionBody(); + return new StaticConstructorDeclaration(funcBody); + } + + Declaration parseStaticDestructorDeclaration() + { + assert(token.type == T.Static); + nT(); // Skip static keyword. + nT(); // Skip ~ + require(T.This); + require(T.LParen); + require(T.RParen); + auto funcBody = parseFunctionBody(); + return new StaticDestructorDeclaration(funcBody); + } + + Declaration parseInvariantDeclaration() + { + assert(token.type == T.Invariant); + nT(); // Skip invariant keyword. + // Optional () for getting ready porting to D 2.0 + if (token.type == T.LParen) + requireNext(T.RParen); + auto funcBody = parseFunctionBody(); + return new InvariantDeclaration(funcBody); + } + + Declaration parseUnittestDeclaration() + { + assert(token.type == T.Unittest); + + nT(); // Skip unittest keyword. + auto funcBody = parseFunctionBody(); + return new UnittestDeclaration(funcBody); + } + + Declaration parseDebugDeclaration() + { + assert(token.type == T.Debug); + + nT(); // Skip debug keyword. + + Token* spec; // debug = Integer ; + // debug = Identifier ; + Token* cond; // debug ( Integer ) + // debug ( Identifier ) + Declaration decls, elseDecls; + + void parseIdentOrInt(ref Token* tok) + { + nT(); + if (token.type == T.Int32 || + token.type == T.Identifier) + { + tok = token; + nT(); + } + else + expected(T.Identifier); // TODO: better error msg + } + + if (token.type == T.Assign) + { + parseIdentOrInt(spec); + require(T.Semicolon); + } + else + { + // Condition: + // Integer + // Identifier + // ( Condition ) + if (token.type == T.LParen) + { + parseIdentOrInt(cond); + require(T.RParen); + } + + // debug DeclarationsBlock + // debug ( Condition ) DeclarationsBlock + decls = parseDeclarationsBlock(); + + // else DeclarationsBlock + if (token.type == T.Else) + { + nT(); + //if (token.type == T.Colon) + // TODO: avoid "else:"? + elseDecls = parseDeclarationsBlock(); + } + } + + return new DebugDeclaration(spec, cond, decls, elseDecls); + } + + Declaration parseVersionDeclaration() + { + assert(token.type == T.Version); + + nT(); // Skip version keyword. + + Token* spec; // version = Integer ; + // version = Identifier ; + Token* cond; // version ( Integer ) + // version ( Identifier ) + Declaration decls, elseDecls; + + void parseIdentOrInt(ref Token* tok) + { + if (token.type == T.Int32 || + token.type == T.Identifier) + { + tok = token; + nT(); + } + else + expected(T.Identifier); // TODO: better error msg + } + + if (token.type == T.Assign) + { + nT(); + parseIdentOrInt(spec); + require(T.Semicolon); + } + else + { + // Condition: + // Integer + // Identifier + + // ( Condition ) + require(T.LParen); + parseIdentOrInt(cond); + require(T.RParen); + + // version ( Condition ) DeclarationsBlock + decls = parseDeclarationsBlock(); + + // else DeclarationsBlock + if (token.type == T.Else) + { + nT(); + //if (token.type == T.Colon) + // TODO: avoid "else:"? + elseDecls = parseDeclarationsBlock(); + } + } + + return new VersionDeclaration(spec, cond, decls, elseDecls); + } + + Declaration parseStaticIfDeclaration() + { + assert(token.type == T.Static); + + nT(); // Skip static keyword. + nT(); // Skip if keyword. + + Expression condition; + Declaration ifDecls, elseDecls; + + require(T.LParen); + condition = parseAssignExpression(); + require(T.RParen); + + if (token.type != T.Colon) + ifDecls = parseDeclarationsBlock(); + else + expected(T.LBrace); // TODO: better error msg + + if (token.type == T.Else) + { + nT(); + if (token.type != T.Colon) + elseDecls = parseDeclarationsBlock(); + else + expected(T.LBrace); // TODO: better error msg + } + + return new StaticIfDeclaration(condition, ifDecls, elseDecls); + } + + Declaration parseStaticAssertDeclaration() + { + assert(token.type == T.Static); + + nT(); // Skip static keyword. + nT(); // Skip assert keyword. + + Expression condition, message; + + require(T.LParen); + + condition = parseAssignExpression(); + + if (token.type == T.Comma) + { + nT(); + message = parseAssignExpression(); + } + + require(T.RParen); + require(T.Semicolon); + + return new StaticAssertDeclaration(condition, message); + } + + Declaration parseTemplateDeclaration() + { + assert(token.type == T.Template); + nT(); // Skip template keyword. + auto templateName = requireId(); + auto templateParams = parseTemplateParameterList(); + auto decls = parseDeclarationDefinitionsBlock(); + return new TemplateDeclaration(templateName, templateParams, decls); + } + + Declaration parseNewDeclaration() + { + assert(token.type == T.New); + nT(); // Skip new keyword. + auto parameters = parseParameterList(); + auto funcBody = parseFunctionBody(); + return new NewDeclaration(parameters, funcBody); + } + + Declaration parseDeleteDeclaration() + { + assert(token.type == T.Delete); + nT(); // Skip delete keyword. + auto parameters = parseParameterList(); + // TODO: only one parameter of type void* allowed. Check in parsing or semantic phase? + auto funcBody = parseFunctionBody(); + return new DeleteDeclaration(parameters, funcBody); + } + + /+ + DotListExpression: + . DotListItems + DotListItems + Typeof + Typeof . DotListItems + DotListItems: + DotListItem + DotListItem . DotListItems + DotListItem: + Identifier + TemplateInstance + NewExpression + TemplateInstance: + Identifier !( TemplateArguments ) + +/ + DotListExpression parseDotListExpression() + { + assert(token.type == T.Identifier || token.type == T.Dot || token.type == T.Typeof); + Expression[] identList; + if (token.type == T.Dot) + { + identList ~= new IdentifierExpression(token); + nT(); + } + else if (token.type == T.Typeof) + { + requireNext(T.LParen); + auto type = new TypeofType(parseExpression()); + require(T.RParen); + identList ~= new TypeofExpression(type); + if (token.type != T.Dot) + goto Lreturn; + nT(); + } + + while (1) + { + auto begin2 = token; + auto ident = requireId(); + Expression e; + if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) + { + nT(); // Skip !. + e = set(new TemplateInstanceExpression(ident, parseTemplateArguments()), begin2); + } + else // Identifier + e = set(new IdentifierExpression(ident), begin2); + + identList ~= e; + + LnewExpressionLoop: + if (token.type != T.Dot) + break; + nT(); // Skip dot. + + if (token.type == T.New) + { + identList ~= parseNewExpression(); + goto LnewExpressionLoop; + } + } + + Lreturn: + return new DotListExpression(identList); + } + + /+ + DotListType: + . TypeItems + TypeItems + Typeof + Typeof . TypeItems + TypeItems: + TypeItem + TypeItem . TypeItems + TypeItem: + Identifier + TemplateInstance + TemplateInstance: + Identifier !( TemplateArguments ) + +/ + DotListType parseDotListType() + { + Type[] identList; + if (token.type == T.Dot) + { + identList ~= new IdentifierType(token); + nT(); + } + else if (token.type == T.Typeof) + { + requireNext(T.LParen); + identList ~= new TypeofType(parseExpression()); + require(T.RParen); + if (token.type != T.Dot) + goto Lreturn; + nT(); + } + + while (1) + { + auto begin2 = token; + auto ident = requireId(); + // NB.: Currently Types can't be followed by "!=" so we don't need to peek for "(" when parsing TemplateInstances. + if (token.type == T.Not/+ && peekNext() == T.LParen+/) // Identifier !( TemplateArguments ) + { + nT(); // Skip !. + identList ~= set(new TemplateInstanceType(ident, parseTemplateArguments()), begin2); + } + else // Identifier + identList ~= set(new IdentifierType(ident), begin2); + + if (token.type != T.Dot) + break; + nT(); + } + Lreturn: + return new DotListType(identList); + } + + /* + TemplateMixin: + mixin ( AssignExpression ) ; + mixin TemplateIdentifier ; + mixin TemplateIdentifier MixinIdentifier ; + mixin TemplateIdentifier !( TemplateArguments ) ; + mixin TemplateIdentifier !( TemplateArguments ) MixinIdentifier ; + */ + Class parseMixin(Class)() + { + assert(token.type == T.Mixin); + auto begin = token; + nT(); // Skip mixin keyword. + + static if (is(Class == MixinDeclaration)) + { + if (token.type == T.LParen) + { + // TODO: What about mixin(...).ident;? + nT(); + auto e = parseAssignExpression(); + require(T.RParen); + require(T.Semicolon); + return new MixinDeclaration(e); + } + } + + Expression[] templateIdent; + Token* mixinIdent; + + // This code is similar to parseDotListType(). + if (token.type == T.Dot) + { + templateIdent ~= new IdentifierExpression(token); + nT(); + } + + while (1) + { + auto ident = requireId(); + Expression e; + if (token.type == T.Not) // Identifier !( TemplateArguments ) + { + // No need to peek for T.LParen. This must be a template instance. + nT(); + e = new TemplateInstanceExpression(ident, parseTemplateArguments()); + } + else // Identifier + e = new IdentifierExpression(ident); + + templateIdent ~= e; + + if (token.type != T.Dot) + break; + nT(); + } + + if (token.type == T.Identifier) + { + mixinIdent = token; + nT(); + } + + require(T.Semicolon); + + return new Class(templateIdent, mixinIdent); + } + + /+++++++++++++++++++++++++++++ + + Statement parsing methods + + +++++++++++++++++++++++++++++/ + + Statements parseStatements() + { + auto begin = token; + require(T.LBrace); + auto statements = new Statements(); + while (token.type != T.RBrace && token.type != T.EOF) + statements ~= parseStatement(); + require(T.RBrace); + return set(statements, begin); + } + + Statement parseStatement() + { +// writefln("°parseStatement:(%d)token='%s'°", lx.loc, token.srcText); + auto begin = token; + Statement s; + Declaration d; + switch (token.type) + { + case T.Align: + int size = -1; + auto intTok = parseAlignAttribute(); + if (intTok) + size = intTok.int_; + // Restrict align attribute to structs in parsing phase. + Declaration structDecl; + if (token.type == T.Struct) + structDecl = parseAggregateDeclaration(); + else + expected(T.Struct); + d = new AlignDeclaration(size, structDecl ? structDecl : new Declarations); + goto case_DeclarationStatement; +/+ Not applicable for statements. +// T.Private, +// T.Package, +// T.Protected, +// T.Public, +// T.Export, +// T.Deprecated, +// T.Override, +// T.Abstract, ++/ + case T.Extern, + T.Final, + T.Const, + T.Auto: + //T.Scope + //T.Static + case_parseAttribute: + s = parseAttributeStatement(); + return s; + case T.Identifier: + if (peekNext() == T.Colon) + { + auto ident = token; + nT(); // Skip Identifier + nT(); // Skip : + s = new LabeledStatement(ident, parseNoScopeOrEmptyStatement()); + break; + } + goto case T.Dot; + case T.Dot, T.Typeof: + bool success; + d = try_(parseDeclaration(), success); + if (success) + goto case_DeclarationStatement; // Declaration + else + goto default; // Expression + // BasicType + case T.Char, T.Wchar, T.Dchar, T.Bool, + T.Byte, T.Ubyte, T.Short, T.Ushort, + T.Int, T.Uint, T.Long, T.Ulong, + T.Float, T.Double, T.Real, + T.Ifloat, T.Idouble, T.Ireal, + T.Cfloat, T.Cdouble, T.Creal, T.Void: + case_parseDeclaration: + d = parseDeclaration(); + goto case_DeclarationStatement; + case T.If: + s = parseIfStatement(); + break; + case T.While: + s = parseWhileStatement(); + break; + case T.Do: + s = parseDoWhileStatement(); + break; + case T.For: + s = parseForStatement(); + break; + case T.Foreach, T.Foreach_reverse: + s = parseForeachStatement(); + break; + case T.Switch: + s = parseSwitchStatement(); + break; + case T.Case: + s = parseCaseStatement(); + break; + case T.Default: + s = parseDefaultStatement(); + break; + case T.Continue: + s = parseContinueStatement(); + break; + case T.Break: + s = parseBreakStatement(); + break; + case T.Return: + s = parseReturnStatement(); + break; + case T.Goto: + s = parseGotoStatement(); + break; + case T.With: + s = parseWithStatement(); + break; + case T.Synchronized: + s = parseSynchronizedStatement(); + break; + case T.Try: + s = parseTryStatement(); + break; + case T.Throw: + s = parseThrowStatement(); + break; + case T.Scope: + if (peekNext() != T.LParen) + goto case_parseAttribute; + s = parseScopeGuardStatement(); + break; + case T.Volatile: + s = parseVolatileStatement(); + break; + case T.Asm: + s = parseAsmStatement(); + break; + case T.Pragma: + s = parsePragmaStatement(); + break; + case T.Mixin: + if (peekNext() == T.LParen) + goto default; // Parse as expression. + s = parseMixin!(MixinStatement)(); + break; + case T.Static: + switch (peekNext()) + { + case T.If: + s = parseStaticIfStatement(); + break; + case T.Assert: + s = parseStaticAssertStatement(); + break; + default: + goto case_parseAttribute; + } + break; + case T.Debug: + s = parseDebugStatement(); + break; + case T.Version: + s = parseVersionStatement(); + break; + // DeclDef + case T.Alias, T.Typedef: + d = parseDeclarationDefinition(); + goto case_DeclarationStatement; + case T.Enum: + d = parseEnumDeclaration(); + goto case_DeclarationStatement; + case T.Class: + d = parseClassDeclaration(); + goto case_DeclarationStatement; + case T.Interface: + d = parseInterfaceDeclaration(); + goto case_DeclarationStatement; + case T.Struct, T.Union: + d = parseAggregateDeclaration(); + goto case_DeclarationStatement; + case_DeclarationStatement: + set(d, begin); + s = new DeclarationStatement(d); + break; + case T.LBrace: + s = parseScopeStatement(); + break; + case T.Semicolon: + nT(); + s = new EmptyStatement(); + break; + default: + bool success; + auto expression = try_(parseExpression(), success); +// writefln("parseExpression()=", failed?"failed":"success"); + if (success) + { + require(T.Semicolon); + s = new ExpressionStatement(expression); + } + else + { + error(MID.ExpectedButFound, "Statement", token.srcText); + s = new IllegalStatement(token); + nT(); + } + } + assert(s !is null); +// writef("§%s§", s.classinfo.name); + set(s, begin); + return s; + } + + /+ + ScopeStatement: + NoScopeStatement + +/ + Statement parseScopeStatement() + { + return new ScopeStatement(parseNoScopeStatement()); + } + + /+ + NoScopeStatement: + NonEmptyStatement + BlockStatement + BlockStatement: + { } + { StatementList } + +/ + Statement parseNoScopeStatement() + { + Statement s; + if (token.type == T.LBrace) + { + nT(); + auto ss = new Statements(); + while (token.type != T.RBrace && token.type != T.EOF) + ss ~= parseStatement(); + require(T.RBrace); + s = ss; + } + else if (token.type == T.Semicolon) + { + error(MID.ExpectedButFound, "non-empty statement", ";"); + s = new EmptyStatement(); + nT(); + } + else + s = parseStatement(); + return s; + } + + /+ + NoScopeOrEmptyStatement: + ; + NoScopeStatement + +/ + Statement parseNoScopeOrEmptyStatement() + { + if (token.type == T.Semicolon) + { + nT(); + return new EmptyStatement(); + } + else + return parseNoScopeStatement(); + } + + Statement parseAttributeStatement() + { + StorageClass stc, tmp; + + void addStorageClass() + { + if (stc & tmp) + { + error(MID.RedundantStorageClass, token.srcText); + } + else + stc |= tmp; + } + + Statement parse() + { + auto begin = token; + Statement s; + switch (token.type) + { + case T.Extern: + tmp = StorageClass.Extern; + addStorageClass(); + nT(); + Linkage linkage; + if (token.type == T.LParen) + { + nT(); + auto ident = requireId(); + switch (ident ? ident.identifier : null) + { + case "C": + if (token.type == T.PlusPlus) + { + nT(); + linkage = Linkage.Cpp; + break; + } + linkage = Linkage.C; + break; + case "D": + linkage = Linkage.D; + break; + case "Windows": + linkage = Linkage.Windows; + break; + case "Pascal": + linkage = Linkage.Pascal; + break; + case "System": + linkage = Linkage.System; + break; + default: + // TODO: issue error msg. Unrecognized LinkageType. + } + require(T.RParen); + } + s = new ExternStatement(linkage, parse()); + break; + case T.Static: + tmp = StorageClass.Static; + goto Lcommon; + case T.Final: + tmp = StorageClass.Final; + goto Lcommon; + case T.Const: + version(D2) + { + if (peekNext() == T.LParen) + goto case_Declaration; + } + tmp = StorageClass.Const; + goto Lcommon; + version(D2) + { + case T.Invariant: // D 2.0 + if (peekNext() == T.LParen) + goto case_Declaration; + tmp = StorageClass.Invariant; + goto Lcommon; + } + case T.Auto: + tmp = StorageClass.Auto; + goto Lcommon; + case T.Scope: + tmp = StorageClass.Scope; + goto Lcommon; + Lcommon: + addStorageClass(); + auto tok = token.type; + nT(); + s = new AttributeStatement(tok, parse()); + break; + // TODO: allow "scope class", "abstract scope class" in function bodies? + //case T.Class: + default: + case_Declaration: + s = new DeclarationStatement(parseDeclaration(stc)); + } + set(s, begin); + return s; + } + return parse(); + } + + Statement parseIfStatement() + { + assert(token.type == T.If); + nT(); + + Statement variable; + Expression condition; + Statement ifBody, elseBody; + + require(T.LParen); + + Token* ident; + // auto Identifier = Expression + if (token.type == T.Auto) + { + auto a = new AttributeStatement(token.type, null); + nT(); + ident = requireId(); + require(T.Assign); + auto init = parseExpression(); + a.statement = new DeclarationStatement(new VariableDeclaration(null, [ident], [init])); + variable = a; + } + else + { + // Declarator = Expression + Type parseDeclaratorAssign() + { + auto type = parseDeclarator(ident); + require(T.Assign); + return type; + } + bool success; + auto type = try_(parseDeclaratorAssign(), success); + if (success) + { + auto init = parseExpression(); + variable = new DeclarationStatement(new VariableDeclaration(type, [ident], [init])); + } + else + condition = parseExpression(); + } + require(T.RParen); + ifBody = parseScopeStatement(); + if (token.type == T.Else) + { + nT(); + elseBody = parseScopeStatement(); + } + return new IfStatement(variable, condition, ifBody, elseBody); + } + + Statement parseWhileStatement() + { + assert(token.type == T.While); + nT(); + require(T.LParen); + auto condition = parseExpression(); + require(T.RParen); + return new WhileStatement(condition, parseScopeStatement()); + } + + Statement parseDoWhileStatement() + { + assert(token.type == T.Do); + nT(); + auto doBody = parseScopeStatement(); + require(T.While); + require(T.LParen); + auto condition = parseExpression(); + require(T.RParen); + return new DoWhileStatement(condition, doBody); + } + + Statement parseForStatement() + { + assert(token.type == T.For); + nT(); + require(T.LParen); + + Statement init, forBody; + Expression condition, increment; + + if (token.type != T.Semicolon) + init = parseNoScopeStatement(); + else + nT(); // Skip ; + if (token.type != T.Semicolon) + condition = parseExpression(); + require(T.Semicolon); + if (token.type != T.RParen) + increment = parseExpression(); + require(T.RParen); + forBody = parseScopeStatement(); + return new ForStatement(init, condition, increment, forBody); + } + + Statement parseForeachStatement() + { + assert(token.type == T.Foreach || token.type == T.Foreach_reverse); + TOK tok = token.type; + nT(); + + auto params = new Parameters; + Expression e; // Aggregate or LwrExpression + + require(T.LParen); + while (1) + { + auto paramBegin = token; + Token* stcTok; + Type type; + Token* ident; + + switch (token.type) + { + case T.Ref, T.Inout: + stcTok = token; + nT(); + // fall through + case T.Identifier: + auto next = peekNext(); + if (next == T.Comma || next == T.Semicolon || next == T.RParen) + { + ident = token; + nT(); + break; + } + // fall through + default: + type = parseDeclarator(ident); + } + + params ~= set(new Parameter(stcTok, type, ident, null), paramBegin); + + if (token.type != T.Comma) + break; + nT(); + } + require(T.Semicolon); + e = parseExpression(); + version(D2) + { //Foreach (ForeachType; LwrExpression .. UprExpression ) ScopeStatement + if (token.type == T.Slice) + { + // if (params.length != 1) + // error(MID.XYZ); // TODO: issue error msg + nT(); + auto upper = parseExpression(); + require(T.RParen); + auto forBody = parseScopeStatement(); + return new ForeachRangeStatement(tok, params, e, upper, forBody); + } + } + // Foreach (ForeachTypeList; Aggregate) ScopeStatement + require(T.RParen); + auto forBody = parseScopeStatement(); + return new ForeachStatement(tok, params, e, forBody); + } + + Statement parseSwitchStatement() + { + assert(token.type == T.Switch); + nT(); + + require(T.LParen); + auto condition = parseExpression(); + require(T.RParen); + auto switchBody = parseScopeStatement(); + return new SwitchStatement(condition, switchBody); + } + + Statement parseCaseDefaultBody() + { + // This function is similar to parseNoScopeStatement() + auto s = new Statements(); + while (token.type != T.Case && + token.type != T.Default && + token.type != T.RBrace && + token.type != T.EOF) + s ~= parseStatement(); + return new ScopeStatement(s); + } + + Statement parseCaseStatement() + { + assert(token.type == T.Case); + // T.Case skipped in do-while. + Expression[] values; + do + { + nT(); + values ~= parseAssignExpression(); + } while (token.type == T.Comma) + require(T.Colon); + + auto caseBody = parseCaseDefaultBody(); + return new CaseStatement(values, caseBody); + } + + Statement parseDefaultStatement() + { + assert(token.type == T.Default); + nT(); + require(T.Colon); + return new DefaultStatement(parseCaseDefaultBody()); + } + + Statement parseContinueStatement() + { + assert(token.type == T.Continue); + nT(); + Token* ident; + if (token.type == T.Identifier) + { + ident = token; + nT(); + } + require(T.Semicolon); + return new ContinueStatement(ident); + } + + Statement parseBreakStatement() + { + assert(token.type == T.Break); + nT(); + Token* ident; + if (token.type == T.Identifier) + { + ident = token; + nT(); + } + require(T.Semicolon); + return new BreakStatement(ident); + } + + Statement parseReturnStatement() + { + assert(token.type == T.Return); + nT(); + Expression expr; + if (token.type != T.Semicolon) + expr = parseExpression(); + require(T.Semicolon); + return new ReturnStatement(expr); + } + + Statement parseGotoStatement() + { + assert(token.type == T.Goto); + nT(); + Token* ident; + Expression caseExpr; + switch (token.type) + { + case T.Case: + nT(); + if (token.type == T.Semicolon) + break; + caseExpr = parseExpression(); + break; + case T.Default: + nT(); + break; + default: + ident = requireId(); + } + require(T.Semicolon); + return new GotoStatement(ident, caseExpr); + } + + Statement parseWithStatement() + { + assert(token.type == T.With); + nT(); + require(T.LParen); + auto expr = parseExpression(); + require(T.RParen); + return new WithStatement(expr, parseScopeStatement()); + } + + Statement parseSynchronizedStatement() + { + assert(token.type == T.Synchronized); + nT(); + Expression expr; + + if (token.type == T.LParen) + { + nT(); + expr = parseExpression(); + require(T.RParen); + } + return new SynchronizedStatement(expr, parseScopeStatement()); + } + + Statement parseTryStatement() + { + assert(token.type == T.Try); + nT(); + + auto tryBody = parseScopeStatement(); + CatchBody[] catchBodies; + FinallyBody finBody; + + while (token.type == T.Catch) + { + nT(); + Parameter param; + if (token.type == T.LParen) + { + nT(); + Token* ident; + auto type = parseDeclarator(ident); + param = new Parameter(null, type, ident, null); + require(T.RParen); + } + catchBodies ~= new CatchBody(param, parseNoScopeStatement()); + if (param is null) + break; // This is a LastCatch + } + + if (token.type == T.Finally) + { + nT(); + finBody = new FinallyBody(parseNoScopeStatement()); + } + + if (catchBodies.length == 0 || finBody is null) + { + // TODO: issue error msg. + } + + return new TryStatement(tryBody, catchBodies, finBody); + } + + Statement parseThrowStatement() + { + assert(token.type == T.Throw); + nT(); + auto expr = parseExpression(); + require(T.Semicolon); + return new ThrowStatement(expr); + } + + Statement parseScopeGuardStatement() + { + assert(token.type == T.Scope); + nT(); + assert(token.type == T.LParen); + nT(); + + Token* condition = requireId(); + if (condition) + switch (condition.identifier) + { + case "exit": + case "success": + case "failure": + break; + default: + // TODO: issue error msg. + } + require(T.RParen); + Statement scopeBody; + if (token.type == T.LBrace) + scopeBody = parseScopeStatement(); + else + scopeBody = parseNoScopeStatement(); + return new ScopeGuardStatement(condition, scopeBody); + } + + Statement parseVolatileStatement() + { + assert(token.type == T.Volatile); + nT(); + Statement volatileBody; + if (token.type == T.Semicolon) + nT(); + else if (token.type == T.LBrace) + volatileBody = parseScopeStatement(); + else + volatileBody = parseStatement(); + return new VolatileStatement(volatileBody); + } + + Statement parsePragmaStatement() + { + assert(token.type == T.Pragma); + nT(); + + Token* ident; + Expression[] args; + Statement pragmaBody; + + require(T.LParen); + ident = requireId(); + + if (token.type == T.Comma) + { + // Parse at least one argument. + nT(); + args ~= parseAssignExpression(); + } + + if (token.type == T.Comma) + args ~= parseArguments(T.RParen); + else + require(T.RParen); + + pragmaBody = parseNoScopeOrEmptyStatement(); + + return new PragmaStatement(ident, args, pragmaBody); + } + + Statement parseStaticIfStatement() + { + assert(token.type == T.Static); + nT(); + assert(token.type == T.If); + nT(); + Expression condition; + Statement ifBody, elseBody; + + require(T.LParen); + condition = parseExpression(); + require(T.RParen); + ifBody = parseNoScopeStatement(); + if (token.type == T.Else) + { + nT(); + elseBody = parseNoScopeStatement(); + } + return new StaticIfStatement(condition, ifBody, elseBody); + } + + Statement parseStaticAssertStatement() + { + assert(token.type == T.Static); + nT(); + assert(token.type == T.Assert); + nT(); + Expression condition, message; + require(T.LParen); + condition = parseAssignExpression(); + if (token.type == T.Comma) + { + nT(); + message = parseAssignExpression(); + } + require(T.RParen); + require(T.Semicolon); + return new StaticAssertStatement(condition, message); + } + + Statement parseDebugStatement() + { + assert(token.type == T.Debug); + nT(); // Skip debug keyword. + + Token* cond; // debug ( Integer ) + // debug ( Identifier ) + Statement debugBody, elseBody; + + void parseIdentOrInt(ref Token* tok) + { + nT(); + if (token.type == T.Int32 || + token.type == T.Identifier) + { + tok = token; + nT(); + } + else + expected(T.Identifier); // TODO: better error msg + } + +// if (token.type == T.Assign) +// { +// parseIdentOrInt(identSpec, levelSpec); +// require(T.Semicolon); +// } +// else + { + // Condition: + // Integer + // Identifier + + // ( Condition ) + if (token.type == T.LParen) + { + parseIdentOrInt(cond); + require(T.RParen); + } + + // debug Statement + // debug ( Condition ) Statement + debugBody = parseNoScopeStatement(); + + // else Statement + if (token.type == T.Else) + { + // debug without condition and else body makes no sense + //if (levelCond == -1 && identCond.length == 0) + // TODO: issue error msg + nT(); + elseBody = parseNoScopeStatement(); + } + } + + return new DebugStatement(cond, debugBody, elseBody); + } + + Statement parseVersionStatement() + { + assert(token.type == T.Version); + + nT(); // Skip version keyword. + + Token* cond; // version ( Integer ) + // version ( Identifier ) + Statement versionBody, elseBody; + + void parseIdentOrInt(ref Token* tok) + { + if (token.type == T.Int32 || + token.type == T.Identifier) + { + tok = token; + nT(); + } + else + expected(T.Identifier); // TODO: better error msg + } + +// if (token.type == T.Assign) +// { +// parseIdentOrInt(identSpec, levelSpec); +// require(T.Semicolon); +// } +// else + { + // Condition: + // Integer + // Identifier + + // ( Condition ) + require(T.LParen); + parseIdentOrInt(cond); + require(T.RParen); + + // version ( Condition ) Statement + versionBody = parseNoScopeStatement(); + + // else Statement + if (token.type == T.Else) + { + nT(); + elseBody = parseNoScopeStatement(); + } + } + + return new VersionStatement(cond, versionBody, elseBody); + } + + /+++++++++++++++++++++++++++++ + + Assembler parsing methods + + +++++++++++++++++++++++++++++/ + + Statement parseAsmStatement() + { + assert(token.type == T.Asm); + nT(); // Skip asm keyword. + require(T.LBrace); + auto ss = new Statements; + while (token.type != T.RBrace && token.type != T.EOF) + ss ~= parseAsmInstruction(); + require(T.RBrace); + return new AsmStatement(ss); + } + + Statement parseAsmInstruction() + { + auto begin = token; + Statement s; + switch (token.type) + { + case T.Identifier: + auto ident = token; + auto next = peekNext(); + if (next == T.Colon) + { + // Identifier : AsmInstruction + nT(); // Skip Identifier + nT(); // Skip : + s = new LabeledStatement(ident, parseAsmInstruction()); + break; + } + + // Opcode ; + // Opcode Operands ; + // Opcode + // Identifier + Expression[] es; + if (next != T.Semicolon) + { + while (1) + { + es ~= parseAsmExpression(); + if (token.type != T.Comma) + break; + nT(); + } + } + require(T.Semicolon); + s = new AsmInstruction(ident, es); + break; + case T.Semicolon: + s = new EmptyStatement(); + nT(); + break; + default: + error(MID.ExpectedButFound, "AsmStatement", token.srcText); + s = new IllegalAsmInstruction(token); + nT(); + } + set(s, begin); + return s; + } + + Expression parseAsmExpression() + { + auto begin = token; + auto e = parseOrOrExpression(); + if (token.type == T.Question) + { + auto tok = token; + nT(); + auto iftrue = parseAsmExpression(); + require(T.Colon); + auto iffalse = parseAsmExpression(); + e = new CondExpression(e, iftrue, iffalse, tok); + set(e, begin); + } + // TODO: create AsmExpression that contains e? + return e; + } + + Expression parseAsmOrOrExpression() + { + auto begin = token; + alias parseAsmAndAndExpression parseNext; + auto e = parseNext(); + while (token.type == T.OrLogical) + { + auto tok = token; + nT(); + e = new OrOrExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAsmAndAndExpression() + { + auto begin = token; + alias parseAsmOrExpression parseNext; + auto e = parseNext(); + while (token.type == T.AndLogical) + { + auto tok = token; + nT(); + e = new AndAndExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAsmOrExpression() + { + auto begin = token; + alias parseAsmXorExpression parseNext; + auto e = parseNext(); + while (token.type == T.OrBinary) + { + auto tok = token; + nT(); + e = new OrExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAsmXorExpression() + { + alias parseAsmAndExpression parseNext; + auto begin = token; + auto e = parseNext(); + while (token.type == T.Xor) + { + auto tok = token; + nT(); + e = new XorExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAsmAndExpression() + { + alias parseAsmCmpExpression parseNext; + auto begin = token; + auto e = parseNext(); + while (token.type == T.AndBinary) + { + auto tok = token; + nT(); + e = new AndExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAsmCmpExpression() + { + alias parseAsmShiftExpression parseNext; + auto begin = token; + auto e = parseNext(); + + auto operator = token; + switch (operator.type) + { + case T.Equal, T.NotEqual: + nT(); + e = new EqualExpression(e, parseNext(), operator); + break; + case T.LessEqual, T.Less, T.GreaterEqual, T.Greater: + nT(); + e = new RelExpression(e, parseNext(), operator); + break; + default: + return e; + } + set(e, begin); + return e; + } + + Expression parseAsmShiftExpression() + { + alias parseAsmAddExpression parseNext; + auto begin = token; + auto e = parseNext(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.LShift: nT(); e = new LShiftExpression(e, parseNext(), operator); break; + case T.RShift: nT(); e = new RShiftExpression(e, parseNext(), operator); break; + case T.URShift: nT(); e = new URShiftExpression(e, parseNext(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseAsmAddExpression() + { + alias parseAsmMulExpression parseNext; + auto begin = token; + auto e = parseNext(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.Plus: nT(); e = new PlusExpression(e, parseNext(), operator); break; + case T.Minus: nT(); e = new MinusExpression(e, parseNext(), operator); break; + // Not allowed in asm + //case T.Tilde: nT(); e = new CatExpression(e, parseNext(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseAsmMulExpression() + { + alias parseAsmPostExpression parseNext; + auto begin = token; + auto e = parseNext(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.Mul: nT(); e = new MulExpression(e, parseNext(), operator); break; + case T.Div: nT(); e = new DivExpression(e, parseNext(), operator); break; + case T.Mod: nT(); e = new ModExpression(e, parseNext(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseAsmPostExpression() + { + auto begin = token; + auto e = parseAsmUnaryExpression(); + while (token.type == T.RBracket) + { + nT(); + e = parseAsmExpression(); + e = new AsmPostBracketExpression(e); + require(T.RBracket); + set(e, begin); + } + return e; + } + + Expression parseAsmUnaryExpression() + { + auto begin = token; + Expression e; + switch (token.type) + { + case T.Identifier: + switch (token.identifier) + { + case "near", "far", "byte", "short", "int", + "word", "dword", "float", "double", "real": + nT(); + if (token.type == T.Identifier && token.identifier == "ptr") + nT(); + else + error(MID.ExpectedButFound, "ptr", token.srcText); + e = new AsmTypeExpression(parseAsmUnaryExpression()); + break; + case "offset": + nT(); + e = new AsmOffsetExpression(parseAsmUnaryExpression()); + break; + case "seg": + nT(); + e = new AsmSegExpression(parseAsmUnaryExpression()); + break; + default: + } + goto default; + case T.Minus: + case T.Plus: + nT(); + e = new SignExpression(parseAsmUnaryExpression()); + break; + case T.Not: + nT(); + e = new NotExpression(parseAsmUnaryExpression()); + break; + case T.Tilde: + nT(); + e = new CompExpression(parseAsmUnaryExpression()); + default: + e = parseAsmPrimaryExpression(); + return e; + } + set(e, begin); + return e; + } + + Expression parseAsmPrimaryExpression() + { + auto begin = token; + Expression e; + switch (token.type) + { + case T.Int32, T.Int64, T.Uint32, T.Uint64: + e = new IntNumberExpression(token.type, token.ulong_); + nT(); + break; + case T.Float32, T.Float64, T.Float80, + T.Imaginary32, T.Imaginary64, T.Imaginary80: + e = new RealNumberExpression(token.type, token.real_); + nT(); + break; + case T.Dollar: + e = new DollarExpression(); + nT(); + break; + case T.LBracket: + // [ AsmExpression ] + nT(); + e = parseAsmExpression(); + require(T.RBracket); + e = new AsmBracketExpression(e); + break; + case T.Identifier: + switch (token.identifier) + { + // __LOCAL_SIZE + case "__LOCAL_SIZE": + e = new AsmLocalSizeExpression(); + nT(); + break; + // Register + case "ST": + auto register = token; + nT(); + // (1) - (7) + Token* number; + if (token.type == T.LParen) + { + nT(); + if (token.type == T.Int32) + { + number = token; + nT(); + } + else + expected(T.Int32); + require(T.RParen); + } + e = new AsmRegisterExpression(register, number); + break; + case "AL", "AH", "AX", "EAX", + "BL", "BH", "BX", "EBX", + "CL", "CH", "CX", "ECX", + "DL", "DH", "DX", "EDX", + "BP", "EBP", + "SP", "ESP", + "DI", "EDI", + "SI", "ESI", + "ES", "CS", "SS", "DS", "GS", "FS", + "CR0", "CR2", "CR3", "CR4", + "DR0", "DR1", "DR2", "DR3", "DR6", "DR7", + "TR3", "TR4", "TR5", "TR6", "TR7", + "MM0", "MM1", "MM2", "MM3", "MM4", "MM5", "MM6", "MM7", + "XMM0", "XMM1", "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7": + e = new AsmRegisterExpression(token); + nT(); + break; + default: + // DotIdentifier + auto begin2 = token; + Expression[] identList; + goto LenterLoop; + while (token.type == T.Dot) + { + nT(); + begin2 = token; + auto ident = requireId(); + LenterLoop: + e = new IdentifierExpression(token); + nT(); + set(e, begin2); + identList ~= e; + } + e = new DotListExpression(identList); + } + break; + default: + error(MID.ExpectedButFound, "Expression", token.srcText); + e = new EmptyExpression(); + break; + } + set(e, begin); + return e; + } + + /+++++++++++++++++++++++++++++ + + Expression parsing methods + + +++++++++++++++++++++++++++++/ + + Expression parseExpression() + { + auto begin = token; + auto e = parseAssignExpression(); + while (token.type == T.Comma) + { + auto comma = token; + nT(); + e = new CommaExpression(e, parseAssignExpression(), comma); + set(e, begin); + } +// if (!trying) +// writef("§%s§", e.classinfo.name); + return e; + } + + Expression parseAssignExpression() + { + auto begin = token; + auto e = parseCondExpression(); + while (1) + { + switch (token.type) + { + case T.Assign: + nT(); e = new AssignExpression(e, parseAssignExpression()); + break; + case T.LShiftAssign: + nT(); e = new LShiftAssignExpression(e, parseAssignExpression()); + break; + case T.RShiftAssign: + nT(); e = new RShiftAssignExpression(e, parseAssignExpression()); + break; + case T.URShiftAssign: + nT(); e = new URShiftAssignExpression(e, parseAssignExpression()); + break; + case T.OrAssign: + nT(); e = new OrAssignExpression(e, parseAssignExpression()); + break; + case T.AndAssign: + nT(); e = new AndAssignExpression(e, parseAssignExpression()); + break; + case T.PlusAssign: + nT(); e = new PlusAssignExpression(e, parseAssignExpression()); + break; + case T.MinusAssign: + nT(); e = new MinusAssignExpression(e, parseAssignExpression()); + break; + case T.DivAssign: + nT(); e = new DivAssignExpression(e, parseAssignExpression()); + break; + case T.MulAssign: + nT(); e = new MulAssignExpression(e, parseAssignExpression()); + break; + case T.ModAssign: + nT(); e = new ModAssignExpression(e, parseAssignExpression()); + break; + case T.XorAssign: + nT(); e = new XorAssignExpression(e, parseAssignExpression()); + break; + case T.CatAssign: + nT(); e = new CatAssignExpression(e, parseAssignExpression()); + break; + default: + return e; + } + set(e, begin); + } + return e; + } + + Expression parseCondExpression() + { + auto begin = token; + auto e = parseOrOrExpression(); + if (token.type == T.Question) + { + auto tok = token; + nT(); + auto iftrue = parseExpression(); + require(T.Colon); + auto iffalse = parseCondExpression(); + e = new CondExpression(e, iftrue, iffalse, tok); + set(e, begin); + } + return e; + } + + Expression parseOrOrExpression() + { + auto begin = token; + alias parseAndAndExpression parseNext; + auto e = parseNext(); + while (token.type == T.OrLogical) + { + auto tok = token; + nT(); + e = new OrOrExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAndAndExpression() + { + auto begin = token; + alias parseOrExpression parseNext; + auto e = parseNext(); + while (token.type == T.AndLogical) + { + auto tok = token; + nT(); + e = new AndAndExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseOrExpression() + { + auto begin = token; + alias parseXorExpression parseNext; + auto e = parseNext(); + while (token.type == T.OrBinary) + { + auto tok = token; + nT(); + e = new OrExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseXorExpression() + { + auto begin = token; + alias parseAndExpression parseNext; + auto e = parseNext(); + while (token.type == T.Xor) + { + auto tok = token; + nT(); + e = new XorExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseAndExpression() + { + auto begin = token; + alias parseCmpExpression parseNext; + auto e = parseNext(); + while (token.type == T.AndBinary) + { + auto tok = token; + nT(); + e = new AndExpression(e, parseNext(), tok); + set(e, begin); + } + return e; + } + + Expression parseCmpExpression() + { + auto begin = token; + auto e = parseShiftExpression(); + + auto operator = token; + switch (operator.type) + { + case T.Equal, T.NotEqual: + nT(); + e = new EqualExpression(e, parseShiftExpression(), operator); + break; + case T.Not: + if (peekNext() != T.Is) + break; + nT(); + // fall through + case T.Is: + nT(); + e = new IdentityExpression(e, parseShiftExpression(), operator); + break; + case T.LessEqual, T.Less, T.GreaterEqual, T.Greater, + T.Unordered, T.UorE, T.UorG, T.UorGorE, + T.UorL, T.UorLorE, T.LorEorG, T.LorG: + nT(); + e = new RelExpression(e, parseShiftExpression(), operator); + break; + case T.In: + nT(); + e = new InExpression(e, parseShiftExpression(), operator); + break; + default: + return e; + } + set(e, begin); + return e; + } + + Expression parseShiftExpression() + { + auto begin = token; + auto e = parseAddExpression(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.LShift: nT(); e = new LShiftExpression(e, parseAddExpression(), operator); break; + case T.RShift: nT(); e = new RShiftExpression(e, parseAddExpression(), operator); break; + case T.URShift: nT(); e = new URShiftExpression(e, parseAddExpression(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseAddExpression() + { + auto begin = token; + auto e = parseMulExpression(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.Plus: nT(); e = new PlusExpression(e, parseMulExpression(), operator); break; + case T.Minus: nT(); e = new MinusExpression(e, parseMulExpression(), operator); break; + case T.Tilde: nT(); e = new CatExpression(e, parseMulExpression(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseMulExpression() + { + auto begin = token; + auto e = parseUnaryExpression(); + while (1) + { + auto operator = token; + switch (operator.type) + { + case T.Mul: nT(); e = new MulExpression(e, parseUnaryExpression(), operator); break; + case T.Div: nT(); e = new DivExpression(e, parseUnaryExpression(), operator); break; + case T.Mod: nT(); e = new ModExpression(e, parseUnaryExpression(), operator); break; + default: + return e; + } + set(e, begin); + } + assert(0); + } + + Expression parseUnaryExpression() + { + auto begin = token; + Expression e; + switch (token.type) + { + case T.AndBinary: + nT(); + e = new AddressExpression(parseUnaryExpression()); + break; + case T.PlusPlus: + nT(); + e = new PreIncrExpression(parseUnaryExpression()); + break; + case T.MinusMinus: + nT(); + e = new PreDecrExpression(parseUnaryExpression()); + break; + case T.Mul: + nT(); + e = new DerefExpression(parseUnaryExpression()); + break; + case T.Minus: + case T.Plus: + nT(); + e = new SignExpression(parseUnaryExpression()); + break; + case T.Not: + nT(); + e = new NotExpression(parseUnaryExpression()); + break; + case T.Tilde: + nT(); + e = new CompExpression(parseUnaryExpression()); + break; + case T.New: + e = parseNewExpression(); + return e; + case T.Delete: + nT(); + e = new DeleteExpression(parseUnaryExpression()); + break; + case T.Cast: + requireNext(T.LParen); + Type type; + switch (token.type) + { + version(D2) + { + auto begin2 = token; + case T.Const: + type = new ConstType(null); + goto case_break; + case T.Invariant: + type = new InvariantType(null); + case_break: + nT(); + set(type, begin2); + break; + } + default: + type = parseType(); + } + require(T.RParen); + e = new CastExpression(parseUnaryExpression(), type); + break; + case T.LParen: + // ( Type ) . Identifier + Type parseType_() + { + nT(); + auto type = parseType(); + require(T.RParen); + require(T.Dot); + return type; + } + bool success; + auto type = try_(parseType_(), success); + if (success) + { + auto ident = requireId(); + e = new TypeDotIdExpression(type, ident); + break; + } + goto default; + default: + e = parsePostExpression(parsePrimaryExpression()); + return e; + } + assert(e !is null); + set(e, begin); + return e; + } + + Expression parsePostExpression(Expression e) + { + typeof(token) begin; + while (1) + { + begin = token; + switch (token.type) + { +/* +// Commented out because parseDotListExpression() handles this. + case T.Dot: + nT(); + if (token.type == T.Identifier) + { + string ident = token.identifier; + nT(); + if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) + { + nT(); // Skip !. + e = new DotTemplateInstanceExpression(e, ident, parseTemplateArguments()); + } + else + { + e = new DotIdExpression(e, ident); + nT(); + } + } + else if (token.type == T.New) + e = parseNewExpression(e); + else + expected(T.Identifier); + continue; +*/ + case T.Dot: + e = new PostDotListExpression(e, parseDotListExpression()); + goto Lset; + case T.PlusPlus: + e = new PostIncrExpression(e); + break; + case T.MinusMinus: + e = new PostDecrExpression(e); + break; + case T.LParen: + e = new CallExpression(e, parseArguments(T.RParen)); + goto Lset; + case T.LBracket: + // parse Slice- and IndexExpression + nT(); + if (token.type == T.RBracket) + { + e = new SliceExpression(e, null, null); + break; + } + + Expression[] es = [parseAssignExpression()]; + + if (token.type == T.Slice) + { + nT(); + e = new SliceExpression(e, es[0], parseAssignExpression()); + require(T.RBracket); + goto Lset; + } + else if (token.type == T.Comma) + { + es ~= parseArguments(T.RBracket); + } + else + require(T.RBracket); + + e = new IndexExpression(e, es); + goto Lset; + default: + return e; + } + nT(); + Lset: + set(e, begin); + } + assert(0); + } + + Expression parsePrimaryExpression() + { + auto begin = token; + Expression e; + switch (token.type) + { +/* +// Commented out because parseDotListExpression() handles this. + case T.Identifier: + string ident = token.identifier; + nT(); + if (token.type == T.Not && peekNext() == T.LParen) // Identifier !( TemplateArguments ) + { + nT(); // Skip !. + e = new TemplateInstanceExpression(ident, parseTemplateArguments()); + } + else + e = new IdentifierExpression(ident); + break; + case T.Dot: + nT(); + e = new IdentifierExpression("."); + break; +*/ + case T.Identifier, T.Dot, T.Typeof: + e = parseDotListExpression(); + break; + case T.This: + nT(); + e = new ThisExpression(); + break; + case T.Super: + nT(); + e = new SuperExpression(); + break; + case T.Null: + nT(); + e = new NullExpression(); + break; + case T.True, T.False: + nT(); + e = new BoolExpression(); + break; + case T.Dollar: + nT(); + e = new DollarExpression(); + break; + case T.Int32, T.Int64, T.Uint32, T.Uint64: + e = new IntNumberExpression(token.type, token.ulong_); + nT(); + break; + case T.Float32, T.Float64, T.Float80, + T.Imaginary32, T.Imaginary64, T.Imaginary80: + e = new RealNumberExpression(token.type, token.real_); + nT(); + break; + case T.CharLiteral, T.WCharLiteral, T.DCharLiteral: + nT(); + e = new CharLiteralExpression(); + break; + case T.String: + Token*[] stringLiterals; + do + { + stringLiterals ~= token; + nT(); + } while (token.type == T.String) + e = new StringLiteralsExpression(stringLiterals); + break; + case T.LBracket: + Expression[] values; + + nT(); + if (token.type != T.RBracket) + { + e = parseAssignExpression(); + if (token.type == T.Colon) + goto LparseAssocArray; + else if (token.type == T.Comma) + values = [e] ~ parseArguments(T.RBracket); + else + require(T.RBracket); + } + else + nT(); + + e = new ArrayLiteralExpression(values); + break; + + LparseAssocArray: + Expression[] keys; + + keys ~= e; + nT(); // Skip colon. + goto LenterLoop; + + while (1) + { + keys ~= parseAssignExpression(); + require(T.Colon); + LenterLoop: + values ~= parseAssignExpression(); + if (token.type != T.Comma) + break; + nT(); + } + require(T.RBracket); + e = new AssocArrayLiteralExpression(keys, values); + break; + case T.LBrace: + // DelegateLiteral := { Statements } + auto funcBody = parseFunctionBody(); + e = new FunctionLiteralExpression(funcBody); + break; + case T.Function, T.Delegate: + // FunctionLiteral := (function|delegate) Type? '(' ArgumentList ')' '{' Statements '}' + nT(); // Skip function|delegate token. + Type returnType; + Parameters parameters; + if (token.type != T.LBrace) + { + if (token.type != T.LParen) // Optional return type + returnType = parseType(); + parameters = parseParameterList(); + } + auto funcBody = parseFunctionBody(); + e = new FunctionLiteralExpression(returnType, parameters, funcBody); + break; + case T.Assert: + Expression msg; + requireNext(T.LParen); + e = parseAssignExpression(); + if (token.type == T.Comma) + { + nT(); + msg = parseAssignExpression(); + } + require(T.RParen); + e = new AssertExpression(e, msg); + break; + case T.Mixin: + requireNext(T.LParen); + e = parseAssignExpression(); + require(T.RParen); + e = new MixinExpression(e); + break; + case T.Import: + requireNext(T.LParen); + e = parseAssignExpression(); + require(T.RParen); + e = new ImportExpression(e); + break; + case T.Typeid: + requireNext(T.LParen); + auto type = parseType(); + require(T.RParen); + e = new TypeidExpression(type); + break; +/* +// Commented out because parseDotListExpression() handles this. + case T.Typeof: + requireNext(T.LParen); + auto type = new TypeofType(parseExpression()); + require(T.RParen); + if (token.type == T.Dot) + { // typeof ( Expression ) . Identifier + nT(); + string ident = requireIdentifier; + e = new TypeDotIdExpression(type, ident); + } + else // typeof ( Expression ) + e = new TypeofExpression(type); + break; +*/ + case T.Is: + requireNext(T.LParen); + + Type type, specType; + Token* ident; // optional Identifier + Token* opTok, specTok; + + type = parseDeclarator(ident, true); + + switch (token.type) + { + case T.Colon, T.Equal: + opTok = token; + nT(); + switch (token.type) + { + case T.Typedef, + T.Struct, + T.Union, + T.Class, + T.Interface, + T.Enum, + T.Function, + T.Delegate, + T.Super, + T.Return: + specTok = token; + nT(); + break; + default: + specType = parseType(); + } + default: + } + require(T.RParen); + e = new IsExpression(type, ident, opTok, specTok, specType); + break; + case T.LParen: + if (tokenAfterParenIs(T.LBrace)) + { + auto parameters = parseParameterList(); + // ( ParameterList ) FunctionBody + auto funcBody = parseFunctionBody(); + e = new FunctionLiteralExpression(null, parameters, funcBody); + } + else + { + // ( Expression ) + nT(); + e = parseExpression(); + require(T.RParen); + // TODO: create ParenExpression? + } + break; + // BasicType . Identifier + case T.Char, T.Wchar, T.Dchar, T.Bool, + T.Byte, T.Ubyte, T.Short, T.Ushort, + T.Int, T.Uint, T.Long, T.Ulong, + T.Float, T.Double, T.Real, + T.Ifloat, T.Idouble, T.Ireal, + T.Cfloat, T.Cdouble, T.Creal, T.Void: + auto type = new IntegralType(token.type); + nT(); + set(type, begin); + require(T.Dot); + auto ident = requireId(); + + e = new TypeDotIdExpression(type, ident); + break; + version(D2) + { + case T.Traits: + nT(); + require(T.LParen); + auto id = requireId(); + TemplateArguments args; + if (token.type == T.Comma) + { + args = parseTemplateArguments2(); + } + else + require(T.RParen); + e = new TraitsExpression(id, args); + break; + } + case T.Special: + e = new SpecialTokenExpression(token); + nT(); + break; + default: + // TODO: issue error msg. + error(MID.ExpectedButFound, "Expression", token.srcText); + e = new EmptyExpression(); + } + set(e, begin); + return e; + } + + Expression parseNewExpression(/*Expression e*/) + { + auto begin = token; + assert(token.type == T.New); + nT(); // Skip new keyword. + + Expression[] newArguments; + Expression[] ctorArguments; + + if (token.type == T.LParen) + newArguments = parseArguments(T.RParen); + + // NewAnonClassExpression: + // new (ArgumentList)opt class (ArgumentList)opt SuperClassopt InterfaceClassesopt ClassBody + if (token.type == T.Class) + { + nT(); + if (token.type == T.LParen) + ctorArguments = parseArguments(T.RParen); + + BaseClass[] bases = token.type != T.LBrace ? parseBaseClasses(false) : null ; + + auto decls = parseDeclarationDefinitionsBlock(); + return set(new NewAnonClassExpression(/*e, */newArguments, bases, ctorArguments, decls), begin); + } + + // NewExpression: + // NewArguments Type [ AssignExpression ] + // NewArguments Type ( ArgumentList ) + // NewArguments Type + auto type = parseType(); + + if (token.type == T.LParen) + ctorArguments = parseArguments(T.RParen); + + return set(new NewExpression(/*e, */newArguments, type, ctorArguments), begin); + } + + Type parseType() + { + return parseBasicType2(parseBasicType()); + } + + Type parseBasicType() + { + auto begin = token; + Type t; +// IdentifierType tident; + + switch (token.type) + { + case T.Char, T.Wchar, T.Dchar, T.Bool, + T.Byte, T.Ubyte, T.Short, T.Ushort, + T.Int, T.Uint, T.Long, T.Ulong, + T.Float, T.Double, T.Real, + T.Ifloat, T.Idouble, T.Ireal, + T.Cfloat, T.Cdouble, T.Creal, T.Void: + t = new IntegralType(token.type); + nT(); + set(t, begin); + break; + case T.Identifier, T.Typeof, T.Dot: + t = parseDotListType(); + break; + version(D2) + { + case T.Const: + // const ( Type ) + nT(); + require(T.LParen); + t = parseType(); + require(T.RParen); + t = new ConstType(t); + set(t, begin); + break; + case T.Invariant: + // invariant ( Type ) + nT(); + require(T.LParen); + t = parseType(); + require(T.RParen); + t = new InvariantType(t); + set(t, begin); + break; + } + default: + // TODO: issue error msg. + error(MID.ExpectedButFound, "BasicType", token.srcText); + t = new UndefinedType(); + nT(); + set(t, begin); + } + return t; + } + + Type parseBasicType2(Type t) + { + typeof(token) begin; + while (1) + { + begin = token; + switch (token.type) + { + case T.Mul: + t = new PointerType(t); + nT(); + break; + case T.LBracket: + t = parseArrayType(t); + continue; + case T.Function, T.Delegate: + TOK tok = token.type; + nT(); + auto parameters = parseParameterList(); + if (tok == T.Function) + t = new FunctionType(t, parameters); + else + t = new DelegateType(t, parameters); + break; + default: + return t; + } + set(t, begin); + } + assert(0); + } + + bool tokenAfterParenIs(TOK tok) + { + // We count nested parentheses tokens because template types may appear inside parameter lists; e.g. (int x, Foo!(int) y). + assert(token.type == T.LParen); + Token* next = token; + uint level = 1; + while (1) + { + lx.peek(next); + switch (next.type) + { + case T.RParen: + if (--level == 0) + { // Closing parentheses found. + lx.peek(next); + break; + } + continue; + case T.LParen: + ++level; + continue; + case T.EOF: + break; + default: + continue; + } + break; + } + + return next.type == tok; + } + + Type parseDeclaratorSuffix(Type t) + { + switch (token.type) + { + case T.LBracket: + // Type Identifier ArrayType + // ArrayType := [] or [Type] or [Expression..Expression] + do + t = parseArrayType(t); + while (token.type == T.LBracket) + break; +/+ // parsed in parseDeclaration() + case T.LParen: + TemplateParameters tparams; + if (tokenAfterParenIs(T.LParen)) + { + // ( TemplateParameterList ) ( ParameterList ) + tparams = parseTemplateParameterList(); + } + + auto params = parseParameterList(); + // ReturnType FunctionName ( ParameterList ) + t = new FunctionType(t, params, tparams); + break; ++/ + default: + break; + } + return t; + } + + Type parseArrayType(Type t) + { + assert(token.type == T.LBracket); + auto begin = token; + nT(); + if (token.type == T.RBracket) + { + t = new ArrayType(t); + nT(); + } + else + { + bool success; + auto assocType = try_(parseType(), success); + if (success) + t = new ArrayType(t, assocType); + else + { + Expression e = parseExpression(), e2; + if (token.type == T.Slice) + { + nT(); + e2 = parseExpression(); + } + t = new ArrayType(t, e, e2); + } + require(T.RBracket); + } + set(t, begin); + return t; + } + + Type parseDeclarator(ref Token* ident, bool identOptional = false) + { + auto t = parseType(); + + if (token.type == T.Identifier) + { + ident = token; + nT(); + t = parseDeclaratorSuffix(t); + } + else if (!identOptional) + expected(T.Identifier); + + return t; + } + + Expression[] parseArguments(TOK terminator) + { + assert(token.type == T.LParen || token.type == T.LBracket || token.type == T.Comma); + assert(terminator == T.RParen || terminator == T.RBracket); + Expression[] args; + + nT(); + if (token.type == terminator) + { + nT(); + return null; + } + + goto LenterLoop; + do + { + nT(); + LenterLoop: + args ~= parseAssignExpression(); + } while (token.type == T.Comma) + + require(terminator); + return args; + } + + Parameters parseParameterList() + out(params) + { + if (params.length > 1) + foreach (param; params.items[0..$-1]) + { + if (param.isVariadic()) + assert(0, "variadic arguments can only appear at the end of the parameter list."); + } + } + body + { + auto begin = token; + require(T.LParen); + + auto params = new Parameters(); + + if (token.type == T.RParen) + { + nT(); + return set(params, begin); + } + + while (1) + { + auto paramBegin = token; + Token* stcTok; + StorageClass stc, tmp; + + if (token.type == T.Ellipses) + { + nT(); + params ~= set(new Parameter(null, null, null, null), paramBegin); + break; // Exit loop. + } + + Lstc_loop: + switch (token.type) + { + version(D2) + { + case T.Invariant: // D2.0 + if (peekNext() == T.LParen) + goto default; + tmp = StorageClass.Invariant; + goto Lcommon; + case T.Const: // D2.0 + if (peekNext() == T.LParen) + goto default; + tmp = StorageClass.Const; + goto Lcommon; + case T.Final: // D2.0 + tmp = StorageClass.Final; + goto Lcommon; + case T.Scope: // D2.0 + tmp = StorageClass.Scope; + goto Lcommon; + case T.Static: // D2.0 + tmp = StorageClass.Static; + goto Lcommon; + case T.In: + tmp = StorageClass.In; + goto Lcommon; + case T.Out: + tmp = StorageClass.Out; + goto Lcommon; + case T.Inout, T.Ref: + tmp = StorageClass.Ref; + goto Lcommon; + case T.Lazy: + tmp = StorageClass.Lazy; + goto Lcommon; + Lcommon: + if (stc & tmp) + error(MID.RedundantStorageClass, token.srcText); + else + stc |= tmp; + nT(); + goto Lstc_loop; + } + else // else body of version(D2) + { + case T.In, T.Out, T.Inout, T.Ref, T.Lazy: + stcTok = token; + nT(); + goto default; + } + default: + version(D2) + { + if (stc != StorageClass.None) + stcTok = begin; + } + Token* ident; + auto type = parseDeclarator(ident, true); + + Expression assignExpr; + if (token.type == T.Assign) + { + nT(); + assignExpr = parseAssignExpression(); + } + + if (token.type == T.Ellipses) + { + auto p = set(new Parameter(stcTok, type, ident, assignExpr), paramBegin); + p.stc |= StorageClass.Variadic; + params ~= p; + nT(); + break; // Exit loop. + } + + params ~= set(new Parameter(stcTok, type, ident, assignExpr), paramBegin); + + if (token.type != T.Comma) + break; // Exit loop. + nT(); + continue; + } + break; // Exit loop. + } + require(T.RParen); + return set(params, begin); + } + + TemplateArguments parseTemplateArguments() + { + auto begin = token; + auto args = new TemplateArguments; + + require(T.LParen); + if (token.type != T.RParen) + { + while (1) + { + bool success; + auto typeArgument = try_(parseType(), success); + if (success) + { + // TemplateArgument: + // Type + // Symbol + args ~= typeArgument; + } + else + { + // TemplateArgument: + // AssignExpression + args ~= parseAssignExpression(); + } + if (token.type != T.Comma) + break; // Exit loop. + nT(); + } + } + require(T.RParen); + set(args, begin); + return args; + } +version(D2) +{ + TemplateArguments parseTemplateArguments2() + { + assert(token.type == T.Comma); + nT(); + auto begin = token; + auto args = new TemplateArguments; + + if (token.type != T.RParen) + { + while (1) + { + bool success; + auto typeArgument = try_(parseType(), success); + if (success) + { + // TemplateArgument: + // Type + // Symbol + args ~= typeArgument; + } + else + { + // TemplateArgument: + // AssignExpression + args ~= parseAssignExpression(); + } + if (token.type != T.Comma) + break; // Exit loop. + nT(); + } + } + else + error(MID.ExpectedButFound, "Type/Expression", ")"); + require(T.RParen); + set(args, begin); + return args; + } +} // version(D2) + TemplateParameters parseTemplateParameterList() + { + auto begin = token; + auto tparams = new TemplateParameters; + + require(T.LParen); + if (token.type == T.RParen) + return tparams; + + while (1) + { + auto paramBegin = token; + TP tp; + Token* ident; + Type valueType; + Type specType, defType; + Expression specValue, defValue; + + switch (token.type) + { + case T.Alias: + // TemplateAliasParameter: + // alias Identifier + tp = TP.Alias; + nT(); // Skip alias keyword. + ident = requireId(); + // : SpecializationType + if (token.type == T.Colon) + { + nT(); + specType = parseType(); + } + // = DefaultType + if (token.type == T.Assign) + { + nT(); + defType = parseType(); + } + break; + case T.Identifier: + ident = token; + switch (peekNext()) + { + case T.Ellipses: + // TemplateTupleParameter: + // Identifier ... + tp = TP.Tuple; + nT(); // Skip Identifier. + nT(); // Skip Ellipses. + // if (token.type == T.Comma) + // error(); // TODO: issue error msg for variadic param not being last. + break; + case T.Comma, T.RParen, T.Colon, T.Assign: + // TemplateTypeParameter: + // Identifier + tp = TP.Type; + nT(); // Skip Identifier. + // : SpecializationType + if (token.type == T.Colon) + { + nT(); + specType = parseType(); + } + // = DefaultType + if (token.type == T.Assign) + { + nT(); + defType = parseType(); + } + break; + default: + // TemplateValueParameter: + // Declarator + ident = null; + goto LTemplateValueParameter; + } + break; + default: + LTemplateValueParameter: + // TemplateValueParameter: + // Declarator + tp = TP.Value; + valueType = parseDeclarator(ident); + // : SpecializationValue + if (token.type == T.Colon) + { + nT(); + specValue = parseCondExpression(); + } + // = DefaultValue + if (token.type == T.Assign) + { + nT(); + defValue = parseCondExpression(); + } + } + + tparams ~= set(new TemplateParameter(tp, valueType, ident, specType, defType, specValue, defValue), paramBegin); + + if (token.type != T.Comma) + break; + nT(); + } + require(T.RParen); + set(tparams, begin); + return tparams; + } + + void expected(TOK tok) + { + if (token.type != tok) + error(MID.ExpectedButFound, Token.Token.toString(tok), token.srcText); + } + + void require(TOK tok) + { + if (token.type == tok) + nT(); + else + error(MID.ExpectedButFound, Token.Token.toString(tok), token.srcText); + } + + void requireNext(TOK tok) + { + nT(); + require(tok); + } + + string requireIdentifier() + { + string identifier; + if (token.type == T.Identifier) + { + identifier = token.identifier; + nT(); + } + else + error(MID.ExpectedButFound, "Identifier", token.srcText); + return identifier; + } + + Token* requireId() + { + if (token.type == T.Identifier) + { + auto id = token; + nT(); + return id; + } + else + error(MID.ExpectedButFound, "Identifier", token.srcText); + return null; + } + + void error(MID id, ...) + { + if (trying) + { + ++errorCount; + return; + } + +// if (errors.length == 10) +// return; + errors ~= new Information(InfoType.Parser, id, lx.loc, arguments(_arguments, _argptr)); +// writefln("(%d)P: ", lx.loc, errors[$-1].getMsg); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Settings.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,104 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Settings; +import Messages; +import Parser, SyntaxTree, Declarations, Expressions; +import std.metastrings; + +version(D2) +{ + const VERSION_MAJOR = 2; + const VERSION_MINOR = 0; +} +else +{ + const VERSION_MAJOR = 1; + const VERSION_MINOR = 0; +} +const string VERSION = Format!("%s.%s", VERSION_MAJOR, VERSION_MINOR); + +const COMPILED_WITH = __VENDOR__; +const COMPILED_VERSION = Format!("%s.%s", __VERSION__/1000, __VERSION__%1000); +const COMPILED_DATE = __TIMESTAMP__; + +const usageHighlight = "highlight (hl) file.d"; + +struct GlobalSettings +{ +static: + string language; /// Language of messages catalogue to load. + string[] messages; /// Table of localized compiler messages. + void load() + { + auto fileName = "config.d"[]; + auto sourceText = cast(char[]) std.file.read(fileName); + auto parser = new Parser(sourceText, fileName); + parser.start(); + auto root = parser.parseModule(); + + if (parser.errors.length || parser.lx.errors.length) + { + throw new Exception("There are errors in " ~ fileName ~ "."); + } + + foreach (decl; root.children) + { + auto v = Cast!(VariableDeclaration)(decl); + if (v && v.idents[0].srcText == "language") + { + auto e = v.values[0]; + if (!e) + throw new Exception("language variable has no value set."); + auto val = Cast!(StringLiteralsExpression)(e); + if (val) + { + GlobalSettings.language = val.getString(); + break; + } + } + } + + // Load messages + if (GlobalSettings.language.length) + { + fileName = "lang_" ~ GlobalSettings.language ~ ".d"; + sourceText = cast(char[]) std.file.read(fileName); + parser = new Parser(sourceText, fileName); + parser.start(); + root = parser.parseModule(); + + if (parser.errors.length || parser.lx.errors.length) + { + throw new Exception("There are errors in "~fileName~"."); + } + + char[][] messages; + foreach (decl; root.children) + { + auto v = Cast!(VariableDeclaration)(decl); + if (v && v.idents[0].srcText == "messages") + { + auto e = v.values[0]; + if (!e) + throw new Exception("messages variable in "~fileName~" has no value set."); + if (auto array = Cast!(ArrayInitializer)(e)) + { + foreach (value; array.values) + { + if (auto str = Cast!(StringLiteralsExpression)(value)) + messages ~= str.getString(); + } + } + else + throw new Exception("messages variable is set to "~e.classinfo.name~" instead of an ArrayInitializer."); + } + } + if (messages.length != MID.max+1) + throw new Exception(std.string.format("messages table in %s must exactly have %d entries, but %s were found.", fileName, MID.max, messages.length)); + GlobalSettings.messages = messages; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Statements.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,567 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Statements; +import SyntaxTree; +import Expressions; +import Declarations; +import Types; +import Token; + +abstract class Statement : Node +{ + this() + { + super(NodeCategory.Statement); + } +} + +class Statements : Statement +{ + this() + { + mixin(set_kind); + } + + void opCatAssign(Statement s) + { + this.children ~= s; + } +} + +class IllegalStatement : Statement +{ + Token* tok; + this(Token* tok) + { + mixin(set_kind); + this.tok = tok; + } +} + +class EmptyStatement : Statement +{ + this() + { + mixin(set_kind); + } +} + +class FunctionBody : Node +{ + Statement funcBody, inBody, outBody; + Token* outIdent; + this() + { + super(NodeCategory.Other); + mixin(set_kind); + } + + void finishConstruction() + { + if (funcBody) + this.children ~= funcBody; + if (inBody) + this.children ~= inBody; + if (outBody) + this.children ~= outBody; + } +} + +class ScopeStatement : Statement +{ + Statement s; + this(Statement s) + { + mixin(set_kind); + this.children = [s]; + this.s = s; + } +} + +class LabeledStatement : Statement +{ + Token* label; + Statement s; + this(Token* label, Statement s) + { + mixin(set_kind); + this.children = [s]; + this.label = label; + this.s = s; + } +} + +class ExpressionStatement : Statement +{ + Expression expression; + this(Expression expression) + { + mixin(set_kind); + this.children = [expression]; + this.expression = expression; + } +} + +class DeclarationStatement : Statement +{ + Declaration declaration; + this(Declaration declaration) + { + mixin(set_kind); + this.children = [declaration]; + this.declaration = declaration; + } +} + +class IfStatement : Statement +{ + Statement variable; // AutoDeclaration or VariableDeclaration + Expression condition; + Statement ifBody; + Statement elseBody; + this(Statement variable, Expression condition, Statement ifBody, Statement elseBody) + { + mixin(set_kind); + if (variable) + this.children ~= variable; + else + this.children ~= condition; + this.children ~= ifBody; + if (elseBody) + this.children ~= elseBody; + this.variable = variable; + this.condition = condition; + this.ifBody = ifBody; + this.elseBody = elseBody; + } +} + +class WhileStatement : Statement +{ + Expression condition; + Statement whileBody; + this(Expression condition, Statement whileBody) + { + mixin(set_kind); + this.children = [cast(Node)condition, whileBody]; + this.condition = condition; + this.whileBody = whileBody; + } +} + +class DoWhileStatement : Statement +{ + Expression condition; + Statement doBody; + this(Expression condition, Statement doBody) + { + mixin(set_kind); + this.children = [cast(Node)condition, doBody]; + this.condition = condition; + this.doBody = doBody; + } +} + +class ForStatement : Statement +{ + Statement init; + Expression condition, increment; + Statement forBody; + + this(Statement init, Expression condition, Expression increment, Statement forBody) + { + mixin(set_kind); + if (init) + this.children ~= init; + if (condition) + this.children ~= condition; + if (increment) + this.children ~= increment; + this.children ~= forBody; + this.init = init; + this.condition = condition; + this.increment = increment; + this.forBody = forBody; + } +} + +class ForeachStatement : Statement +{ + TOK tok; + Parameters params; + Expression aggregate; + Statement forBody; + + this(TOK tok, Parameters params, Expression aggregate, Statement forBody) + { + mixin(set_kind); + this.children = [cast(Node)params, aggregate, forBody]; + this.tok = tok; + this.params = params; + this.aggregate = aggregate; + this.forBody = forBody; + } +} + +version(D2) +{ +class ForeachRangeStatement : Statement +{ + TOK tok; + Parameters params; + Expression lower, upper; + Statement forBody; + + this(TOK tok, Parameters params, Expression lower, Expression upper, Statement forBody) + { + mixin(set_kind); + this.children = [cast(Node)params, lower, upper, forBody]; + this.tok = tok; + this.params = params; + this.lower = lower; + this.upper = upper; + this.forBody = forBody; + } +} +} + +class SwitchStatement : Statement +{ + Expression condition; + Statement switchBody; + + this(Expression condition, Statement switchBody) + { + mixin(set_kind); + this.children = [cast(Node)condition, switchBody]; + this.condition = condition; + this.switchBody = switchBody; + } +} + +class CaseStatement : Statement +{ + Expression[] values; + Statement caseBody; + + this(Expression[] values, Statement caseBody) + { + mixin(set_kind); + this.children = cast(Node[])values ~ [caseBody]; + this.values = values; + this.caseBody = caseBody; + } +} + +class DefaultStatement : Statement +{ + Statement defaultBody; + this(Statement defaultBody) + { + mixin(set_kind); + this.children = [defaultBody]; + this.defaultBody = defaultBody; + } +} + +class ContinueStatement : Statement +{ + Token* ident; + this(Token* ident) + { + mixin(set_kind); + this.ident = ident; + } +} + +class BreakStatement : Statement +{ + Token* ident; + this(Token* ident) + { + mixin(set_kind); + this.ident = ident; + } +} + +class ReturnStatement : Statement +{ + Expression expr; + this(Expression expr) + { + mixin(set_kind); + if (expr) + this.children = [expr]; + this.expr = expr; + } +} + +class GotoStatement : Statement +{ + Token* ident; + Expression caseExpr; + this(Token* ident, Expression caseExpr) + { + mixin(set_kind); + if (caseExpr) + this.children = [caseExpr]; + this.ident = ident; + this.caseExpr = caseExpr; + } +} + +class WithStatement : Statement +{ + Expression expr; + Statement withBody; + this(Expression expr, Statement withBody) + { + mixin(set_kind); + this.children = [cast(Node)expr, withBody]; + this.expr = expr; + this.withBody = withBody; + } +} + +class SynchronizedStatement : Statement +{ + Expression expr; + Statement syncBody; + this(Expression expr, Statement withBody) + { + mixin(set_kind); + this.children = [cast(Node)expr, syncBody]; + this.expr = expr; + this.syncBody = syncBody; + } +} + +class TryStatement : Statement +{ + Statement tryBody; + CatchBody[] catchBodies; + FinallyBody finallyBody; + this(Statement tryBody, CatchBody[] catchBodies, FinallyBody finallyBody) + { + mixin(set_kind); + this.children = [tryBody]; + if (catchBodies.length) + this.children ~= catchBodies; + if (finallyBody) + this.children ~= finallyBody; + this.tryBody = tryBody; + this.catchBodies = catchBodies; + this.finallyBody = finallyBody; + } +} + +class CatchBody : Statement +{ + Parameter param; + Statement catchBody; + this(Parameter param, Statement catchBody) + { + mixin(set_kind); + this.children = [cast(Node)param, catchBody]; + this.param = param; + this.catchBody = catchBody; + } +} + +class FinallyBody : Statement +{ + Statement finallyBody; + this(Statement finallyBody) + { + mixin(set_kind); + this.children = [finallyBody]; + this.finallyBody = finallyBody; + } +} + +class ScopeGuardStatement : Statement +{ + Token* condition; + Statement scopeBody; + this(Token* condition, Statement scopeBody) + { + mixin(set_kind); + this.children = [scopeBody]; + this.condition = condition; + this.scopeBody = scopeBody; + } +} + +class ThrowStatement : Statement +{ + Expression expr; + this(Expression expr) + { + mixin(set_kind); + this.children = [expr]; + this.expr = expr; + } +} + +class VolatileStatement : Statement +{ + Statement volatileBody; + this(Statement volatileBody) + { + mixin(set_kind); + if (volatileBody) + this.children = [volatileBody]; + this.volatileBody = volatileBody; + } +} + +class AsmStatement : Statement +{ + Statements statements; + this(Statements statements) + { + mixin(set_kind); + this.children = [statements]; + this.statements = statements; + } +} + +class AsmInstruction : Statement +{ + Token* ident; + Expression[] operands; + this(Token* ident, Expression[] operands) + { + mixin(set_kind); + this.children = operands; + this.ident = ident; + this.operands = operands; + } +} + +class IllegalAsmInstruction : IllegalStatement +{ + this(Token* token) + { + super(token); + mixin(set_kind); + } +} + +class PragmaStatement : Statement +{ + Token* ident; + Expression[] args; + Statement pragmaBody; + this(Token* ident, Expression[] args, Statement pragmaBody) + { + mixin(set_kind); + if (args.length) + this.children = args; + this.children ~= pragmaBody; + this.ident = ident; + this.args = args; + this.pragmaBody = pragmaBody; + } +} + +class MixinStatement : Statement +{ + Expression[] templateIdents; + Token* mixinIdent; + this(Expression[] templateIdents, Token* mixinIdent) + { + mixin(set_kind); + this.children = templateIdents; + this.templateIdents = templateIdents; + this.mixinIdent = mixinIdent; + } +} + +class StaticIfStatement : Statement +{ + Expression condition; + Statement ifBody, elseBody; + this(Expression condition, Statement ifBody, Statement elseBody) + { + mixin(set_kind); + this.children = [cast(Node)condition, ifBody]; + if (elseBody) + this.children ~= elseBody; + this.condition = condition; + this.ifBody = ifBody; + this.elseBody = elseBody; + } +} + +class StaticAssertStatement : Statement +{ + Expression condition, message; + this(Expression condition, Expression message) + { + mixin(set_kind); + this.children = [condition]; + if (message) + this.children ~= message; + this.condition = condition; + this.message = message; + } +} + +class DebugStatement : Statement +{ + Token* cond; + Statement debugBody, elseBody; + this(Token* cond, Statement debugBody, Statement elseBody) + { + mixin(set_kind); + this.children = [debugBody]; + if (elseBody) + this.children ~= elseBody; + this.cond = cond; + this.debugBody = debugBody; + this.elseBody = elseBody; + } +} + +class VersionStatement : Statement +{ + Token* cond; + Statement versionBody, elseBody; + this(Token* cond, Statement versionBody, Statement elseBody) + { + mixin(set_kind); + this.children = [versionBody]; + if (elseBody) + this.children ~= [elseBody]; + this.cond = cond; + this.versionBody = versionBody; + this.elseBody = elseBody; + } +} + +class AttributeStatement : Statement +{ + TOK tok; + Statement statement; + this(TOK tok, Statement statement) + { + mixin(set_kind); + this.children = [statement]; + this.tok = tok; + this.statement = statement; + } +} + +class ExternStatement : AttributeStatement +{ + Linkage linkage; + this(Linkage linkage, Statement statement) + { + super(TOK.Extern, statement); + mixin(set_kind); + this.linkage = linkage; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/SyntaxTree.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,238 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module SyntaxTree; +import Token; + +enum NodeCategory +{ + Declaration, + Statement, + Expression, + Type, + Other +} + +enum NodeKind +{ + // Declarations: + Declarations, + EmptyDeclaration, + IllegalDeclaration, + ModuleDeclaration, + ImportDeclaration, + AliasDeclaration, + TypedefDeclaration, + EnumDeclaration, + ClassDeclaration, + InterfaceDeclaration, + StructDeclaration, + UnionDeclaration, + ConstructorDeclaration, + StaticConstructorDeclaration, + DestructorDeclaration, + StaticDestructorDeclaration, + FunctionDeclaration, + VariableDeclaration, + InvariantDeclaration, + UnittestDeclaration, + DebugDeclaration, + VersionDeclaration, + StaticIfDeclaration, + StaticAssertDeclaration, + TemplateDeclaration, + NewDeclaration, + DeleteDeclaration, + AttributeDeclaration, + ExternDeclaration, + AlignDeclaration, + PragmaDeclaration, + MixinDeclaration, + + // Statements: + Statements, + IllegalStatement, + EmptyStatement, + ScopeStatement, + LabeledStatement, + ExpressionStatement, + DeclarationStatement, + IfStatement, + ConditionalStatement, + WhileStatement, + DoWhileStatement, + ForStatement, + ForeachStatement, + ForeachRangeStatement, // D2.0 + SwitchStatement, + CaseStatement, + DefaultStatement, + ContinueStatement, + BreakStatement, + ReturnStatement, + GotoStatement, + WithStatement, + SynchronizedStatement, + TryStatement, + CatchBody, + FinallyBody, + ScopeGuardStatement, + ThrowStatement, + VolatileStatement, + AsmStatement, + AsmInstruction, + IllegalAsmInstruction, + PragmaStatement, + MixinStatement, + StaticIfStatement, + StaticAssertStatement, + DebugStatement, + VersionStatement, + AttributeStatement, + ExternStatement, + + // Expressions: + EmptyExpression, + BinaryExpression, + CondExpression, + CommaExpression, + OrOrExpression, + AndAndExpression, + OrExpression, + XorExpression, + AndExpression, + CmpExpression, + EqualExpression, + IdentityExpression, + RelExpression, + InExpression, + LShiftExpression, + RShiftExpression, + URShiftExpression, + PlusExpression, + MinusExpression, + CatExpression, + MulExpression, + DivExpression, + ModExpression, + AssignExpression, + LShiftAssignExpression, + RShiftAssignExpression, + URShiftAssignExpression, + OrAssignExpression, + AndAssignExpression, + PlusAssignExpression, + MinusAssignExpression, + DivAssignExpression, + MulAssignExpression, + ModAssignExpression, + XorAssignExpression, + CatAssignExpression, + UnaryExpression, + AddressExpression, + PreIncrExpression, + PreDecrExpression, + PostIncrExpression, + PostDecrExpression, + DerefExpression, + SignExpression, + NotExpression, + CompExpression, + PostDotListExpression, + CallExpression, + NewExpression, + NewAnonClassExpression, + DeleteExpression, + CastExpression, + IndexExpression, + SliceExpression, + PrimaryExpressio, + IdentifierExpression, + SpecialTokenExpression, + DotListExpression, + TemplateInstanceExpression, + ThisExpression, + SuperExpression, + NullExpression, + DollarExpression, + BoolExpression, + IntNumberExpression, + RealNumberExpression, + CharLiteralExpression, + StringLiteralsExpression, + ArrayLiteralExpression, + AssocArrayLiteralExpression, + AssertExpression, + MixinExpression, + ImportExpression, + TypeofExpression, + TypeDotIdExpression, + TypeidExpression, + IsExpression, + FunctionLiteralExpression, + TraitsExpression, // D2.0 + VoidInitializer, + ArrayInitializer, + StructInitializer, + AsmTypeExpression, + AsmOffsetExpression, + AsmSegExpression, + AsmPostBracketExpression, + AsmBracketExpression, + AsmLocalSizeExpression, + AsmRegisterExpression, + + // Types: + IntegralType, + UndefinedType, + DotListType, + IdentifierType, + TypeofType, + TemplateInstanceType, + PointerType, + ArrayType, + FunctionType, + DelegateType, + ConstType, // D2.0 + InvariantType, // D2.0 + + // Other: + FunctionBody, + Parameter, + Parameters, + BaseClass, + TemplateParameter, + TemplateParameters, + TemplateArguments, +} + +/// This string is mixed into the constructor of a class that inherits from Node. +const string set_kind = `this.kind = mixin("NodeKind." ~ typeof(this).stringof);`; + +Class Cast(Class)(Node n) +{ + assert(n !is null); + if (n.kind == mixin("NodeKind." ~ typeof(Class).stringof)) + return cast(Class)cast(void*)n; + return null; +} + +class Node +{ + NodeCategory category; + NodeKind kind; + Node[] children; + Token* begin, end; + + this(NodeCategory category) + { + this.category = category; + } + + void setTokens(Token* begin, Token* end) + { + this.begin = begin; + this.end = end; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Token.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,257 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Token; +import std.c.stdlib : malloc, free; +import std.outofmemory; + +struct Position +{ + size_t loc; + size_t col; +} + +enum TOK : ushort +{ + Invalid, + + /// Flag for whitespace tokens that must be ignored in the parsing phase. + Whitespace = 0x8000, + Comment = 1 | Whitespace, + Shebang = 2 | Whitespace, + HashLine = 3 | Whitespace, + Filespec = 4 | Whitespace, + + Identifier = 5, + String, + Special, + CharLiteral, WCharLiteral, DCharLiteral, + + // Numbers + Int32, Int64, Uint32, Uint64, + // Floating point number scanner relies on this order. (FloatXY + 3 == ImaginaryXY) + Float32, Float64, Float80, + Imaginary32, Imaginary64, Imaginary80, + + + // Brackets + LParen, + RParen, + LBracket, + RBracket, + LBrace, + RBrace, + + Dot, Slice, Ellipses, + + // Floating point number operators + Unordered, + UorE, + UorG, + UorGorE, + UorL, + UorLorE, + LorEorG, + LorG, + + // Normal operators + Assign, Equal, NotEqual, Not, + LessEqual, Less, + GreaterEqual, Greater, + LShiftAssign, LShift, + RShiftAssign,RShift, + URShiftAssign, URShift, + OrAssign, OrLogical, OrBinary, + AndAssign, AndLogical, AndBinary, + PlusAssign, PlusPlus, Plus, + MinusAssign, MinusMinus, Minus, + DivAssign, Div, + MulAssign, Mul, + ModAssign, Mod, + XorAssign, Xor, + CatAssign, Catenate, + Tilde, + Identity, NotIdentity, + + Colon, + Semicolon, + Question, + Comma, + Dollar, + + /* Keywords: + NB.: Token.isKeyword() depends on this list being contiguous. + */ + Abstract,Alias,Align,Asm,Assert,Auto,Body, + Bool,Break,Byte,Case,Cast,Catch,Cdouble, + Cent,Cfloat,Char,Class,Const,Continue,Creal, + Dchar,Debug,Default,Delegate,Delete,Deprecated,Do, + Double,Else,Enum,Export,Extern,False,Final, + Finally,Float,For,Foreach,Foreach_reverse,Function,Goto, + Idouble,If,Ifloat,Import,In,Inout,Int, + Interface,Invariant,Ireal,Is,Lazy,Long,Macro/+D2.0+/, + Mixin,Module,New,Null,Out,Override,Package, + Pragma,Private,Protected,Public,Real,Ref/+D2.0+/,Return, + Scope,Short,Static,Struct,Super,Switch,Synchronized, + Template,This,Throw,Traits/+D2.0+/,True,Try,Typedef,Typeid, + Typeof,Ubyte,Ucent,Uint,Ulong,Union,Unittest, + Ushort,Version,Void,Volatile,Wchar,While,With, + + HEAD, // start of linked list + EOF +} + +alias TOK.Abstract KeywordsBegin; +alias TOK.With KeywordsEnd; + +struct Token +{ + TOK type; +// Position pos; + + Token* next, prev; + + char* start; + char* end; + + union + { + struct + { + Token* line_num; // #line number + Token* line_filespec; // #line number filespec + } + struct + { + string str; + char pf; + } + dchar dchar_; + long long_; + ulong ulong_; + int int_; + uint uint_; + float float_; + double double_; + real real_; + } + + alias srcText identifier; + + string srcText() + { + assert(start && end); + return start[0 .. end - start]; + } + + static string toString(TOK tok) + { + return tokToString[tok]; + } + + bool isKeyword() + { + return KeywordsBegin <= type && type <= KeywordsEnd; + } + + bool isWhitespace() + { + return !!(type & TOK.Whitespace); + } + + int opEquals(TOK type2) + { + return type == type2; + } + + new(size_t size) + { + void* p = malloc(size); + if (p is null) + throw new OutOfMemoryException(); + *cast(Token*)p = Token.init; + return p; + } + + delete(void* p) + { + free(p); + } +} + +string[] tokToString = [ + "Invalid", + + "Comment", + "#! /shebang/", + "#line", + + "Identifier", + "String", + "Special", + "CharLiteral", "WCharLiteral", "DCharLiteral", + + "Int32", "Int64", "Uint32", "Uint64", + "Float32", "Float64", "Float80", + "Imaginary32", "Imaginary64", "Imaginary80", + + "(", + ")", + "[", + "]", + "{", + "}", + + ".", "..", "...", + + "Unordered", + "UorE", + "UorG", + "UorGorE", + "UorL", + "UorLorE", + "LorEorG", + "LorG", + + "=", "==", "!=", "!", + "<=", "<", + ">=", ">", + "<<=", "<<", + ">>=",">>", + ">>>=", ">>>", + "|=", "||", "|", + "&=", "&&", "&", + "+=", "++", "+", + "-=", "--", "-", + "/=", "/", + "*=", "*", + "%=", "%", + "^=", "^", + "~=", "~", + "~", + "is", "!is", + + ":", + ";", + "?", + ",", + "$", + + "abstract","alias","align","asm","assert","auto","body", + "bool","break","byte","case","cast","catch","cdouble", + "cent","cfloat","char","class","const","continue","creal", + "dchar","debug","default","delegate","delete","deprecated","do", + "double","else","enum","export","extern","false","final", + "finally","float","for","foreach","foreach_reverse","function","goto", + "idouble","if","ifloat","import","in","inout","int", + "interface","invariant","ireal","is","lazy","long","macro", + "mixin","module","new","null","out","override","package", + "pragma","private","protected","public","real","ref","return", + "scope","short","static","struct","super","switch","synchronized", + "template","this","throw","true","try","typedef","typeid", + "typeof","ubyte","ucent","uint","ulong","union","unittest", + "ushort","version","void","volatile","wchar","while","with", + + "EOF" +];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/dil/Types.d Tue Aug 21 16:28:05 2007 +0000 @@ -0,0 +1,426 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module Types; +import SyntaxTree; +import Token; +import Expressions; + +enum Linkage +{ + Invalid, + C, + Cpp, + D, + Windows, + Pascal, + System +} + +enum StorageClass +{ + None = 0, + Abstract = 1, + Auto = 1<<2, + Const = 1<<3, + Deprecated = 1<<4, + Extern = 1<<5, + Final = 1<<6, + Invariant = 1<<7, + Override = 1<<8, + Scope = 1<<9, + Static = 1<<10, + Synchronized = 1<<11, + In = 1<<12, + Out = 1<<13, + Ref = 1<<14, + Lazy = 1<<15, + Variadic = 1<<16, +} + +class Parameter : Node +{ + StorageClass stc; + Token* stcTok; + Type type; + Token* ident; + Expression assignExpr; + + this(Token* stcTok, Type type, Token* ident, Expression assignExpr) + { + super(NodeCategory.Other); + mixin(set_kind); + if (type) // type can be null when param in foreach statement + this.children = [type]; + if (assignExpr) + this.children ~= assignExpr; + + StorageClass stc; + if (stcTok !is null) + { + // NB: In D 2.0 StorageClass.In means final/scope/const + switch (stcTok.type) + { + // TODO: D 2.0 invariant/const/final/scope + case TOK.In: stc = StorageClass.In; break; + case TOK.Out: stc = StorageClass.Out; break; + case TOK.Inout: + case TOK.Ref: stc = StorageClass.Ref; break; + case TOK.Lazy: stc = StorageClass.Lazy; break; + case TOK.Ellipses: + stc = StorageClass.Variadic; + default: + } + } + + this.stc = stc; + this.stcTok = stcTok; + this.type = type; + this.ident = ident; + this.assignExpr = assignExpr; + } + + bool isVariadic() + { + return !!(stc & StorageClass.Variadic); + } + + bool isOnlyVariadic() + { + return stc == StorageClass.Variadic; + } +} + +class Parameters : Node +{ + this() + { + super(NodeCategory.Other); + mixin(set_kind); + } + + bool hasVariadic() + { + if (children.length != 0) + return items[$-1].isVariadic(); + return false; + } + + void opCatAssign(Parameter param) + { children ~= param; } + + Parameter[] items() + { return cast(Parameter[])children; } + + size_t length() + { return children.length; } +} + + +enum Protection +{ + None, + Private = 1, + Protected = 1<<1, + Package = 1<<2, + Public = 1<<3, + Export = 1<<4 +} + +class BaseClass : Node +{ + Protection prot; + Type type; + this(Protection prot, Type type) + { + super(NodeCategory.Other); + mixin(set_kind); + this.children = [type]; + this.prot = prot; + this.type = type; + } +} + +enum TP +{ + Type, + Value, + Alias, + Tuple +} + +class TemplateParameter : Node +{ + TP tp; + Type valueType; + Token* ident; + Type specType, defType; + Expression specValue, defValue; + this(TP tp, Type valueType, Token* ident, Type specType, Type defType, Expression specValue, Expression defValue) + { + super(NodeCategory.Other); + mixin(set_kind); + if (valueType) + this.children ~= valueType; + if (specType) + this.children ~= specType; + if (defType) + this.children ~= defType; + if (specValue) + this.children ~= specValue; + if (defValue) + this.children ~= defValue; + this.tp = tp; + this.valueType = valueType; + this.ident = ident; + this.specType = specType; + this.defType = defType; + this.specValue = specValue; + this.defValue = defValue; + } +} + +class TemplateParameters : Node +{ + this() + { + super(NodeCategory.Other); + mixin(set_kind); + } + + void opCatAssign(TemplateParameter parameter) + { + this.children ~= parameter; + } + + TemplateParameter[] items() + { + return cast(TemplateParameter[])children; + } +} + +class TemplateArguments : Node +{ + this() + { + super(NodeCategory.Other); + mixin(set_kind); + } + + void opCatAssign(Node argument) + { + this.children ~= argument; + } +} + +enum TID +{ + Void = TOK.Void, + Char = TOK.Char, + Wchar = TOK.Wchar, + Dchar = TOK.Dchar, + Bool = TOK.Bool, + Byte = TOK.Byte, + Ubyte = TOK.Ubyte, + Short = TOK.Short, + Ushort = TOK.Ushort, + Int = TOK.Int, + Uint = TOK.Uint, + Long = TOK.Long, + Ulong = TOK.Ulong, + Float = TOK.Float, + Double = TOK.Double, + Real = TOK.Real, + Ifloat = TOK.Ifloat, + Idouble = TOK.Idouble, + Ireal = TOK.Ireal, + Cfloat = TOK.Cfloat, + Cdouble = TOK.Cdouble, + Creal = TOK.Creal, + + Undefined, + Function, + Delegate, + Pointer, + Array, + DotList, + Identifier, + Typeof, + TemplateInstance, + Const, // D2 + Invariant, // D2 +} + +abstract class Type : Node +{ + TID tid; + Type next; + + this(TID tid) + { + this(tid, null); + } + + this(TID tid, Type next) + { + super(NodeCategory.Type); + if (next) + this.children ~= next; + this.tid = tid; + this.next = next; + } +} + +class IntegralType : Type +{ + this(TOK tok) + { + super(cast(TID)tok); + mixin(set_kind); + } +} + +class UndefinedType : Type +{ + this() + { + super(TID.Undefined); + mixin(set_kind); + } +} + +class DotListType : Type +{ + Type[] dotList; + this(Type[] dotList) + { + super(TID.DotList); + mixin(set_kind); + this.children ~= dotList; + this.dotList = dotList; + } +} + +class IdentifierType : Type +{ + Token* ident; + this(Token* ident) + { + super(TID.Identifier); + mixin(set_kind); + this.ident = ident; + } +} + +class TypeofType : Type +{ + Expression e; + this(Expression e) + { + super(TID.Typeof); + mixin(set_kind); + this.children ~= e; + this.e = e; + } +} + +class TemplateInstanceType : Type +{ + Token* ident; + TemplateArguments targs; + this(Token* ident, TemplateArguments targs) + { + super(TID.TemplateInstance); + mixin(set_kind); + this.children ~= targs; + this.ident = ident; + this.targs = targs; + } +} + +class PointerType : Type +{ + this(Type t) + { + super(TID.Pointer, t); + mixin(set_kind); + } +} + +class ArrayType : Type +{ + Expression e, e2; + Type assocType; + this(Type t) + { + super(TID.Array, t); + mixin(set_kind); + } + this(Type t, Expression e, Expression e2) + { + this.children = [e]; + if (e2) + this.children ~= e2; + this.e = e; + this.e2 = e2; + this(t); + } + this(Type t, Type assocType) + { + this.children = [assocType]; + this.assocType = assocType; + this(t); + } +} + +class FunctionType : Type +{ + Type returnType; + Parameters parameters; + this(Type returnType, Parameters parameters) + { + super(TID.Function); + mixin(set_kind); + this.children = [cast(Node)returnType, parameters]; + this.returnType = returnType; + this.parameters = parameters; + } +} + +class DelegateType : Type +{ + Type returnType; + Parameters parameters; + this(Type returnType, Parameters parameters) + { + super(TID.Delegate); + mixin(set_kind); + this.children = [cast(Node)returnType, parameters]; + this.returnType = returnType; + this.parameters = parameters; + } +} + +version(D2) +{ +class ConstType : Type +{ + this(Type t) + { + // If t is null: cast(const) + super(TID.Const, t); + mixin(set_kind); + } +} + +class InvariantType : Type +{ + this(Type t) + { + // If t is null: cast(invariant) + super(TID.Invariant, t); + mixin(set_kind); + } +} +} // version(D2)