forked from M-Labs/artiq
compiler/inline: cleanup reference manager, recognize Fraction
This commit is contained in:
parent
fe5b3cc67e
commit
5481baac1d
|
@ -1,17 +1,11 @@
|
||||||
from collections import namedtuple, defaultdict
|
from collections import namedtuple, defaultdict
|
||||||
|
from fractions import Fraction
|
||||||
import inspect, textwrap, ast
|
import inspect, textwrap, ast
|
||||||
|
|
||||||
from artiq.compiler.tools import eval_ast, value_to_ast
|
from artiq.compiler.tools import eval_ast, value_to_ast
|
||||||
from artiq.language import core as core_language
|
from artiq.language import core as core_language
|
||||||
from artiq.language import units
|
from artiq.language import units
|
||||||
|
|
||||||
def _replace_global(obj, ref):
|
|
||||||
try:
|
|
||||||
value = eval_ast(ref, inspect.getmodule(obj).__dict__)
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
return value_to_ast(value)
|
|
||||||
|
|
||||||
_UserVariable = namedtuple("_UserVariable", "name")
|
_UserVariable = namedtuple("_UserVariable", "name")
|
||||||
|
|
||||||
def _is_in_attr_list(obj, attr, al):
|
def _is_in_attr_list(obj, attr, al):
|
||||||
|
@ -30,12 +24,13 @@ class _ReferenceManager:
|
||||||
self.kernel_attr_init = []
|
self.kernel_attr_init = []
|
||||||
|
|
||||||
# reserved names
|
# reserved names
|
||||||
self.use_count["Quantity"] = 1
|
|
||||||
self.use_count["base_s_unit"] = 1
|
|
||||||
self.use_count["base_Hz_unit"] = 1
|
|
||||||
for kg in core_language.kernel_globals:
|
for kg in core_language.kernel_globals:
|
||||||
self.use_count[kg] = 1
|
self.use_count[kg] = 1
|
||||||
self.use_count["range"] = 1
|
self.use_count["range"] = 1
|
||||||
|
self.use_count["Fraction"] = 1
|
||||||
|
self.use_count["Quantity"] = 1
|
||||||
|
self.use_count["s_unit"] = 1
|
||||||
|
self.use_count["Hz_unit"] = 1
|
||||||
|
|
||||||
def new_name(self, base_name):
|
def new_name(self, base_name):
|
||||||
if base_name[-1].isdigit():
|
if base_name[-1].isdigit():
|
||||||
|
@ -54,26 +49,12 @@ class _ReferenceManager:
|
||||||
if isinstance(ref, ast.Name):
|
if isinstance(ref, ast.Name):
|
||||||
key = (id(obj), funcname, ref.id)
|
key = (id(obj), funcname, ref.id)
|
||||||
try:
|
try:
|
||||||
ival = self.to_inlined[key]
|
return self.to_inlined[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if store:
|
if store:
|
||||||
iname = self.new_name(ref.id)
|
ival = _UserVariable(self.new_name(ref.id))
|
||||||
self.to_inlined[key] = _UserVariable(iname)
|
self.to_inlined[key] = ival
|
||||||
return ast.Name(iname, ast.Store())
|
|
||||||
else:
|
|
||||||
if isinstance(ival, _UserVariable):
|
|
||||||
return ast.Name(ival.name, ref.ctx)
|
|
||||||
elif isinstance(ival, ast.AST):
|
|
||||||
assert(not store)
|
|
||||||
return ival
|
return ival
|
||||||
else:
|
|
||||||
if store:
|
|
||||||
raise NotImplementedError("Cannot turn object into user variable")
|
|
||||||
else:
|
|
||||||
a = value_to_ast(ival)
|
|
||||||
if a is None:
|
|
||||||
raise NotImplementedError("Cannot represent inlined value")
|
|
||||||
return a
|
|
||||||
|
|
||||||
if isinstance(ref, ast.Attribute) and isinstance(ref.value, ast.Name):
|
if isinstance(ref, ast.Attribute) and isinstance(ref.value, ast.Name):
|
||||||
try:
|
try:
|
||||||
|
@ -82,34 +63,30 @@ class _ReferenceManager:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if _is_in_attr_list(value, ref.attr, "kernel_attr_ro"):
|
if _is_in_attr_list(value, ref.attr, "kernel_attr_ro"):
|
||||||
if isinstance(ref.ctx, ast.Store):
|
if store:
|
||||||
raise TypeError("Attempted to assign to read-only kernel attribute")
|
raise TypeError("Attempted to assign to read-only kernel attribute")
|
||||||
a = value_to_ast(getattr(value, ref.attr))
|
return getattr(value, ref.attr)
|
||||||
if a is None:
|
|
||||||
raise NotImplementedError("Cannot represent read-only kernel attribute")
|
|
||||||
return a
|
|
||||||
if _is_in_attr_list(value, ref.attr, "kernel_attr"):
|
if _is_in_attr_list(value, ref.attr, "kernel_attr"):
|
||||||
key = (id(value), ref.attr, None)
|
key = (id(value), ref.attr, None)
|
||||||
try:
|
try:
|
||||||
ival = self.to_inlined[key]
|
ival = self.to_inlined[key]
|
||||||
assert(isinstance(ival, _UserVariable))
|
assert(isinstance(ival, _UserVariable))
|
||||||
iname = ival.name
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
iname = self.new_name(ref.attr)
|
iname = self.new_name(ref.attr)
|
||||||
ival = _UserVariable(iname)
|
ival = _UserVariable(iname)
|
||||||
self.to_inlined[key] = _UserVariable(iname)
|
self.to_inlined[key] = ival
|
||||||
a = value_to_ast(getattr(value, ref.attr))
|
a = value_to_ast(getattr(value, ref.attr))
|
||||||
if a is None:
|
if a is None:
|
||||||
raise NotImplementedError("Cannot represent initial value of kernel attribute")
|
raise NotImplementedError("Cannot represent initial value of kernel attribute")
|
||||||
self.kernel_attr_init.append(ast.Assign(
|
self.kernel_attr_init.append(ast.Assign(
|
||||||
[ast.Name(iname, ast.Store())], a))
|
[ast.Name(iname, ast.Store())], a))
|
||||||
return ast.Name(iname, ref.ctx)
|
return ival
|
||||||
|
|
||||||
if not store:
|
if not store:
|
||||||
repl = _replace_global(obj, ref)
|
evd = self.get_constants(obj, funcname)
|
||||||
if repl is not None:
|
evd.update(inspect.getmodule(obj).__dict__)
|
||||||
return repl
|
return eval_ast(ref, evd)
|
||||||
|
else:
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
def set(self, obj, funcname, name, value):
|
def set(self, obj, funcname, name, value):
|
||||||
|
@ -123,10 +100,10 @@ class _ReferenceManager:
|
||||||
and not isinstance(v, (_UserVariable, ast.AST))}
|
and not isinstance(v, (_UserVariable, ast.AST))}
|
||||||
|
|
||||||
_embeddable_calls = {
|
_embeddable_calls = {
|
||||||
units.Quantity,
|
|
||||||
core_language.delay, core_language.at, core_language.now,
|
core_language.delay, core_language.at, core_language.now,
|
||||||
core_language.syscall,
|
core_language.syscall,
|
||||||
range
|
range,
|
||||||
|
Fraction, units.Quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReferenceReplacer(ast.NodeTransformer):
|
class _ReferenceReplacer(ast.NodeTransformer):
|
||||||
|
@ -135,22 +112,30 @@ class _ReferenceReplacer(ast.NodeTransformer):
|
||||||
self.rm = rm
|
self.rm = rm
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
self.funcname = funcname
|
self.funcname = funcname
|
||||||
self.module = inspect.getmodule(self.obj)
|
|
||||||
|
|
||||||
def visit_ref(self, node):
|
def visit_ref(self, node):
|
||||||
return ast.copy_location(
|
store = isinstance(node.ctx, ast.Store)
|
||||||
self.rm.get(self.obj, self.funcname, node),
|
ival = self.rm.get(self.obj, self.funcname, node)
|
||||||
node)
|
if isinstance(ival, _UserVariable):
|
||||||
|
newnode = ast.Name(ival.name, node.ctx)
|
||||||
|
elif isinstance(ival, ast.AST):
|
||||||
|
assert(not store)
|
||||||
|
newnode = ival
|
||||||
|
else:
|
||||||
|
if store:
|
||||||
|
raise NotImplementedError("Cannot turn object into user variable")
|
||||||
|
else:
|
||||||
|
newnode = value_to_ast(ival)
|
||||||
|
if newnode is None:
|
||||||
|
raise NotImplementedError("Cannot represent inlined value")
|
||||||
|
return ast.copy_location(newnode, node)
|
||||||
|
|
||||||
visit_Name = visit_ref
|
visit_Name = visit_ref
|
||||||
visit_Attribute = visit_ref
|
visit_Attribute = visit_ref
|
||||||
visit_Subscript = visit_ref
|
visit_Subscript = visit_ref
|
||||||
|
|
||||||
def visit_Call(self, node):
|
def visit_Call(self, node):
|
||||||
calldict = self.rm.get_constants(self.obj, self.funcname)
|
func = self.rm.get(self.obj, self.funcname, node.func)
|
||||||
calldict.update(self.module.__dict__)
|
|
||||||
func = eval_ast(node.func, calldict)
|
|
||||||
|
|
||||||
new_args = [self.visit(arg) for arg in node.args]
|
new_args = [self.visit(arg) for arg in node.args]
|
||||||
|
|
||||||
if func in _embeddable_calls:
|
if func in _embeddable_calls:
|
||||||
|
|
Loading…
Reference in New Issue