Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: fd3c8a28304b
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 94a2d5f5fa3e
Choose a head ref
  • 2 commits
  • 17 files changed
  • 1 contributor

Commits on Aug 15, 2015

  1. Copy the full SHA
    00efc8c View commit details
  2. Implement class attribute access through instances.

    whitequark committed Aug 15, 2015

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    94a2d5f View commit details
6 changes: 3 additions & 3 deletions artiq/compiler/asttyped.py
Original file line number Diff line number Diff line change
@@ -25,15 +25,15 @@ class scoped(object):
class argT(ast.arg, commontyped):
pass

class ClassDefT(ast.ClassDef, scoped):
pass
class ClassDefT(ast.ClassDef):
_types = ("constructor_type",)
class FunctionDefT(ast.FunctionDef, scoped):
_types = ("signature_type",)
class ModuleT(ast.Module, scoped):
pass

class ExceptHandlerT(ast.ExceptHandler):
_fields = ("filter", "name", "body") # rename ast.ExceptHandler.type
_fields = ("filter", "name", "body") # rename ast.ExceptHandler.type to filter
_types = ("name_type",)

class SliceT(ast.Slice, commontyped):
36 changes: 13 additions & 23 deletions artiq/compiler/builtins.py
Original file line number Diff line number Diff line change
@@ -96,44 +96,32 @@ class TException(types.TMono):
def __init__(self, name="Exception"):
super().__init__(name)

class TIndexError(TException):
def __init__(self):
super().__init__("IndexError")

class TValueError(TException):
def __init__(self):
super().__init__("ValueError")

class TZeroDivisionError(TException):
def __init__(self):
super().__init__("ZeroDivisionError")

def fn_bool():
return types.TConstructor("bool")
return types.TConstructor(TBool())

def fn_int():
return types.TConstructor("int")
return types.TConstructor(TInt())

def fn_float():
return types.TConstructor("float")
return types.TConstructor(TFloat())

def fn_str():
return types.TConstructor("str")
return types.TConstructor(TStr())

def fn_list():
return types.TConstructor("list")
return types.TConstructor(TList())

def fn_Exception():
return types.TExceptionConstructor("Exception")
return types.TExceptionConstructor(TException("Exception"))

def fn_IndexError():
return types.TExceptionConstructor("IndexError")
return types.TExceptionConstructor(TException("IndexError"))

def fn_ValueError():
return types.TExceptionConstructor("ValueError")
return types.TExceptionConstructor(TException("ValueError"))

def fn_ZeroDivisionError():
return types.TExceptionConstructor("ZeroDivisionError")
return types.TExceptionConstructor(TException("ZeroDivisionError"))

def fn_range():
return types.TBuiltinFunction("range")
@@ -214,5 +202,7 @@ def is_collection(typ):

def is_allocated(typ):
return typ.fold(False, lambda accum, typ:
is_list(typ) or is_str(typ) or types.is_function(typ) or
is_exception(typ))
accum or not (is_none(typ) or is_bool(typ) or is_int(typ) or
is_float(typ) or is_range(typ) or
types.is_c_function(typ) or types.is_rpc_function(typ) or
types.is_value(typ)))
35 changes: 31 additions & 4 deletions artiq/compiler/ir.py
Original file line number Diff line number Diff line change
@@ -554,7 +554,7 @@ def __init__(self, env, var_name, name=""):
self.var_name = var_name

def opcode(self):
return "getlocal({})".format(self.var_name)
return "getlocal({})".format(repr(self.var_name))

def environment(self):
return self.operands[0]
@@ -582,14 +582,41 @@ def __init__(self, env, var_name, value, name=""):
self.var_name = var_name

def opcode(self):
return "setlocal({})".format(self.var_name)
return "setlocal({})".format(repr(self.var_name))

def environment(self):
return self.operands[0]

def value(self):
return self.operands[1]

class GetConstructor(Instruction):
"""
An intruction that loads a local variable with the given type
from an environment, possibly going through multiple levels of indirection.
:ivar var_name: (string) variable name
"""

"""
:param env: (:class:`Value`) local environment
:param var_name: (string) local variable name
:param var_type: (:class:`types.Type`) local variable type
"""
def __init__(self, env, var_name, var_type, name=""):
assert isinstance(env, Value)
assert isinstance(env.type, TEnvironment)
assert isinstance(var_name, str)
assert isinstance(var_type, types.Type)
super().__init__([env], var_type, name)
self.var_name = var_name

def opcode(self):
return "getconstructor({})".format(repr(self.var_name))

def environment(self):
return self.operands[0]

class GetAttr(Instruction):
"""
An intruction that loads an attribute from an object,
@@ -636,9 +663,9 @@ def __init__(self, obj, attr, value, name=""):
assert isinstance(attr, (str, int))
assert isinstance(value, Value)
if isinstance(attr, int):
assert value.type == obj.type.elts[attr]
assert value.type == obj.type.elts[attr].find()
else:
assert value.type == obj.type.attributes[attr]
assert value.type == obj.type.attributes[attr].find()
super().__init__([obj, value], builtins.TNone(), name)
self.attr = attr

58 changes: 47 additions & 11 deletions artiq/compiler/transforms/artiq_ir_generator.py
Original file line number Diff line number Diff line change
@@ -73,6 +73,7 @@ def __init__(self, module_name, engine):
self.name = [module_name] if module_name != "" else []
self.current_loc = None
self.current_function = None
self.current_class = None
self.current_globals = set()
self.current_block = None
self.current_env = None
@@ -156,6 +157,17 @@ def visit_ModuleT(self, node):

# Statement visitors

def visit_ClassDefT(self, node):
klass = self.append(ir.Alloc([], node.constructor_type,
name="class.{}".format(node.name)))
self._set_local(node.name, klass)

try:
old_class, self.current_class = self.current_class, klass
self.visit(node.body)
finally:
self.current_class = old_class

def visit_function(self, node, is_lambda, is_internal):
if is_lambda:
name = "lambda@{}:{}".format(node.loc.line(), node.loc.column())
@@ -239,9 +251,12 @@ def visit_function(self, node, is_lambda, is_internal):

return self.append(ir.Closure(func, self.current_env))

def visit_FunctionDefT(self, node):
def visit_FunctionDefT(self, node, in_class=None):
func = self.visit_function(node, is_lambda=False, is_internal=len(self.name) > 2)
self._set_local(node.name, func)
if in_class is None:
self._set_local(node.name, func)
else:
self.append(ir.SetAttr(in_class, node.name, func))

def visit_Return(self, node):
if node.value is None:
@@ -668,9 +683,19 @@ def _env_for(self, name):
return self.current_env

def _get_local(self, name):
return self.append(ir.GetLocal(self._env_for(name), name, name="local." + name))
if self.current_class is not None and \
name in self.current_class.type.attributes:
return self.append(ir.GetAttr(self.current_class, name,
name="local." + name))

return self.append(ir.GetLocal(self._env_for(name), name,
name="local." + name))

def _set_local(self, name, value):
if self.current_class is not None and \
name in self.current_class.type.attributes:
return self.append(ir.SetAttr(self.current_class, name, value))

self.append(ir.SetLocal(self._env_for(name), name, value))

def visit_NameT(self, node):
@@ -686,6 +711,14 @@ def visit_AttributeT(self, node):
finally:
self.current_assign = old_assign

if node.attr not in node.type.find().attributes:
# A class attribute. Get the constructor (class object) and
# extract the attribute from it.
constructor = obj.type.constructor
obj = self.append(ir.GetConstructor(self._env_for(constructor.name),
constructor.name, constructor,
name="constructor." + constructor.name))

if self.current_assign is None:
return self.append(ir.GetAttr(obj, node.attr,
name="{}.{}".format(_readable_name(obj), node.attr)))
@@ -706,7 +739,7 @@ def _map_index(self, length, index, one_past_the_end=False, loc=None):
head = self.current_block

self.current_block = out_of_bounds_block = self.add_block()
exn = self.alloc_exn(builtins.TIndexError(),
exn = self.alloc_exn(builtins.TException("IndexError"),
ir.Constant("index {0} out of bounds 0:{1}", builtins.TStr()),
index, length)
self.raise_exn(exn, loc=loc)
@@ -790,7 +823,7 @@ def visit_SubscriptT(self, node):
step = self.visit(node.slice.step)
self._make_check(
self.append(ir.Compare(ast.NotEq(loc=None), step, ir.Constant(0, step.type))),
lambda: self.alloc_exn(builtins.TValueError(),
lambda: self.alloc_exn(builtins.TException("ValueError"),
ir.Constant("step cannot be zero", builtins.TStr())),
loc=node.slice.step.loc)
else:
@@ -811,7 +844,7 @@ def visit_SubscriptT(self, node):
name="slice.size"))
self._make_check(
self.append(ir.Compare(ast.LtE(loc=None), slice_size, length)),
lambda: self.alloc_exn(builtins.TValueError(),
lambda: self.alloc_exn(builtins.TException("ValueError"),
ir.Constant("slice size {0} is larger than iterable length {1}",
builtins.TStr()),
slice_size, length),
@@ -894,7 +927,7 @@ def visit_ListT(self, node):
self._make_check(
self.append(ir.Compare(ast.Eq(loc=None), length,
ir.Constant(len(node.elts), self._size_type))),
lambda: self.alloc_exn(builtins.TValueError(),
lambda: self.alloc_exn(builtins.TException("ValueError"),
ir.Constant("list must be {0} elements long to decompose", builtins.TStr()),
length))

@@ -1002,13 +1035,13 @@ def visit_BinOpT(self, node):
# Check for negative shift amount.
self._make_check(
self.append(ir.Compare(ast.GtE(loc=None), rhs, ir.Constant(0, rhs.type))),
lambda: self.alloc_exn(builtins.TValueError(),
lambda: self.alloc_exn(builtins.TException("ValueError"),
ir.Constant("shift amount must be nonnegative", builtins.TStr())),
loc=node.right.loc)
elif isinstance(node.op, (ast.Div, ast.FloorDiv)):
self._make_check(
self.append(ir.Compare(ast.NotEq(loc=None), rhs, ir.Constant(0, rhs.type))),
lambda: self.alloc_exn(builtins.TZeroDivisionError(),
lambda: self.alloc_exn(builtins.TException("ZeroDivisionError"),
ir.Constant("cannot divide by zero", builtins.TStr())),
loc=node.right.loc)

@@ -1373,10 +1406,13 @@ def body_gen(index):
assert False

def visit_CallT(self, node):
if types.is_builtin(node.func.type):
typ = node.func.type.find()

if types.is_constructor(typ) and not types.is_exn_constructor(typ):
return self.append(ir.Alloc([], typ.instance))
elif types.is_builtin(typ):
return self.visit_builtin_call(node)
else:
typ = node.func.type.find()
func = self.visit(node.func)
args = [None] * (len(typ.args) + len(typ.optargs))

Loading