Mercurial > lcfOS
changeset 166:da0087b82fbe
Improved type checking
author | Windel Bouwman |
---|---|
date | Fri, 22 Mar 2013 16:15:31 +0100 |
parents | 598d3888a11c |
children | 0b5b2ee6b435 |
files | python/c3/analyse.py python/c3/astnodes.py python/c3/builder.py python/c3/parser.py python/c3/typecheck.py python/c3/visitor.py python/testc3.py |
diffstat | 7 files changed, 64 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/python/c3/analyse.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/analyse.py Fri Mar 22 16:15:31 2013 +0100 @@ -22,7 +22,7 @@ def a1(self, sym): pass def analyze(self, sym): - if type(sym) is Variable: + if type(sym) in [Variable, Constant]: sym.typ = self.resolveDesignator(sym.typ, sym) elif type(sym) is VariableUse: sym.target = self.resolveDesignator(sym.target, sym) @@ -30,6 +30,4 @@ sym.proc = self.resolveDesignator(sym.proc, sym) elif type(sym) is FunctionType: sym.returntype = self.resolveDesignator(sym.returntype) - elif type(sym) is Constant: - print(sym)
--- a/python/c3/astnodes.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/astnodes.py Fri Mar 22 16:15:31 2013 +0100 @@ -94,8 +94,7 @@ self.b = b self.op = op # Operation: '+', '-', '*', '/', 'mod' def __repr__(self): - typ = self.typ if hasattr(self, 'typ') else '' - return 'BINOP {0} {1}'.format(self.op, typ) + return 'BINOP {0}'.format(self.op) class VariableUse(Node): def __init__(self, target):
--- a/python/c3/builder.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/builder.py Fri Mar 22 16:15:31 2013 +0100 @@ -4,8 +4,7 @@ class Builder: def __init__(self, diag): self.diag = diag - self.sema = Semantics(diag) - self.p = Parser(self.sema, diag) + self.p = Parser(diag) self.tc = TypeChecker(diag) self.al = Analyzer(diag) self.cg = CodeGenerator() @@ -16,27 +15,19 @@ print('[0] source:') print(src) print('[1] parsing') - self.p.parseSource(src) - ok = len(self.diag.diags) == 0 - if not ok: - return - pkg = self.sema.mod - self.pkg = pkg - self.al.analyzePackage(pkg) - self.tc.checkPackage(pkg) + self.pkg = self.p.parseSource(src) + self.al.analyzePackage(self.pkg) + self.tc.checkPackage(self.pkg) print('{0} errors'.format(len(self.diag.diags))) - for d in self.diag.diags: print('ERROR:') ppci.printError(src, d) print('[2] ast:') - self.ap.printAst(pkg) - - #printAst(sema.mod) + self.ap.printAst(self.pkg) ok = len(self.diag.diags) == 0 if ok: print('Generating ir-code') - i = cg.gencode(pkg) + i = self.cg.gencode(self.pkg) return i
--- a/python/c3/parser.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/parser.py Fri Mar 22 16:15:31 2013 +0100 @@ -8,8 +8,8 @@ class Parser: """ Parses sourcecode into an abstract syntax tree (AST) """ - def __init__(self, sema, diag): - self.sema = sema + def __init__(self, diag): + self.sema = semantics.Semantics(diag) self.diag = diag def parseSource(self, source): self.initLex(source) @@ -17,6 +17,7 @@ self.parsePackage() except CompilerError as e: self.diag.addDiag(e) + return self.sema.mod def Error(self, msg): raise CompilerError(msg, self.token.loc) # Lexer helpers: @@ -40,11 +41,17 @@ return False def NextToken(self): t = self.token - if t.typ != 'END': self.token = self.tokens.__next__() + if t.typ != 'END': + self.token = self.tokens.__next__() return t def initLex(self, source): self.tokens = lexer.tokenize(source) # Lexical stage self.token = self.tokens.__next__() + def skipToSemi(self, tt): + while self.Peak != tt and self.Peak != 'END': + self.NextToken() + if self.Peak == tt: + self.Consume(tt) def parsePackage(self): self.Consume('package') @@ -172,7 +179,9 @@ self.Consume('{') statements = [] while not self.hasConsumed('}'): - statements.append(self.parseStatement()) + s = self.parseStatement() + if not type(s) is astnodes.EmptyStatement: + statements.append(s) return astnodes.CompoundStatement(statements) def parseStatement(self): @@ -201,6 +210,13 @@ # Parsing expressions: def parseExpression(self): return self.parseBinopRhs(self.parsePrimary(), 0) + # TODO: use this error handling: + try: + return self.parseBinopRhs(self.parsePrimary(), 0) + except CompilerError as e: + self.diag.addDiag(e) + self.skipToSemi(';') + return astnodes.Literal(0) def parsePrimary(self): if self.hasConsumed('('): e = self.parseExpression() @@ -212,6 +228,12 @@ elif self.Peak == 'REAL': val = self.Consume('REAL') return self.sema.actOnNumber(val.val, val.loc) + elif self.Peak == 'true': + val = self.Consume('true') + return self.sema.actOnNumber(True, val.loc) + elif self.Peak == 'false': + val = self.Consume('false') + return self.sema.actOnNumber(False, val.loc) elif self.Peak == 'ID': d = self.parseDesignator() if self.Peak == '(':
--- a/python/c3/typecheck.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/typecheck.py Fri Mar 22 16:15:31 2013 +0100 @@ -22,7 +22,7 @@ pass elif type(sym) in [IfStatement, WhileStatement]: if not equalTypes(sym.condition.typ, boolType): - self.diag.error('Condition must be a boolean expression', sym.condition.loc) + self.diag.error('Condition must be of type {0}'.format(boolType), sym.condition.loc) elif type(sym) is Assignment: if not equalTypes(sym.lval.typ, sym.rval.typ): self.diag.error('Cannot assign {0} to {1}'.format(sym.rval.typ, sym.lval.typ), sym.loc) @@ -30,7 +30,8 @@ pass elif type(sym) is ProcedureCall: # Check arguments: - + if sym.proc: + pass # determine return type: sym.typ = sym.proc.typ.returntype elif type(sym) is VariableUse: @@ -43,6 +44,8 @@ sym.typ = intType elif type(sym.val) is float: sym.typ = doubleType + elif type(sym.val) is bool: + sym.typ = boolType else: self.diag.error('Unknown literal type', sym.loc) elif type(sym) is Binop: @@ -57,6 +60,12 @@ sym.typ = boolType if not equalTypes(sym.a.typ, sym.b.typ): self.diag.error('Types unequal', sym.loc) + elif sym.op in ['or', 'and']: + sym.typ = boolType + if not equalTypes(sym.a.typ, boolType): + self.diag.error('Must be {0}'.format(boolType), sym.a.loc) + if not equalTypes(sym.b.typ, boolType): + self.diag.error('Must be {0}'.format(boolType), sym.b.loc) else: sym.typ = voidType print('unknown binop', sym.op) @@ -64,7 +73,11 @@ # check initial value type: # TODO pass - elif type(sym) in [EmptyStatement, CompoundStatement, Package]: + elif type(sym) is Constant: + if not equalTypes(sym.typ, sym.value.typ): + self.diag.error('Cannot assign {0} to {1}'.format(sym.value.typ, sym.typ), sym.loc) + + elif type(sym) in [EmptyStatement, CompoundStatement, Package, Function]: pass else: print('Unknown type check', sym)
--- a/python/c3/visitor.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/c3/visitor.py Fri Mar 22 16:15:31 2013 +0100 @@ -35,7 +35,9 @@ elif type(node) is Binop: self.visit(node.a) self.visit(node.b) - elif type(node) in [EmptyStatement, Constant, VariableUse, Variable, Literal, FunctionType]: + elif type(node) is Constant: + self.visit(node.value) + elif type(node) in [EmptyStatement, VariableUse, Variable, Literal, FunctionType]: # Those nodes do not have child nodes. pass else:
--- a/python/testc3.py Fri Mar 22 15:12:38 2013 +0100 +++ b/python/testc3.py Fri Mar 22 16:15:31 2013 +0100 @@ -7,7 +7,7 @@ var double e; var int f; -const int A = 1337; +const int A = 1337.; function void test1() { @@ -40,6 +40,16 @@ return a + b; } +function int t3(int aap, int blah) +{ + if (a > blah and blah < 45 + 33 or 33 > aap or 6 and true) + { + a = 2 + t2(a - 1); + } + + return a + b; +} + var int hahaa = 23 * 2;