forked from M-Labs/artiq
Implement class definitions and class attribute access.
This commit is contained in:
parent
fd3c8a2830
commit
00efc8c636
@ -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):
|
||||
|
@ -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")
|
||||
@ -215,4 +203,4 @@ 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))
|
||||
is_exception(typ) or types.is_constructor(typ))
|
||||
|
@ -636,9 +636,9 @@ class SetAttr(Instruction):
|
||||
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
|
||||
|
||||
|
@ -73,6 +73,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
# 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 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
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 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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):
|
||||
@ -706,7 +731,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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 +815,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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 +836,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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 +919,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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 +1027,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
# 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)
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
to a typedtree (:mod:`..asttyped`).
|
||||
"""
|
||||
|
||||
from pythonparser import algorithm, diagnostic
|
||||
from collections import OrderedDict
|
||||
from pythonparser import ast, algorithm, diagnostic
|
||||
from .. import asttyped, types, builtins
|
||||
|
||||
# This visitor will be called for every node with a scope,
|
||||
@ -16,7 +17,7 @@ class LocalExtractor(algorithm.Visitor):
|
||||
|
||||
self.in_root = False
|
||||
self.in_assign = False
|
||||
self.typing_env = {}
|
||||
self.typing_env = OrderedDict()
|
||||
|
||||
# which names are global have to be recorded in the current scope
|
||||
self.global_ = set()
|
||||
@ -189,6 +190,7 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||
self.engine = engine
|
||||
self.globals = None
|
||||
self.env_stack = [prelude]
|
||||
self.in_class = None
|
||||
|
||||
def _try_find_name(self, name):
|
||||
for typing_env in reversed(self.env_stack):
|
||||
@ -196,11 +198,17 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||
return typing_env[name]
|
||||
|
||||
def _find_name(self, name, loc):
|
||||
if self.in_class is not None:
|
||||
typ = self.in_class.constructor_type.attributes.get(name)
|
||||
if typ is not None:
|
||||
return typ
|
||||
|
||||
typ = self._try_find_name(name)
|
||||
if typ is not None:
|
||||
return typ
|
||||
|
||||
diag = diagnostic.Diagnostic("fatal",
|
||||
"name '{name}' is not bound to anything", {"name":name}, loc)
|
||||
"undefined variable '{name}'", {"name":name}, loc)
|
||||
self.engine.process(diag)
|
||||
|
||||
# Visitors that replace node with a typed node
|
||||
@ -239,6 +247,66 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||
finally:
|
||||
self.env_stack.pop()
|
||||
|
||||
def visit_ClassDef(self, node):
|
||||
if any(node.bases) or any(node.keywords) or \
|
||||
node.starargs is not None or node.kwargs is not None:
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"inheritance is not supported", {},
|
||||
node.lparen_loc.join(node.rparen_loc))
|
||||
self.engine.process(diag)
|
||||
|
||||
for child in node.body:
|
||||
if isinstance(child, (ast.Assign, ast.FunctionDef, ast.Pass)):
|
||||
continue
|
||||
|
||||
diag = diagnostic.Diagnostic("fatal",
|
||||
"class body must contain only assignments and function definitions", {},
|
||||
child.loc)
|
||||
self.engine.process(diag)
|
||||
|
||||
if node.name in self.env_stack[-1]:
|
||||
diag = diagnostic.Diagnostic("fatal",
|
||||
"variable '{name}' is already defined", {"name":name}, loc)
|
||||
self.engine.process(diag)
|
||||
|
||||
extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine)
|
||||
extractor.visit(node)
|
||||
|
||||
# Now we create two types.
|
||||
# The first type is the type of instances created by the constructor.
|
||||
# Its attributes are those of the class environment, but wrapped
|
||||
# appropriately so that they are linked to the class from which they
|
||||
# originate.
|
||||
instance_type = types.TMono(node.name)
|
||||
instance_type.attributes = OrderedDict({}) # TODO
|
||||
|
||||
# The second type is the type of the constructor itself (in other words,
|
||||
# the class object): it is simply a singleton type that has the class
|
||||
# environment as attributes.
|
||||
constructor_type = types.TConstructor(instance_type)
|
||||
constructor_type.attributes = extractor.typing_env
|
||||
|
||||
self.env_stack[-1][node.name] = constructor_type
|
||||
|
||||
node = asttyped.ClassDefT(
|
||||
constructor_type=constructor_type,
|
||||
name=node.name,
|
||||
bases=self.visit(node.bases), keywords=self.visit(node.keywords),
|
||||
starargs=self.visit(node.starargs), kwargs=self.visit(node.kwargs),
|
||||
body=node.body,
|
||||
decorator_list=self.visit(node.decorator_list),
|
||||
keyword_loc=node.keyword_loc, name_loc=node.name_loc,
|
||||
lparen_loc=node.lparen_loc, star_loc=node.star_loc,
|
||||
dstar_loc=node.dstar_loc, rparen_loc=node.rparen_loc,
|
||||
colon_loc=node.colon_loc, at_locs=node.at_locs,
|
||||
loc=node.loc)
|
||||
|
||||
try:
|
||||
old_in_class, self.in_class = self.in_class, node
|
||||
return self.generic_visit(node)
|
||||
finally:
|
||||
self.in_class = old_in_class
|
||||
|
||||
def visit_arg(self, node):
|
||||
return asttyped.argT(type=self._find_name(node.arg, node.loc),
|
||||
arg=node.arg, annotation=self.visit(node.annotation),
|
||||
@ -426,7 +494,6 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||
visit_YieldFrom = visit_unsupported
|
||||
|
||||
# stmt
|
||||
visit_ClassDef = visit_unsupported
|
||||
visit_Delete = visit_unsupported
|
||||
visit_Import = visit_unsupported
|
||||
visit_ImportFrom = visit_unsupported
|
||||
|
@ -467,7 +467,7 @@ class Inferencer(algorithm.Visitor):
|
||||
else:
|
||||
diagnose(valid_forms())
|
||||
|
||||
self._unify(node.type, getattr(builtins, "T" + typ.name)(),
|
||||
self._unify(node.type, typ.instance,
|
||||
node.loc, None)
|
||||
elif types.is_builtin(typ, "bool"):
|
||||
valid_forms = lambda: [
|
||||
@ -895,38 +895,47 @@ class Inferencer(algorithm.Visitor):
|
||||
"decorators are not supported", {},
|
||||
node.at_locs[index], [decorator.loc])
|
||||
self.engine.process(diag)
|
||||
return
|
||||
|
||||
old_function, self.function = self.function, node
|
||||
old_in_loop, self.in_loop = self.in_loop, False
|
||||
old_has_return, self.has_return = self.has_return, False
|
||||
try:
|
||||
old_function, self.function = self.function, node
|
||||
old_in_loop, self.in_loop = self.in_loop, False
|
||||
old_has_return, self.has_return = self.has_return, False
|
||||
|
||||
self.generic_visit(node)
|
||||
self.generic_visit(node)
|
||||
|
||||
# Lack of return statements is not the only case where the return
|
||||
# type cannot be inferred. The other one is infinite (possibly mutual)
|
||||
# recursion. Since Python functions don't have to return a value,
|
||||
# we ignore that one.
|
||||
if not self.has_return:
|
||||
def makenotes(printer, typea, typeb, loca, locb):
|
||||
return [
|
||||
diagnostic.Diagnostic("note",
|
||||
"function with return type {typea}",
|
||||
{"typea": printer.name(typea)},
|
||||
node.name_loc),
|
||||
]
|
||||
self._unify(node.return_type, builtins.TNone(),
|
||||
node.name_loc, None, makenotes)
|
||||
|
||||
self.function = old_function
|
||||
self.in_loop = old_in_loop
|
||||
self.has_return = old_has_return
|
||||
# Lack of return statements is not the only case where the return
|
||||
# type cannot be inferred. The other one is infinite (possibly mutual)
|
||||
# recursion. Since Python functions don't have to return a value,
|
||||
# we ignore that one.
|
||||
if not self.has_return:
|
||||
def makenotes(printer, typea, typeb, loca, locb):
|
||||
return [
|
||||
diagnostic.Diagnostic("note",
|
||||
"function with return type {typea}",
|
||||
{"typea": printer.name(typea)},
|
||||
node.name_loc),
|
||||
]
|
||||
self._unify(node.return_type, builtins.TNone(),
|
||||
node.name_loc, None, makenotes)
|
||||
finally:
|
||||
self.function = old_function
|
||||
self.in_loop = old_in_loop
|
||||
self.has_return = old_has_return
|
||||
|
||||
signature_type = self._type_from_arguments(node.args, node.return_type)
|
||||
if signature_type:
|
||||
self._unify(node.signature_type, signature_type,
|
||||
node.name_loc, None)
|
||||
|
||||
def visit_ClassDefT(self, node):
|
||||
if any(node.decorator_list):
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"decorators are not supported", {},
|
||||
node.at_locs[0], [node.decorator_list[0].loc])
|
||||
self.engine.process(diag)
|
||||
|
||||
self.generic_visit(node)
|
||||
|
||||
def visit_Return(self, node):
|
||||
if not self.function:
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
|
@ -437,7 +437,7 @@ class LLVMIRGenerator:
|
||||
size=llsize)
|
||||
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 1, name=insn.name)
|
||||
return llvalue
|
||||
elif builtins.is_exception(insn.type):
|
||||
elif builtins.is_exception(insn.type) or types.is_constructor(insn.type):
|
||||
llalloc = self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True))
|
||||
for index, operand in enumerate(insn.operands):
|
||||
lloperand = self.map(operand)
|
||||
|
@ -319,9 +319,17 @@ class TConstructor(TBuiltin):
|
||||
A type of a constructor of a builtin class, e.g. ``list``.
|
||||
Note that this is not the same as the type of an instance of
|
||||
the class, which is ``TMono("list", ...)``.
|
||||
|
||||
:ivar instance: (:class:`Type`)
|
||||
the type of the instance created by this constructor
|
||||
"""
|
||||
|
||||
class TExceptionConstructor(TBuiltin):
|
||||
def __init__(self, instance):
|
||||
assert isinstance(instance, TMono)
|
||||
super().__init__(instance.name)
|
||||
self.instance = instance
|
||||
|
||||
class TExceptionConstructor(TConstructor):
|
||||
"""
|
||||
A type of a constructor of a builtin exception, e.g. ``Exception``.
|
||||
Note that this is not the same as the type of an instance of
|
||||
@ -402,6 +410,14 @@ def is_builtin(typ, name=None):
|
||||
return isinstance(typ, TBuiltin) and \
|
||||
typ.name == name
|
||||
|
||||
def is_constructor(typ, name=None):
|
||||
typ = typ.find()
|
||||
if name is not None:
|
||||
return isinstance(typ, TConstructor) and \
|
||||
typ.name == name
|
||||
else:
|
||||
return isinstance(typ, TConstructor)
|
||||
|
||||
def is_exn_constructor(typ, name=None):
|
||||
typ = typ.find()
|
||||
if name is not None:
|
||||
@ -459,9 +475,11 @@ class TypePrinter(object):
|
||||
elif isinstance(typ, TFunction):
|
||||
return signature
|
||||
elif isinstance(typ, TBuiltinFunction):
|
||||
return "<function %s>" % typ.name
|
||||
return "<function {}>".format(typ.name)
|
||||
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
|
||||
return "<constructor %s>" % typ.name
|
||||
attrs = ", ".join(["{}: {}".format(attr, self.name(typ.attributes[attr]))
|
||||
for attr in typ.attributes])
|
||||
return "<constructor {} {{{}}}>".format(typ.name, attrs)
|
||||
elif isinstance(typ, TValue):
|
||||
return repr(typ.value)
|
||||
else:
|
||||
|
@ -208,7 +208,7 @@ class EscapeValidator(algorithm.Visitor):
|
||||
loc)
|
||||
]
|
||||
|
||||
def visit_in_region(self, node, region):
|
||||
def visit_in_region(self, node, region, typing_env):
|
||||
try:
|
||||
old_youngest_region = self.youngest_region
|
||||
self.youngest_region = region
|
||||
@ -216,8 +216,8 @@ class EscapeValidator(algorithm.Visitor):
|
||||
old_youngest_env = self.youngest_env
|
||||
self.youngest_env = {}
|
||||
|
||||
for name in node.typing_env:
|
||||
if builtins.is_allocated(node.typing_env[name]):
|
||||
for name in typing_env:
|
||||
if builtins.is_allocated(typing_env[name]):
|
||||
self.youngest_env[name] = Region(None) # not yet known
|
||||
else:
|
||||
self.youngest_env[name] = None # lives forever
|
||||
@ -230,11 +230,15 @@ class EscapeValidator(algorithm.Visitor):
|
||||
self.youngest_region = old_youngest_region
|
||||
|
||||
def visit_ModuleT(self, node):
|
||||
self.visit_in_region(node, None)
|
||||
self.visit_in_region(node, None, node.typing_env)
|
||||
|
||||
def visit_FunctionDefT(self, node):
|
||||
self.youngest_env[node.name] = self.youngest_region
|
||||
self.visit_in_region(node, Region(node.loc))
|
||||
self.visit_in_region(node, Region(node.loc), node.typing_env)
|
||||
|
||||
def visit_ClassDefT(self, node):
|
||||
self.youngest_env[node.name] = self.youngest_region
|
||||
self.visit_in_region(node, Region(node.loc), node.constructor_type.attributes)
|
||||
|
||||
# Only three ways for a pointer to escape:
|
||||
# * Assigning or op-assigning it (we ensure an outlives relationship)
|
||||
|
@ -1,28 +1,28 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
# CHECK-L: bool:<constructor bool>():bool
|
||||
# CHECK-L: bool:<constructor bool {}>():bool
|
||||
bool()
|
||||
|
||||
# CHECK-L: bool:<constructor bool>([]:list(elt='a)):bool
|
||||
# CHECK-L: bool:<constructor bool {}>([]:list(elt='a)):bool
|
||||
bool([])
|
||||
|
||||
# CHECK-L: int:<constructor int>():int(width='b)
|
||||
# CHECK-L: int:<constructor int {}>():int(width='b)
|
||||
int()
|
||||
|
||||
# CHECK-L: int:<constructor int>(1.0:float):int(width='c)
|
||||
# CHECK-L: int:<constructor int {}>(1.0:float):int(width='c)
|
||||
int(1.0)
|
||||
|
||||
# CHECK-L: int:<constructor int>(1.0:float, width=64:int(width='d)):int(width=64)
|
||||
# CHECK-L: int:<constructor int {}>(1.0:float, width=64:int(width='d)):int(width=64)
|
||||
int(1.0, width=64)
|
||||
|
||||
# CHECK-L: float:<constructor float>():float
|
||||
# CHECK-L: float:<constructor float {}>():float
|
||||
float()
|
||||
|
||||
# CHECK-L: float:<constructor float>(1:int(width='e)):float
|
||||
# CHECK-L: float:<constructor float {}>(1:int(width='e)):float
|
||||
float(1)
|
||||
|
||||
# CHECK-L: list:<constructor list>():list(elt='f)
|
||||
# CHECK-L: list:<constructor list {}>():list(elt='f)
|
||||
list()
|
||||
|
||||
# CHECK-L: len:<function len>([]:list(elt='g)):int(width=32)
|
||||
|
14
lit-test/test/inferencer/class.py
Normal file
14
lit-test/test/inferencer/class.py
Normal file
@ -0,0 +1,14 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
class c:
|
||||
a = 1
|
||||
def f():
|
||||
pass
|
||||
|
||||
# CHECK-L: c:<constructor c {a: int(width='a), f: ()->NoneType}>
|
||||
c
|
||||
# CHECK-L: .a:int(width='a)
|
||||
c.a
|
||||
# CHECK-L: .f:()->NoneType
|
||||
c.f
|
10
lit-test/test/inferencer/error_class.py
Normal file
10
lit-test/test/inferencer/error_class.py
Normal file
@ -0,0 +1,10 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
# CHECK-L: ${LINE:+1}: error: inheritance is not supported
|
||||
class a(1):
|
||||
pass
|
||||
|
||||
class b:
|
||||
# CHECK-L: ${LINE:+1}: fatal: class body must contain only assignments and function definitions
|
||||
x += 1
|
@ -1,5 +1,5 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
# CHECK-L: ${LINE:+1}: fatal: name 'x' is not bound to anything
|
||||
# CHECK-L: ${LINE:+1}: fatal: undefined variable 'x'
|
||||
x
|
||||
|
@ -1,7 +1,7 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
# CHECK-L: Exception:<constructor Exception>
|
||||
# CHECK-L: Exception:<constructor Exception {}>
|
||||
Exception
|
||||
|
||||
try:
|
||||
|
@ -58,16 +58,16 @@ k = "x"
|
||||
# CHECK-L: k:str
|
||||
|
||||
IndexError()
|
||||
# CHECK-L: IndexError:<constructor IndexError>():IndexError
|
||||
# CHECK-L: IndexError:<constructor IndexError {}>():IndexError
|
||||
|
||||
IndexError("x")
|
||||
# CHECK-L: IndexError:<constructor IndexError>("x":str):IndexError
|
||||
# CHECK-L: IndexError:<constructor IndexError {}>("x":str):IndexError
|
||||
|
||||
IndexError("x", 1)
|
||||
# CHECK-L: IndexError:<constructor IndexError>("x":str, 1:int(width=64)):IndexError
|
||||
# CHECK-L: IndexError:<constructor IndexError {}>("x":str, 1:int(width=64)):IndexError
|
||||
|
||||
IndexError("x", 1, 1)
|
||||
# CHECK-L: IndexError:<constructor IndexError>("x":str, 1:int(width=64), 1:int(width=64)):IndexError
|
||||
# CHECK-L: IndexError:<constructor IndexError {}>("x":str, 1:int(width=64), 1:int(width=64)):IndexError
|
||||
|
||||
IndexError("x", 1, 1, 1)
|
||||
# CHECK-L: IndexError:<constructor IndexError>("x":str, 1:int(width=64), 1:int(width=64), 1:int(width=64)):IndexError
|
||||
# CHECK-L: IndexError:<constructor IndexError {}>("x":str, 1:int(width=64), 1:int(width=64), 1:int(width=64)):IndexError
|
||||
|
12
lit-test/test/integration/class.py
Normal file
12
lit-test/test/integration/class.py
Normal file
@ -0,0 +1,12 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python %s
|
||||
|
||||
class c:
|
||||
a = 1
|
||||
def f():
|
||||
return 2
|
||||
|
||||
# CHECK-L: a 1
|
||||
print("a", c.a)
|
||||
# CHECK-L: f() 2
|
||||
print("f()", c.f())
|
Loading…
Reference in New Issue
Block a user