compiler.embedding: show suggestions for mistyped host object attributes.

This commit is contained in:
whitequark 2015-11-24 17:44:58 +08:00
parent e1cd2ccd40
commit 14993e89e2
4 changed files with 63 additions and 16 deletions

View File

@ -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,13 +278,27 @@ 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)
diag = diagnostic.Diagnostic("error", if suggestion is not None:
"host object does not have an attribute '{attr}'", diag = diagnostic.Diagnostic("error",
{"attr": node.attr}, "host object does not have an attribute '{attr}'; "
object_loc, notes=[note]) "did you mean '{suggestion}'?",
{"attr": node.attr, "suggestion": suggestion},
object_loc, notes=[note])
else:
diag = diagnostic.Diagnostic("error",
"host object does not have an attribute '{attr}'",
{"attr": node.attr},
object_loc, notes=[note])
self.engine.process(diag) self.engine.process(diag)
return return

View File

@ -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}
} }
} }

View File

@ -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

View File

@ -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()