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()