Now ErrorLeaf and ErrorNode are part of the syntax tree. This makes probably sense. The documentation will follow once it's clear how they will shape out.

This commit is contained in:
Dave Halter
2016-05-30 00:33:58 +02:00
parent daa68b66ad
commit 4f6368e7eb
8 changed files with 66 additions and 13 deletions

View File

@@ -133,7 +133,11 @@ class Completion:
if completion_parts.name:
pos = pos[0], pos[1] - len(completion_parts.name)
try:
stack = helpers.get_stack_at_position(grammar, self._source, self._module, pos)
except helpers.OnErrorLeaf:
return []
allowed_keywords, allowed_tokens = \
helpers.get_possible_completion_types(grammar, stack)

View File

@@ -69,13 +69,21 @@ def get_user_or_error_stmt(module, position):
if user_stmt is None or user_stmt.type == 'whitespace':
# If there's no error statement and we're just somewhere, we want
# completions for just whitespace.
'''
for error_stmt in module.error_statements:
if error_stmt.start_pos < position <= error_stmt.end_pos:
return error_stmt
'''
return user_stmt
class OnErrorLeaf(Exception):
@property
def error_leaf(self):
return self.args[0]
def get_stack_at_position(grammar, source, module, pos):
"""
Returns the possible node names (e.g. import_from, xor_test or yield_stmt).
@@ -87,11 +95,25 @@ def get_stack_at_position(grammar, source, module, pos):
else:
if user_stmt is None:
user_stmt = module.get_leaf_for_position(pos, include_prefixes=True)
print(user_stmt)
if pos <= user_stmt.start_pos:
try:
leaf = user_stmt.get_previous_leaf()
except IndexError:
pass
else:
user_stmt = get_user_or_error_stmt(module, leaf.start_pos)
# Only if were in front of the leaf we want to get the stack,
# because after there's probably a newline or whatever that would
# be actually tokenized and is not just prefix.
if pos <= user_stmt.start_pos:
try:
leaf = user_stmt.get_previous_leaf()
except IndexError:
# Seems to be the first element.
pass
else:
'''
for error_stmt in reversed(module.error_statements):
if leaf.start_pos <= error_stmt.start_pos <= user_stmt.start_pos:
# The leaf appears not to be the last leaf. It's actually an
@@ -100,6 +122,11 @@ def get_stack_at_position(grammar, source, module, pos):
break
else:
user_stmt = get_user_or_error_stmt(module, leaf.start_pos)
'''
if user_stmt.type == 'error_leaf':
# Error leafs cannot be parsed.
raise OnErrorLeaf(user_stmt)
print(user_stmt.start_pos, pos)
code = _get_code(source, user_stmt.start_pos, pos)

View File

@@ -27,7 +27,7 @@ def deep_ast_copy(obj, parent=None, new_elements=None):
for child in obj.children:
typ = child.type
if typ in ('whitespace', 'operator', 'keyword', 'number', 'string',
'indent', 'dedent'):
'indent', 'dedent', 'error_leaf'):
# At the moment we're not actually copying those primitive
# elements, because there's really no need to. The parents are
# obviously wrong, but that's not an issue.

View File

@@ -422,6 +422,8 @@ class ParserWithRecovery(Parser):
# TODO document the shizzle!
#self._error_statements.append(ErrorStatement(stack, None, None,
# self.position_modifier, error_leaf.end_pos))
error_leaf = pt.ErrorLeaf(self.position_modifier, value, start_pos, prefix)
stack[-1][2][1].append(error_leaf)
return
if typ == INDENT:
@@ -462,17 +464,20 @@ class ParserWithRecovery(Parser):
failed_stack = []
found = False
all_nodes = []
for dfa, state, (typ, nodes) in stack[start_index:]:
if nodes:
found = True
if found:
symbol = grammar.number2symbol[typ]
failed_stack.append((symbol, nodes))
all_nodes += nodes
if nodes and nodes[0] in ('def', 'class', 'lambda'):
self._scope_names_stack.pop()
if failed_stack:
err = ErrorStatement(failed_stack, arcs, value, self.position_modifier, start_pos)
self._error_statements.append(err)
stack[start_index - 1][2][1].append(pt.ErrorNode(all_nodes))
self._last_failed_start_pos = start_pos

View File

@@ -641,6 +641,22 @@ class Node(BaseNode):
return "%s(%s, %r)" % (self.__class__.__name__, self.type, self.children)
class ErrorNode(BaseNode):
"""
TODO doc
"""
__slots__ = ()
type = 'error_node'
class ErrorLeaf(Leaf):
"""
TODO doc
"""
__slots__ = ()
type = 'error_leaf'
class IsScopeMeta(type):
def __instancecheck__(self, other):
return other.is_scope()

View File

@@ -31,7 +31,8 @@ def wrong_indents():
asdf = 3
asdf
asdf(
#? int()
# TODO this seems to be wrong now?
##? int()
asdf
def openbrace():
asdf = 3

View File

@@ -2,7 +2,7 @@
#? ['raise']
raise
#? ['except', 'Exception']
#? ['Exception']
except
#? []

View File

@@ -86,7 +86,7 @@ from os import path
# should not return a function, because `a` is a function above
def f(b, a): return a
#? []
#? ['in', 'is', 'and', 'if', 'or', 'not']
f(b=3)
# -----------------