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;