Mercurial > projects > dang
changeset 144:6e6355fb5f0f
- Parsing nested attributes.
- Creating classes and interfaces in AST.
- Updated AstPrinter to print attributes, classes and interfaces.
author | Anders Johnsen <skabet@gmail.com> |
---|---|
date | Mon, 21 Jul 2008 17:41:40 +0200 |
parents | d76cc5cad4fc |
children | a14ac9e5c858 |
files | ast/Decl.d ast/Module.d basic/Attribute.d parser/Action.d parser/Parser.d sema/AstAction.d sema/DType.d sema/ScopeBuilder.d sema/Visitor.d tests/parser/public_1.d tools/AstPrinter.d |
diffstat | 11 files changed, 868 insertions(+), 298 deletions(-) [+] |
line wrap: on
line diff
--- a/ast/Decl.d Mon Jul 21 01:05:20 2008 +0200 +++ b/ast/Decl.d Mon Jul 21 17:41:40 2008 +0200 @@ -20,6 +20,8 @@ ImportDecl, FuncDecl, StructDecl, + ClassDecl, + InterfaceDecl, } class Decl @@ -220,3 +222,69 @@ private DType myType; } +class ClassDecl : Decl +{ + this(Identifier identifier) + { + super(DeclType.ClassDecl); + this.identifier = identifier; + } + + void addMember(Decl decl) + { + decls ~= decl; + } + + void addBaseClass(Identifier identifier) + { + baseClasses ~= identifier; + } + + void simplify() + { + } + + override DType type() + { + return env.findType(identifier); + } + + Identifier identifier; + Identifier[] baseClasses; + Decl[] decls; + private DType myType; +} + +class InterfaceDecl : Decl +{ + this(Identifier identifier) + { + super(DeclType.InterfaceDecl); + this.identifier = identifier; + } + + void addMember(Decl decl) + { + decls ~= decl; + } + + void addBaseClass(Identifier identifier) + { + baseClasses ~= identifier; + } + + void simplify() + { + } + + override DType type() + { + return env.findType(identifier); + } + + Identifier identifier; + Identifier[] baseClasses; + Decl[] decls; + private DType myType; +} +
--- a/ast/Module.d Mon Jul 21 01:05:20 2008 +0200 +++ b/ast/Module.d Mon Jul 21 17:41:40 2008 +0200 @@ -25,15 +25,23 @@ case DeclType.StructDecl: structs ~= cast(StructDecl)decl; break; + case DeclType.ClassDecl: + classes ~= cast(ClassDecl)decl; + break; + case DeclType.InterfaceDecl: + interfaces ~= cast(InterfaceDecl)decl; + break; default: assert(0, "DeclType not implemented"); } decls ~= decl; } - VarDecl[] vars; - FuncDecl[] functions; - StructDecl[] structs; + VarDecl[] vars; + FuncDecl[] functions; + StructDecl[] structs; + ClassDecl[] classes; + InterfaceDecl[] interfaces; Decl[] decls; char[] moduleName;
--- a/basic/Attribute.d Mon Jul 21 01:05:20 2008 +0200 +++ b/basic/Attribute.d Mon Jul 21 17:41:40 2008 +0200 @@ -94,13 +94,20 @@ return e; } - void setStatic() { att &= ~Static; } - void setFinal() { att &= ~Final; } - void setConst() { att &= ~Const; } - void setAbstract() { att &= ~Abstract; } - void setOverride() { att &= ~Override; } - void setDepracted() { att &= ~Depracted; } - void setAuto() { att &= ~Auto; } + void setStatic() { att |= Static; } + bool getStatic() { return att & Static ? true : false; } + void setFinal() { att |= Final; } + bool getFinal() { return att & Final ? true : false; } + void setConst() { att |= Const; } + bool getConst() { return att & Const ? true : false; } + void setAbstract() { att |= Abstract; } + bool getAbstract() { return att & Abstract ? true : false; } + void setOverride() { att |= Override; } + bool getOverride() { return att & Override ? true : false; } + void setDepracted() { att |= Depracted; } + bool getDepracted() { return att & Depracted ? true : false; } + void setAuto() { att |= Auto; } + bool getAuto() { return att & Auto ? true : false; } char[] toString() {
--- a/parser/Action.d Mon Jul 21 01:05:20 2008 +0200 +++ b/parser/Action.d Mon Jul 21 17:41:40 2008 +0200 @@ -171,7 +171,7 @@ /** Add a class member to a struct. */ - void actOnClassMember(DeclT st_decl, DeclT m_decl) + void actOnClassMember(DeclT cl_decl, DeclT m_decl) { return null; } @@ -179,7 +179,23 @@ /** Add a class member to a struct. */ - void actOnClassBaseClass(DeclT st_decl, ref Id name) + void actOnClassBaseClass(DeclT cl_decl, ref Id name) + { + return null; + } + + /** + Add a class member to a struct. + */ + void actOnInterfaceMember(DeclT if_decl, DeclT m_decl) + { + return null; + } + + /** + Add a class member to a struct. + */ + void actOnInterfaceBaseClass(DeclT if_decl, ref Id name) { return null; }
--- a/parser/Parser.d Mon Jul 21 01:05:20 2008 +0200 +++ b/parser/Parser.d Mon Jul 21 17:41:40 2008 +0200 @@ -35,163 +35,105 @@ this.action = act; Module m; - if (lexer.peek.type == Tok.Module) + if ( isa(Tok.Module) ) { - Token _module = lexer.next; + Token _module = next; ModuleName name = parseModuleName(); m = action.actOnModule(_module, sm.getText(name.asRange())); require(Tok.Seperator); } else { - SLoc loc = lexer.peek.location; + SLoc loc = peek.location; m = action.actOnImplicitModule(loc, sm.getFile(loc)); } - Attribute att; - while (lexer.peek.type != Tok.EOF) - foreach (d; parseDeclDef(&att)) + auto nes = parseAttributeInit; + while( !isa(Tok.EOF) ) + { + while ( peek.isAttribute ) + nes ~= parseAttribute(nes[$-1]); + + foreach (d; parseDeclDef(nes[$-1].a)) action.actOnModuleDecl(m, d); + nes = parseAttributeScope(nes); + } + return m; } private: - Decl[] parseDeclDef(Attribute* a) + Decl[] parseDeclDef(Attribute a) { - Token t = lexer.peek; - if (t.type == Tok.Import) + if ( isa (Tok.Import) ) return parseImports(); - else - return [parseDecl(a)]; + + return [parseDecl(a)]; } - Decl parseDecl(Attribute* all_res) + Decl parseDecl(Attribute att) { - Token t = lexer.peek; - - Attribute att = *all_res; - - while ( t.isAttribute ) - { - Attribute* a = &att; - bool sco; - if(lexer.peek(1).type == Tok.Colon) - sco = true; - -LSwitch: switch(t.type) - { - case Tok.Public: - a.setProtection(Protection.Public); - break; - case Tok.Private: - a.setProtection(Protection.Private); - break; - case Tok.Package: - a.setProtection(Protection.Package); - break; - case Tok.Protected: - a.setProtection(Protection.Protected); - break; - case Tok.Export: - a.setProtection(Protection.Export); - break; - case Tok.Static: - a.setStatic; - break; - case Tok.Final: - a.setFinal; - break; - case Tok.Const: - a.setConst; - break; - case Tok.Abstract: - a.setAbstract; - break; - case Tok.Override: - a.setOverride; - break; - case Tok.Depracted: - a.setDepracted; - break; - case Tok.Auto: - a.setAuto; - break; - case Tok.Extern: - Extern e = parseLinkageType; - a.setExtern(e); - break; - } - if(sco) - { - sco = false; - a = all_res; - lexer.next; - goto LSwitch; - } - lexer.next; - t = lexer.peek; - } + Token t = peek; if (t.isBasicType || t.isIdentifier) { Id type; Id iden; int len = peekParseType; - if(lexer.peek(len).type == Tok.Identifier && len != 0) + if (peek(len).type == Tok.Identifier && len != 0) { type = parseType; parseDeclAfterInvalidType: iden = Id(require(Tok.Identifier)); - Token next = lexer.peek(); - if (next.type == Tok.Seperator) + if ( isa(Tok.Seperator) ) { - Token sep = lexer.next(); + Token sep = next; return action.actOnDeclarator(type, iden, null, att); } - else if (next.type == Tok.Assign) + else if ( isa(Tok.Assign) ) { - Token assign = lexer.next(); + Token assign = next(); Exp exp = parseExpression(); require(Tok.Seperator); return action.actOnDeclarator(type, iden, exp, att); } - else if (next.type == Tok.OpenParentheses) + else if ( isa(Tok.OpenParentheses) ) return parseFunc(type, iden, att); else messages.report(UnexpectedTok, next.location).arg(next.getType); return null; } - t = lexer.peek(len); + t = peek(len); messages.report(InvalidDeclType, t.location) .arg(sm.getText(t.asRange)); while(len--) - lexer.next; - while(lexer.peek.type != Tok.Identifier) - lexer.next; - type = Id(lexer.peek); + next; + while(peek.type != Tok.Identifier) + next; + type = Id(peek); goto parseDeclAfterInvalidType; } else if (t.type == Tok.Struct) { - Id type = Id(lexer.next); + Id type = Id(next); Id iden = Id(require(Tok.Identifier)); return parseStruct(type, iden, att); } else if (t.type == Tok.Class) { - Id type = Id(lexer.next); + Id type = Id(next); Id iden = Id(require(Tok.Identifier)); return parseClass(type, iden, att); } else if (t.type == Tok.Interface) { - Id type = Id(lexer.next); + Id type = Id(next); Id iden = Id(require(Tok.Identifier)); - return parseClass(type, iden, att); + return parseInterface(type, iden, att); } messages.report(UnexpectedTok, t.location) .arg(t.getType) @@ -202,18 +144,18 @@ Extern parseLinkageType() { Extern e = Extern.D; - if(lexer.peek(1).type != Tok.OpenParentheses) + if(peek(1).type != Tok.OpenParentheses) return e; - lexer.next; lexer.next; + next; next; Token t = require(Tok.Identifier); switch(sm.getText(t.asRange)) { case "C": - if (lexer.peek(0).type == Tok.Plus && - lexer.peek(1).type == Tok.Plus) + if (peek(0).type == Tok.Plus && + peek(1).type == Tok.Plus) e = Extern.CPlusPlus; else e = Extern.C; @@ -248,16 +190,16 @@ void addToRes(Decl d) { res ~= d; } bool done = false; - while (!done && !on_a(Tok.Seperator)) + while (!done && !isa(Tok.Seperator)) { ModuleName mod = parseModuleName(); - Token tok = lexer.peek; + Token tok = peek; switch (tok.type) { case Tok.Comma: // import A, B.C; // parse another module-name - lexer.next(); + next(); res ~= action.actOnImport(_import, mod, null); break; case Tok.Assign: @@ -271,7 +213,7 @@ } //if (isStatic) // error("Static imports cannot be renamed"); - lexer.next(); + next(); Id name = mod.id; mod = parseModuleName(); // create from mod and rename to `name` @@ -280,7 +222,7 @@ case Tok.Colon: // import A : a; // selective imports, potentially import A : print = a - lexer.next(); + next(); Decl d = action.actOnImport(_import, mod, null); // do-while on a comma: // add explicit symbol @@ -313,8 +255,8 @@ require(Tok.Seperator); return res.safe(); Lerror: - while (!on_a (Tok.Seperator)) - lexer.next(); + while (!isa (Tok.Seperator)) + next(); return res.safe(); } @@ -325,37 +267,42 @@ { auto decl = action.actOnDeclarator(type, iden, null, att); - if (lexer.peek.type == Tok.Colon) + if (peek.type == Tok.Colon) // SuperInterfaces { - lexer.next; // Remove colon. + next; // Remove colon. - Token identifier; + Id identifier; // The identifier - identifier = require(Tok.Identifier); + identifier = Id(require(Tok.Identifier)); - // FIXME: Register Interface here + action.actOnInterfaceBaseClass(decl, identifier); // We should now have an optional list of items, each starting ',' - while (lexer.peek.type == Tok.Comma) + while (peek.type == Tok.Comma) { - lexer.next; // Remove comma + next; // Remove comma // The identifier - identifier = require(Tok.Identifier); + identifier = Id(require(Tok.Identifier)); - // FIXME: Register Interface here + action.actOnInterfaceBaseClass(decl, identifier); } } require(Tok.OpenBrace); - Attribute a; - while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute) + auto nes = parseAttributeInit; + while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) ) { - auto m_decl = parseDecl(&a); - action.actOnStructMember(decl, m_decl); + while ( peek.isAttribute ) + nes ~= parseAttribute(nes[$-1]); + + auto m_decl = parseDecl(nes[$-1].a); + action.actOnInterfaceMember(decl, m_decl); + + nes = parseAttributeScope(nes); } require(Tok.CloseBrace); @@ -370,41 +317,49 @@ { auto decl = action.actOnDeclarator(type, iden, null, att); - if (lexer.peek.type == Tok.Colon) + if (peek.type == Tok.Colon) // BaseClassList - Super class and interfaces(in that order) { - lexer.next; // Remove colon. + next; // Remove colon. - Token protection, identifier; + Token protection; + Id identifier; // First we expect an optional protection level. - if (lexer.peek.isBaseClassProtection) - protection = lexer.next; + if (peek.isBaseClassProtection) + protection = next; // Then the identifier - identifier = require(Tok.Identifier); + identifier = Id(require(Tok.Identifier)); - // FIXME: Register Interface here + action.actOnClassBaseClass(decl, identifier); // We should now have an optional list of items, each starting ',' - while (lexer.peek.type == Tok.Comma) + while (peek.type == Tok.Comma) { - lexer.next; // Remove comma + next; // Remove comma // First we expect an optional protection level. - if (lexer.peek.isBaseClassProtection) - protection = lexer.next; + if (peek.isBaseClassProtection) + protection = next; // Then the identifier - identifier = require(Tok.Identifier); + identifier = Id(require(Tok.Identifier)); + + action.actOnClassBaseClass(decl, identifier); } } require(Tok.OpenBrace); - Attribute a; - while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute) + auto nes = parseAttributeInit; + while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) ) { - auto m_decl = parseDecl(&a); - action.actOnStructMember(decl, m_decl); // FIXME: Should call actOnClassMember + while ( peek.isAttribute ) + nes ~= parseAttribute(nes[$-1]); + + auto m_decl = parseDecl(nes[$-1].a); + action.actOnClassMember(decl, m_decl); + + nes = parseAttributeScope(nes); } require(Tok.CloseBrace); @@ -421,11 +376,16 @@ require(Tok.OpenBrace); - Attribute a; - while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute) + auto nes = parseAttributeInit; + while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) ) { - auto m_decl = parseDecl(&a); + while ( peek.isAttribute ) + nes ~= parseAttribute(nes[$-1]); + + auto m_decl = parseDecl(nes[$-1].a); action.actOnStructMember(decl, m_decl); + + nes = parseAttributeScope(nes); } require(Tok.CloseBrace); @@ -433,48 +393,162 @@ return decl; } - /** - Parse statements. + Att[] parseAttributeInit() + { + Att[] nes; + nes ~= Att(); + nes[0].nested = Scope; + return nes; + } - This is the place to attack! - */ - Stmt parseStatement() + Att[] parseAttributeScope(Att[] nes) { - Token t = lexer.peek; + while ( nes[$-1].nested == Single ) + nes.length = nes.length - 1; - if (t.isReturn) + while ( isa(Tok.CloseBrace) && nes.length > 1) { - Token ret = lexer.next; - Exp exp; - if (lexer.peek.type != Tok.Seperator) - exp = parseExpression(); - require(Tok.Seperator); - return action.actOnReturnStmt(ret, exp); + while ( nes.length > 1 ) + { + if( nes[$-1].nested == Scope ) + { + nes.length = nes.length - 1; + next; + break; + } + nes.length = nes.length - 1; + } + } + + return nes; + } + + Att parseAttribute(Att last) + { + Att _parseAttribute(Att last) + { + Att a = last; + a.nested = Single; - /* - if (cond) - single statement | compound statement - [else - single statement | compound statement] - */ + switch(peek.type) + { + case Tok.Public: + a.a.setProtection(Protection.Public); + break; + case Tok.Private: + a.a.setProtection(Protection.Private); + break; + case Tok.Package: + a.a.setProtection(Protection.Package); + break; + case Tok.Protected: + a.a.setProtection(Protection.Protected); + break; + case Tok.Export: + a.a.setProtection(Protection.Export); + break; + case Tok.Static: + a.a.setStatic; + break; + case Tok.Final: + a.a.setFinal; + break; + case Tok.Const: + a.a.setConst; + break; + case Tok.Abstract: + a.a.setAbstract; + break; + case Tok.Override: + a.a.setOverride; + break; + case Tok.Depracted: + a.a.setDepracted; + break; + case Tok.Auto: + a.a.setAuto; + break; + case Tok.Extern: + Extern e = parseLinkageType; + a.a.setExtern(e); + break; + } + next; + + return a; } - else if (t.isIf) + + Att a = _parseAttribute(last); + + while (peek.isAttribute) { - Token _if = lexer.next(); + a = parseAttribute(a); + } - require(Tok.OpenParentheses); - Exp cond = parseExpression(); - require(Tok.CloseParentheses); + if (peek.type == Tok.Colon) + { + a.nested = All; + next; + } + else if (peek.type == Tok.OpenBrace) + { + a.nested = Scope; + next; + } + + return a; + } - Stmt thenB = parseSingleOrCompoundStatement(); +enum : uint { Single, Scope, All } + + struct Att + { + Attribute a; + uint nested; + } + + /** + Parse statements. + + This is the place to attack! + */ + Stmt parseStatement() + { + Token t = peek; - // if there is no else part we use the if as token, to have - // something than can be passed along - Token _else = _if; - Stmt elseB; - if (lexer.peek.type == Tok.Else) + if (t.isReturn) + { + Token ret = next; + Exp exp; + if (peek.type != Tok.Seperator) + exp = parseExpression(); + require(Tok.Seperator); + return action.actOnReturnStmt(ret, exp); + + /* + if (cond) + single statement | compound statement + [else + single statement | compound statement] + */ + } + else if (t.isIf) + { + Token _if = next(); + + require(Tok.OpenParentheses); + Exp cond = parseExpression(); + require(Tok.CloseParentheses); + + Stmt thenB = parseSingleOrCompoundStatement(); + + // if there is no else part we use the if as token, to have + // something than can be passed along + Token _else = _if; + Stmt elseB; + if (peek.type == Tok.Else) { - _else = lexer.next; + _else = next; elseB = parseSingleOrCompoundStatement(); } @@ -487,7 +561,7 @@ } else if (t.isWhile) { - Token _while = lexer.next; + Token _while = next; require(Tok.OpenParentheses); Exp cond = parseExpression(); require(Tok.CloseParentheses); @@ -506,14 +580,14 @@ } else if (t.isBasicType || t.isIdentifier) { - Token iden = lexer.peek; - Token n = lexer.peek(1); + Token iden = peek; + Token n = peek(1); // Must be an decl, if we start with a basic type, or two // identifiers in a row if ( n.type == Tok.Star || n.type == Tok.OpenBracket) { int len = peekParseType; - if(lexer.peek(len).type == Tok.Identifier && len != 0) + if(peek(len).type == Tok.Identifier && len != 0) return action.actOnDeclStmt(parseVarDecl()); Exp exp = parseExpression(); @@ -531,7 +605,7 @@ } else if(t.isSwitch) { - lexer.next; + next; require(Tok.OpenParentheses); auto target = parseExpression(); auto res = action.actOnStartOfSwitchStmt(target); @@ -544,18 +618,18 @@ { require(Tok.Colon); statements.length = 0; - while (lexer.peek.type != Tok.Case - && lexer.peek.type != Tok.Default - && lexer.peek.type != Tok.CloseBrace) + while (peek.type != Tok.Case + && peek.type != Tok.Default + && peek.type != Tok.CloseBrace) statements ~= parseStatement(); action.actOnDefaultStmt(res, statements); continue; } - Token _case = lexer.peek; + Token _case = peek; if (_case.type != Tok.Case) break; - lexer.next(); + next(); Exp[] literals; do @@ -563,21 +637,21 @@ Exp e = parseExpression(); // IntegerLit lit = cast(IntegerLit)e; // if (lit is null) -// messages.report(CaseValueMustBeInt, lexer.peek.location).arg(lexer.next.getType); +// messages.report(CaseValueMustBeInt, peek.location).arg(next.getType); // else literals ~= e; } while (skip(Tok.Comma)); require(Tok.Colon); - while (lexer.peek.type != Tok.Case - && lexer.peek.type != Tok.Default - && lexer.peek.type != Tok.CloseBrace) + while (peek.type != Tok.Case + && peek.type != Tok.Default + && peek.type != Tok.CloseBrace) statements ~= parseStatement(); action.actOnCaseStmt(res, literals, statements); - if (lexer.peek.type == Tok.CloseBrace) + if (peek.type == Tok.CloseBrace) break; } require(Tok.CloseBrace); @@ -591,7 +665,7 @@ require(Tok.Seperator); return action.actOnExprStmt(exp); } - messages.report(UnexpectedBeginStmt, lexer.peek.location).arg(lexer.next.getType); + messages.report(UnexpectedBeginStmt, peek.location).arg(next.getType); return null; } messages.report(UnexpectedTok, t.location); @@ -603,7 +677,7 @@ // manually hardcoded to only support "type id [= exp];" // as that is the only thing the codegen understands Id type = parseType; - Id id = Id(lexer.next); + Id id = Id(next); Exp init; if (skip(Tok.Assign)) init = parseExpression(); @@ -621,9 +695,9 @@ Decl func = action.actOnStartOfFunctionDef(type, name, att); parseFuncArgs(func); - if(lexer.peek.type == Tok.Seperator) + if(peek.type == Tok.Seperator) { - lexer.next; + next; return func; } Stmt stmt = parseCompoundStatement(); @@ -640,16 +714,16 @@ { require(Tok.OpenParentheses); // Remove the "(" token. - while(lexer.peek.type != Tok.CloseParentheses) + while(peek.type != Tok.CloseParentheses) { auto t = parseType(); Id i; - if(lexer.peek.type == Tok.Identifier) + if(peek.type == Tok.Identifier) i = parseIdentifier(); action.addFuncArg(func, t, i); - if(lexer.peek.type == Tok.Comma) - lexer.next; + if(peek.type == Tok.Comma) + next; } require(Tok.CloseParentheses); // Remove the ")" @@ -661,7 +735,7 @@ */ Stmt parseSingleOrCompoundStatement() { - if (lexer.peek.type == Tok.OpenBrace) + if (peek.type == Tok.OpenBrace) return parseCompoundStatement(); return parseStatement(); } @@ -676,7 +750,7 @@ { Token lbrace = require(Tok.OpenBrace); SmallArray!(Stmt, 32) stmts; // Try to use the stack only - while (lexer.peek.type != Tok.CloseBrace) + while (peek.type != Tok.CloseBrace) stmts ~= parseStatement(); Token rbrace = require(Tok.CloseBrace); return action.actOnCompoundStmt(lbrace, rbrace, stmts.unsafe()); @@ -684,7 +758,7 @@ Id parseIdentifier() { - Token tok = lexer.next; + Token tok = next; if (tok.type is Tok.Identifier) return Id(tok); @@ -701,8 +775,8 @@ while (skip(Tok.Dot)) { mod.packages ~= id; - if (lexer.peek.type != Tok.Identifier) { - messages.report(ExpectedIdAfterPackage, lexer.peek.location); + if (peek.type != Tok.Identifier) { + messages.report(ExpectedIdAfterPackage, peek.location); goto Lerror; } id = parseIdentifier(); @@ -711,7 +785,7 @@ return mod; Lerror: while (!skip(Tok.Seperator)) - lexer.next(); + next(); return mod; } @@ -721,7 +795,7 @@ */ Id parseType() { - Token type = lexer.next; + Token type = next; Id currentType; @@ -729,19 +803,19 @@ messages.report(InvalidType, type.location); currentType = Id(type); - type = lexer.peek; + type = peek; while(type.type == Tok.Star || type.type == Tok.OpenBracket) { if(type.type == Tok.Star) { currentType = PointerId(currentType); - lexer.next; + next; } else { - lexer.next; - if(lexer.peek.type == Tok.Integer) + next; + if(peek.type == Tok.Integer) currentType = StaticArrayId( currentType, action.actOnNumericConstant( @@ -749,7 +823,7 @@ require(Tok.CloseBracket); } - type = lexer.peek; + type = peek; } return currentType; @@ -758,7 +832,7 @@ int peekParseType() { int i; - Token type = lexer.peek(i); + Token type = peek(i); Id currentType; @@ -766,7 +840,7 @@ return 0; currentType = Id(type); - type = lexer.peek(++i); + type = peek(++i); while(type.type == Tok.Star || type.type == Tok.OpenBracket) { @@ -776,20 +850,20 @@ } else { - if(lexer.peek(i++).type != Tok.OpenBracket) + if(peek(i++).type != Tok.OpenBracket) return 0; - if(lexer.peek(i).type == Tok.Integer) + if(peek(i).type == Tok.Integer) { i++; - if(lexer.peek(i++).type != Tok.CloseBracket) + if(peek(i++).type != Tok.CloseBracket) return 0; } else - if(lexer.peek(i++).type != Tok.CloseBracket) + if(peek(i++).type != Tok.CloseBracket) return 0; } - type = lexer.peek(i); + type = peek(i); } return i; @@ -799,22 +873,22 @@ // -- Expression parsing -- // Exp parsePostfixExp(Exp target) { - switch(lexer.peek.type) + switch(peek.type) { case Tok.Dot: - switch(lexer.peek(1).type) + switch(peek(1).type) { case Tok.Identifier: - Token op = lexer.next; - Id member = Id(lexer.next); + Token op = next; + Id member = Id(next); Exp exp = action.actOnMemberReference(target, op.location, member); return parsePostfixExp(exp); default: - Token t = lexer.peek(1); + Token t = peek(1); messages.report(ExpectedIdAfterDot, t.location); } case Tok.OpenBracket: - Token open = lexer.next; + Token open = next; Exp index = parseExpression(); Token close = require(Tok.CloseBracket); return action.actOnIndexEpr(target, open, index, close); @@ -826,15 +900,15 @@ Exp parseExpression(int p = 0) { auto exp = P(); - Token next = lexer.peek(); + Token n = peek(); BinOp* op = null; - while ((op = binary(next.type)) != null && op.prec >= p) + while ((op = binary(n.type)) != null && op.prec >= p) { - lexer.next(); + next(); int q = op.leftAssoc? 1 + op.prec : op.prec; auto exp2 = parseExpression(q); - exp = action.actOnBinaryOp(next.location, op.operator, exp, exp2); - next = lexer.peek(); + exp = action.actOnBinaryOp(n.location, op.operator, exp, exp2); + n = peek(); } return exp; @@ -842,46 +916,46 @@ Exp P() { - Token next = lexer.next(); - if (auto op = unary(next.type)) - return action.actOnUnaryOp(next, parseExpression(op.prec)); - else if (next.type == Tok.OpenParentheses) + Token n = next(); + if (auto op = unary(n.type)) + return action.actOnUnaryOp(n, parseExpression(op.prec)); + else if (n.type == Tok.OpenParentheses) { auto e = parseExpression(0); require(Tok.CloseParentheses); return e; } - else if (next.type == Tok.Identifier) + else if (n.type == Tok.Identifier) { - Exp value = action.actOnIdentifierExp(Id(next)); + Exp value = action.actOnIdentifierExp(Id(n)); Exp iden = parsePostfixExp(value); - switch(lexer.peek.type) + switch(peek.type) { case Tok.OpenParentheses: - Token lp = lexer.next; + Token lp = next; SmallArray!(Exp, 8) args; - while(lexer.peek.type != Tok.CloseParentheses) + while(peek.type != Tok.CloseParentheses) { - if(lexer.peek.type == Tok.Comma) - lexer.next; + if(peek.type == Tok.Comma) + next; args ~= parseExpression(); } - Token rp = lexer.next(); + Token rp = next(); return action.actOnCallExpr(iden, lp, args.unsafe(), rp); default: return iden; } } - else if (next.type == Tok.Cast) - return parseCast(next); - else if (next.type == Tok.Integer) - return action.actOnNumericConstant(next); - else if (next.type == Tok.String) - return action.actOnStringExp(next); + else if (n.type == Tok.Cast) + return parseCast(n); + else if (n.type == Tok.Integer) + return action.actOnNumericConstant(n); + else if (n.type == Tok.String) + return action.actOnStringExp(n); - messages.report(ExpectedExp, next.location) + messages.report(ExpectedExp, n.location) .fatal(ExitLevel.Parser); return null; } @@ -889,13 +963,13 @@ Exp parseCast(ref Token _cast) { require(Tok.OpenParentheses); - auto next = lexer.next; - if(!next.isBasicType && !next.isIdentifier) - messages.report(ExpectedCastType, next.location); + auto n = next; + if(!n.isBasicType && !n.isIdentifier) + messages.report(ExpectedCastType, n.location); require(Tok.CloseParentheses); auto exp = P(); - return action.actOnCastExpr(_cast, Id(next), exp); + return action.actOnCastExpr(_cast, Id(n), exp); } struct UnOp @@ -980,27 +1054,37 @@ Token require(Tok t) { - if (lexer.peek().type != t) - messages.report(UnexpectedTokSingle, lexer.peek.location) - .arg(lexer.peek.getType) + if (peek().type != t) + messages.report(UnexpectedTokSingle, peek.location) + .arg(peek.getType) .arg(t); - return lexer.next(); + return next(); } bool skip(Tok t) { - if (lexer.peek().type != t) + if (peek().type != t) return false; - lexer.next(); + next(); return true; } - bool on_a(Tok t) + bool isa(Tok t) { - return lexer.peek.type == t; + return peek.type == t; } - Lexer lexer; + Token next() + { + return lexer.next; + } + + Token peek(int i = 0) + { + return lexer.peek(i); + } + + Lexer lexer; SourceManager sm; }
--- a/sema/AstAction.d Mon Jul 21 01:05:20 2008 +0200 +++ b/sema/AstAction.d Mon Jul 21 17:41:40 2008 +0200 @@ -41,24 +41,25 @@ { return new Identifier(t.location, sm.getText(t.asRange)); } - - override ModuleT actOnModule(ref Token _module, char[] name) +override +{ + ModuleT actOnModule(ref Token _module, char[] name) { return new Module(name); } - override ModuleT actOnImplicitModule(SLoc startLoc, char[] name) + ModuleT actOnImplicitModule(SLoc startLoc, char[] name) { return new Module(name); } - override void actOnModuleDecl(ModuleT m, DeclT d) + void actOnModuleDecl(ModuleT m, DeclT d) { (cast(Module)m).addDecl(cast(Decl)d); } // -- Declarations -- - override DeclT actOnImport(ref Token _, ref ModuleName target, Id* name) + DeclT actOnImport(ref Token _, ref ModuleName target, Id* name) { auto res = new ImportDecl; Identifier[] packages = new Identifier[target.packages.length]; @@ -72,7 +73,7 @@ return res; } - override void addSelectiveImport(DeclT _import, ref Id target, Id* name) + void addSelectiveImport(DeclT _import, ref Id target, Id* name) { auto d = cast(ImportDecl)_import; Identifier t = identifierFromTok(target.tok); @@ -82,12 +83,16 @@ d.explicitSymbols ~= [t, n]; } - override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init, Attribute att) + DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init, Attribute att) { Decl d; Exp exp = cast(Exp)init; - if(type.tok.type == Tok.Struct) + if (type.tok.type == Tok.Struct) d = new StructDecl(identifierFromTok(id.tok)); + else if (type.tok.type == Tok.Class) + d = new ClassDecl(identifierFromTok(id.tok)); + else if (type.tok.type == Tok.Interface) + d = new InterfaceDecl(identifierFromTok(id.tok)); else d = new VarDecl(handleType(type), identifierFromTok(id.tok), exp); @@ -95,27 +100,51 @@ return d; } - override void actOnStructMember(DeclT st_decl, DeclT m_decl) //ref Id type, ref Id name, ExprT init) + void actOnStructMember(DeclT st_decl, DeclT m_decl) //ref Id type, ref Id name, ExprT init) { StructDecl st = cast(StructDecl)st_decl; st.addMember(cast(Decl)m_decl); } - override ExprT actOnMemberReference(ExprT lhs, SLoc op, Id member) + void actOnClassMember(DeclT cl_decl, DeclT m_decl) + { + ClassDecl cl = cast(ClassDecl)cl_decl; + cl.addMember(cast(Decl)m_decl); + } + + void actOnClassBaseClass(DeclT cl_decl, ref Id name) + { + ClassDecl cl = cast(ClassDecl)cl_decl; + cl.addBaseClass(identifierFromTok(name.tok)); + } + + void actOnInterfaceMember(DeclT if_decl, DeclT m_decl) + { + InterfaceDecl inf = cast(InterfaceDecl)if_decl; + inf.addMember(cast(Decl)m_decl); + } + + void actOnInterfaceBaseClass(DeclT if_decl, ref Id name) + { + InterfaceDecl inf = cast(InterfaceDecl)if_decl; + inf.addBaseClass(identifierFromTok(name.tok)); + } + + ExprT actOnMemberReference(ExprT lhs, SLoc op, Id member) { Exp exp = cast(Exp)lhs; Identifier id = identifierFromTok(member.tok); return new MemberReference(op, exp, id); } - override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name, Attribute att) + DeclT actOnStartOfFunctionDef(ref Id type, ref Id name, Attribute att) { auto res = new FuncDecl(identifierFromTok(type.tok), identifierFromTok(name.tok)); res.att = att; return res; } - override void addFuncArg(DeclT func, Id type, Id name) + void addFuncArg(DeclT func, Id type, Id name) { FuncDecl fd = cast(FuncDecl)func; if(name) @@ -124,7 +153,7 @@ fd.addParam(identifierFromTok(type.tok)); } - override DeclT actOnEndOfFunction(DeclT func, StmtT stmts) + DeclT actOnEndOfFunction(DeclT func, StmtT stmts) { FuncDecl fd = cast(FuncDecl)func; fd.setBody(cast(CompoundStatement)stmts); @@ -132,18 +161,18 @@ } // -- Statements -- - override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts) + StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts) { Stmt[] statements = cast(Stmt[])stmts; return new CompoundStatement(statements.dup); } - override StmtT actOnExprStmt(ExprT exp) + StmtT actOnExprStmt(ExprT exp) { return new ExpStmt(cast(Exp)exp); } - override StmtT actOnReturnStmt(ref Token loc, ExprT exp) + StmtT actOnReturnStmt(ref Token loc, ExprT exp) { Exp e = cast(Exp)exp; auto res = new ReturnStmt; @@ -151,7 +180,7 @@ return res; } - override StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody, + StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody, ref Token elseTok, StmtT elseBody) { Exp c = cast(Exp)cond; @@ -160,53 +189,53 @@ return new IfStmt(c, t, e); } - override StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody) + StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody) { Exp c = cast(Exp)cond; Stmt b = cast(Stmt)whileBody; return new WhileStmt(c, b); } - override StmtT actOnDeclStmt(DeclT decl) + StmtT actOnDeclStmt(DeclT decl) { Decl d = cast(Decl)decl; return new DeclStmt(d); } - override StmtT actOnStartOfSwitchStmt(ExprT exp) + StmtT actOnStartOfSwitchStmt(ExprT exp) { return new SwitchStmt(cast(Exp)exp); } - override void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts) + void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts) { auto sw = cast(SwitchStmt)stmt; sw.addCase(cast(Exp[])exps, cast(Stmt[])stmts); } - override void actOnDefaultStmt(StmtT stmt, StmtT[] stmts) + void actOnDefaultStmt(StmtT stmt, StmtT[] stmts) { auto sw = cast(SwitchStmt)stmt; sw.setDefault(cast(Stmt[])stmts); } // -- Expressions -- - override ExprT actOnNumericConstant(Token c) + ExprT actOnNumericConstant(Token c) { return new IntegerLit(c.location, sm.getText(c.asRange)); } - override ExprT actOnStringExp(Token s) + ExprT actOnStringExp(Token s) { return new StringExp(s.location, sm.getText(s.asRange)); } - override ExprT actOnIdentifierExp(Id id) + ExprT actOnIdentifierExp(Id id) { return identifierFromTok(id.tok); } - override ExprT actOnBinaryOp(SLoc op_loc, Operator op, ExprT l, ExprT r) + ExprT actOnBinaryOp(SLoc op_loc, Operator op, ExprT l, ExprT r) { Exp left = cast(Exp)l; Exp right = cast(Exp)r; @@ -225,7 +254,7 @@ } } - override ExprT actOnUnaryOp(Token op, ExprT operand) + ExprT actOnUnaryOp(Token op, ExprT operand) { Exp target = cast(Exp)operand; if (op.type == Tok.Minus) @@ -235,21 +264,21 @@ assert(0, "Only valid unary expressions are -x and *x"); } - override ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token) + ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token) { Exp f = cast(Exp)fn; Exp[] arguments = cast(Exp[])args.dup; return new CallExp(f, arguments); } - override ExprT actOnCastExpr(ref Token _cast, Id id, ExprT exp) + ExprT actOnCastExpr(ref Token _cast, Id id, ExprT exp) { Exp target = cast(Exp)exp; Identifier target_type = identifierFromTok(id.tok); return new CastExp(_cast.location, target_type, target); } - override ExprT + ExprT actOnIndexEpr(ExprT arr, ref Token lb, ExprT index, ref Token rb) { Exp target = cast(Exp)arr; @@ -257,4 +286,5 @@ return new IndexExp(target, lb.location, idx, rb.location); } } +}
--- a/sema/DType.d Mon Jul 21 01:05:20 2008 +0200 +++ b/sema/DType.d Mon Jul 21 17:41:40 2008 +0200 @@ -31,6 +31,16 @@ /// Return a DStruct if this is one, otherwise return null DStruct asStruct() { return null; } + /// Is this type a DClass + bool isClass() { return false; } + /// Return a DClass if this is one, otherwise return null + DClass asClass() { return null; } + + /// Is this type a DInterface + bool isInterface() { return false; } + /// Return a DInterface if this is one, otherwise return null + DInterface asInterface() { return null; } + /// Is this type a DStaticArray bool isStaticArray() { return false; } /// Return a DStaticArray if this is one, otherwise return null @@ -349,6 +359,116 @@ } } +class DClass : DType +{ + this(Identifier id, DType actual = null) + { + super(id, actual); + } + + int byteSize() { return bytes_total; } + + override bool isClass() { return true; } + override DClass asClass() { return this; } + + void addMember(DType type, char[] name) + { + auto s = DClassMember(type, members.length); + members[name] = s; + + bytes_total += type.byteSize(); + } + + int indexOf(char[] name) + { + if(name in members) + return members[name].index; + + return -1; + } + + DType typeOf(char[] name) + { + if (auto res = name in members) + return res.type; + return null; + } + + DClassMember[char[]] members; + private int bytes_total; + + override char[] mangle() + { + return "S"~Integer.toString(name.length)~name; + } + + struct DClassMember + { + DType type; + int index; + + char[] toString() + { + return type.toString(); + } + } +} + +class DInterface : DType +{ + this(Identifier id, DType actual = null) + { + super(id, actual); + } + + int byteSize() { return bytes_total; } + + override bool isInterface() { return true; } + override DInterface asInterface() { return this; } + + void addMember(DType type, char[] name) + { + auto s = DInterfaceMember(type, members.length); + members[name] = s; + + bytes_total += type.byteSize(); + } + + int indexOf(char[] name) + { + if(name in members) + return members[name].index; + + return -1; + } + + DType typeOf(char[] name) + { + if (auto res = name in members) + return res.type; + return null; + } + + DInterfaceMember[char[]] members; + private int bytes_total; + + override char[] mangle() + { + return "S"~Integer.toString(name.length)~name; + } + + struct DInterfaceMember + { + DType type; + int index; + + char[] toString() + { + return type.toString(); + } + } +} + class DStaticArray : DType { this(DType arrayOf, int size, DType actual = null)
--- a/sema/ScopeBuilder.d Mon Jul 21 01:05:20 2008 +0200 +++ b/sema/ScopeBuilder.d Mon Jul 21 17:41:40 2008 +0200 @@ -72,6 +72,26 @@ current.symbol = old; } + override void visitClassDecl(ClassDecl s) + { + auto old = current.symbol; + current.symbol = s.sym; + inFunctionBodyStack.push(false); + super.visitClassDecl(s); + inFunctionBodyStack.pop(); + current.symbol = old; + } + + override void visitInterfaceDecl(InterfaceDecl s) + { + auto old = current.symbol; + current.symbol = s.sym; + inFunctionBodyStack.push(false); + super.visitInterfaceDecl(s); + inFunctionBodyStack.pop(); + current.symbol = old; + } + DType typeOf(Identifier id, Scope sc) { if(auto i = cast(PointerIdentifier)id) @@ -124,6 +144,59 @@ } } + override void visitClassDecl(ClassDecl s) + { + auto st = s.env.findType(s.identifier).asClass; + s.sym = current.symbol.createMember( + s.identifier.get, + st, + s.env.find(s.identifier)); + + foreach (decl; s.decls) + { + DType type; + char[] name; + if (auto varDecl = cast(VarDecl)decl) + { + type = typeOf(varDecl.varType, varDecl.env); + name = varDecl.identifier.get; + } + else if (auto fd = cast(FuncDecl)decl) + { + type = fd.type; + name = fd.identifier.get; + } + st.addMember(type, name); + } + } + + override void visitInterfaceDecl(InterfaceDecl s) + { + auto st = s.env.findType(s.identifier).asInterface; + s.sym = current.symbol.createMember( + s.identifier.get, + st, + s.env.find(s.identifier)); + + foreach (decl; s.decls) + { + DType type; + char[] name; + if (auto varDecl = cast(VarDecl)decl) + { + type = typeOf(varDecl.varType, varDecl.env); + name = varDecl.identifier.get; + } + else if (auto fd = cast(FuncDecl)decl) + { + type = fd.type; + name = fd.identifier.get; + } + st.addMember(type, name); + } + } + + DType typeOf(Identifier id, Scope sc) { if(auto i = cast(PointerIdentifier)id) @@ -282,11 +355,38 @@ sc.types[s.identifier.get] = type; sc = push(); - Stdout(sc).newline; super.visitStructDecl(s); pop(sc); } + override void visitClassDecl(ClassDecl s) + { + auto sc = current(); + sc.put(s.identifier, s); + s.env = sc; + auto type = new DClass(s.identifier); + + sc.types[s.identifier.get] = type; + + sc = push(); + super.visitClassDecl(s); + pop(sc); + } + + override void visitInterfaceDecl(InterfaceDecl s) + { + auto sc = current(); + sc.put(s.identifier, s); + s.env = sc; + auto type = new DInterface(s.identifier); + + sc.types[s.identifier.get] = type; + + sc = push(); + super.visitInterfaceDecl(s); + pop(sc); + } + override void visitDeclStmt(DeclStmt d) { ++need_push;
--- a/sema/Visitor.d Mon Jul 21 01:05:20 2008 +0200 +++ b/sema/Visitor.d Mon Jul 21 17:41:40 2008 +0200 @@ -45,6 +45,10 @@ return visitImportDecl(cast(ImportDecl)decl); case DeclType.StructDecl: return visitStructDecl(cast(StructDecl)decl); + case DeclType.ClassDecl: + return visitClassDecl(cast(ClassDecl)decl); + case DeclType.InterfaceDecl: + return visitInterfaceDecl(cast(InterfaceDecl)decl); default: throw new Exception("Unknown declaration type"); } @@ -169,6 +173,38 @@ return DeclT.init; } + DeclT visitClassDecl(ClassDecl s) + { + visitExp(s.identifier); + + foreach (arg; s.decls) + visitDecl(arg); + + foreach (arg; s.baseClasses) + visitExp(arg); + + static if (is(DeclT == void)) + return; + else + return DeclT.init; + } + + DeclT visitInterfaceDecl(InterfaceDecl s) + { + visitExp(s.identifier); + + foreach (arg; s.decls) + visitDecl(arg); + + foreach (arg; s.baseClasses) + visitExp(arg); + + static if (is(DeclT == void)) + return; + else + return DeclT.init; + } + // Statements: StmtT visitReturnStmt(ReturnStmt s) {
--- a/tests/parser/public_1.d Mon Jul 21 01:05:20 2008 +0200 +++ b/tests/parser/public_1.d Mon Jul 21 17:41:40 2008 +0200 @@ -1,16 +1,30 @@ +module tests.parser.public_1; + public struct name { static: public void foo() { } - +public +{ private void bar() { } +auto: final int i; } +static: + public void food() + { + } + private void bard() + { + } + final int id; +} + void main() { }
--- a/tools/AstPrinter.d Mon Jul 21 01:05:20 2008 +0200 +++ b/tools/AstPrinter.d Mon Jul 21 17:41:40 2008 +0200 @@ -7,7 +7,8 @@ ast.Stmt, ast.Exp; -import basic.SourceManager; +import basic.SourceManager, + basic.Attribute; class AstPrinter { @@ -22,7 +23,8 @@ void print(Module m) { printBeginLine("module "); - printEndLine(m.moduleName); + print(m.moduleName); + printEndLine(";"); printEndLine(); foreach(decl ; m.decls) { @@ -38,6 +40,7 @@ case DeclType.FuncDecl: auto funcDecl = cast(FuncDecl)decl; printBeginLine(); + printAttribute(decl.att); printIdentifier(funcDecl.returnType); space; printIdentifier(funcDecl.identifier); @@ -51,6 +54,7 @@ case DeclType.VarDecl: auto varDecl = cast(VarDecl)decl; printBeginLine(); + printAttribute(decl.att); printExp(varDecl.varType); space; printExp(varDecl.identifier); @@ -64,6 +68,7 @@ case DeclType.StructDecl: auto structDecl = cast(StructDecl)decl; + printAttribute(decl.att); printBeginLine("struct "); printIdentifier(structDecl.identifier); printEndLine; @@ -73,13 +78,48 @@ printCloseBrace; break; + case DeclType.ClassDecl: + auto classDecl = cast(ClassDecl)decl; + printAttribute(decl.att); + printBeginLine("class "); + printIdentifier(classDecl.identifier); + foreach(i, iden ; classDecl.baseClasses ) + { + print(i ? " : " : ", "); + printIdentifier(iden); + } + printEndLine; + printOpenBrace; + foreach( var ; classDecl.decls) + printDecl(var); + printCloseBrace; + break; + + case DeclType.InterfaceDecl: + auto interfaceDecl = cast(InterfaceDecl)decl; + printAttribute(decl.att); + printBeginLine("interface "); + printIdentifier(interfaceDecl.identifier); + foreach(i, iden ; interfaceDecl.baseClasses ) + { + print(i ? " : " : ", "); + printIdentifier(iden); + } + printEndLine; + printOpenBrace; + foreach( var ; interfaceDecl.decls) + printDecl(var); + printCloseBrace; + break; + case DeclType.ImportDecl: auto i = cast(ImportDecl)decl; + printAttribute(decl.att); printBeginLine("import "); printEndLine(i.get); break; } - printEndLine(); +// printEndLine(); } void printStatement(Stmt stmt) @@ -218,6 +258,53 @@ printEndLine(tabIndex~"}"); } + void printAttribute(Attribute a) + { + switch(a.getExtern) + { + case Extern.C: + print("extern(C) "); + break; + case Extern.CPlusPlus: + print("extern(C++) "); + break; + case Extern.D: + break; + } + switch(a.getProtection) + { + case Protection.Public: + print("public "); + break; + case Protection.Private: + print("private "); + break; + case Protection.Package: + print("package "); + break; + case Protection.Protected: + print("protected "); + break; + case Protection.Export: + print("export "); + break; + } + if ( a.getStatic ) + print("static "); + if ( a.getFinal ) + print("final "); + if ( a.getConst ) + print("const "); + if ( a.getAbstract ) + print("abstract "); + if ( a.getOverride ) + print("override "); + if ( a.getDepracted ) + print("depracted "); + if ( a.getAuto ) + print("auto "); + } + void printBeginLine(char[] line = "") { Stdout(tabIndex~line);