forked from M-Labs/artiq
compiler: give suggestions in diagnostics for unbound variable.
This uses the Jaro-Winkler edit distance, which seemed like the best fit for identifiers, even though it is intended for people's names.
This commit is contained in:
parent
9670939ca6
commit
c8cfa7c7bd
|
@ -11,6 +11,8 @@ from collections import OrderedDict, defaultdict
|
||||||
from pythonparser import ast, algorithm, source, diagnostic, parse_buffer
|
from pythonparser import ast, algorithm, source, diagnostic, parse_buffer
|
||||||
from pythonparser import lexer as source_lexer, parser as source_parser
|
from pythonparser import lexer as source_lexer, parser as source_parser
|
||||||
|
|
||||||
|
from Levenshtein import jaro_winkler
|
||||||
|
|
||||||
from ..language import core as language_core
|
from ..language import core as language_core
|
||||||
from . import types, builtins, asttyped, prelude
|
from . import types, builtins, asttyped, prelude
|
||||||
from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer
|
from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer
|
||||||
|
@ -224,12 +226,31 @@ class StitchingASTTypedRewriter(ASTTypedRewriter):
|
||||||
# Try to find this value in the host environment and quote it.
|
# Try to find this value in the host environment and quote it.
|
||||||
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:
|
||||||
|
suggestion = self._most_similar_ident(node.id)
|
||||||
|
if suggestion is not None:
|
||||||
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
|
"name '{name}' is not bound to anything; did you mean '{suggestion}'?",
|
||||||
|
{"name": node.id, "suggestion": suggestion},
|
||||||
|
node.loc)
|
||||||
|
self.engine.process(diag)
|
||||||
else:
|
else:
|
||||||
diag = diagnostic.Diagnostic("fatal",
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
"name '{name}' is not bound to anything", {"name": node.id},
|
"name '{name}' is not bound to anything", {"name": node.id},
|
||||||
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)
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -27,7 +27,8 @@ requirements = [
|
||||||
"sphinx", "sphinx-argparse", "pyserial", "numpy", "scipy",
|
"sphinx", "sphinx-argparse", "pyserial", "numpy", "scipy",
|
||||||
"python-dateutil", "prettytable", "h5py", "pydaqmx", "pyelftools",
|
"python-dateutil", "prettytable", "h5py", "pydaqmx", "pyelftools",
|
||||||
"quamash", "pyqtgraph", "pygit2", "aiohttp",
|
"quamash", "pyqtgraph", "pygit2", "aiohttp",
|
||||||
"llvmlite_artiq", "pythonparser", "lit", "OutputCheck",
|
"llvmlite_artiq", "pythonparser", "python-Levenshtein",
|
||||||
|
"lit", "OutputCheck",
|
||||||
]
|
]
|
||||||
|
|
||||||
scripts = [
|
scripts = [
|
||||||
|
|
Loading…
Reference in New Issue