forked from M-Labs/artiq
compiler.embedding: show suggestions for mistyped host object attributes.
This commit is contained in:
parent
e1cd2ccd40
commit
14993e89e2
|
@ -207,6 +207,13 @@ class ASTSynthesizer:
|
||||||
return ast.Assign(targets=[attr_node], value=value_node,
|
return ast.Assign(targets=[attr_node], value=value_node,
|
||||||
op_locs=[equals_loc], loc=name_loc.join(value_node.loc))
|
op_locs=[equals_loc], loc=name_loc.join(value_node.loc))
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_identifier(id, names):
|
||||||
|
sorted_names = sorted(names, key=lambda other: jaro_winkler(id, other), reverse=True)
|
||||||
|
if len(sorted_names) > 0:
|
||||||
|
if jaro_winkler(id, sorted_names[0]) > 0.0:
|
||||||
|
return sorted_names[0]
|
||||||
|
|
||||||
class StitchingASTTypedRewriter(ASTTypedRewriter):
|
class StitchingASTTypedRewriter(ASTTypedRewriter):
|
||||||
def __init__(self, engine, prelude, globals, host_environment, quote):
|
def __init__(self, engine, prelude, globals, host_environment, quote):
|
||||||
super().__init__(engine, prelude)
|
super().__init__(engine, prelude)
|
||||||
|
@ -227,7 +234,12 @@ class StitchingASTTypedRewriter(ASTTypedRewriter):
|
||||||
if node.id in self.host_environment:
|
if node.id in self.host_environment:
|
||||||
return self.quote(self.host_environment[node.id], node.loc)
|
return self.quote(self.host_environment[node.id], node.loc)
|
||||||
else:
|
else:
|
||||||
suggestion = self._most_similar_ident(node.id)
|
names = set()
|
||||||
|
names.update(self.host_environment.keys())
|
||||||
|
for typing_env in reversed(self.env_stack):
|
||||||
|
names.update(typing_env.keys())
|
||||||
|
|
||||||
|
suggestion = suggest_identifier(node.id, names)
|
||||||
if suggestion is not None:
|
if suggestion is not None:
|
||||||
diag = diagnostic.Diagnostic("fatal",
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
"name '{name}' is not bound to anything; did you mean '{suggestion}'?",
|
"name '{name}' is not bound to anything; did you mean '{suggestion}'?",
|
||||||
|
@ -240,17 +252,6 @@ class StitchingASTTypedRewriter(ASTTypedRewriter):
|
||||||
node.loc)
|
node.loc)
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
|
|
||||||
def _most_similar_ident(self, id):
|
|
||||||
names = set()
|
|
||||||
names.update(self.host_environment.keys())
|
|
||||||
for typing_env in reversed(self.env_stack):
|
|
||||||
names.update(typing_env.keys())
|
|
||||||
|
|
||||||
sorted_names = sorted(names, key=lambda other: jaro_winkler(id, other), reverse=True)
|
|
||||||
if len(sorted_names) > 0:
|
|
||||||
if jaro_winkler(id, sorted_names[0]) > 0.0:
|
|
||||||
return sorted_names[0]
|
|
||||||
|
|
||||||
class StitchingInferencer(Inferencer):
|
class StitchingInferencer(Inferencer):
|
||||||
def __init__(self, engine, value_map, quote):
|
def __init__(self, engine, value_map, quote):
|
||||||
super().__init__(engine)
|
super().__init__(engine)
|
||||||
|
@ -277,9 +278,23 @@ class StitchingInferencer(Inferencer):
|
||||||
# which would be the optimal solution.
|
# which would be the optimal solution.
|
||||||
for object_value, object_loc in self.value_map[object_type]:
|
for object_value, object_loc in self.value_map[object_type]:
|
||||||
if not hasattr(object_value, node.attr):
|
if not hasattr(object_value, node.attr):
|
||||||
|
if node.attr.startswith('_'):
|
||||||
|
names = set(filter(lambda name: not name.startswith('_'),
|
||||||
|
dir(object_value)))
|
||||||
|
else:
|
||||||
|
names = set(dir(object_value))
|
||||||
|
suggestion = suggest_identifier(node.attr, names)
|
||||||
|
|
||||||
note = diagnostic.Diagnostic("note",
|
note = diagnostic.Diagnostic("note",
|
||||||
"attribute accessed here", {},
|
"attribute accessed here", {},
|
||||||
node.loc)
|
node.loc)
|
||||||
|
if suggestion is not None:
|
||||||
|
diag = diagnostic.Diagnostic("error",
|
||||||
|
"host object does not have an attribute '{attr}'; "
|
||||||
|
"did you mean '{suggestion}'?",
|
||||||
|
{"attr": node.attr, "suggestion": suggestion},
|
||||||
|
object_loc, notes=[note])
|
||||||
|
else:
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"host object does not have an attribute '{attr}'",
|
"host object does not have an attribute '{attr}'",
|
||||||
{"attr": node.attr},
|
{"attr": node.attr},
|
||||||
|
|
|
@ -4,5 +4,11 @@
|
||||||
"module": "artiq.coredevice.comm_dummy",
|
"module": "artiq.coredevice.comm_dummy",
|
||||||
"class": "Comm",
|
"class": "Comm",
|
||||||
"arguments": {}
|
"arguments": {}
|
||||||
|
},
|
||||||
|
"core": {
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.core",
|
||||||
|
"class": "Core",
|
||||||
|
"arguments": {"ref_period": 1e-9}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
from artiq.language.core import *
|
||||||
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
class c:
|
||||||
|
xx = 1
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
# CHECK-L: <synthesized>:1: error: host object does not have an attribute 'x'; did you mean 'xx'?
|
||||||
|
# CHECK-L: ${LINE:+1}: note: expanded from here
|
||||||
|
a = c
|
||||||
|
# CHECK-L: ${LINE:+1}: note: attribute accessed here
|
||||||
|
a.x
|
|
@ -0,0 +1,10 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
from artiq.language.core import *
|
||||||
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
# CHECK-L: ${LINE:+1}: fatal: name 'prnt' is not bound to anything; did you mean 'print'?
|
||||||
|
prnt()
|
Loading…
Reference in New Issue