Added first version of console autocompletion
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
from collections import namedtuple
|
||||
|
||||
import parso
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.services.SheerkaFunctionsParametersHistory import SheerkaFunctionsParametersHistory
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parso.python.tree import Name, PythonNode, Operator
|
||||
|
||||
func_found = namedtuple("func_found", "name params")
|
||||
|
||||
|
||||
class UpdateFunctionsParametersEvaluator(OneReturnValueEvaluator):
|
||||
"""
|
||||
This evaluator scans all successful PythonEvaluator results
|
||||
It then records the parameters of every functions found.
|
||||
For example, if the PythonEvaluator successfully evaluated
|
||||
foo(1, 'string') + bar(3.14)
|
||||
the parameters 1 and 'string' will be recorded for the function 'foo'
|
||||
and the parameter 3.14 will be recorded for the function 'bar'
|
||||
|
||||
These records will later be used as input for auto-completion
|
||||
"""
|
||||
NAME = "UpdateFunctionsParameters"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 79)
|
||||
|
||||
def matches(self, context, return_value):
|
||||
"""
|
||||
True if the return value is the successful result of PythonEvaluator
|
||||
:param context:
|
||||
:param return_value:
|
||||
:return:
|
||||
"""
|
||||
return return_value.status and return_value.who == context.sheerka.get_evaluator_name(PythonEvaluator.NAME)
|
||||
|
||||
def eval(self, context: ExecutionContext, return_value):
|
||||
sheerka = context.sheerka
|
||||
params_record_service = sheerka.services[SheerkaFunctionsParametersHistory.NAME]
|
||||
|
||||
if not return_value.parents:
|
||||
return self.add_not_found_error(sheerka, return_value)
|
||||
|
||||
for parent in return_value.parents:
|
||||
if parent.who == sheerka.get_parser_name("Python") and \
|
||||
parent.status and \
|
||||
sheerka.isinstance(parent.body, BuiltinConcepts.PARSER_RESULT):
|
||||
break
|
||||
else:
|
||||
return self.add_not_found_error(sheerka, return_value)
|
||||
|
||||
source = parent.body.source
|
||||
parsed = parso.parse(source)
|
||||
self.process_functions(context, params_record_service, parsed)
|
||||
return return_value
|
||||
|
||||
def process_functions(self, context, service, node):
|
||||
if not hasattr(node, "children"):
|
||||
return
|
||||
|
||||
if (func := self.get_function(node)) is not None:
|
||||
for i, p in enumerate(func.params):
|
||||
service.record_function_parameter(context, func.name, i, p)
|
||||
|
||||
function_params = node.children[1].children[1]
|
||||
if hasattr(function_params, "children"):
|
||||
for child in function_params.children: # function parameters
|
||||
self.process_functions(context, service, child)
|
||||
else:
|
||||
for child in node.children:
|
||||
self.process_functions(context, service, child)
|
||||
|
||||
def add_not_found_error(self, sheerka, return_value):
|
||||
error = sheerka.ret(self.name,
|
||||
False,
|
||||
sheerka.new(BuiltinConcepts.NOT_FOUND, body="source code"),
|
||||
parents=[return_value])
|
||||
if return_value.parents is None:
|
||||
return_value.parents = [error]
|
||||
else:
|
||||
return_value.parents.append(error)
|
||||
|
||||
return return_value
|
||||
|
||||
@staticmethod
|
||||
def get_function(node):
|
||||
if len(node.children) == 2 and \
|
||||
isinstance(node.children[0], Name) and \
|
||||
isinstance(node.children[1], PythonNode) and \
|
||||
node.children[1].type == "trailer" and \
|
||||
len(node.children[1].children) >= 2 and \
|
||||
isinstance(node.children[1].children[0], Operator) and \
|
||||
node.children[1].children[0].value == "(" and \
|
||||
isinstance(node.children[1].children[-1], Operator) and \
|
||||
node.children[1].children[-1].value == ")":
|
||||
name = node.children[0].value
|
||||
if len(node.children[1].children) == 2:
|
||||
params = []
|
||||
else:
|
||||
params_nodes = node.children[1].children[1]
|
||||
if hasattr(params_nodes, "children"):
|
||||
params = [p.get_code().strip() for p in params_nodes.children if not isinstance(p, Operator)]
|
||||
|
||||
else:
|
||||
params = [params_nodes.get_code().strip()]
|
||||
return func_found(name=name, params=params)
|
||||
else:
|
||||
return None
|
||||
Reference in New Issue
Block a user