From 61434a8da35a2c6654f423f9b9c478680bcb5bd5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 13 Jun 2015 10:29:26 +0300 Subject: [PATCH] Split off builtins from types. builtins will contain attribute definitions as well. --- artiq/py2llvm/builtins.py | 63 +++++++++++++++++++++++++++++++++++++++ artiq/py2llvm/types.py | 58 ++--------------------------------- artiq/py2llvm/typing.py | 26 ++++++++-------- 3 files changed, 78 insertions(+), 69 deletions(-) create mode 100644 artiq/py2llvm/builtins.py diff --git a/artiq/py2llvm/builtins.py b/artiq/py2llvm/builtins.py new file mode 100644 index 000000000..e898eed28 --- /dev/null +++ b/artiq/py2llvm/builtins.py @@ -0,0 +1,63 @@ +""" +The :mod:`builtins` module contains the builtin Python and ARTIQ +types, such as int or float. +""" + +from . import types + +class TNone(types.TMono): + def __init__(self): + super().__init__("NoneType") + +class TBool(types.TMono): + def __init__(self): + super().__init__("bool") + +class TInt(types.TMono): + def __init__(self, width=None): + if width is None: + width = types.TVar() + super().__init__("int", {"width": width}) + +class TFloat(types.TMono): + def __init__(self): + super().__init__("float") + +class TTuple(types.Type): + """A tuple type.""" + + def __init__(self, elts=[]): + self.elts = elts + + def find(self): + return self + + def unify(self, other): + if isinstance(other, TTuple) and len(self.elts) == len(other.elts): + for selfelt, otherelt in zip(self.elts, other.elts): + selfelt.unify(otherelt) + elif isinstance(other, TVar): + other.unify(self) + else: + raise UnificationError(self, other) + + def __repr__(self): + return "TTuple(%s)" % (", ".join(map(repr, self.elts))) + + def __eq__(self, other): + return isinstance(other, TTuple) and \ + self.elts == other.elts + + def __ne__(self, other): + return not (self == other) + +class TList(types.TMono): + def __init__(self, elt=None): + if elt is None: + elt = types.TVar() + super().__init__("list", {"elt": elt}) + + +def is_numeric(typ): + return isinstance(typ, types.TMono) and \ + typ.name in ('int', 'float') diff --git a/artiq/py2llvm/types.py b/artiq/py2llvm/types.py index f56aa34a8..2397ea61f 100644 --- a/artiq/py2llvm/types.py +++ b/artiq/py2llvm/types.py @@ -37,6 +37,8 @@ class TVar(Type): folded into this class. """ + attributes = () + def __init__(self): self.parent = self @@ -99,34 +101,6 @@ class TMono(Type): def __ne__(self, other): return not (self == other) -class TTuple(Type): - """A tuple type.""" - - def __init__(self, elts=[]): - self.elts = elts - - def find(self): - return self - - def unify(self, other): - if isinstance(other, TTuple) and len(self.elts) == len(other.elts): - for selfelt, otherelt in zip(self.elts, other.elts): - selfelt.unify(otherelt) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - - def __repr__(self): - return "TTuple(%s)" % (", ".join(map(repr, self.elts))) - - def __eq__(self, other): - return isinstance(other, TTuple) and \ - self.elts == other.elts - - def __ne__(self, other): - return not (self == other) - class TValue(Type): """ A type-level value (such as the integer denoting width of @@ -155,30 +129,6 @@ class TValue(Type): def __ne__(self, other): return not (self == other) -def TNone(): - """The type of None.""" - return TMono("NoneType") - -def TBool(): - """A boolean type.""" - return TMono("bool") - -def TInt(width=None): - """A generic integer type.""" - if width is None: - width = TVar() - return TMono("int", {"width": width}) - -def TFloat(): - """A double-precision floating point type.""" - return TMono("float") - -def TList(elt=None): - """A generic list type.""" - if elt is None: - elt = TVar() - return TMono("list", {"elt": elt}) - def is_var(typ): return isinstance(typ, TVar) @@ -190,10 +140,6 @@ def is_mono(typ, name, **params): return isinstance(typ, TMono) and \ typ.name == name and params_match -def is_numeric(typ): - return isinstance(typ, TMono) and \ - typ.name in ('int', 'float') - class TypePrinter(object): """ diff --git a/artiq/py2llvm/typing.py b/artiq/py2llvm/typing.py index aa11f0e53..70201a04f 100644 --- a/artiq/py2llvm/typing.py +++ b/artiq/py2llvm/typing.py @@ -1,5 +1,5 @@ from pythonparser import source, ast, algorithm, diagnostic, parse_buffer -from . import asttyped, types +from . import asttyped, types, builtins # This visitor will be called for every node with a scope, # i.e.: class, function, comprehension, lambda @@ -222,9 +222,9 @@ class Inferencer(algorithm.Transformer): def visit_Num(self, node): if isinstance(node.n, int): - typ = types.TInt() + typ = builtins.TInt() elif isinstance(node.n, float): - typ = types.TFloat() + typ = builtins.TFloat() else: diag = diagnostic.Diagnostic("fatal", "numeric type {type} is not supported", {"type": node.n.__class__.__name__}, @@ -239,19 +239,19 @@ class Inferencer(algorithm.Transformer): def visit_NameConstant(self, node): if node.value is True or node.value is False: - typ = types.TBool() + typ = builtins.TBool() elif node.value is None: - typ = types.TNone() + typ = builtins.TNone() return asttyped.NameConstantT(type=typ, value=node.value, loc=node.loc) def visit_Tuple(self, node): node = self.generic_visit(node) - return asttyped.TupleT(type=types.TTuple([x.type for x in node.elts]), + return asttyped.TupleT(type=builtins.TTuple([x.type for x in node.elts]), elts=node.elts, ctx=node.ctx, loc=node.loc) def visit_List(self, node): node = self.generic_visit(node) - node = asttyped.ListT(type=types.TList(), + node = asttyped.ListT(type=builtins.TList(), elts=node.elts, ctx=node.ctx, loc=node.loc) return self.visit(node) @@ -307,7 +307,7 @@ class Inferencer(algorithm.Transformer): def visit_SubscriptT(self, node): # TODO: support more than just lists - self._unify(types.TList(node.type), node.value.type, + self._unify(builtins.TList(node.type), node.value.type, node.loc, node.value.loc) return node @@ -325,10 +325,10 @@ class Inferencer(algorithm.Transformer): def visit_UnaryOpT(self, node): if isinstance(node.op, ast.Not): - node.type = types.TBool() + node.type = builtins.TBool() else: operand_type = node.operand.type.find() - if types.is_numeric(operand_type): + if builtins.is_numeric(operand_type): node.type = operand_type elif not types.is_var(operand_type): diag = diagnostic.Diagnostic("error", @@ -361,7 +361,7 @@ class Inferencer(algorithm.Transformer): def visit_Assign(self, node): node = self.generic_visit(node) if len(node.targets) > 1: - self._unify(types.TTuple([x.type for x in node.targets]), node.value.type, + self._unify(builtins.TTuple([x.type for x in node.targets]), node.value.type, node.targets[0].loc.join(node.targets[-1].loc), node.value.loc) else: self._unify(node.targets[0].type, node.value.type, @@ -377,7 +377,7 @@ class Inferencer(algorithm.Transformer): def visit_For(self, node): node = self.generic_visit(node) # TODO: support more than just lists - self._unify(TList(node.target.type), node.iter.type, + self._unify(builtins.TList(node.target.type), node.iter.type, node.target.loc, node.iter.loc) return node @@ -395,7 +395,7 @@ class Inferencer(algorithm.Transformer): node.loc) ] if node.value is None: - self._unify(self.function.return_type, types.TNone(), + self._unify(self.function.return_type, builtins.TNone(), self.function.name_loc, node.loc, makenotes) else: self._unify(self.function.return_type, node.value.type,