def __init__(self): global_context = {} for (name, (value, type)) in BUILTINS.items(): global_context[name] = type self.context = ScopedContext(global_context, level='global') self.toplevel_context = ScopedContext({}, self.context, level='toplevel') self.context = self.toplevel_context self.current_defn = None self.forwards = {} self.structs = {} # struct name -> StructDefinition self.return_type = None self.within_control = False self.verbose = False
def __init__(self): global_context = {} for (name, (value, type)) in BUILTINS.iteritems(): global_context[name] = type self.context = ScopedContext(global_context, level='global') self.toplevel_context = ScopedContext({}, self.context, level='toplevel') self.context = self.toplevel_context self.forwards = {} self.structs = {} # struct name -> StructDefinition self.return_type = None self.within_control = False self.verbose = False
def type_of(self, ast): if ast.tag == 'Op': if ast.value in ('and', 'or'): self.assert_eq(self.type_of(ast.children[0]), Boolean()) self.assert_eq(self.type_of(ast.children[1]), Boolean()) ast.type = Boolean() elif ast.value in ('+', '-', '*', '/'): type1 = self.type_of(ast.children[0]) type2 = self.type_of(ast.children[1]) self.assert_eq(type1, type2) self.assert_eq(type1, Integer()) ast.type = Integer() elif ast.value in ('==', '!=', '>', '>=', '<', '<='): type1 = self.type_of(ast.children[0]) type2 = self.type_of(ast.children[1]) self.assert_eq(type1, type2) ast.type = Boolean() elif ast.tag == 'Not': type1 = self.type_of(ast.children[0]) self.assert_eq(type1, Boolean()) ast.type = Boolean() elif ast.tag == 'IntLit': ast.type = Integer() elif ast.tag == 'StrLit': ast.type = String() elif ast.tag == 'BoolLit': ast.type = Boolean() elif ast.tag == 'FunLit': save_context = self.context self.context = ScopedContext({}, self.toplevel_context, level='argument') self.return_type = None arg_types = self.type_of(ast.children[0]) # args t = self.type_of(ast.children[1]) # body self.assert_eq(t, Void()) self.context = save_context return_type = self.return_type self.return_type = None if return_type is None: return_type = Void() ast.type = Function(arg_types, return_type) elif ast.tag == 'Args': types = [] for child in ast.children: types.append(self.type_of(child)) return types # NOT A TYPE elif ast.tag == 'Arg': ast.type = self.set(ast.value, self.type_of(ast.children[0])) elif ast.tag == 'Type': map = { 'integer': Integer(), 'boolean': Boolean(), 'string': String(), 'void': Void(), } ast.type = map[ast.value] elif ast.tag == 'Body': self.context = ScopedContext({}, self.context, level='local') self.assert_eq(self.type_of(ast.children[1]), Void()) self.context = self.context.parent ast.type = Void() elif ast.tag == 'FunType': return_type = self.type_of(ast.children[0]) ast.type = Function([self.type_of(c) for c in ast.children[1:]], return_type) elif ast.tag == 'UnionType': ast.type = Union([self.type_of(c) for c in ast.children]) elif ast.tag == 'StructType': ast.type = Struct(ast.value) elif ast.tag == 'VarRef': ast.type = self.context[ast.value] ast.aux = self.context.level(ast.value) elif ast.tag == 'None': ast.type = Void() elif ast.tag == 'FunCall': t1 = self.type_of(ast.children[0]) assert isinstance(t1, Function), \ '%r is not a function' % t1 if len(t1.arg_types) != len(ast.children) - 1: raise CastileTypeError("argument mismatch") i = 0 for child in ast.children[1:]: self.assert_eq(self.type_of(child), t1.arg_types[i]) i += 1 ast.type = t1.return_type elif ast.tag == 'Return': t1 = self.type_of(ast.children[0]) if self.return_type is None: self.return_type = t1 else: self.assert_eq(t1, self.return_type) ast.type = Void() elif ast.tag == 'Break': ast.type = Void() elif ast.tag == 'If': within_control = self.within_control self.within_control = True 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) ast.type = t2 else: ast.type = Void() self.within_control = within_control elif ast.tag == 'While': within_control = self.within_control self.within_control = True t1 = self.type_of(ast.children[0]) self.assert_eq(t1, Boolean()) t2 = self.type_of(ast.children[1]) ast.type = Void() self.within_control = within_control elif ast.tag == 'Block': for child in ast.children: self.assert_eq(self.type_of(child), Void()) ast.type = Void() elif ast.tag == 'Assignment': t2 = self.type_of(ast.children[1]) t1 = None name = ast.children[0].value if ast.aux == 'defining instance': if self.within_control: raise CastileTypeError('definition of %s within control block' % name) if name in self.context: raise CastileTypeError('definition of %s shadows previous' % name) self.set(name, t2) t1 = t2 else: if name not in self.context: raise CastileTypeError('variable %s used before definition' % name) t1 = self.type_of(ast.children[0]) self.assert_eq(t1, t2) # not quite useless now (typecase still likes this) if self.context.level(ast.children[0].value) != 'local': raise CastileTypeError('cannot assign to non-local') ast.type = Void() elif ast.tag == 'Make': t = self.type_of(ast.children[0]) if t.name not in self.structs: raise CastileTypeError("undefined struct %s" % t.name) struct_defn = self.structs[t.name] if len(struct_defn.content_types) != len(ast.children) - 1: raise CastileTypeError("argument mismatch") i = 0 for defn in ast.children[1:]: name = defn.value t1 = self.type_of(defn) pos = struct_defn.field_names[name] defn.aux = pos self.assert_eq(t1, struct_defn.content_types[pos]) i += 1 ast.type = t elif ast.tag == 'FieldInit': ast.type = self.type_of(ast.children[0]) elif ast.tag == 'Index': t = self.type_of(ast.children[0]) field_name = ast.value struct_fields = self.structs[t.name].field_names if field_name not in struct_fields: raise CastileTypeError("undefined field") index = struct_fields[field_name] # we make this value available to compiler backends ast.aux = index # we look up the type from the StructDefinition ast.type = self.structs[t.name].content_types[index] elif ast.tag == 'TypeCase': t1 = self.type_of(ast.children[0]) t2 = self.type_of(ast.children[1]) if not isinstance(t1, Union): raise CastileTypeError('bad typecase, %s not a union' % t1) if not t1.contains(t2): raise CastileTypeError('bad typecase, %s not in %s' % (t2, t1)) # typecheck t3 with variable in children[0] having type t2 assert ast.children[0].tag == 'VarRef' within_control = self.within_control self.within_control = True self.context = ScopedContext({}, self.context, level='typecase') self.context[ast.children[0].value] = t2 ast.type = self.type_of(ast.children[2]) self.context = self.context.parent self.within_control = within_control elif ast.tag == 'Program': for defn in ast.children: self.assert_eq(self.type_of(defn), Void()) ast.type = Void() self.resolve_structs(ast) elif ast.tag == 'Defn': t = self.type_of(ast.children[0]) if ast.value in self.forwards: self.assert_eq(self.forwards[ast.value], t) del self.forwards[ast.value] else: self.set(ast.value, t) if ast.value == 'main': # any return type is fine, for now, so, # we compare it against itself rt = t.return_type self.assert_eq(t, Function([], rt)) ast.type = Void() elif ast.tag == 'Forward': t = self.type_of(ast.children[0]) self.forwards[ast.value] = t self.set(ast.value, t) ast.type = Void() elif ast.tag == 'StructDefn': ast.type = Void() elif ast.tag == 'TypeCast': val_t = self.type_of(ast.children[0]) uni_t = self.type_of(ast.children[1]) if not isinstance(uni_t, Union): raise CastileTypeError('bad cast, not a union: %s' % uni_t) if not uni_t.contains(val_t): raise CastileTypeError('bad cast, %s does not include %s' % (uni_t, val_t)) ast.type = uni_t else: raise NotImplementedError(repr(ast)) return ast.type
def type_of(self, ast): if ast.tag == 'Op': if ast.value in ('and', 'or'): self.assert_eq(ast, self.type_of(ast.children[0]), Boolean()) self.assert_eq(ast, self.type_of(ast.children[1]), Boolean()) ast.type = Boolean() elif ast.value in ('+', '-', '*', '/'): type1 = self.type_of(ast.children[0]) type2 = self.type_of(ast.children[1]) self.assert_eq(ast, type1, type2) self.assert_eq(ast, type1, Integer()) ast.type = Integer() elif ast.value in ('==', '!=', '>', '>=', '<', '<='): type1 = self.type_of(ast.children[0]) type2 = self.type_of(ast.children[1]) self.assert_eq(ast, type1, type2) if isinstance(type1, Struct): raise CastileTypeError(ast, "structs cannot be compared") if isinstance(type1, Union) and type1.contains_instance_of(Struct): raise CastileTypeError( ast, "unions containing structs cannot be compared") ast.type = Boolean() elif ast.tag == 'Not': type1 = self.type_of(ast.children[0]) self.assert_eq(ast, type1, Boolean()) ast.type = Boolean() elif ast.tag == 'IntLit': ast.type = Integer() elif ast.tag == 'StrLit': ast.type = String() elif ast.tag == 'BoolLit': ast.type = Boolean() elif ast.tag == 'FunLit': save_context = self.context self.context = ScopedContext({}, self.toplevel_context, level='argument') self.return_type = None arg_types = self.type_of(ast.children[0]) # args t = self.type_of(ast.children[1]) # body self.assert_eq(ast, t, Void()) self.context = save_context return_type = self.return_type self.return_type = None if return_type is None: return_type = Void() ast.type = Function(arg_types, return_type) elif ast.tag == 'Args': types = [] for child in ast.children: types.append(self.type_of(child)) return types # NOT A TYPE elif ast.tag == 'Arg': ast.type = self.set(ast.value, self.type_of(ast.children[0])) elif ast.tag == 'Type': map = { 'integer': Integer(), 'boolean': Boolean(), 'string': String(), 'void': Void(), } ast.type = map[ast.value] elif ast.tag == 'Body': self.context = ScopedContext({}, self.context, level='local') self.assert_eq(ast, self.type_of(ast.children[1]), Void()) self.context = self.context.parent ast.type = Void() elif ast.tag == 'FunType': return_type = self.type_of(ast.children[0]) ast.type = Function([self.type_of(c) for c in ast.children[1:]], return_type) elif ast.tag == 'UnionType': types = [] for c in ast.children: type_ = self.type_of(c) if type_ in types: raise CastileTypeError(c, "bad union type") types.append(type_) ast.type = Union(types) elif ast.tag == 'StructType': ast.type = Struct(ast.value) elif ast.tag == 'VarRef': ast.type = self.context[ast.value] ast.aux = self.context.level(ast.value) elif ast.tag == 'None': ast.type = Void() elif ast.tag == 'FunCall': t1 = self.type_of(ast.children[0]) assert isinstance(t1, Function), \ '%r is not a function' % t1 if len(t1.arg_types) != len(ast.children) - 1: raise CastileTypeError(ast, "argument mismatch") i = 0 for child in ast.children[1:]: self.assert_eq(ast, self.type_of(child), t1.arg_types[i]) i += 1 ast.type = t1.return_type elif ast.tag == 'Return': t1 = self.type_of(ast.children[0]) if self.return_type is None: self.return_type = t1 else: self.assert_eq(ast, t1, self.return_type) ast.type = Void() elif ast.tag == 'Break': ast.type = Void() elif ast.tag == 'If': within_control = self.within_control self.within_control = True 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(ast, t2, t3) ast.type = t2 else: ast.type = Void() self.within_control = within_control elif ast.tag == 'While': within_control = self.within_control self.within_control = True t1 = self.type_of(ast.children[0]) self.assert_eq(ast, t1, Boolean()) t2 = self.type_of(ast.children[1]) ast.type = Void() self.within_control = within_control elif ast.tag == 'Block': for child in ast.children: self.assert_eq(ast, self.type_of(child), Void()) ast.type = Void() elif ast.tag == 'Assignment': t2 = self.type_of(ast.children[1]) t1 = None name = ast.children[0].value if ast.aux == 'defining instance': if self.within_control: raise CastileTypeError( ast, 'definition of %s within control block' % name) if name in self.context: raise CastileTypeError( ast, 'definition of %s shadows previous' % name) self.set(name, t2) t1 = t2 else: if name not in self.context: raise CastileTypeError( ast, 'variable %s used before definition' % name) t1 = self.type_of(ast.children[0]) self.assert_eq(ast, t1, t2) # not quite useless now (typecase still likes this) if self.context.level(ast.children[0].value) != 'local': raise CastileTypeError(ast, 'cannot assign to non-local') ast.type = Void() elif ast.tag == 'Make': t = self.type_of(ast.children[0]) if t.name not in self.structs: raise CastileTypeError(ast, "undefined struct %s" % t.name) struct_defn = self.structs[t.name] if struct_defn.scope_idents is not None: if self.current_defn not in struct_defn.scope_idents: raise CastileTypeError( ast, "inaccessible struct %s for make: %s not in %s" % (t.name, self.current_defn, struct_defn.scope_idents)) if len(struct_defn.content_types) != len(ast.children) - 1: raise CastileTypeError( ast, "argument mismatch; expected {}, got {} in {}".format( len(struct_defn.content_types), len(ast.children) - 1, ast)) i = 0 for defn in ast.children[1:]: name = defn.value t1 = self.type_of(defn) pos = struct_defn.field_names[name] defn.aux = pos self.assert_eq(ast, t1, struct_defn.content_types[pos]) i += 1 ast.type = t elif ast.tag == 'FieldInit': ast.type = self.type_of(ast.children[0]) elif ast.tag == 'Index': t = self.type_of(ast.children[0]) struct_defn = self.structs[t.name] if struct_defn.scope_idents is not None: if self.current_defn not in struct_defn.scope_idents: raise CastileTypeError( ast, "inaccessible struct %s for access: %s not in %s" % (t.name, self.current_defn, struct_defn.scope_idents)) field_name = ast.value struct_fields = struct_defn.field_names if field_name not in struct_fields: raise CastileTypeError(ast, "undefined field") index = struct_fields[field_name] # we make this value available to compiler backends ast.aux = index # we look up the type from the StructDefinition ast.type = struct_defn.content_types[index] elif ast.tag == 'TypeCase': t1 = self.type_of(ast.children[0]) t2 = self.type_of(ast.children[1]) if not isinstance(t1, Union): raise CastileTypeError(ast, 'bad typecase, %s not a union' % t1) if not t1.contains(t2): raise CastileTypeError(ast, 'bad typecase, %s not in %s' % (t2, t1)) # typecheck t3 with variable in children[0] having type t2 assert ast.children[0].tag == 'VarRef' within_control = self.within_control self.within_control = True self.context = ScopedContext({}, self.context, level='typecase') self.context[ast.children[0].value] = t2 ast.type = self.type_of(ast.children[2]) self.context = self.context.parent self.within_control = within_control elif ast.tag == 'Program': for defn in ast.children: self.assert_eq(ast, self.type_of(defn), Void()) ast.type = Void() self.resolve_structs(ast) elif ast.tag == 'Defn': self.current_defn = ast.value t = self.type_of(ast.children[0]) self.current_defn = None if ast.value in self.forwards: self.assert_eq(ast, self.forwards[ast.value], t) del self.forwards[ast.value] else: self.set(ast.value, t) if ast.value == 'main': # any return type is fine, for now, so, # we compare it against itself rt = t.return_type self.assert_eq(ast, t, Function([], rt)) ast.type = Void() elif ast.tag == 'Forward': t = self.type_of(ast.children[0]) self.forwards[ast.value] = t self.set(ast.value, t) ast.type = Void() elif ast.tag == 'StructDefn': ast.type = Void() elif ast.tag == 'TypeCast': value_t = self.type_of(ast.children[0]) union_t = self.type_of(ast.children[1]) if not isinstance(union_t, Union): raise CastileTypeError(ast, 'bad cast, not a union: %s' % union_t) if not union_t.contains(value_t): raise CastileTypeError( ast, 'bad cast, %s does not include %s' % (union_t, value_t)) ast.type = union_t else: raise NotImplementedError(repr(ast)) return ast.type