Commit 465f90f6 authored by eckhart's avatar eckhart

- added syntaxtree.Node.__deepcopy__

parent ad1709b9
......@@ -34,6 +34,7 @@ See module ``ebnf`` for a sample of the implementation of a
compiler object.
"""
import copy
import os
import re
......@@ -216,8 +217,9 @@ class Compiler:
def compile_source(source: str,
preprocessor: Optional[PreprocessorFunc], # str -> str
parser: Grammar, # str -> Node (concrete syntax tree (CST))
transformer: TransformationFunc, # Node -> Node (abstract syntax tree (AST))
compiler: Compiler) -> Tuple[Any, List[Error], Node]: # Node (AST) -> Any
transformer: TransformationFunc, # Node (CST) -> Node (abstract syntax tree (AST))
compiler: Compiler, # Node (AST) -> Any
preserve_ast: bool = False) -> Tuple[Any, List[Error], Node]:
"""
Compiles a source in four stages:
1. Pre-Processing (if needed)
......@@ -239,13 +241,15 @@ def compile_source(source: str,
transforms it (in place) into an abstract syntax tree.
compiler (function): A compiler function or compiler class
instance
preserve_ast (bool): Preserves the AST-tree.
Returns (tuple):
The result of the compilation as a 3-tuple
(result, errors, abstract syntax tree). In detail:
1. The result as returned by the compiler or ``None`` in case of failure
2. A list of error or warning messages
3. The root-node of the abstract syntax tree
3. The root-node of the abstract syntax tree if `preserve_ast` is True
or `None` otherwise.
"""
original_text = load_if_file(source)
log_file_name = logfile_basename(source, compiler)
......@@ -272,6 +276,8 @@ def compile_source(source: str,
if is_logging():
log_ST(syntax_tree, log_file_name + '.ast')
if not is_error(syntax_tree.error_flag):
if preserve_ast:
ast = copy.deepcopy(syntax_tree)
result = compiler(syntax_tree)
# print(syntax_tree.as_sxpr())
# messages.extend(syntax_tree.collect_errors())
......@@ -279,4 +285,4 @@ def compile_source(source: str,
messages = syntax_tree.collect_errors()
adjust_error_locations(messages, original_text, source_mapping)
return result, messages, syntax_tree
return result, messages, (ast if preserve_ast else None)
......@@ -540,10 +540,6 @@ class EBNFCompiler(Compiler):
definitions.append((self.WHITESPACE_PARSER_KEYWORD,
'Whitespace(%s)' % self.WHITESPACE_KEYWORD))
# definitions.append(('wspR__', self.WHITESPACE_KEYWORD
# if 'right' in self.directives['literalws'] else "''"))
# definitions.append(('wspL__', self.WHITESPACE_KEYWORD
# if 'left' in self.directives['literalws'] else "''"))
definitions.append((self.WHITESPACE_KEYWORD,
("mixin_comment(whitespace=" + self.RAW_WS_KEYWORD +
", comment=" + self.COMMENT_KEYWORD + ")")))
......
......@@ -53,8 +53,8 @@ __all__ = ('Parser',
'TKN',
'Whitespace',
'mixin_comment',
# 'UnaryOperator',
# 'NaryOperator',
'UnaryOperator',
'NaryOperator',
'Synonym',
'Option',
'ZeroOrMore',
......
......@@ -26,6 +26,7 @@ parser classes are defined in the ``parse`` module.
import collections.abc
from collections import OrderedDict
import copy
from DHParser.error import Error, linebreaks, line_col
from DHParser.stringview import StringView
......@@ -278,6 +279,17 @@ class Node(collections.abc.Sized):
self.result = result
self.parser = parser or ZOMBIE_PARSER
def __deepcopy__(self, memo):
if self.children:
duplicate = self.__class__(self.parser, copy.deepcopy(self.children), False)
else:
duplicate = self.__class__(self.parser, self.result, True)
duplicate.errors = copy.deepcopy(self.errors) if self.errors else []
duplicate._pos = self._pos
duplicate._len = self._len
if hasattr(self, '_xml_attr'):
duplicate._xml_attr = copy.deepcopy(self._xml_attr)
return duplicate
def __str__(self):
s = "".join(str(child) for child in self.children) if self.children else self.content
......
Markdown is supported
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