diff --git a/artiq/py2llvm/builtins.py b/artiq/py2llvm/builtins.py index daa94c70a..90e222374 100644 --- a/artiq/py2llvm/builtins.py +++ b/artiq/py2llvm/builtins.py @@ -1,6 +1,6 @@ """ -The :mod:`builtins` module contains the builtin Python and ARTIQ -types, such as int or float. +The :mod:`builtins` module contains the builtin Python +and ARTIQ types, such as int or float. """ from . import types @@ -32,16 +32,16 @@ class TList(types.TMono): super().__init__("list", {"elt": elt}) def fn_len(): - return types.TBuiltin("len") + return types.TBuiltin("function len") def fn_round(): - return types.TBuiltin("round") + return types.TBuiltin("function round") def fn_range(): - return types.TBuiltin("range") + return types.TBuiltin("function range") def fn_syscall(): - return types.TBuiltin("syscall") + return types.TBuiltin("function syscall") # Accessors @@ -79,3 +79,8 @@ def is_collection(typ): typ = typ.find() return isinstance(typ, types.TTuple) or \ types.is_mono(typ, "list") + +def is_function(typ, name): + typ = typ.find() + return isinstance(typ, types.TBuiltin) and \ + typ.name == "function " + name diff --git a/artiq/py2llvm/prelude.py b/artiq/py2llvm/prelude.py new file mode 100644 index 000000000..4e4d93fe7 --- /dev/null +++ b/artiq/py2llvm/prelude.py @@ -0,0 +1,17 @@ +""" +The :mod:`prelude` module contains the initial global environment +in which ARTIQ kernels are evaluated. +""" + +from . import builtins + +def globals(): + return { + "bool": builtins.TBool(), + "int": builtins.TInt(), + "float": builtins.TFloat(), + "round": builtins.fn_round(), + "len": builtins.fn_len(), + "range": builtins.fn_range(), + "syscall": builtins.fn_syscall(), + } diff --git a/artiq/py2llvm/typing.py b/artiq/py2llvm/typing.py index 3ceae8eb3..676dce879 100644 --- a/artiq/py2llvm/typing.py +++ b/artiq/py2llvm/typing.py @@ -24,7 +24,7 @@ class LocalExtractor(algorithm.Visitor): # parameters can't be declared as global or nonlocal self.params = set() - if len(self.env_stack) == 0: + if len(self.env_stack) == 1: self.env_stack.append(self.typing_env) def visit_in_assign(self, node): @@ -115,7 +115,7 @@ class LocalExtractor(algorithm.Visitor): self.global_.add(name) self._assignable(name) - self.env_stack[0][name] = self.typing_env[name] + self.env_stack[1][name] = self.typing_env[name] def visit_Nonlocal(self, node): for name, loc in zip(node.names, node.name_locs): @@ -123,9 +123,9 @@ class LocalExtractor(algorithm.Visitor): self._check_not_in(name, self.params, "a parameter", "nonlocal", loc): continue - # nonlocal does not search global scope + # nonlocal does not search prelude and global scopes found = False - for outer_env in reversed(self.env_stack[1:]): + for outer_env in reversed(self.env_stack[2:]): if name in outer_env: found = True break @@ -156,9 +156,9 @@ class ASTTypedRewriter(algorithm.Transformer): via :class:`LocalExtractor`. """ - def __init__(self, engine): + def __init__(self, engine, globals={}): self.engine = engine - self.env_stack = [] + self.env_stack = [globals] def _find_name(self, name, loc): for typing_env in reversed(self.env_stack): @@ -990,6 +990,7 @@ class Printer(algorithm.Visitor): def main(): import sys, fileinput, os + from . import prelude if len(sys.argv) > 1 and sys.argv[1] == '+diag': del sys.argv[1] @@ -1009,7 +1010,7 @@ def main(): buf = source.Buffer("".join(fileinput.input()).expandtabs(), os.path.basename(fileinput.filename())) parsed, comments = parse_buffer(buf, engine=engine) - typed = ASTTypedRewriter(engine=engine).visit(parsed) + typed = ASTTypedRewriter(globals=prelude.globals(), engine=engine).visit(parsed) Inferencer(engine=engine).visit(typed) printer = Printer(buf) diff --git a/lit-test/py2llvm/typing/prelude.py b/lit-test/py2llvm/typing/prelude.py new file mode 100644 index 000000000..d1229f66c --- /dev/null +++ b/lit-test/py2llvm/typing/prelude.py @@ -0,0 +1,10 @@ +# RUN: %python -m artiq.py2llvm.typing %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: x: +x = len + +def f(): + global len + # CHECK-L: len:int(width='a) = + len = 1