changeset 165:598d3888a11c

Added front class and fided AST view
author Windel Bouwman
date Fri, 22 Mar 2013 15:12:38 +0100
parents e023d3ce1d63
children da0087b82fbe
files python/astviewer.py python/c3/__init__.py python/c3/astnodes.py python/c3/builder.py python/c3/parser.py python/c3/semantics.py python/c3/typecheck.py python/ide.py python/testc3.py
diffstat 9 files changed, 113 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/python/astviewer.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/astviewer.py	Fri Mar 22 15:12:38 2013 +0100
@@ -2,30 +2,40 @@
 from PyQt4.QtGui import *
 from c3 import Visitor
 
-def astToNamedElement(astNode, parentNode):
-   """ Helper to convert and AST tree to NamedElement tree: """
-   item = QStandardItem(str(astNode))
-   item.setData(astNode)
-   parentNode.appendRow(item)
-   for c in astNode.getChildren():
-      astToNamedElement(c, item)
+class AstModelBuilder:
+   def __init__(self):
+      self.visitor = Visitor(self.p1, self.p2)
+   def build(self, pkg):
+      model = QStandardItemModel()
+      model.setHorizontalHeaderLabels(['Object', 'Type'])
+      self.curItem = model.invisibleRootItem()
+      self.visitor.visit(pkg)
+      return model
+   def p1(self, node):
+      i = QStandardItem(str(node))
+      typ = str(node.typ) if hasattr(node, 'typ') else ''
+      ti = QStandardItem(str(typ))
+      ti.setData(node)
+      i.setData(node)
+      self.curItem.appendRow([i, ti])
+      self.curItem = i
+   def p2(self, node):
+      self.curItem = self.curItem.parent()
 
 # The actual widget:
 class AstViewer(QTreeView):
    sigNodeSelected = pyqtSignal(object)
    def __init__(self, parent=None):
       super(AstViewer, self).__init__(parent)
-      self.setHeaderHidden(True)
       self.clicked.connect(self.selectHandler)
+      self.modelBuilder = AstModelBuilder()
 
    def setAst(self, ast):
       """ Create a new model and add all ast elements to it """
-      model = QStandardItemModel()
       print(ast)
       if ast:
-         astToNamedElement(ast, model.invisibleRootItem())
-      self.setModel(model)
-      self.expandAll()
+         self.setModel(self.modelBuilder.build(ast))
+         self.expandAll()
 
    def selectHandler(self, index):
       if not index.isValid():
--- a/python/c3/__init__.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/c3/__init__.py	Fri Mar 22 15:12:38 2013 +0100
@@ -7,4 +7,5 @@
 from .codegenerator import CodeGenerator
 from .astprinter import AstPrinter
 from .visitor import Visitor
+from .builder import Builder
 
--- a/python/c3/astnodes.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/c3/astnodes.py	Fri Mar 22 15:12:38 2013 +0100
@@ -23,14 +23,15 @@
   def __init__(self, name):
     self.name = name
   def __repr__(self):
-    return '[TYPE {0}]'.format(self.name)
+    return '{0}'.format(self.name)
 
 class FunctionType(Type):
    def __init__(self, parameters, returntype):
       self.parameters = parameters
       self.returntype = returntype
    def __repr__(self):
-      return '[FUNCTYPE {0} RET {1}]'.format(self.parameters, self.returntype)
+      params = ','.join([str(v) for v in self.parameters])
+      return '{1} f({0})'.format(params, self.returntype)
 
 class DefinedType(Type):
    def __init__(self, name, typ):
@@ -67,7 +68,7 @@
       self.isReadOnly = False
       self.isParameter = False
    def __repr__(self):
-      return 'VAR {0} : {1} usage: {2}'.format(self.name, self.typ, self.References)
+      return '{0}'.format(self.name)
 
 # Procedure types
 class Function(Symbol):
@@ -77,7 +78,7 @@
       self.body = block
       self.typ = typ
    def __repr__(self):
-      return 'PROCEDURE {0} {1}'.format(self.name, self.typ)
+      return '{0}'.format(self.name)
 
 # Operations / Expressions:
 class Unop(Node):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/c3/builder.py	Fri Mar 22 15:12:38 2013 +0100
@@ -0,0 +1,42 @@
+import ppci
+from . import Parser, Semantics, TypeChecker, Analyzer, CodeGenerator, AstPrinter
+
+class Builder:
+   def __init__(self, diag):
+      self.diag = diag
+      self.sema = Semantics(diag)
+      self.p = Parser(self.sema, 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
+      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)
+      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)
+
+      ok = len(self.diag.diags) == 0
+      if ok:
+         print('Generating ir-code')
+         i = cg.gencode(pkg)
+         return i
+
--- a/python/c3/parser.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/c3/parser.py	Fri Mar 22 15:12:38 2013 +0100
@@ -126,7 +126,7 @@
 
    # Statements:
    def parseAssignment(self, lval):
-      lval = self.sema.actOnVariableUse(lval)
+      lval = self.sema.actOnVariableUse(lval, lval.loc)
       loc = self.Consume('=').loc
       rval = self.parseExpression()
       self.Consume(';')
@@ -143,15 +143,16 @@
       return astnodes.ProcedureCall(procedure, args)
 
    def parseIfStatement(self):
-      self.Consume('if')
+      loc = self.Consume('if').loc
       self.Consume('(')
       condition = self.parseExpression()
       self.Consume(')')
       yes = self.parseCompoundStatement()
       if self.hasConsumed('else'):
          no = self.parseCompoundStatement()
-         return astnodes.IfStatement(condition, yes, no)
-      return astnodes.IfStatement(condition, yes, astnodes.EmptyStatement())
+      else:
+         no = astnodes.EmptyStatement()
+      return self.sema.actOnIfStatement(condition, yes, no, loc)
 
    def parseWhileStatement(self):
       self.Consume('while')
@@ -216,7 +217,7 @@
          if self.Peak == '(':
             return self.parseProcedureCall(d)
          else:
-            return self.sema.actOnVariableUse(d)
+            return self.sema.actOnVariableUse(d, d.loc)
       self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak))
 
    def parseBinopRhs(self, lhs, min_prec):
--- a/python/c3/semantics.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/c3/semantics.py	Fri Mar 22 15:12:38 2013 +0100
@@ -55,11 +55,15 @@
       n = astnodes.Literal(num)
       n.loc = loc
       return n
-   def actOnVariableUse(self, d):
+   def actOnVariableUse(self, d, loc):
       vu = astnodes.VariableUse(d)
+      vu.loc = loc
       return vu
    def actOnAssignment(self, lval, rval, loc):
       a = astnodes.Assignment(lval, rval)
       a.loc = loc
       return a
-
+   def actOnIfStatement(self, cond, yes, no, loc):
+      i = astnodes.IfStatement(cond, yes, no)
+      i.loc = loc
+      return i
--- a/python/c3/typecheck.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/c3/typecheck.py	Fri Mar 22 15:12:38 2013 +0100
@@ -20,8 +20,7 @@
    def check2(self, sym):
       if type(sym) is Function:
          pass
-      elif type(sym) is IfStatement:
-         print(sym.condition)
+      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)
       elif type(sym) is Assignment:
@@ -38,7 +37,7 @@
          if sym.target:
             sym.typ = sym.target.typ
          else:
-            sym.typ = voidType
+            sym.typ = intType
       elif type(sym) is Literal:
          if type(sym.val) is int:
             sym.typ = intType
@@ -51,18 +50,22 @@
             if equalTypes(sym.a.typ, sym.b.typ):
                sym.typ = sym.a.typ
             else:
-               # assume void here?
-               sym.typ = voidType
+               # assume void here? TODO: throw exception!
+               sym.typ = intType
                self.diag.error('Types unequal', sym.loc)
          elif sym.op in ['>', '<']:
-            if equalTypes(sym.a.typ, sym.b.typ):
-               sym.typ = boolType
-            else:
-               sym.typ = voidType
+            sym.typ = boolType
+            if not equalTypes(sym.a.typ, sym.b.typ):
                self.diag.error('Types unequal', sym.loc)
          else:
             sym.typ = voidType
             print('unknown binop', sym.op)
+      elif type(sym) is Variable:
+         # check initial value type:
+         # TODO
+         pass
+      elif type(sym) in [EmptyStatement, CompoundStatement, Package]:
+         pass
       else:
          print('Unknown type check', sym)
 
--- a/python/ide.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/ide.py	Fri Mar 22 15:12:38 2013 +0100
@@ -14,6 +14,7 @@
 from codeedit import CodeEdit
 stutil = __import__('st-util')
 import testc3
+import c3
 
 lcfospng = base64.decodestring(b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A\n/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEhMKBk7B678AAAA/SURBVFjD\n7dbBCQAgDATBi9h/y7EFA4Kf2QLCwH1S6XQu6sqoujublc8BAAAAAAAAAAB8B+zXT6YJAAAAAKYd\nWSgFQNUyijIAAAAASUVORK5CYII=\n')
 
@@ -118,7 +119,6 @@
   def __init__(self, parent=None):
     super(Ide, self).__init__(parent)
     self.setWindowTitle('LCFOS IDE')
-    self.compiler = None # TODO
     icon = QPixmap()
     icon.loadFromData(lcfospng)
     self.setWindowIcon(QIcon(icon))
@@ -201,6 +201,7 @@
     ce.Source = testc3.testsrc
 
     self.diag = ppci.DiagnosticsManager()
+    self.c3front = c3.Builder(self.diag)
 
   # File handling:
   def newProject(self):
@@ -319,9 +320,9 @@
       ce = self.activeMdiChild()
       if not ce:
          return
-      if node.location:
-         row, col = node.location
-         ce.highlightErrorLocation( row, col )
+      if node.loc:
+         row, col = node.loc.row, node.loc.col
+         ce.setRowCol( row, col )
       else:
          ce.clearErrors()
 
@@ -340,9 +341,9 @@
      if ce:
         source = ce.Source
         self.buildOutput.clear()
-        self.buildOutput.append(str(self.compiler))
-        ast = testc3.c3compile(source, self.diag)
-        #ast = self.compiler.compilesource(source)
+        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!")
@@ -351,9 +352,7 @@
      print('BUILD project')
      self.buildOutput.clear()
      self.diag.diags.clear()
-     self.buildOutput.append(str(self.compiler))
      self.buildFile()
-     #mods = self.compiler.compileProject(self.project)
 
      self.builderrors.setErrorList(self.diag.diags)
      #self.astViewer.setAst(mods[0])
--- a/python/testc3.py	Mon Mar 18 22:15:57 2013 +0100
+++ b/python/testc3.py	Fri Mar 22 15:12:38 2013 +0100
@@ -46,51 +46,22 @@
 """
 
 def c3compile(src, diag):
-   print('[0] source:')
-   print(src)
-   print('[1] parsing')
    # Structures:
-   sema = c3.Semantics(diag)
-   p = c3.Parser(sema, diag)
-   tc = c3.TypeChecker(diag)
-   al = c3.Analyzer(diag)
-   cg = c3.CodeGenerator()
-   ap = c3.AstPrinter()
-
+   builder = c3.Builder(diag)
+   ir = builder.build(src)
+   # optional optimize here
    x86gen = x86.X86CodeGen(diag)
-   p.parseSource(src)
    ok = len(diag.diags) == 0
    if not ok:
+      print('Not generating code')
       return
-   al.analyzePackage(sema.mod)
-   tc.checkPackage(sema.mod)
-   print('{0} errors'.format(len(diag.diags)))
-
-   for d in diag.diags:
-      print('ERROR:')
-      ppci.printError(testsrc, d)
-   print('[2] ast:')
-   ap.printAst(sema.mod)
-
-   #printAst(sema.mod)
-
-   ok = len(diag.diags) == 0
-   if ok:
-      print('Generating ir-code')
-      i = cg.gencode(sema.mod)
-      #ir.printIr(i)
-
-      print('generating x86 code')
-
-      x86gen.genBin(i)
-
-      with open('dummydummy.asm', 'w') as f:
-         f.write('bits 64\n')
-         for a in x86gen.asm:
-            print(a)
-            f.write(str(a) + '\n')
-   else:
-      print('Not generating code')
+   print('generating x86 code')
+   x86gen.genBin(ir)
+   with open('dummydummy.asm', 'w') as f:
+      f.write('bits 64\n')
+      for a in x86gen.asm:
+         print(a)
+         f.write(str(a) + '\n')
    
 def do():
    diag = ppci.DiagnosticsManager()