# HG changeset patch # User Anders Johnsen # Date 1210005860 -7200 # Node ID 771ac63898e2caddd11b7b4903078a8ce6d1fac8 # Parent 1a24e61eb104fb131e326972f95081ceb990c940 A few better parser errors plus renaming most of the sema classes to match that they do now. Some have changes a lot. diff -r 1a24e61eb104 -r 771ac63898e2 ast/Decl.d --- a/ast/Decl.d Mon May 05 17:07:16 2008 +0200 +++ b/ast/Decl.d Mon May 05 18:44:20 2008 +0200 @@ -7,7 +7,7 @@ import tango.io.Stdout; -import sema.SymbolTable, +import sema.Scope, sema.DType, basic.SmallArray; diff -r 1a24e61eb104 -r 771ac63898e2 ast/Exp.d --- a/ast/Exp.d Mon May 05 17:07:16 2008 +0200 +++ b/ast/Exp.d Mon May 05 18:44:20 2008 +0200 @@ -8,7 +8,7 @@ import lexer.Token; -import sema.SymbolTable, +import sema.Scope, sema.DType; enum ExpType diff -r 1a24e61eb104 -r 771ac63898e2 ast/Stmt.d --- a/ast/Stmt.d Mon May 05 17:07:16 2008 +0200 +++ b/ast/Stmt.d Mon May 05 18:44:20 2008 +0200 @@ -7,7 +7,7 @@ import ast.Exp, ast.Decl; -import sema.SymbolTable, +import sema.Scope, basic.SourceLocation, misc.Error; diff -r 1a24e61eb104 -r 771ac63898e2 basic/Message.d --- a/basic/Message.d Mon May 05 17:07:16 2008 +0200 +++ b/basic/Message.d Mon May 05 18:44:20 2008 +0200 @@ -19,6 +19,13 @@ public import basic.Messages; +enum ExitLevel +{ + Normal = 1, + Lexer = 2, + Parser = 3, +} + class MessageHandler { public: @@ -28,31 +35,36 @@ this.src_mgr = src_mgr; } - Message report(uint opcode, SLoc location, bool fatal = false) + Message report(uint opcode, SLoc location) { - Message m = new Message(opcode, location, src_mgr); + Message m = new Message(opcode, location, src_mgr, this); messages ~= m; - if(fatal) - checkErrors(); return m; } - void checkErrors() + void checkErrors(ExitLevel exitlevel = ExitLevel.Normal) { if(messages.length == 0) return; + if(warnings) + checkWarnings; foreach(m ; messages) if(m.type == MessageType.Error) { Stdout(m).newline; } - exit(1); + exit(exitlevel); } void checkWarnings() { + foreach(m ; messages) + if(m.type == MessageType.Warning) + { + Stdout(m).newline; + } } void showWarnings(bool value) @@ -69,12 +81,13 @@ class Message { - this(int opcode, SLoc location, SourceManager src_mgr) + this(int opcode, SLoc location, SourceManager src_mgr, MessageHandler msg_handler) { this.src_mgr = src_mgr; this.location = location; args ~= Messages[opcode].message; this.type = Messages[opcode].type; + this.msg_handler = msg_handler; } char[] toString() @@ -95,7 +108,7 @@ char[] line = src_mgr.getLine(location); char[] marks = line.dup; marks[] = ' '; - size_t p = src_mgr.getOffsetToLine(location); + size_t p = src_mgr.getColumn(location); marks[p .. p + t.length] = '^'; msg ~= "\n "; @@ -141,6 +154,12 @@ return arg(sym.type.name ~ " " ~ sym.id.get); } + Message fatal(ExitLevel exitlevel = ExitLevel.Normal) + { + msg_handler.checkErrors(exitlevel); + return this; + } + /* Message loc(SLoc loc) { @@ -154,4 +173,5 @@ char[][] args; SLoc location; SourceManager src_mgr; + MessageHandler msg_handler; } diff -r 1a24e61eb104 -r 771ac63898e2 basic/Messages.d --- a/basic/Messages.d Mon May 05 17:07:16 2008 +0200 +++ b/basic/Messages.d Mon May 05 18:44:20 2008 +0200 @@ -2,7 +2,6 @@ enum : uint { - InvalidType, InvalidSymbol, InvalidIlligaleType, UnexpectedEOFBlock, @@ -16,7 +15,9 @@ UnexpectedTokType, ExpectedIdAfterDot, ExpectedExp, - ExpectedCastType + ExpectedCastType, + InvalidDeclType, + InvalidType, } enum MessageType @@ -36,7 +37,6 @@ static this() { Messages = [ - InvalidType : MessageEntry(MessageType.Error, "InvalidType"), UnexpectedEOFBlock : MessageEntry(MessageType.Error, "Unexpected end of file. Unclosed comment block"), InvalidSymbol : MessageEntry(MessageType.Error, "Read invalid symbol: '%0'"), OnlyOneDotFloating : MessageEntry(MessageType.Error, "Only one '.' is allowed in an floating number"), @@ -49,6 +49,8 @@ UnexpectedTokType : MessageEntry(MessageType.Error, "Unexpected token in Type parsing. Got %0"), ExpectedIdAfterDot : MessageEntry(MessageType.Error, "Expected identifier after '.'"), ExpectedExp : MessageEntry(MessageType.Error, "Expected expression"), - ExpectedCastType : MessageEntry(MessageType.Error, "Expected cast type") + ExpectedCastType : MessageEntry(MessageType.Error, "Expected cast type"), + InvalidDeclType : MessageEntry(MessageType.Error, "Invalid declaration type"), + InvalidType : MessageEntry(MessageType.Error, "Invalid type") ]; } diff -r 1a24e61eb104 -r 771ac63898e2 basic/SourceManager.d --- a/basic/SourceManager.d Mon May 05 17:07:16 2008 +0200 +++ b/basic/SourceManager.d Mon May 05 18:44:20 2008 +0200 @@ -94,13 +94,12 @@ } /** - Extracts a string containing the entire line loc appears in. + Gets the column of where the loc appears. **/ - int getOffsetToLine(SourceLocation loc) + int getColumn(SourceLocation loc) { - // The line is extracted by getting two pointers to the exact location - // and decreasing one until the nearest newline while the other ptr is - // increased to the nearest newline. + // Use same approach as getLine + CP* cp = &checkpoints[loc.fileID]; char* ptr = cp.data.ptr + loc.fileOffset; char* ptr_lo = ptr; diff -r 1a24e61eb104 -r 771ac63898e2 dang/compiler.d --- a/dang/compiler.d Mon May 05 17:07:16 2008 +0200 +++ b/dang/compiler.d Mon May 05 18:44:20 2008 +0200 @@ -24,9 +24,9 @@ import sema.Visitor, sema.AstAction, - sema.SymbolTableBuilder, - sema.ImplicitCast, - sema.Declarations; + sema.ScopeBuilder, + sema.ScopeCheck, + sema.TypeCheck; import Opt = dang.OptParse; @@ -190,19 +190,19 @@ auto action = new AstAction(src_mgr); auto decls = cast(Decl[])parser.parse(src_mgr, lexer, action); timings ~= Measurement("Lex + Parse", watch.stop); - messages.checkErrors(); + messages.checkErrors(ExitLevel.Parser); StopWatch watch2; watch.start; watch2.start; - (new SymbolTableBuilder).visit(decls); - auto symbol_table = watch2.stop; + (new ScopeBuilder).visit(decls); + auto scope_builder = watch2.stop; watch2.start; - (new Declarations).visit(decls); - auto declarations = watch2.stop; + (new ScopeCheck).visit(decls); + auto scope_check = watch2.stop; watch2.start; - (new ImplicitCast).visit(decls); - auto implicit_casts = watch2.stop; + (new TypeCheck).visit(decls); + auto type_check = watch2.stop; watch2.start; foreach (decl; decls) @@ -210,9 +210,9 @@ auto simplify = watch2.stop; auto extra_stuff = watch.stop; timings ~= Measurement("Extra stuff", watch.stop); - timings ~= Measurement(" - Building scopes", symbol_table); - timings ~= Measurement(" - Extracting declarations", declarations); - timings ~= Measurement(" - Making casts explicit", implicit_casts); + timings ~= Measurement(" - Building scopes", scope_builder); + timings ~= Measurement(" - Checking scopes", scope_check); + timings ~= Measurement(" - Checking types", type_check); postParse(decls, src_mgr); } diff -r 1a24e61eb104 -r 771ac63898e2 gen/CodeGen.d --- a/gen/CodeGen.d Mon May 05 17:07:16 2008 +0200 +++ b/gen/CodeGen.d Mon May 05 18:44:20 2008 +0200 @@ -15,7 +15,7 @@ import lexer.Token; -import sema.SymbolTableBuilder, +import sema.Scope, sema.Visitor; private char[] genBuildCmp(char[] p) @@ -136,7 +136,7 @@ table.leaveScope; - debug m.verify(); +// debug m.verify(); if(optimize) m.optimize(inline); diff -r 1a24e61eb104 -r 771ac63898e2 lexer/Lexer.d --- a/lexer/Lexer.d Mon May 05 17:07:16 2008 +0200 +++ b/lexer/Lexer.d Mon May 05 18:44:20 2008 +0200 @@ -356,7 +356,9 @@ CharType c = charTable[current]; if(c == CharType.INVALID) - messages.report(InvalidSymbol, Loc(), 1).arg(Integer.toString(cast(int)current)); + messages.report(InvalidSymbol, Loc()) + .arg(Integer.toString(cast(int)current)) + .fatal(ExitLevel.Lexer); return c; diff -r 1a24e61eb104 -r 771ac63898e2 parser/Parser.d --- a/parser/Parser.d Mon May 05 17:07:16 2008 +0200 +++ b/parser/Parser.d Mon May 05 18:44:20 2008 +0200 @@ -48,25 +48,41 @@ if (t.isBasicType || t.isIdentifier) { - Id type = Id(lexer.next); - Id iden = Id(require(Tok.Identifier)); - Token next = lexer.peek(); - if (next.type == Tok.Seperator) - { - Token sep = lexer.next(); - return action.actOnDeclarator(type, iden, null); - } - else if (next.type == Tok.Assign) + Id type; + Id iden; + int len = peekParseType; + if(lexer.peek(len).type == Tok.Identifier && len != 0) { - Token assign = lexer.next(); - Exp exp = parseExpression(); - require(Tok.Seperator); - return action.actOnDeclarator(type, iden, exp); + type = parseType; +parseDeclAfterInvalidType: + iden = Id(require(Tok.Identifier)); + Token next = lexer.peek(); + if (next.type == Tok.Seperator) + { + Token sep = lexer.next(); + return action.actOnDeclarator(type, iden, null); + } + else if (next.type == Tok.Assign) + { + Token assign = lexer.next(); + Exp exp = parseExpression(); + require(Tok.Seperator); + return action.actOnDeclarator(type, iden, exp); + } + else if (next.type == Tok.OpenParentheses) + return parseFunc(type, iden); + else + messages.report(UnexpectedTok, next.location).arg(next.getType); } - else if (next.type == Tok.OpenParentheses) - return parseFunc(type, iden); - else - messages.report(UnexpectedTok, next.location).arg(next.getType); + t = lexer.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); + goto parseDeclAfterInvalidType; } else if (t.type == Tok.Struct) { @@ -75,7 +91,10 @@ return parseStruct(type, iden); } - messages.report(UnexpectedTok, t.location).arg(t.getType); + messages.report(UnexpectedTok, t.location) + .arg(t.getType) + .arg(Tok.Identifier) + .fatal(ExitLevel.Parser); } /** @@ -330,8 +349,7 @@ Id currentType; if ( !(type.isBasicType || type.type == Tok.Identifier) ) - messages.report(UnexpectedTokSingle, type.location) - .arg(type.getType); + messages.report(InvalidType, type.location); currentType = Id(type); type = lexer.peek; @@ -346,7 +364,8 @@ else { lexer.next; - currentType = ArrayId(currentType, action.actOnNumericConstant(require(Tok.Integer))); + if(lexer.peek.type == Tok.Integer) + currentType = ArrayId(currentType, action.actOnNumericConstant(require(Tok.Integer))); require(Tok.CloseBracket); } @@ -379,10 +398,15 @@ { if(lexer.peek(i++).type != Tok.OpenBracket) return 0; - if(lexer.peek(i++).type != Tok.Integer) - return 0; - if(lexer.peek(i++).type != Tok.CloseBracket) - return 0; + if(lexer.peek(i).type == Tok.Integer) + { + i++; + if(lexer.peek(i++).type != Tok.CloseBracket) + return 0; + } + else + if(lexer.peek(i++).type != Tok.CloseBracket) + return 0; } type = lexer.peek(i); @@ -475,8 +499,8 @@ else if (next.type == Tok.Integer) return action.actOnNumericConstant(next); - messages.report(ExpectedExp, next.location, true); -// assert(0, "Should not happen"); + messages.report(ExpectedExp, next.location) + .fatal(ExitLevel.Parser); return null; } diff -r 1a24e61eb104 -r 771ac63898e2 sema/Declarations.d --- a/sema/Declarations.d Mon May 05 17:07:16 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -module sema.Declarations; - -import sema.Visitor, - sema.DType; - -import tango.io.Stdout; - -import misc.Error; - -class Declarations : Visitor!(void) -{ - int[char[]] types; - - private Error error(uint line, char[] msg) - { - return new Error(msg); - } - - override void visitIdentifier(Identifier i) - { - auto symbol = i.env.find(i); - - if(symbol is null) - throw error(__LINE__, "Undefined identifier: '%0'") - .arg(i.get); - //.loc(i.token.location); - } - - override void visitVarDecl(VarDecl d) - { - if(!d.env.findType(d.varType)) - throw error(__LINE__, "Undefined type: '%0'") - .arg(d.varType.get); - //.loc(d.varType.token.location); - - visitExp(d.identifier); - if (d.init) - visitExp(d.init); - } - - override void visitFuncDecl(FuncDecl f) - { - visitExp(f.identifier); - - foreach (stmt; f.statements) - visitStmt(stmt); - } - - override void visitCastExp(CastExp exp) - { - visitExp(exp.exp); - } - - override void visitMemberReference(MemberReference m) - { - switch(m.target.expType) - { - case ExpType.Identifier: - auto target = cast(Identifier)m.target; - auto child = m.child; - auto st = cast(DStruct)(target.env.find(target).type); - if((child.get in st.members) is null) - throw error(__LINE__, "%0 %1 has no member %2") - .arg(st.name) - .arg(target.get) - .arg(child.get); - //.tok(child.token); - break; - case ExpType.MemberReference: - break; - } - } - - private bool isType(char[] s) - { - return (s in types? true : false); - } -} - diff -r 1a24e61eb104 -r 771ac63898e2 sema/ImplicitCast.d --- a/sema/ImplicitCast.d Mon May 05 17:07:16 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -module sema.ImplicitCast; - -import sema.Visitor, - sema.DType; - -import tango.io.Stdout; - -import misc.Error, - basic.SourceLocation; - -class ImplicitCast : Visitor!(void) -{ - private Error error(uint line, char[] msg) - { - return new Error(msg); - } - - override void visitBinaryExp(BinaryExp exp) - { - super.visitBinaryExp(exp); - - if(exp.left.type.byteSize > exp.right.type.byteSize) - { - if(!exp.right.type.hasImplicitConversionTo(exp.left.type)) - throw error(__LINE__, "Cannot make implicit cast"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(exp.left.type.name), - exp.right); - castExp.env = exp.env; - exp.right = castExp; - } - - if(exp.left.type.byteSize < exp.right.type.byteSize) - { - if(!exp.left.type.hasImplicitConversionTo(exp.right.type)) - throw error(__LINE__, "Cannot make implicit cast"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(exp.right.type.name), - exp.left); - castExp.env = exp.env; - exp.left = castExp; - } - - } - - override void visitCallExp(CallExp exp) - { - super.visitCallExp(exp); - - Exp[] newArgs; - - foreach(i, arg; exp.args) - { - auto argType = (cast(DFunction)exp.exp.type).params[i]; - auto expType = arg.type; - if(argType.byteSize != expType.byteSize) - { - if(!expType.hasImplicitConversionTo(argType)) - throw error(__LINE__, "Cannot make implicit cast"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(argType.name), - arg); - castExp.env = exp.exp.env; - newArgs ~= castExp; - } - else - newArgs ~= arg; - } - - exp.args = newArgs; - } - - override void visitAssignExp(AssignExp exp) - { - super.visitAssignExp(exp); - - auto identifierType = exp.identifier.type; - auto expType = exp.exp.type; - - if(identifierType != expType) - { - if(!expType.hasImplicitConversionTo(identifierType)) - throw error(__LINE__, "Cannot make implicit cast between"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(expType.name), - exp.exp); - castExp.env = exp.exp.env; - exp.exp = castExp; - } - } - - override void visitReturnStmt(ReturnStmt stmt) - { - super.visitReturnStmt(stmt); - - if(stmt.exp) - { - auto returnType = stmt.env.parentFunction.type.asFunction.returnType; - auto expType = stmt.exp.type; - if(returnType != expType) - { - if(!expType.hasImplicitConversionTo(returnType)) - throw error(__LINE__, "Cannot make implicit cast"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(returnType.name), - stmt.exp); - castExp.env = stmt.exp.env; - stmt.exp = castExp; - } - } - } - - override void visitVarDecl(VarDecl decl) - { - super.visitVarDecl(decl); - - if(decl.init) - { - auto varType = decl.type; - auto expType = decl.init.type; - if(varType.byteSize != expType.byteSize) - { - if(!expType.hasImplicitConversionTo(varType)) - throw error(__LINE__, "Cannot make implicit cast"); - - auto castExp = new CastExp( - SLoc.Invalid, - new Identifier(varType.name), - decl.init); - castExp.env = decl.init.env; - decl.init = castExp; - } - } - } -} - diff -r 1a24e61eb104 -r 771ac63898e2 sema/Scope.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sema/Scope.d Mon May 05 18:44:20 2008 +0200 @@ -0,0 +1,108 @@ +module sema.Scope; + +import tango.io.Stdout; + +import lexer.Token, + ast.Decl, + ast.Exp; + +import sema.DType; + +public +import sema.Symbol; + +class Scope +{ + this() {} + this(Scope enclosing) + { + this.enclosing = enclosing; + this.func = enclosing.func; + } + + Scope enclosing; + + Symbol add(Identifier id) + { + auto s = new Symbol; + s.id = id; + symbols[id] = s; + return s; + } + + Symbol find(Identifier id) + { + if(!id) + return null; + if (auto sym = id in symbols) + return *sym; + if (enclosing !is null) + return enclosing.find(id); + return null; + } + + DType findType(Identifier id) + { + if (auto type = id.get in types) + return *type; + if (enclosing !is null) + return enclosing.findType(id); + return null; + } + + char[][] names() + { + char[][] res; + if (parentFunction() !is null) + res ~= "pf: " ~ parentFunction().identifier.get; + if (enclosing) + res = enclosing.names; + foreach (id, sym; symbols) + res ~= sym.id.name ~ " : " ~ (sym.type is null? "?" : sym.type.name); + return res; + } + + FuncDecl parentFunction() + { + if (func !is null) + return func; + else if (enclosing !is null) + return enclosing.parentFunction(); + else + return null; + } + + int stmtIndex() + { + if (currentStmtIndex != -1) + return currentStmtIndex; + else if (enclosing !is null) + return enclosing.stmtIndex(); + else + return -1; + } + + int opEquals(Object o) + { + return this is o; + } + + char[] toString() + { + if (func) + return Stdout.layout.convert("{}: {}", func.identifier.get, symbols.length); + return Stdout.layout.convert("root: {}", symbols.length); + } + + FuncDecl parentFunction(FuncDecl f) + { + func = f; + return f; + } + DType[char[]] types; + int currentStmtIndex = -1; +private: + Symbol[Identifier] symbols; + FuncDecl func; +} + diff -r 1a24e61eb104 -r 771ac63898e2 sema/ScopeBuilder.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sema/ScopeBuilder.d Mon May 05 18:44:20 2008 +0200 @@ -0,0 +1,227 @@ +module sema.ScopeBuilder; + +import tango.io.Stdout, + tango.core.Array : find; + +public +import sema.Scope; + +import sema.Visitor, + basic.SmallArray; + +class ForwardReference : Visitor!(void) +{ + override void visit(Decl[] decls) + { + foreach (decl; decls) + visitDecl(decl); + } + + override void visitFuncDecl(FuncDecl d) + { + visitExp(d.returnType); + visitExp(d.identifier); + foreach (arg; d.funcArgs) + visitDecl(arg); + foreach (stmt; d.statements) + visitStmt(stmt); + + auto sym = d.env.find(d.identifier); + sym.type = d.type; + } + + override void visitVarDecl(VarDecl d) + { + visitExp(d.varType); + visitExp(d.identifier); + + if (d.init) + visitExp(d.init); + + d.env.find(d.identifier).type = typeOf(d.varType, d.env); + } + + override void visitStructDecl(StructDecl s) + { + DType[char[]] types; + + auto st = s.env.types[s.identifier.get].asStruct; + foreach(varDecl ; s.vars) + st.addMember(typeOf(varDecl.varType, varDecl.env), varDecl.identifier.get); + + super.visitStructDecl(s); + } + + DType typeOf(Identifier id, Scope sc) + { + if(auto i = cast(PointerIdentifier)id) + return (typeOf(i.pointerOf, sc)).getPointerTo(); + if(auto i = cast(ArrayIdentifier)id) + return typeOf(i.arrayOf, sc).getAsArray(i.size); + return sc.findType(id); + } +} + +class ScopeBuilder : Visitor!(void) +{ + this() + { + table ~= new Scope; + table[0].types["void"] = DType.Void; + table[0].types["bool"] = DType.Bool; + table[0].types["byte"] = DType.Byte; + table[0].types["ubyte"] = DType.UByte; + table[0].types["short"] = DType.Short; + table[0].types["ushort"] = DType.UShort; + table[0].types["int"] = DType.Int; + table[0].types["uint"] = DType.UInt; + table[0].types["long"] = DType.Long; + table[0].types["ulong"] = DType.ULong; + } + + override void visit(Decl[] decls) + { + foreach (decl; decls) + visitDecl(decl); + auto fr = new ForwardReference(); + fr.visit(decls); + } + + override void visitDecl(Decl d) + { + d.env = current(); + super.visitDecl(d); + } + + override void visitStmt(Stmt s) + { + s.env = current(); + s.stmtIndex = s.env.stmtIndex; + super.visitStmt(s); + } + + override void visitExp(Exp e) + { + e.env = current(); + e.stmtIndex = e.env.stmtIndex; + super.visitExp(e); + } + + override void visitFuncDecl(FuncDecl d) + { + auto sym = current().add(d.identifier); + auto sc = push(); + + visitExp(d.returnType); + visitExp(d.identifier); + d.env = current(); + sc.parentFunction = d; + foreach (arg; d.funcArgs) + visitDecl(arg); + foreach (stmt; d.statements) + { + sc.currentStmtIndex++; + visitStmt(stmt); + } + pop(sc); + } + + override void visitVarDecl(VarDecl d) + { + if (d.init) + visitExp(d.init); + + if (need_push > 0 && current().parentFunction !is null) { + push(); + --need_push; + } + + auto sc = current(); + auto sym = sc.add(d.identifier); + d.env = sc; + visitExp(d.varType); + visitExp(d.identifier); + } + + override void visitStructDecl(StructDecl s) + { + auto sc = current(); + auto sym = sc.add(s.identifier); + s.env = sc; + auto type = new DStruct(s.identifier); + + sc.types[s.identifier.get] = type; + + sc = push(); + super.visitStructDecl(s); + pop(sc); + } + + override void visitDeclStmt(DeclStmt d) + { + ++need_push; + super.visitDeclStmt(d); + } + private uint need_push = 0; + + override void visitIfStmt(IfStmt s) + { + s.env = current(); + visitExp(s.cond); + auto sc = push(); + visitStmt(s.then_body); + pop(sc); + + if (s.else_body !is null) + { + sc = push(); + visitStmt(s.else_body); + pop(sc); + } + } + + override void visitWhileStmt(WhileStmt s) + { + s.env = current(); + auto sc = push(); + super.visitWhileStmt(s); + pop(sc); + } + + override void visitCompoundStmt(CompoundStatement s) + { + s.env = current(); + auto sc = push(); + super.visitCompoundStmt(s); + pop(sc); + } + +private: + Scope[] table; + + Scope push() + { + auto sc = new Scope(current()); + table ~= sc; + return sc; + } + + Scope pop(Scope sc = null) + { + if (sc !is null) + { + table.length = table.find(sc); + return sc; + } + + auto res = table[$ - 1]; + table.length = table.length - 1; + return res; + } + + Scope current() + { + return table[$ - 1]; + } +} + diff -r 1a24e61eb104 -r 771ac63898e2 sema/ScopeCheck.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sema/ScopeCheck.d Mon May 05 18:44:20 2008 +0200 @@ -0,0 +1,79 @@ +module sema.ScopeCheck; + +import sema.Visitor, + sema.DType; + +import tango.io.Stdout; + +import misc.Error; + +class ScopeCheck : Visitor!(void) +{ + int[char[]] types; + + private Error error(uint line, char[] msg) + { + return new Error(msg); + } + + override void visitIdentifier(Identifier i) + { + auto symbol = i.env.find(i); + + if(symbol is null) + throw error(__LINE__, "Undefined identifier: '%0'") + .arg(i.get); + //.loc(i.token.location); + } + + override void visitVarDecl(VarDecl d) + { + if(!d.env.findType(d.varType)) + throw error(__LINE__, "Undefined type: '%0'") + .arg(d.varType.get); + //.loc(d.varType.token.location); + + visitExp(d.identifier); + if (d.init) + visitExp(d.init); + } + + override void visitFuncDecl(FuncDecl f) + { + visitExp(f.identifier); + + foreach (stmt; f.statements) + visitStmt(stmt); + } + + override void visitCastExp(CastExp exp) + { + visitExp(exp.exp); + } + + override void visitMemberReference(MemberReference m) + { + switch(m.target.expType) + { + case ExpType.Identifier: + auto target = cast(Identifier)m.target; + auto child = m.child; + auto st = cast(DStruct)(target.env.find(target).type); + if((child.get in st.members) is null) + throw error(__LINE__, "%0 %1 has no member %2") + .arg(st.name) + .arg(target.get) + .arg(child.get); + //.tok(child.token); + break; + case ExpType.MemberReference: + break; + } + } + + private bool isType(char[] s) + { + return (s in types? true : false); + } +} + diff -r 1a24e61eb104 -r 771ac63898e2 sema/SymbolTable.d --- a/sema/SymbolTable.d Mon May 05 17:07:16 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -module sema.SymbolTable; - -import tango.io.Stdout; - -import lexer.Token, - ast.Decl, - ast.Exp; - -import sema.DType; - -public -import sema.Symbol; - -class Scope -{ - this() {} - this(Scope enclosing) - { - this.enclosing = enclosing; - this.func = enclosing.func; - } - - Scope enclosing; - - Symbol add(Identifier id) - { - auto s = new Symbol; - s.id = id; - symbols[id] = s; - return s; - } - - Symbol find(Identifier id) - { - if(!id) - return null; - if (auto sym = id in symbols) - return *sym; - if (enclosing !is null) - return enclosing.find(id); - return null; - } - - DType findType(Identifier id) - { - if (auto type = id.get in types) - return *type; - if (enclosing !is null) - return enclosing.findType(id); - return null; - } - - char[][] names() - { - char[][] res; - if (parentFunction() !is null) - res ~= "pf: " ~ parentFunction().identifier.get; - if (enclosing) - res = enclosing.names; - foreach (id, sym; symbols) - res ~= sym.id.name ~ " : " ~ (sym.type is null? "?" : sym.type.name); - return res; - } - - FuncDecl parentFunction() - { - if (func !is null) - return func; - else if (enclosing !is null) - return enclosing.parentFunction(); - else - return null; - } - - int stmtIndex() - { - if (currentStmtIndex != -1) - return currentStmtIndex; - else if (enclosing !is null) - return enclosing.stmtIndex(); - else - return -1; - } - - int opEquals(Object o) - { - return this is o; - } - - char[] toString() - { - if (func) - return Stdout.layout.convert("{}: {}", func.identifier.get, symbols.length); - return Stdout.layout.convert("root: {}", symbols.length); - } - - FuncDecl parentFunction(FuncDecl f) - { - func = f; - return f; - } - DType[char[]] types; - int currentStmtIndex = -1; -private: - Symbol[Identifier] symbols; - FuncDecl func; -} - diff -r 1a24e61eb104 -r 771ac63898e2 sema/SymbolTableBuilder.d --- a/sema/SymbolTableBuilder.d Mon May 05 17:07:16 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -module sema.SymbolTableBuilder; - -import tango.io.Stdout, - tango.core.Array : find; - -public -import sema.SymbolTable; - -import sema.Visitor, - basic.SmallArray; - -class SymbolTableBuilder : Visitor!(void) -{ - override void visit(Decl[] decls) - { - auto sb = new ScopeBuilder(); - sb.visit(decls); - foreach (decl; decls) - visitDecl(decl); - } - - override void visitFuncDecl(FuncDecl d) - { - visitExp(d.returnType); - visitExp(d.identifier); - foreach (arg; d.funcArgs) - visitDecl(arg); - foreach (stmt; d.statements) - visitStmt(stmt); - - auto sym = d.env.find(d.identifier); - sym.type = d.type; - } - - override void visitVarDecl(VarDecl d) - { - visitExp(d.varType); - visitExp(d.identifier); - - if (d.init) - visitExp(d.init); - - d.env.find(d.identifier).type = typeOf(d.varType, d.env); - } - - override void visitStructDecl(StructDecl s) - { - DType[char[]] types; - - auto st = s.env.types[s.identifier.get].asStruct; - foreach(varDecl ; s.vars) - st.addMember(typeOf(varDecl.varType, varDecl.env), varDecl.identifier.get); - - super.visitStructDecl(s); - } - - DType typeOf(Identifier id, Scope sc) - { - if(auto i = cast(PointerIdentifier)id) - return (typeOf(i.pointerOf, sc)).getPointerTo(); - if(auto i = cast(ArrayIdentifier)id) - return typeOf(i.arrayOf, sc).getAsArray(i.size); - return sc.findType(id); - } -} - -class ScopeBuilder : Visitor!(void) -{ - this() - { - table ~= new Scope; - table[0].types["void"] = DType.Void; - table[0].types["bool"] = DType.Bool; - table[0].types["byte"] = DType.Byte; - table[0].types["ubyte"] = DType.UByte; - table[0].types["short"] = DType.Short; - table[0].types["ushort"] = DType.UShort; - table[0].types["int"] = DType.Int; - table[0].types["uint"] = DType.UInt; - table[0].types["long"] = DType.Long; - table[0].types["ulong"] = DType.ULong; - } - - override void visit(Decl[] decls) - { - foreach (decl; decls) - visitDecl(decl); - } - - override void visitDecl(Decl d) - { - d.env = current(); - super.visitDecl(d); - } - - override void visitStmt(Stmt s) - { - s.env = current(); - s.stmtIndex = s.env.stmtIndex; - super.visitStmt(s); - } - - override void visitExp(Exp e) - { - e.env = current(); - e.stmtIndex = e.env.stmtIndex; - super.visitExp(e); - } - - override void visitFuncDecl(FuncDecl d) - { - auto sym = current().add(d.identifier); - auto sc = push(); - - visitExp(d.returnType); - visitExp(d.identifier); - d.env = current(); - sc.parentFunction = d; - foreach (arg; d.funcArgs) - visitDecl(arg); - foreach (stmt; d.statements) - { - sc.currentStmtIndex++; - visitStmt(stmt); - } - pop(sc); - } - - override void visitVarDecl(VarDecl d) - { - if (d.init) - visitExp(d.init); - - if (need_push > 0 && current().parentFunction !is null) { - push(); - --need_push; - } - - auto sc = current(); - auto sym = sc.add(d.identifier); - d.env = sc; - visitExp(d.varType); - visitExp(d.identifier); - } - - override void visitStructDecl(StructDecl s) - { - auto sc = current(); - auto sym = sc.add(s.identifier); - s.env = sc; - auto type = new DStruct(s.identifier); - - sc.types[s.identifier.get] = type; - - sc = push(); - super.visitStructDecl(s); - pop(sc); - } - - override void visitDeclStmt(DeclStmt d) - { - ++need_push; - super.visitDeclStmt(d); - } - private uint need_push = 0; - - override void visitIfStmt(IfStmt s) - { - s.env = current(); - visitExp(s.cond); - auto sc = push(); - visitStmt(s.then_body); - pop(sc); - - if (s.else_body !is null) - { - sc = push(); - visitStmt(s.else_body); - pop(sc); - } - } - - override void visitWhileStmt(WhileStmt s) - { - s.env = current(); - auto sc = push(); - super.visitWhileStmt(s); - pop(sc); - } - - override void visitCompoundStmt(CompoundStatement s) - { - s.env = current(); - auto sc = push(); - super.visitCompoundStmt(s); - pop(sc); - } - -private: - Scope[] table; - - Scope push() - { - auto sc = new Scope(current()); - table ~= sc; - return sc; - } - - Scope pop(Scope sc = null) - { - if (sc !is null) - { - table.length = table.find(sc); - return sc; - } - - auto res = table[$ - 1]; - table.length = table.length - 1; - return res; - } - - Scope current() - { - return table[$ - 1]; - } -} - diff -r 1a24e61eb104 -r 771ac63898e2 sema/TypeCheck.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sema/TypeCheck.d Mon May 05 18:44:20 2008 +0200 @@ -0,0 +1,146 @@ +module sema.TypeCheck; + +import sema.Visitor, + sema.DType; + +import tango.io.Stdout; + +import misc.Error, + basic.SourceLocation; + +class TypeCheck : Visitor!(void) +{ + private Error error(uint line, char[] msg) + { + return new Error(msg); + } + + override void visitBinaryExp(BinaryExp exp) + { + super.visitBinaryExp(exp); + + if(exp.left.type.byteSize > exp.right.type.byteSize) + { + if(!exp.right.type.hasImplicitConversionTo(exp.left.type)) + throw error(__LINE__, "Cannot make implicit cast"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(exp.left.type.name), + exp.right); + castExp.env = exp.env; + exp.right = castExp; + } + + if(exp.left.type.byteSize < exp.right.type.byteSize) + { + if(!exp.left.type.hasImplicitConversionTo(exp.right.type)) + throw error(__LINE__, "Cannot make implicit cast"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(exp.right.type.name), + exp.left); + castExp.env = exp.env; + exp.left = castExp; + } + + } + + override void visitCallExp(CallExp exp) + { + super.visitCallExp(exp); + + Exp[] newArgs; + + foreach(i, arg; exp.args) + { + auto argType = (cast(DFunction)exp.exp.type).params[i]; + auto expType = arg.type; + if(argType.byteSize != expType.byteSize) + { + if(!expType.hasImplicitConversionTo(argType)) + throw error(__LINE__, "Cannot make implicit cast"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(argType.name), + arg); + castExp.env = exp.exp.env; + newArgs ~= castExp; + } + else + newArgs ~= arg; + } + + exp.args = newArgs; + } + + override void visitAssignExp(AssignExp exp) + { + super.visitAssignExp(exp); + + auto identifierType = exp.identifier.type; + auto expType = exp.exp.type; + + if(identifierType != expType) + { + if(!expType.hasImplicitConversionTo(identifierType)) + throw error(__LINE__, "Cannot make implicit cast between"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(expType.name), + exp.exp); + castExp.env = exp.exp.env; + exp.exp = castExp; + } + } + + override void visitReturnStmt(ReturnStmt stmt) + { + super.visitReturnStmt(stmt); + + if(stmt.exp) + { + auto returnType = stmt.env.parentFunction.type.asFunction.returnType; + auto expType = stmt.exp.type; + if(returnType != expType) + { + if(!expType.hasImplicitConversionTo(returnType)) + throw error(__LINE__, "Cannot make implicit cast"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(returnType.name), + stmt.exp); + castExp.env = stmt.exp.env; + stmt.exp = castExp; + } + } + } + + override void visitVarDecl(VarDecl decl) + { + super.visitVarDecl(decl); + + if(decl.init) + { + auto varType = decl.type; + auto expType = decl.init.type; + if(varType.byteSize != expType.byteSize) + { + if(!expType.hasImplicitConversionTo(varType)) + throw error(__LINE__, "Cannot make implicit cast"); + + auto castExp = new CastExp( + SLoc.Invalid, + new Identifier(varType.name), + decl.init); + castExp.env = decl.init.env; + decl.init = castExp; + } + } + } +} +