Commit 7a26a74a authored by Eckhart Arnold's avatar Eckhart Arnold
Browse files

After the parsing stage, line and column of error messages are now being...

After the parsing stage, line and column of error messages are now being determined when adding an error to the root-node, already. No need to call Error.adjust_error_locations() on later tree processing stages
parent 5bf4eb9e
......@@ -48,7 +48,7 @@ from DHParser.parse import Grammar
from DHParser.error import adjust_error_locations, is_error, is_fatal, Error, \
TREE_PROCESSING_CRASH, COMPILER_CRASH, AST_TRANSFORM_CRASH
from DHParser.log import log_parsing_history, log_ST, is_logging
from DHParser.toolkit import load_if_file, is_filename, NOPE
from DHParser.toolkit import load_if_file, is_filename, identity
__all__ = ('CompilerError',
......@@ -357,18 +357,13 @@ def compile_source(source: str,
if preprocessor is None:
source_text = original_text # type: str
source_mapping = lambda i: i # type: SourceMapFunc
source_mapping = identity # type: SourceMapFunc
else:
source_text, source_mapping = with_source_mapping(preprocessor(original_text))
# if out_source_data is not NOPE:
# assert out_source_data == []
# out_source_data.append(original_text)
# out_source_data.append(source_mapping)
# parsing
syntax_tree = parser(source_text) # type: RootNode
syntax_tree = parser(source_text, source_mapping=source_mapping) # type: RootNode
syntax_tree.source = original_text
syntax_tree.source_mapping = source_mapping
if 'cst' in log_syntax_trees:
......@@ -430,7 +425,8 @@ def compile_source(source: str,
result = compiler(syntax_tree)
messages = syntax_tree.errors_sorted # type: List[Error]
adjust_error_locations(messages, original_text, source_mapping)
# Obsolete, because RootNode adjusts error locations whenever an error is added:
# adjust_error_locations(messages, original_text, source_mapping)
return result, messages, ast
......@@ -502,7 +498,8 @@ def process_tree(tp: TreeProcessor, tree: RootNode) -> Tuple[RootNode, List[Erro
messages = tree.errors_sorted # type: List[Error]
new_msgs = [msg for msg in messages if msg.line < 0]
adjust_error_locations(new_msgs, tree.source, tree.source_mapping)
# Obsolete, because RootNode adjusts error locations whenever an error is added:
# adjust_error_locations(new_msgs, tree.source, tree.source_mapping)
return tree, messages
......
......@@ -183,7 +183,7 @@ class Error:
self.orig_pos = orig_pos # type: int
self.line = line # type: int
self.column = column # type: int
# support for Languager Server Protocol Diagnostics
# support for Language Server Protocol Diagnostics
# see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
self.length = length # type: int
self.end_line = -1 # type: int
......
......@@ -50,7 +50,7 @@ from DHParser.stringview import StringView, EMPTY_STRING_VIEW
from DHParser.syntaxtree import ChildrenType, Node, RootNode, WHITESPACE_PTYPE, \
TOKEN_PTYPE, ZOMBIE_TAG, EMPTY_NODE, ResultType
from DHParser.toolkit import sane_parser_name, escape_control_characters, re, cython, \
abbreviate_middle, RX_NEVER_MATCH, RxPatternType, linebreaks, line_col
abbreviate_middle, RX_NEVER_MATCH, RxPatternType, linebreaks, line_col, identity
__all__ = ('ParserError',
......@@ -1334,6 +1334,7 @@ class Grammar:
def __call__(self,
document: str,
start_parser: Union[str, Parser] = "root_parser__",
source_mapping = identity,
*, complete_match: bool = True) -> RootNode:
"""
Parses a document with with parser-combinators.
......@@ -1484,7 +1485,7 @@ class Grammar:
result.result = result.children + (error_node,)
else:
self.tree__.new_error(result, error_msg, error_code)
self.tree__.swallow(result)
self.tree__.swallow(result, document, source_mapping)
if not self.tree__.source: self.tree__.source = document
self.start_parser__ = None
# self.history_tracking__ = save_history_tracking
......@@ -2254,7 +2255,7 @@ class Counted(UnaryParser):
>>> Grammar(A2_4)('AAAAA', complete_match=False).as_sxpr()
'(:Counted (:Text "A") (:Text "A") (:Text "A") (:Text "A"))'
>>> Grammar(A2_4)('A', complete_match=False).as_sxpr()
'(ZOMBIE__ `(Error (1040): Parser did not match!))'
'(ZOMBIE__ `(1:1: Error (1040): Parser did not match!))'
>>> moves = OneOrMore(Counted(Text('A'), (1, 3)) + Counted(Text('B'), (1, 3)))
>>> result = Grammar(moves)('AAABABB')
>>> result.tag_name, result.content
......
......@@ -23,8 +23,8 @@ to map the locations of parser and compiler errors to the
non-preprocessed source text.
Preprocessing (and source mapping of errors) will only be needed
for some domain specific languages, most notable those that
cannot completely be described with context-free grammars.
for some domain specific languages, most notably those that
cannot completely be described entirely with context-free grammars.
"""
......
......@@ -912,7 +912,7 @@ class Server:
values: `SERVER_OFFLINE`, `SERVER_STARTING`, `SERVER_ONLINE`,
`SERVER_TERMINATING`
:var host: The host, the server runs on, e.g. "127.0.0.1"
:var port: The port of the server, e.g. 8888
:var port: The port of the server, e.g. 8890
:var server: The asyncio.Server if the server is online, or `None`.
:var serving_task: The task in which the asyncio.Server is run.
:var stop_response: The response string that is written to the stream
......
......@@ -380,7 +380,8 @@ from typing import Callable, cast, Iterator, Sequence, List, Set, Union, \
Tuple, Container, Optional, Dict
from DHParser.configuration import get_config_value, ALLOWED_PRESET_VALUES
from DHParser.error import Error, ErrorCode, ERROR, PARSER_STOPPED_BEFORE_END
from DHParser.error import Error, ErrorCode, ERROR, PARSER_STOPPED_BEFORE_END, \
adjust_error_locations
from DHParser.preprocess import SourceMapFunc
from DHParser.stringview import StringView # , real_indices
from DHParser.toolkit import re, cython, linebreaks, line_col, JSONnull, \
......@@ -968,7 +969,7 @@ class Node: # (collections.abc.Sized): Base class omitted for cython-compatibil
return self._xml_attr
@attr.setter
def attr(self, attr_dict: OrderedDict[str, str]):
def attr(self, attr_dict: Dict[str, str]):
self._xml_attr = attr_dict
def get_attr(self, attribute: str, default: str) -> str:
......@@ -2252,24 +2253,26 @@ class RootNode(Node):
during the parsing process, already. In order to connect the root node to
the tree, when parsing is finished, the swallow()-method must be called.
errors (list): A list of all errors that have occurred so far during
processing (i.e. parsing, AST-transformation, compiling)
of this tree.
error_nodes (dict): A mapping of node-ids to a list of errors that
occurred on the node with the respective id.
error_positions (dict): A mapping of locations to a set of ids of
nodes that contain an error at that particular location
error_flag (int): the highest warning or error level of all errors
that occurred.
inline_tags (set of strings): see `Node.as_xml()` for an explanation.
omit_tags (set of strings): see `Node.as_xml()` for an explanation.
empty_tags (set oif strings): see `Node.as_xml()` for an explanation.
:ivar errors: A list of all errors that have occurred so far during
processing (i.e. parsing, AST-transformation, compiling) of this tree.
:ivar errors_sorted: (read-only property) The list of errors orderd by
their position.
:ivar error_nodes: A mapping of node-ids to a list of errors that
occurred on the node with the respective id.
:ivar error_positions: A mapping of locations to a set of ids of nodes
that contain an error at that particular location
:ivar error_flag: the highest warning or error level of all errors
that occurred.
:ivar source: The source code (after preprocessing)
:ivar source_mapping: A source mapping function to map source code
position to positions of the non-preprocessed source.
See module `preprocess`
:ivar lbreaks: A list of indicies of all linebreaks in the source.
:ivar inline_tags: see `Node.as_xml()` for an explanation.
:ivar omit_tags: see `Node.as_xml()` for an explanation.
:ivar empty_tags: see `Node.as_xml()` for an explanation.
"""
def __init__(self, node: Optional[Node] = None,
......@@ -2280,8 +2283,6 @@ class RootNode(Node):
self.error_nodes = dict() # type: Dict[int, List[Error]] # id(node) -> error list
self.error_positions = dict() # type: Dict[int, Set[int]] # pos -> set of id(node)
self.error_flag = 0
if node is not None:
self.swallow(node)
# info on source code (to be carried along all stages of tree-processing)
self.source = source # type: str
self.source_mapping = source_mapping # type: SourceMapFunc
......@@ -2290,6 +2291,8 @@ class RootNode(Node):
self.inline_tags = set() # type: Set[str]
self.omit_tags = set() # type: Set[str]
self.empty_tags = set() # type: Set[str]
if node is not None:
self.swallow(node, source, source_mapping)
# def clear_errors(self):
# """
......@@ -2353,7 +2356,7 @@ class RootNode(Node):
It is possible to add errors to a RootNode object, before it
has actually swallowed the root of the syntax tree.
"""
if source:
if source and source != self.source:
self.source = source
self.lbreaks = linebreaks(source)
if source_mapping != identity: self.source_mapping = source_mapping
......@@ -2373,6 +2376,8 @@ class RootNode(Node):
# self._content = node._content
if id(node) in self.error_nodes:
self.error_nodes[id(self)] = self.error_nodes[id(node)]
if self.source:
adjust_error_locations(self.errors, self.source, self.source_mapping)
return self
def add_error(self, node: Optional[Node], error: Error) -> 'RootNode':
......@@ -2409,6 +2414,8 @@ class RootNode(Node):
self.error_nodes.setdefault(id(node), []).append(error)
if node.pos == error.pos:
self.error_positions.setdefault(error.pos, set()).add(id(node))
if self.source:
adjust_error_locations([error], self.source, self.source_mapping)
self.errors.append(error)
self.error_flag = max(self.error_flag, error.code)
return self
......
......@@ -37,7 +37,7 @@ LOGGING_REQUEST = 'logging("")'
LOG_PATH = 'LOGS/'
DEFAULT_HOST = '127.0.0.1'
DEFAULT_PORT = 8888
DEFAULT_PORT = 8890
ALTERNATIVE_PORTS = [8888, 8889, 8898, 8980, 8988, 8989]
DATA_RECEIVE_LIMIT = 262144
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment