Mercurial > lcfOS
changeset 186:46d62dadd61b
Improved testsuite
author | Windel Bouwman |
---|---|
date | Sat, 25 May 2013 14:26:25 +0200 |
parents | 51a6440d6398 |
children | bf5ab358f43a |
files | python/c3/analyse.py python/c3/astnodes.py python/c3/builder.py python/c3/codegenerator.py python/c3/parser.py python/c3/typecheck.py python/c3/visitor.py python/ir/builder.py python/pyyacc.py python/testc3.py |
diffstat | 10 files changed, 86 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- a/python/c3/analyse.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/analyse.py Sat May 25 14:26:25 2013 +0200 @@ -6,8 +6,11 @@ def __init__(self, diag): self.diag = diag self.visitor = Visitor(self.a1, self.analyze) + def analyzePackage(self, pkg): - self.visitor.visit(pkg) + self.ok = True + self.visitor.visit(pkg) + return self.ok def resolveDesignator(self, d, referee=None): assert type(d) is Designator if d.scope.hasSymbol(d.tname): @@ -17,6 +20,7 @@ s.addRef(referee) return s else: + self.ok = False msg = 'Cannot resolve name {0}'.format(d.tname) self.diag.error(msg, d.loc) def a1(self, sym):
--- a/python/c3/astnodes.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/astnodes.py Sat May 25 14:26:25 2013 +0200 @@ -73,10 +73,8 @@ # Procedure types class Function(Symbol): """ Actual implementation of a function """ - def __init__(self, name, typ=None, block=None): + def __init__(self, name): super().__init__(name) - self.body = block - self.typ = typ def __repr__(self): return '{0}'.format(self.name)
--- a/python/c3/builder.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/builder.py Sat May 25 14:26:25 2013 +0200 @@ -2,21 +2,26 @@ from . import Parser, Semantics, TypeChecker, Analyzer, CodeGenerator, AstPrinter class Builder: - def __init__(self, diag): + """ + Generates IR-code from c3 source. + Reports errors to the diagnostics system + """ + def __init__(self, diag): self.diag = diag - self.p = Parser(diag) + self.parser = Parser(diag) self.tc = TypeChecker(diag) self.al = Analyzer(diag) self.cg = CodeGenerator() self.ap = AstPrinter() - def build(self, src): - # Store src for later: - self.src = src - self.pkg = self.p.parseSource(src) - self.al.analyzePackage(self.pkg) - self.tc.checkPackage(self.pkg) - ok = len(self.diag.diags) == 0 - if ok: - i = self.cg.gencode(self.pkg) - return i + def build(self, src): + """ Create IR-code from sources """ + pkg = self.parser.parseSource(src) + if not pkg: + return + if not self.al.analyzePackage(pkg): + return + if not self.tc.checkPackage(pkg): + return + ircode = self.cg.gencode(pkg) + return ircode
--- a/python/c3/codegenerator.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/codegenerator.py Sat May 25 14:26:25 2013 +0200 @@ -23,8 +23,9 @@ self.funcMap[s] = f for s in pkg.scope: if type(s) is astnodes.Variable: - # TODO - pass + v = self.builder.newTmp(s.name) + #self.builder.addIns(ir.Alloc(v)) + self.varMap[s] = v elif type(s) is astnodes.Function: # TODO: handle arguments f = self.funcMap[s]
--- a/python/c3/parser.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/parser.py Sat May 25 14:26:25 2013 +0200 @@ -16,9 +16,9 @@ self.sema.reinit() try: self.parsePackage() + return self.sema.mod except CompilerError as e: self.diag.addDiag(e) - return self.sema.mod def Error(self, msg): raise CompilerError(msg, self.token.loc) # Lexer helpers:
--- a/python/c3/typecheck.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/typecheck.py Sat May 25 14:26:25 2013 +0200 @@ -13,8 +13,14 @@ def __init__(self, diag): self.diag = diag self.visitor = Visitor(self.precheck, self.check2) + def error(self, msg, loc): + """ Wrapper that registers the message and marks the result invalid """ + self.diag.error(msg, loc) + self.ok = False def checkPackage(self, pkg): - self.visitor.visit(pkg) + self.ok = True + self.visitor.visit(pkg) + return self.ok def precheck(self, sym): pass def check2(self, sym): @@ -22,10 +28,10 @@ pass elif type(sym) in [IfStatement, WhileStatement]: if not equalTypes(sym.condition.typ, boolType): - self.diag.error('Condition must be of type {0}'.format(boolType), sym.condition.loc) + self.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) + self.error('Cannot assign {0} to {1}'.format(sym.rval.typ, sym.lval.typ), sym.loc) elif type(sym) is ReturnStatement: pass elif type(sym) is FunctionCall: @@ -35,11 +41,11 @@ ptypes = sym.proc.typ.parametertypes nreq = len(ptypes) if ngiv != nreq: - self.diag.error('Function {2}: {0} arguments required, {1} given'.format(nreq, ngiv, sym.proc.name), sym.loc) + self.error('Function {2}: {0} arguments required, {1} given'.format(nreq, ngiv, sym.proc.name), sym.loc) else: for a, at in zip(sym.args, ptypes): if not equalTypes(a.typ, at): - self.diag.error('Got {0}, expected {1}'.format(a.typ, at), a.loc) + self.error('Got {0}, expected {1}'.format(a.typ, at), a.loc) # determine return type: sym.typ = sym.proc.typ.returntype else: @@ -57,29 +63,29 @@ elif type(sym.val) is bool: sym.typ = boolType else: - self.diag.error('Unknown literal type', sym.loc) + self.error('Unknown literal type', sym.loc) elif type(sym) is Binop: if sym.op in ['+', '-', '*', '/']: if equalTypes(sym.a.typ, sym.b.typ): if equalTypes(sym.a.typ, intType): sym.typ = sym.a.typ else: - self.diag.error('Can only add integers', sym.loc) + self.error('Can only add integers', sym.loc) sym.typ = intType else: # assume void here? TODO: throw exception! sym.typ = intType - self.diag.error('Types unequal', sym.loc) + self.error('Types unequal', sym.loc) elif sym.op in ['>', '<', '==', '<=', '>=']: sym.typ = boolType if not equalTypes(sym.a.typ, sym.b.typ): - self.diag.error('Types unequal', sym.loc) + self.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) + self.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) + self.error('Must be {0}'.format(boolType), sym.b.loc) else: sym.typ = voidType print('unknown binop', sym.op) @@ -89,10 +95,10 @@ pass 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) + self.error('Cannot assign {0} to {1}'.format(sym.value.typ, sym.typ), sym.loc) elif type(sym) in [EmptyStatement, CompoundStatement, Package, Function, FunctionType]: pass else: - print('Unknown type check', sym) + raise Exception('Unknown type check {0}'.format(sym))
--- a/python/c3/visitor.py Fri May 24 20:45:03 2013 +0200 +++ b/python/c3/visitor.py Sat May 25 14:26:25 2013 +0200 @@ -44,7 +44,6 @@ self.visit(node.condition) self.visit(node.dostatement) else: - print('UNK visit "{0}"'.format(node)) + raise Exception('UNK visit "{0}"'.format(node)) self.f2(node) -
--- a/python/ir/builder.py Fri May 24 20:45:03 2013 +0200 +++ b/python/ir/builder.py Sat May 25 14:26:25 2013 +0200 @@ -52,5 +52,7 @@ def setBB(self, bb): self.bb = bb def addIns(self, i): + if not self.bb: + raise Exception('No basic block') self.bb.addIns(i)
--- a/python/pyyacc.py Fri May 24 20:45:03 2013 +0200 +++ b/python/pyyacc.py Sat May 25 14:26:25 2013 +0200 @@ -9,10 +9,12 @@ ACCEPT = 3 class ParserGenerationException(Exception): + """ Raised when something goes wrong during parser generation """ pass class ParserException(Exception): + """ Raised during a failure in the parsing process """ pass @@ -43,6 +45,11 @@ @property def first(self): + """ + The first set is a mapping from a grammar symbol to a set of + set of all terminal symbols that can be the first terminal when + looking for the grammar symbol + """ if not self._first: self._first = self.calcFirstSets() return self._first @@ -85,12 +92,12 @@ if not itm in itemset: itemset.add(itm) worklist.append(itm) - def first2(itm, la): + def first2(itm): # When using the first sets, create a copy: - f = set(self.first[item.NextNext]) + f = set(self.first[itm.NextNext]) if EPS in f: f.discard(EPS) - f.add(item.look_ahead) + f.add(itm.look_ahead) return f # Start of algorithm: while worklist: @@ -101,7 +108,7 @@ continue C = item.Next for add_p in self.productionsForName(C): - for b in first2(item, item.look_ahead): + for b in first2(item): addIt(Item(add_p, 0, b)) return frozenset(itemset) @@ -194,6 +201,12 @@ class Item: + """ + Represents a partially parsed item + It has a production it is looking for, a position + in this production called the 'dot' and a look ahead + symbol that must follow this item. + """ def __init__(self, production, dotpos, look_ahead): self.production = production self.dotpos = dotpos @@ -214,14 +227,17 @@ @property def IsReduce(self): + """ Check if this item has the dot at the end """ return self.dotpos == len(self.production.symbols) @property def IsShift(self): + """ Check if this item is a shift item, i.e. the dot can proceed """ return not self.IsReduce @property def Next(self): + """ Returns the symbol after the dot """ return self.production.symbols[self.dotpos] def can_shift_over(self, symbol): @@ -234,6 +250,7 @@ @property def NextNext(self): + """ Gets the symbol after the next symbol, or EPS if at the end """ if self.dotpos + 1 >= len(self.production.symbols): return EPS else: @@ -243,8 +260,8 @@ prod = self.production predot = ' '.join(prod.symbols[0:self.dotpos]) postdot = ' '.join(prod.symbols[self.dotpos:]) - nt = prod.name - args = (nt, predot, postdot, self.look_ahead) + name = prod.name + args = (name, predot, postdot, self.look_ahead) return '[{0} -> {1} . {2} -> {3}]'.format(*args)
--- a/python/testc3.py Fri May 24 20:45:03 2013 +0200 +++ b/python/testc3.py Sat May 25 14:26:25 2013 +0200 @@ -138,10 +138,10 @@ self.diag.clear() ir = self.builder.build(snippet) assert len(self.diag.diags) == 3 - assert self.diag.diags[0].loc.row == 8 - assert self.diag.diags[1].loc.row == 9 - assert self.diag.diags[2].loc.row == 10 - assert ir == None + self.assertEqual(self.diag.diags[0].loc.row, 8) + self.assertEqual(self.diag.diags[1].loc.row, 9) + self.assertEqual(self.diag.diags[2].loc.row, 10) + self.assertFalse(ir) def testEmpty(self): snippet = """ package A @@ -159,8 +159,8 @@ """ self.diag.clear() self.builder.build(snippet) - assert len(self.diag.diags) == 1 - assert self.diag.diags[0].loc.row == 5 + self.assertEqual(len(self.diag.diags), 1) + self.assertEqual(self.diag.diags[0].loc.row, 5) def testWhile(self): snippet = """ package tstwhile; @@ -171,11 +171,14 @@ while (i < 1054) { i = i + 3; - a = a + i + a = a + i; } } """ - self.builder.build(snippet) + ir = self.builder.build(snippet) + if not ir: + self.diag.printErrors(snippet) + self.assertTrue(ir) def testIf(self): snippet = """ package tstIFF; @@ -198,14 +201,14 @@ return b; } """ - self.builder.build(snippet) + ir = self.builder.build(snippet) + self.assertTrue(ir) def test2(self): # testsrc2 is valid code: self.diag.clear() ir = self.builder.build(testsrc2) - print(self.diag.diags) assert ir - ir.dump() + #ir.dump() if __name__ == '__main__': do()