2015-06-13 15:29:26 +08:00
|
|
|
"""
|
2015-06-24 16:46:15 +08:00
|
|
|
The :mod:`builtins` module contains the builtin Python
|
|
|
|
and ARTIQ types, such as int or float.
|
2015-06-13 15:29:26 +08:00
|
|
|
"""
|
|
|
|
|
2015-07-16 21:03:24 +08:00
|
|
|
from collections import OrderedDict
|
2015-06-13 15:29:26 +08:00
|
|
|
from . import types
|
|
|
|
|
2015-06-24 16:28:24 +08:00
|
|
|
# Types
|
|
|
|
|
2015-06-13 15:29:26 +08:00
|
|
|
class TNone(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("NoneType")
|
|
|
|
|
|
|
|
class TBool(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("bool")
|
|
|
|
|
2015-07-16 21:03:24 +08:00
|
|
|
@staticmethod
|
|
|
|
def zero():
|
|
|
|
return False
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def one():
|
|
|
|
return True
|
|
|
|
|
2015-06-13 15:29:26 +08:00
|
|
|
class TInt(types.TMono):
|
|
|
|
def __init__(self, width=None):
|
|
|
|
if width is None:
|
|
|
|
width = types.TVar()
|
|
|
|
super().__init__("int", {"width": width})
|
|
|
|
|
2015-07-16 21:03:24 +08:00
|
|
|
@staticmethod
|
|
|
|
def zero():
|
|
|
|
return 0
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def one():
|
|
|
|
return 1
|
|
|
|
|
2023-10-05 14:35:50 +08:00
|
|
|
def TInt8():
|
|
|
|
return TInt(types.TValue(8))
|
|
|
|
|
2015-11-21 03:22:47 +08:00
|
|
|
def TInt32():
|
|
|
|
return TInt(types.TValue(32))
|
|
|
|
|
|
|
|
def TInt64():
|
|
|
|
return TInt(types.TValue(64))
|
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
def _int_printer(typ, printer, depth, max_depth):
|
2016-07-06 12:03:54 +08:00
|
|
|
if types.is_var(typ["width"]):
|
|
|
|
return "numpy.int?"
|
|
|
|
else:
|
|
|
|
return "numpy.int{}".format(types.get_value(typ.find()["width"]))
|
2016-07-06 17:51:57 +08:00
|
|
|
types.TypePrinter.custom_printers["int"] = _int_printer
|
2016-07-06 12:03:54 +08:00
|
|
|
|
2015-06-13 15:29:26 +08:00
|
|
|
class TFloat(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("float")
|
|
|
|
|
2015-07-16 21:03:24 +08:00
|
|
|
@staticmethod
|
|
|
|
def zero():
|
|
|
|
return 0.0
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def one():
|
|
|
|
return 1.0
|
|
|
|
|
2015-07-21 19:27:48 +08:00
|
|
|
class TStr(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("str")
|
|
|
|
|
2017-06-09 13:49:55 +08:00
|
|
|
class TBytes(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("bytes")
|
|
|
|
|
2017-06-09 14:59:30 +08:00
|
|
|
class TByteArray(types.TMono):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__("bytearray")
|
|
|
|
|
2015-06-13 15:29:26 +08:00
|
|
|
class TList(types.TMono):
|
|
|
|
def __init__(self, elt=None):
|
|
|
|
if elt is None:
|
|
|
|
elt = types.TVar()
|
|
|
|
super().__init__("list", {"elt": elt})
|
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
class TArray(types.TMono):
|
2020-07-28 06:36:42 +08:00
|
|
|
def __init__(self, elt=None, num_dims=1):
|
2016-07-06 17:51:57 +08:00
|
|
|
if elt is None:
|
|
|
|
elt = types.TVar()
|
2020-07-28 06:36:42 +08:00
|
|
|
if isinstance(num_dims, int):
|
|
|
|
# Make TArray more convenient to instantiate from (ARTIQ) user code.
|
|
|
|
num_dims = types.TValue(num_dims)
|
2020-07-26 08:07:03 +08:00
|
|
|
# For now, enforce number of dimensions to be known, as we'd otherwise
|
|
|
|
# need to implement custom unification logic for the type of `shape`.
|
|
|
|
# Default to 1 to keep compatibility with old user code from before
|
|
|
|
# multidimensional array support.
|
|
|
|
assert isinstance(num_dims.value, int), "Number of dimensions must be resolved"
|
|
|
|
|
|
|
|
super().__init__("array", {"elt": elt, "num_dims": num_dims})
|
2020-07-26 05:19:12 +08:00
|
|
|
self.attributes = OrderedDict([
|
2020-07-28 06:21:23 +08:00
|
|
|
("buffer", types._TPointer(elt)),
|
2020-07-26 08:07:03 +08:00
|
|
|
("shape", types.TTuple([TInt32()] * num_dims.value)),
|
2020-07-26 05:19:12 +08:00
|
|
|
])
|
2016-07-06 17:51:57 +08:00
|
|
|
|
|
|
|
def _array_printer(typ, printer, depth, max_depth):
|
2020-07-26 08:07:03 +08:00
|
|
|
return "numpy.array(elt={}, num_dims={})".format(
|
|
|
|
printer.name(typ["elt"], depth, max_depth), typ["num_dims"].value)
|
2016-07-06 17:51:57 +08:00
|
|
|
types.TypePrinter.custom_printers["array"] = _array_printer
|
|
|
|
|
2015-06-26 23:53:20 +08:00
|
|
|
class TRange(types.TMono):
|
|
|
|
def __init__(self, elt=None):
|
|
|
|
if elt is None:
|
|
|
|
elt = types.TVar()
|
|
|
|
super().__init__("range", {"elt": elt})
|
2015-07-16 19:57:44 +08:00
|
|
|
self.attributes = OrderedDict([
|
|
|
|
("start", elt),
|
|
|
|
("stop", elt),
|
|
|
|
("step", elt),
|
|
|
|
])
|
2015-06-26 23:53:20 +08:00
|
|
|
|
2015-06-29 03:48:15 +08:00
|
|
|
class TException(types.TMono):
|
2015-07-25 10:37:37 +08:00
|
|
|
# All exceptions share the same internal layout:
|
|
|
|
# * Pointer to the unique global with the name of the exception (str)
|
|
|
|
# (which also serves as the EHABI type_info).
|
|
|
|
# * File, line and column where it was raised (str, int, int).
|
|
|
|
# * Message, which can contain substitutions {0}, {1} and {2} (str).
|
2016-07-06 12:03:54 +08:00
|
|
|
# * Three 64-bit integers, parameterizing the message (numpy.int64).
|
2022-01-23 21:10:46 +08:00
|
|
|
# These attributes are prefixed with `#` so that users cannot access them,
|
|
|
|
# and we don't have to do string allocation in the runtime.
|
|
|
|
# #__name__ is now a string key in the host. TStr may not be an actual
|
|
|
|
# CSlice in the runtime, they might be a CSlice with length = i32::MAX and
|
|
|
|
# ptr = string key in the host.
|
2015-07-25 10:37:37 +08:00
|
|
|
|
|
|
|
# Keep this in sync with the function ARTIQIRGenerator.alloc_exn.
|
|
|
|
attributes = OrderedDict([
|
2022-01-23 21:10:46 +08:00
|
|
|
("#__name__", TInt32()),
|
|
|
|
("#__file__", TStr()),
|
|
|
|
("#__line__", TInt32()),
|
|
|
|
("#__col__", TInt32()),
|
|
|
|
("#__func__", TStr()),
|
|
|
|
("#__message__", TStr()),
|
|
|
|
("#__param0__", TInt64()),
|
|
|
|
("#__param1__", TInt64()),
|
|
|
|
("#__param2__", TInt64()),
|
2015-07-25 10:37:37 +08:00
|
|
|
])
|
|
|
|
|
2015-12-31 21:54:54 +08:00
|
|
|
def __init__(self, name="Exception", id=0):
|
2015-07-16 19:58:40 +08:00
|
|
|
super().__init__(name)
|
2015-12-31 21:54:54 +08:00
|
|
|
self.id = id
|
2015-07-16 19:58:40 +08:00
|
|
|
|
2015-06-26 16:16:08 +08:00
|
|
|
def fn_bool():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TConstructor(TBool())
|
2015-06-26 16:16:08 +08:00
|
|
|
|
|
|
|
def fn_int():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TConstructor(TInt())
|
2015-06-26 16:16:08 +08:00
|
|
|
|
2016-07-07 13:00:09 +08:00
|
|
|
def fn_int32():
|
2016-11-21 22:01:11 +08:00
|
|
|
return types.TBuiltinFunction("int32")
|
2016-07-07 13:00:09 +08:00
|
|
|
|
|
|
|
def fn_int64():
|
2016-11-21 22:01:11 +08:00
|
|
|
return types.TBuiltinFunction("int64")
|
2016-07-07 13:00:09 +08:00
|
|
|
|
2015-06-26 16:16:08 +08:00
|
|
|
def fn_float():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TConstructor(TFloat())
|
2015-06-26 16:16:08 +08:00
|
|
|
|
2015-07-21 19:27:48 +08:00
|
|
|
def fn_str():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TConstructor(TStr())
|
2015-07-21 19:27:48 +08:00
|
|
|
|
2017-06-09 13:49:55 +08:00
|
|
|
def fn_bytes():
|
|
|
|
return types.TConstructor(TBytes())
|
|
|
|
|
2017-06-09 14:59:30 +08:00
|
|
|
def fn_bytearray():
|
|
|
|
return types.TConstructor(TByteArray())
|
|
|
|
|
2015-06-26 16:16:08 +08:00
|
|
|
def fn_list():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TConstructor(TList())
|
2015-06-26 16:16:08 +08:00
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
def fn_array():
|
2022-04-22 06:43:20 +08:00
|
|
|
# numpy.array() is actually a "magic" macro that is expanded in-place, but
|
|
|
|
# just as for builtin functions, we do not want to quote it, etc.
|
|
|
|
return types.TBuiltinFunction("array")
|
2016-07-06 17:51:57 +08:00
|
|
|
|
2015-06-29 03:48:15 +08:00
|
|
|
def fn_Exception():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TExceptionConstructor(TException("Exception"))
|
2015-06-29 03:48:15 +08:00
|
|
|
|
2015-07-16 19:58:40 +08:00
|
|
|
def fn_IndexError():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TExceptionConstructor(TException("IndexError"))
|
2015-07-16 19:58:40 +08:00
|
|
|
|
|
|
|
def fn_ValueError():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TExceptionConstructor(TException("ValueError"))
|
2015-07-16 19:58:40 +08:00
|
|
|
|
2015-07-23 06:26:50 +08:00
|
|
|
def fn_ZeroDivisionError():
|
2015-08-15 21:45:16 +08:00
|
|
|
return types.TExceptionConstructor(TException("ZeroDivisionError"))
|
2015-07-23 06:26:50 +08:00
|
|
|
|
2018-08-07 13:53:13 +08:00
|
|
|
def fn_RuntimeError():
|
|
|
|
return types.TExceptionConstructor(TException("RuntimeError"))
|
|
|
|
|
2015-06-26 23:53:20 +08:00
|
|
|
def fn_range():
|
2015-06-29 03:40:57 +08:00
|
|
|
return types.TBuiltinFunction("range")
|
2015-06-26 23:53:20 +08:00
|
|
|
|
2015-06-24 16:28:24 +08:00
|
|
|
def fn_len():
|
2015-06-29 03:40:57 +08:00
|
|
|
return types.TBuiltinFunction("len")
|
2015-06-24 16:28:24 +08:00
|
|
|
|
|
|
|
def fn_round():
|
2015-06-29 03:40:57 +08:00
|
|
|
return types.TBuiltinFunction("round")
|
2015-06-24 16:28:24 +08:00
|
|
|
|
2019-04-13 07:43:45 +08:00
|
|
|
def fn_abs():
|
|
|
|
return types.TBuiltinFunction("abs")
|
|
|
|
|
2016-06-22 09:09:41 +08:00
|
|
|
def fn_min():
|
|
|
|
return types.TBuiltinFunction("min")
|
|
|
|
|
|
|
|
def fn_max():
|
|
|
|
return types.TBuiltinFunction("max")
|
|
|
|
|
2016-07-07 14:33:30 +08:00
|
|
|
def fn_make_array():
|
|
|
|
return types.TBuiltinFunction("make_array")
|
|
|
|
|
2015-07-22 03:32:10 +08:00
|
|
|
def fn_print():
|
|
|
|
return types.TBuiltinFunction("print")
|
|
|
|
|
2015-08-07 12:54:35 +08:00
|
|
|
def fn_kernel():
|
|
|
|
return types.TBuiltinFunction("kernel")
|
|
|
|
|
2016-02-22 21:51:08 +08:00
|
|
|
def obj_parallel():
|
|
|
|
return types.TBuiltin("parallel")
|
|
|
|
|
2016-02-22 21:24:43 +08:00
|
|
|
def obj_interleave():
|
|
|
|
return types.TBuiltin("interleave")
|
2015-09-03 07:46:09 +08:00
|
|
|
|
2015-12-10 23:03:28 +08:00
|
|
|
def obj_sequential():
|
|
|
|
return types.TBuiltin("sequential")
|
2015-09-03 07:46:09 +08:00
|
|
|
|
2015-08-31 23:59:33 +08:00
|
|
|
def fn_delay():
|
|
|
|
return types.TBuiltinFunction("delay")
|
|
|
|
|
|
|
|
def fn_now_mu():
|
|
|
|
return types.TBuiltinFunction("now_mu")
|
|
|
|
|
|
|
|
def fn_delay_mu():
|
|
|
|
return types.TBuiltinFunction("delay_mu")
|
|
|
|
|
|
|
|
def fn_at_mu():
|
|
|
|
return types.TBuiltinFunction("at_mu")
|
|
|
|
|
2016-02-15 11:40:43 +08:00
|
|
|
def fn_rtio_log():
|
|
|
|
return types.TBuiltinFunction("rtio_log")
|
|
|
|
|
2023-10-05 14:35:50 +08:00
|
|
|
def fn_subkernel_await():
|
|
|
|
return types.TBuiltinFunction("subkernel_await")
|
|
|
|
|
|
|
|
def fn_subkernel_preload():
|
|
|
|
return types.TBuiltinFunction("subkernel_preload")
|
|
|
|
|
2015-06-24 16:28:24 +08:00
|
|
|
# Accessors
|
2015-06-13 15:29:26 +08:00
|
|
|
|
2015-06-14 17:07:13 +08:00
|
|
|
def is_none(typ):
|
|
|
|
return types.is_mono(typ, "NoneType")
|
|
|
|
|
|
|
|
def is_bool(typ):
|
|
|
|
return types.is_mono(typ, "bool")
|
|
|
|
|
2015-06-13 18:45:09 +08:00
|
|
|
def is_int(typ, width=None):
|
2015-06-29 03:48:15 +08:00
|
|
|
if width is not None:
|
2015-08-09 07:17:19 +08:00
|
|
|
return types.is_mono(typ, "int", width=width)
|
2015-06-13 18:45:09 +08:00
|
|
|
else:
|
|
|
|
return types.is_mono(typ, "int")
|
|
|
|
|
2016-01-02 22:51:04 +08:00
|
|
|
def is_int32(typ):
|
|
|
|
return is_int(typ, types.TValue(32))
|
|
|
|
|
|
|
|
def is_int64(typ):
|
|
|
|
return is_int(typ, types.TValue(64))
|
|
|
|
|
2015-06-14 17:07:13 +08:00
|
|
|
def get_int_width(typ):
|
|
|
|
if is_int(typ):
|
2015-06-15 13:40:37 +08:00
|
|
|
return types.get_value(typ.find()["width"])
|
2015-06-14 17:07:13 +08:00
|
|
|
|
|
|
|
def is_float(typ):
|
|
|
|
return types.is_mono(typ, "float")
|
|
|
|
|
2015-07-21 19:27:48 +08:00
|
|
|
def is_str(typ):
|
|
|
|
return types.is_mono(typ, "str")
|
|
|
|
|
2017-06-09 13:49:55 +08:00
|
|
|
def is_bytes(typ):
|
|
|
|
return types.is_mono(typ, "bytes")
|
|
|
|
|
2017-06-09 14:59:30 +08:00
|
|
|
def is_bytearray(typ):
|
|
|
|
return types.is_mono(typ, "bytearray")
|
|
|
|
|
2015-06-13 15:29:26 +08:00
|
|
|
def is_numeric(typ):
|
2015-06-14 17:07:13 +08:00
|
|
|
typ = typ.find()
|
2015-06-13 15:29:26 +08:00
|
|
|
return isinstance(typ, types.TMono) and \
|
|
|
|
typ.name in ('int', 'float')
|
2015-06-14 17:07:13 +08:00
|
|
|
|
|
|
|
def is_list(typ, elt=None):
|
2015-06-29 03:48:15 +08:00
|
|
|
if elt is not None:
|
2015-08-09 07:17:19 +08:00
|
|
|
return types.is_mono(typ, "list", elt=elt)
|
2015-06-14 17:07:13 +08:00
|
|
|
else:
|
|
|
|
return types.is_mono(typ, "list")
|
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
def is_array(typ, elt=None):
|
|
|
|
if elt is not None:
|
|
|
|
return types.is_mono(typ, "array", elt=elt)
|
|
|
|
else:
|
|
|
|
return types.is_mono(typ, "array")
|
|
|
|
|
|
|
|
def is_listish(typ, elt=None):
|
2017-06-09 13:49:55 +08:00
|
|
|
if is_list(typ, elt) or is_array(typ, elt):
|
|
|
|
return True
|
|
|
|
elif elt is None:
|
2017-06-09 14:59:30 +08:00
|
|
|
return is_str(typ) or is_bytes(typ) or is_bytearray(typ)
|
2017-06-09 13:49:55 +08:00
|
|
|
else:
|
|
|
|
return False
|
2016-07-06 17:51:57 +08:00
|
|
|
|
2015-06-26 23:53:20 +08:00
|
|
|
def is_range(typ, elt=None):
|
2015-06-29 03:48:15 +08:00
|
|
|
if elt is not None:
|
2015-06-26 23:53:20 +08:00
|
|
|
return types.is_mono(typ, "range", {"elt": elt})
|
|
|
|
else:
|
|
|
|
return types.is_mono(typ, "range")
|
|
|
|
|
2015-07-25 10:37:37 +08:00
|
|
|
def is_exception(typ, name=None):
|
|
|
|
if name is None:
|
|
|
|
return isinstance(typ.find(), TException)
|
|
|
|
else:
|
|
|
|
return isinstance(typ.find(), TException) and \
|
|
|
|
typ.name == name
|
2015-07-17 21:05:02 +08:00
|
|
|
|
2015-06-26 23:53:20 +08:00
|
|
|
def is_iterable(typ):
|
2017-06-09 14:50:48 +08:00
|
|
|
return is_listish(typ) or is_range(typ)
|
2015-06-26 23:53:20 +08:00
|
|
|
|
|
|
|
def get_iterable_elt(typ):
|
compiler: Change type inference rules for empty array() calls
array([...]), the constructor for NumPy arrays, currently has the
status of some weird kind of macro in ARTIQ Python, as it needs
to determine the number of dimensions in the resulting array
type, which is a fixed type parameter on which inference cannot
be performed.
This leads to an ambiguity for empty lists, which could contain
elements of arbitrary type, including other lists (which would
add to the number of dimensions).
Previously, I had chosen to make array([]) to be of completely
indeterminate type for this reason. However, this is different
to how the call behaves in host NumPy, where this is a well-formed
call creating an empty 1D array (or 2D for array([[], []]), etc.).
This commit adds special matching for (recursive lists of) empty
ListT AST nodes to treat them as scalar dimensions, with the
element type still unknown.
This also happens to fix type inference for embedding empty 1D
NumPy arrays from host object attributes, although multi-dimensional
arrays will still require work (see GitHub #1633).
GitHub: Fixes #1626.
2021-03-15 06:36:40 +08:00
|
|
|
# TODO: Arrays count as listish, but this returns the innermost element type for
|
|
|
|
# n-dimensional arrays, rather than the n-1 dimensional result of iterating over
|
|
|
|
# the first axis, which makes the name a bit misleading.
|
2017-06-09 14:59:30 +08:00
|
|
|
if is_str(typ) or is_bytes(typ) or is_bytearray(typ):
|
2023-10-05 14:35:50 +08:00
|
|
|
return TInt8()
|
2020-07-28 06:21:23 +08:00
|
|
|
elif types._is_pointer(typ) or is_iterable(typ):
|
2017-06-09 14:50:48 +08:00
|
|
|
return typ.find()["elt"].find()
|
2016-08-08 12:05:52 +08:00
|
|
|
else:
|
|
|
|
assert False
|
2015-06-26 23:53:20 +08:00
|
|
|
|
2015-06-14 17:07:13 +08:00
|
|
|
def is_collection(typ):
|
|
|
|
typ = typ.find()
|
|
|
|
return isinstance(typ, types.TTuple) or \
|
|
|
|
types.is_mono(typ, "list")
|
2015-06-24 16:46:15 +08:00
|
|
|
|
2015-07-21 19:27:48 +08:00
|
|
|
def is_allocated(typ):
|
2015-08-19 13:44:09 +08:00
|
|
|
return not (is_none(typ) or is_bool(typ) or is_int(typ) or
|
|
|
|
is_float(typ) or is_range(typ) or
|
2015-08-20 03:37:22 +08:00
|
|
|
types._is_pointer(typ) or types.is_function(typ) or
|
2020-08-02 20:42:24 +08:00
|
|
|
types.is_external_function(typ) or types.is_rpc(typ) or
|
2023-10-05 14:35:50 +08:00
|
|
|
types.is_subkernel(typ) or types.is_method(typ) or
|
|
|
|
types.is_tuple(typ) or types.is_value(typ))
|