Commits

catseye  committed 1ca4e64

Types on every AST node; simpler AST structure; AST.copy().

  • Participants
  • Parent commits cc216af

Comments (0)

Files changed (3)

File src/castile/ast.py

 class AST(object):
-    def __init__(self, tag, children=None, value=None):
-        # TODO 'type' should be
-        # the type, in the type system, of the value this node evaluates to
-        self._tag = tag
-        self._value = value
+    def __init__(self, tag, children=None, value=None, type=None, aux=None):
+        self.tag = tag
+        self.value = value
+        # typechecker may populate this.  parser will not.
+        self.type = type
+        # typechecker may populate this.  parser will not.
+        # TODO document what it means for particular nodes
+        self.aux = aux
         if children is not None:
-            self._children = children
+            self.children = children
         else:
-            self._children = []
+            self.children = []
         assert isinstance(self.children, list)
         for child in self.children:
             assert isinstance(child, AST), \
               "child %r of %r is not an AST node" % (child, self)
-        self.type = None  # typechecker may populate this
-        self.aux = None  # typechecker may populate this
-        # TODO document what it means for particular nodes
         #print "created %r" % self
 
-    @property
-    def tag(self):
-        return self._tag
-
-    @property
-    def value(self):
-        return self._value
-
-    @property
-    def children(self):
-        return self._children
+    def copy(self, children=None, value=None, type=None, aux=None):
+        if children is None:
+            children = self.children
+        if value is None:
+            value = self.value
+        if type is None:
+            type = self.type
+        if aux is None:
+            aux = self.aux
+        return AST(self.tag, children=children, value=value,
+                   type=type, aux=aux)
 
     def __repr__(self):
         if self.value is None:
             return 'AST(%r,%r)' % (self.tag, self.children)
         if not self.children:
-            return 'AST(%r,value=%r)' % (self.ttag, self.value)
+            return 'AST(%r,value=%r)' % (self.tag, self.value)
         return 'AST(%r,%r,value=%r)' % (self.tag, self.children, self.value)
 
     def minirepr(self):

File src/castile/checker.py

             types = []
             for child in ast.children:
                 types.append(self.type_of(child))
-            return types
+            return types  # NOT A TYPE
         elif ast.tag == 'Arg':
-            return self.set(ast.value, self.type_of(ast.children[0]))
+            ast.type = self.set(ast.value, self.type_of(ast.children[0]))
         elif ast.tag == 'Type':
             map = {
                 'integer': Integer(),
                 'string': String(),
                 'void': Void(),
             }
-            return map[ast.value]
+            ast.type = map[ast.value]
         elif ast.tag == 'Body':
             self.context = ScopedContext({}, self.context)
             for child in ast.children:
                 self.assert_eq(self.type_of(child), Void())
             self.context = self.context.parent
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'VarDecls':
             for child in ast.children:
                 self.assert_eq(self.type_of(child), Void())
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'VarDecl':
             name = ast.value
             if name in self.context:
                 raise CastileTypeError('declaration of %s shadows previous' % name)
             self.assignable[name] = True
             self.set(name, self.type_of(ast.children[0]))
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'FunType':
             return_type = self.type_of(ast.children[0])
-            return Function([self.type_of(c) for c in ast.children[1:]],
+            ast.type = Function([self.type_of(c) for c in ast.children[1:]],
                             return_type)
         elif ast.tag == 'UnionType':
-            return Union([self.type_of(c) for c in ast.children])
+            ast.type = Union([self.type_of(c) for c in ast.children])
         elif ast.tag == 'StructType':
-            return Struct(ast.value)
+            ast.type = Struct(ast.value)
         elif ast.tag == 'VarRef':
             ast.type = self.context[ast.value]
             ast.aux = self.context.level(ast.value)
                 self.return_type = t1
             else:
                 self.assert_eq(t1, self.return_type)
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'Break':
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'If':
             t1 = self.type_of(ast.children[0])
             assert t1 == Boolean()
             t2 = self.type_of(ast.children[1])
             if len(ast.children) == 3:
+                # TODO useless!  is void.
                 t3 = self.type_of(ast.children[2])
                 self.assert_eq(t2, t3)
-                return t2
+                ast.type = t2
             else:
-                return Void()
+                ast.type = Void()
         elif ast.tag == 'While':
             t1 = self.type_of(ast.children[0])
-            assert t1 == Boolean()
+            self.assert_eq(t1, Boolean())
             t2 = self.type_of(ast.children[1])
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'Block':
             for child in ast.children:
                 self.assert_eq(self.type_of(child), Void())
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'Assignment':
             t1 = self.type_of(ast.children[0])
             if not self.is_assignable(ast.children[0]):
                 raise CastileTypeError('cannot assign to non-local')
             t2 = self.type_of(ast.children[1])
             self.assert_eq(t1, t2)
-            return Void()
+            ast.type = Void()
         elif ast.tag == 'Make':
             t = self.type_of(ast.children[0])
             if t.name not in self.structs:
                 i += 1
             ast.type = t
         elif ast.tag == 'FieldInit':
-            return self.type_of(ast.children[0])
+            ast.type = self.type_of(ast.children[0])
         elif ast.tag == 'Index':
             t = self.type_of(ast.children[0])
             field_name = ast.value
             assert ast.children[0].tag == 'VarRef'
             self.context = ScopedContext({}, self.context)
             self.context[ast.children[0].value] = t2
-            t3 = self.type_of(ast.children[2])
+            ast.type = self.type_of(ast.children[2])
             self.context = self.context.parent
             ast.aux = str(t2)
-            return t3
         elif ast.tag == 'Program':
             for defn in ast.children:
-                t1 = self.type_of(defn)
-            return Void()
+                self.assert_eq(self.type_of(defn), Void())
+            ast.type = Void()
         elif ast.tag == 'Defn':
             # reset assignable
             self.assignable = {}
                 # we compare it against itself
                 rt = t.return_type
                 self.assert_eq(t, Function([], rt))
-            return t
+            ast.type = Void()
         elif ast.tag == 'Forward':
             t = self.type_of(ast.children[0])
             self.forwards[ast.value] = t
-            return self.set(ast.value, t)
+            self.set(ast.value, t)
+            ast.type = Void()
         elif ast.tag == 'StructDefn':
-            pass
+            ast.type = Void()
         elif ast.tag == 'TypeCast':
             val_t = self.type_of(ast.children[0])
             uni_t = self.type_of(ast.children[1])

File src/castile/transformer.py

                     else:
                         non_fun_defns.append(child)
             children = non_fun_defns + lifted_defns + non_lifted_defns
-            return AST(ast.tag, children, value=ast.value)
+            return ast.copy(children=children)
         elif ast.tag == 'Defn':
             # skip toplevel funlits; they don't have to be lifted.
             children = []
                     grandchildren = []
                     for grandchild in child.children:
                         grandchildren.append(self.lift_functions(grandchild))
-                    children.append(AST('FunLit', grandchildren, value=child.value))
+                    children.append(child.copy(children=grandchildren))
                 else:
                     children.append(self.lift_functions(child))
-            return AST(ast.tag, children, value=ast.value)
+            return ast.copy(children=children)
         elif ast.tag == 'FunLit':
             children = []
             for child in ast.children:
                 children.append(self.lift_functions(child))
-            new_ast = AST(ast.tag, children, value=ast.value)
-            new_ast.aux = ast.aux   # TODO i wish there was a nicer way
             name = self.make_name()
-            self.lifted_functions.append((name, new_ast))
-            a = AST('VarRef', value=name)
-            a.aux = 'toplevel'
-            return a
+            self.lifted_functions.append((name, ast.copy(children=children)))
+            return AST('VarRef', value=name, type=ast.type, aux='toplevel')
         else:
             children = []
             for child in ast.children:
                 children.append(self.lift_functions(child))
-            a = AST(ast.tag, children, value=ast.value)
-            a.aux = ast.aux
-            return a
+            return ast.copy(children=children)