changeset 167:0b5b2ee6b435

Added 2 unit tests
author Windel Bouwman
date Fri, 22 Mar 2013 17:40:13 +0100
parents da0087b82fbe
children 49f1ab80d040
files python/c3/analyse.py python/c3/astnodes.py python/c3/builder.py python/c3/codegenerator.py python/c3/parser.py python/c3/semantics.py python/c3/typecheck.py python/c3/visitor.py python/codeedit.py python/ide.py python/ppci/errors.py python/testc3.py
diffstat 12 files changed, 99 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/analyse.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/analyse.py	Fri Mar 22 17:40:13 2013 +0100
@@ -24,10 +24,13 @@
    def analyze(self, sym):
       if type(sym) in [Variable, Constant]:
          sym.typ = self.resolveDesignator(sym.typ, sym)
+      elif type(sym) is Function:
+         pass
       elif type(sym) is VariableUse:
          sym.target = self.resolveDesignator(sym.target, sym)
-      elif type(sym) is ProcedureCall:
+      elif type(sym) is FunctionCall:
          sym.proc = self.resolveDesignator(sym.proc, sym)
       elif type(sym) is FunctionType:
          sym.returntype = self.resolveDesignator(sym.returntype)
+         sym.parametertypes = [self.resolveDesignator(pt) for pt in sym.parametertypes]
 
--- a/python/c3/astnodes.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/astnodes.py	Fri Mar 22 17:40:13 2013 +0100
@@ -26,11 +26,11 @@
     return '{0}'.format(self.name)
 
 class FunctionType(Type):
-   def __init__(self, parameters, returntype):
-      self.parameters = parameters
+   def __init__(self, parametertypes, returntype):
+      self.parametertypes = parametertypes
       self.returntype = returntype
    def __repr__(self):
-      params = ','.join([str(v) for v in self.parameters])
+      params = ', '.join([str(v) for v in self.parametertypes])
       return '{1} f({0})'.format(params, self.returntype)
 
 class DefinedType(Type):
@@ -140,7 +140,7 @@
    def __repr__(self):
       return 'ASSIGNMENT'
 
-class ProcedureCall(Node):
+class FunctionCall(Node):
   def __init__(self, proc, args):
     self.proc = proc
     self.args = args
--- a/python/c3/builder.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/builder.py	Fri Mar 22 17:40:13 2013 +0100
@@ -12,19 +12,9 @@
    def build(self, src):
       # Store src for later:
       self.src = src
-      print('[0] source:')
-      print(src)
-      print('[1] parsing')
       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(self.pkg)
-
       ok = len(self.diag.diags) == 0
       if ok:
          print('Generating ir-code')
--- a/python/c3/codegenerator.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/codegenerator.py	Fri Mar 22 17:40:13 2013 +0100
@@ -36,12 +36,12 @@
    elif type(code) is astnodes.IfStatement:
       genExprCode(bb, code.condition)
       # TODO: implement IF.
-      t1, t2 = 1,2
+      t1, t2 = 1, 2
       b = ir.BranchInstruction(t1, t2)
       bb.Instructions.append(b)
       genCode(bb, code.truestatement)
       genCode(bb, code.falsestatement)
-   elif type(code) is astnodes.ProcedureCall:
+   elif type(code) is astnodes.FunctionCall:
       ins = ir.CallInstruction('f', [])
       bb.Instructions.append(ins)
    elif type(code) is astnodes.EmptyStatement:
--- a/python/c3/parser.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/parser.py	Fri Mar 22 17:40:13 2013 +0100
@@ -139,7 +139,7 @@
       self.Consume(';')
       return self.sema.actOnAssignment(lval, rval, loc)
 
-   def parseProcedureCall(self, procedure):
+   def parseProcedureCall(self, func):
       self.Consume('(')
       args = [] 
       if not self.hasConsumed(')'):
@@ -147,7 +147,7 @@
          while self.hasConsumed(','):
             args.append(self.parseExpression())
          self.Consume(')')
-      return astnodes.ProcedureCall(procedure, args)
+      return self.sema.actOnFunctionCall(func, args, func.loc)
 
    def parseIfStatement(self):
       loc = self.Consume('if').loc
--- a/python/c3/semantics.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/semantics.py	Fri Mar 22 17:40:13 2013 +0100
@@ -36,7 +36,8 @@
       return p
    def actOnFuncDef2(self, parameters, returntype, body):
       self.curFunc.body = body
-      self.curFunc.typ = astnodes.FunctionType(parameters, returntype)
+      paramtypes = [p.typ for p in parameters]
+      self.curFunc.typ = astnodes.FunctionType(paramtypes, returntype)
       self.curFunc = None
       self.curScope = self.curScope.parent
    def actOnType(self, tok):
@@ -63,6 +64,10 @@
       a = astnodes.Assignment(lval, rval)
       a.loc = loc
       return a
+   def actOnFunctionCall(self, func, args, loc):
+      fc = astnodes.FunctionCall(func, args)
+      fc.loc = loc
+      return fc
    def actOnIfStatement(self, cond, yes, no, loc):
       i = astnodes.IfStatement(cond, yes, no)
       i.loc = loc
--- a/python/c3/typecheck.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/typecheck.py	Fri Mar 22 17:40:13 2013 +0100
@@ -28,12 +28,22 @@
             self.diag.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 ProcedureCall:
-         # Check arguments:
+      elif type(sym) is FunctionCall:
          if sym.proc:
-            pass
-         # determine return type:
-         sym.typ = sym.proc.typ.returntype
+            # Check arguments:
+            ngiv = len(sym.args)
+            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)
+            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)
+            # determine return type:
+            sym.typ = sym.proc.typ.returntype
+         else:
+            sym.typ = intType
       elif type(sym) is VariableUse:
          if sym.target:
             sym.typ = sym.target.typ
--- a/python/c3/visitor.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/c3/visitor.py	Fri Mar 22 17:40:13 2013 +0100
@@ -24,9 +24,9 @@
          self.visit(node.condition)
          self.visit(node.truestatement)
          self.visit(node.falsestatement)
-      elif type(node) is ProcedureCall:
-         pass
-         # TODO
+      elif type(node) is FunctionCall:
+         for arg in node.args:
+            self.visit(arg)
       elif type(node) is Assignment:
          self.visit(node.lval)
          self.visit(node.rval)
--- a/python/codeedit.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/codeedit.py	Fri Mar 22 17:40:13 2013 +0100
@@ -70,6 +70,7 @@
       txt = '\n'.join(prevRows)
       c = clipVal(c, 1, len(self.getRow(r)))
       self.CursorPosition = len(txt) + c + 1
+      self.showRow(self.CursorRow)
    def getRow(self, r):
       rows = self.Rows
       r = r - 1
@@ -149,11 +150,13 @@
                painter.setPen(errorPen)
                x = self.xposTXT + (e.loc.col - 1) * chw - 2
                wt = e.loc.length * chw + 4
-               painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7)
+               dy = self.charDescent
+               painter.drawLine(x, ypos + dy, x + wt, ypos + dy)
+               #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7)
                # print error balloon
-               painter.drawText(x, ypos + chh, e.msg)
-         if len(curErrors) > 0:
-            ypos += chh
+               #painter.drawText(x, ypos + chh, e.msg)
+         #if len(curErrors) > 0:
+         #   ypos += chh
 
          ypos += chh
    def keyPressEvent(self, event):
@@ -221,6 +224,8 @@
    Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v))
    def setErrors(self, el):
       self.ic.setErrors(el)
+   def setFocus(self):
+      self.ic.setFocus()
 
 if __name__ == '__main__':
    app = QApplication(sys.argv)
--- a/python/ide.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/ide.py	Fri Mar 22 17:40:13 2013 +0100
@@ -26,7 +26,7 @@
       self.setReadOnly(True)
       self.append('Build output will appear here!')
 
-class BuildErrors(QListView):
+class BuildErrors(QTreeView):
    sigErrorSelected = pyqtSignal(object)
    def __init__(self, parent=None):
       super(BuildErrors, self).__init__(parent)
@@ -36,10 +36,15 @@
       self.errorIcon = QIcon('error.png')
    def setErrorList(self, errorlist):
       model = QStandardItemModel()
+      model.setHorizontalHeaderLabels(['Message', 'Row', 'Column'])
       for e in errorlist:
-         item = QStandardItem(self.errorIcon, str(e))
+         item = QStandardItem(self.errorIcon, str(e.msg))
          item.setData(e)
-         model.appendRow(item)
+         irow = QStandardItem(str(e.loc.row))
+         irow.setData(e)
+         icol = QStandardItem(str(e.loc.col))
+         icol.setData(e)
+         model.appendRow([item, irow, icol])
       self.setModel(model)
    def itemSelected(self, index):
       if not index.isValid():
@@ -331,20 +336,19 @@
      if not ce:
         return
      ce.setRowCol(err.loc.row, err.loc.col)
+     ce.setFocus()
 
   # Project loading:
 
   # Build recepy:
   def buildFile(self):
      ce = self.activeMdiChild()
-     print('BUILD file')
      if ce:
         source = ce.Source
         self.buildOutput.clear()
         self.buildOutput.append('Starting build')
         ir = self.c3front.build(source)
         ast = self.c3front.pkg
-        print('setting ast', ast)
         self.astViewer.setAst(ast)
         self.buildOutput.append("Done!")
   def buildProject(self):
@@ -360,7 +364,6 @@
         self.buildOutput.append(str(err))
      ce = self.activeMdiChild()
      if ce:
-        print('setting errors')
         ce.setErrors(self.diag.diags)
      self.buildOutput.append("Done!")
 
--- a/python/ppci/errors.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/ppci/errors.py	Fri Mar 22 17:40:13 2013 +0100
@@ -8,7 +8,7 @@
     self.msg = msg
     self.loc = loc
   def __repr__(self):
-     return 'Compilererror {0} at {1}'.format(self.msg, self.loc)
+     return 'Compilererror {0} at row {1}'.format(self.msg, self.loc.row)
 
 def printError(source, e):
      def printLine(row, txt):
@@ -42,4 +42,6 @@
       self.diags.append(d)
    def error(self, msg, loc):
       self.addDiag(CompilerError(msg, loc))
+   def clear(self):
+      self.diags.clear()
 
--- a/python/testc3.py	Fri Mar 22 16:15:31 2013 +0100
+++ b/python/testc3.py	Fri Mar 22 17:40:13 2013 +0100
@@ -1,5 +1,6 @@
 import c3
 import time, ppci, x86, ir
+import unittest
 
 testsrc = """package test;
 
@@ -7,7 +8,7 @@
 var double e;
 var int f;
 
-const int A = 1337.;
+const int A = 1337;
 
 function void test1() 
 {
@@ -34,7 +35,7 @@
 {
    if (a > 0)
    {
-      a = 2 + t2(a - 1);
+      a = 2 + t2(a - 1, 1.0);
    }
 
    return a + b;
@@ -77,5 +78,43 @@
    diag = ppci.DiagnosticsManager()
    c3compile(testsrc, diag)
 
-do()
+class testA(unittest.TestCase):
+   def setUp(self):
+      self.diag = ppci.DiagnosticsManager()
+      self.builder = c3.Builder(self.diag)
+   def testFunctArgs(self):
+      snippet = """
+         package testargs;
+         function void t2(int a, double b)
+         {
+            t2(2, 2);
+            t2(2);
+            t2(1, 1.2);
+         }
+      """
+      self.diag.clear()
+      ir = self.builder.build(snippet)
+      print(self.diag.diags)
 
+   def testExpressions(self):
+      snippet = """
+         package test;
+         function void t(int a, double b)
+         {
+            var int a2;
+            var bool c;
+
+            a2 = b * a;
+            c = a;
+            c = b > 1;
+         }
+      """
+      self.diag.clear()
+      ir = self.builder.build(snippet)
+      print(self.diag.diags)
+
+if __name__ == '__main__':
+   do()
+   unittest.main()
+
+