load_grammar, reconstruct, and visitorsgm/2021-09-23T00Z/github.com--lark-parser-lark/1.0b
@@ -1,31 +0,0 @@ | |||
from typing import List, Tuple, Union, Callable, Dict, Optional | |||
from .tree import Tree | |||
from .grammar import RuleOptions | |||
from .exceptions import UnexpectedInput | |||
class Grammar: | |||
rule_defs: List[Tuple[str, Tuple[str, ...], Tree, RuleOptions]] | |||
term_defs: List[Tuple[str, Tuple[Tree, int]]] | |||
ignore: List[str] | |||
class GrammarBuilder: | |||
global_keep_all_tokens: bool | |||
import_paths: List[Union[str, Callable]] | |||
used_files: Dict[str, str] | |||
def __init__(self, global_keep_all_tokens: bool = False, import_paths: List[Union[str, Callable]] = None, used_files: Dict[str, str]=None) -> None: ... | |||
def load_grammar(self, grammar_text: str, grammar_name: str = ..., mangle: Callable[[str], str] = None) -> None: ... | |||
def do_import(self, dotted_path: Tuple[str, ...], base_path: Optional[str], aliases: Dict[str, str], | |||
base_mangle: Callable[[str], str] = None) -> None: ... | |||
def validate(self) -> None: ... | |||
def build(self) -> Grammar: ... | |||
def find_grammar_errors(text: str, start: str='start') -> List[Tuple[UnexpectedInput, str]]: ... |
@@ -1,39 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
from typing import List, Dict, Union, Callable, Iterable | |||
from .grammar import Symbol | |||
from .lark import Lark | |||
from .tree import Tree | |||
from .visitors import Transformer_InPlace | |||
from .lexer import TerminalDef | |||
class WriteTokensTransformer(Transformer_InPlace): | |||
def __init__(self, tokens: Dict[str, TerminalDef], term_subs: Dict[str, Callable[[Symbol], str]] = ...): ... | |||
class MatchTree(Tree): | |||
pass | |||
class MakeMatchTree: | |||
name: str | |||
expansion: List[TerminalDef] | |||
def __init__(self, name: str, expansion: List[TerminalDef]): | |||
... | |||
def __call__(self, args: List[Union[str, Tree]]): | |||
... | |||
class Reconstructor: | |||
def __init__(self, parser: Lark, term_subs: Dict[str, Callable[[Symbol], str]] = ...): | |||
... | |||
def reconstruct(self, tree: Tree, postproc: Callable[[Iterable[str]], Iterable[str]]=None, | |||
insert_spaces: bool = True) -> str: | |||
... |
@@ -1,108 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
from typing import TypeVar, Tuple, List, Callable, Generic, Type, Union | |||
from abc import ABC | |||
from .tree import Tree | |||
_T = TypeVar('_T') | |||
_R = TypeVar('_R') | |||
_FUNC = Callable[..., _T] | |||
_DECORATED = Union[_FUNC, type] | |||
class Transformer(ABC, Generic[_T]): | |||
def __init__(self, visit_tokens: bool = True) -> None: | |||
... | |||
def transform(self, tree: Tree) -> _T: | |||
... | |||
def __mul__(self, other: Transformer[_T]) -> TransformerChain[_T]: | |||
... | |||
class TransformerChain(Generic[_T]): | |||
transformers: Tuple[Transformer[_T], ...] | |||
def __init__(self, *transformers: Transformer[_T]) -> None: | |||
... | |||
def transform(self, tree: Tree) -> _T: | |||
... | |||
def __mul__(self, other: Transformer[_T]) -> TransformerChain[_T]: | |||
... | |||
class Transformer_InPlace(Transformer): | |||
pass | |||
class Transformer_NonRecursive(Transformer): | |||
pass | |||
class Transformer_InPlaceRecursive(Transformer): | |||
pass | |||
class VisitorBase: | |||
pass | |||
class Visitor(VisitorBase, ABC, Generic[_T]): | |||
def visit(self, tree: Tree) -> Tree: | |||
... | |||
def visit_topdown(self, tree: Tree) -> Tree: | |||
... | |||
class Visitor_Recursive(VisitorBase): | |||
def visit(self, tree: Tree) -> Tree: | |||
... | |||
def visit_topdown(self, tree: Tree) -> Tree: | |||
... | |||
class Interpreter(ABC, Generic[_T]): | |||
def visit(self, tree: Tree) -> _T: | |||
... | |||
def visit_children(self, tree: Tree) -> List[_T]: | |||
... | |||
_InterMethod = Callable[[Type[Interpreter], _T], _R] | |||
def v_args( | |||
inline: bool = False, | |||
meta: bool = False, | |||
tree: bool = False, | |||
wrapper: Callable = None | |||
) -> Callable[[_DECORATED], _DECORATED]: | |||
... | |||
def visit_children_decor(func: _InterMethod) -> _InterMethod: | |||
... | |||
class Discard(Exception): | |||
pass | |||
# Deprecated | |||
class InlineTransformer: | |||
pass | |||
# Deprecated | |||
def inline_args(obj: _FUNC) -> _FUNC: | |||
... |
@@ -1,13 +1,14 @@ | |||
"Provides Indentation services for languages with indentation similar to Python" | |||
from abc import ABC, abstractmethod | |||
from typing import Tuple, List, Iterator, Optional | |||
from .exceptions import LarkError | |||
from .lark import PostLex | |||
from .lexer import Token | |||
###{standalone | |||
from typing import Tuple, List, Iterator, Optional | |||
class DedentError(LarkError): | |||
pass | |||
@@ -8,6 +8,7 @@ import pkgutil | |||
from ast import literal_eval | |||
from numbers import Integral | |||
from contextlib import suppress | |||
from typing import List, Tuple, Union, Callable, Dict, Optional | |||
from .utils import bfs, Py36, logger, classify_bool, is_id_continue, is_id_start, bfs_all_unique | |||
from .lexer import Token, TerminalDef, PatternStr, PatternRE | |||
@@ -17,7 +18,7 @@ from .parser_frontends import ParsingFrontend | |||
from .common import LexerConf, ParserConf | |||
from .grammar import RuleOptions, Rule, Terminal, NonTerminal, Symbol | |||
from .utils import classify, dedup_list | |||
from .exceptions import GrammarError, UnexpectedCharacters, UnexpectedToken, ParseError | |||
from .exceptions import GrammarError, UnexpectedCharacters, UnexpectedToken, ParseError, UnexpectedInput | |||
from .tree import Tree, SlottedTree as ST | |||
from .visitors import Transformer, Visitor, v_args, Transformer_InPlace, Transformer_NonRecursive | |||
@@ -552,9 +553,9 @@ def nr_deepcopy_tree(t): | |||
class Grammar: | |||
def __init__(self, rule_defs, term_defs, ignore): | |||
self.term_defs = term_defs | |||
self.rule_defs = rule_defs | |||
self.ignore = ignore | |||
self.term_defs: List[Tuple[str, Tuple[Tree, int]]] = term_defs | |||
self.rule_defs: List[Tuple[str, Tuple[str, ...], Tree, RuleOptions]] = rule_defs | |||
self.ignore: List[str] = ignore | |||
def compile(self, start, terminals_to_keep): | |||
# We change the trees in-place (to support huge grammars) | |||
@@ -874,7 +875,7 @@ def _search_interactive_parser(interactive_parser, predicate): | |||
if predicate(p): | |||
return path, p | |||
def find_grammar_errors(text, start='start'): | |||
def find_grammar_errors(text: str, start: str='start') -> List[Tuple[UnexpectedInput, str]]: | |||
errors = [] | |||
def on_error(e): | |||
errors.append((e, _error_repr(e))) | |||
@@ -923,10 +924,10 @@ def _mangle_exp(exp, mangle): | |||
class GrammarBuilder: | |||
def __init__(self, global_keep_all_tokens=False, import_paths=None, used_files=None): | |||
self.global_keep_all_tokens = global_keep_all_tokens | |||
self.import_paths = import_paths or [] | |||
self.used_files = used_files or {} | |||
def __init__(self, global_keep_all_tokens: bool=False, import_paths: List[Union[str, Callable]]=None, used_files: Dict[str, str]=None) -> None: | |||
self.global_keep_all_tokens: bool = global_keep_all_tokens | |||
self.import_paths: List[Union[str, Callable]] = import_paths or [] | |||
self.used_files: Dict[str, str] = used_files or {} | |||
self._definitions = {} | |||
self._ignore_names = [] | |||
@@ -1067,7 +1068,7 @@ class GrammarBuilder: | |||
return name, exp, params, opts | |||
def load_grammar(self, grammar_text, grammar_name="<?>", mangle=None): | |||
def load_grammar(self, grammar_text: str, grammar_name: str="<?>", mangle: Callable[[str], str]=None) -> None: | |||
tree = _parse_grammar(grammar_text, grammar_name) | |||
imports = {} | |||
@@ -1130,7 +1131,7 @@ class GrammarBuilder: | |||
self._definitions = {k: v for k, v in self._definitions.items() if k in _used} | |||
def do_import(self, dotted_path, base_path, aliases, base_mangle=None): | |||
def do_import(self, dotted_path: Tuple[str, ...], base_path: Optional[str], aliases: Dict[str, str], base_mangle: Callable[[str], str]=None) -> None: | |||
assert dotted_path | |||
mangle = _get_mangle('__'.join(dotted_path), aliases, base_mangle) | |||
grammar_path = os.path.join(*dotted_path) + EXT | |||
@@ -1166,7 +1167,7 @@ class GrammarBuilder: | |||
assert False, "Couldn't import grammar %s, but a corresponding file was found at a place where lark doesn't search for it" % (dotted_path,) | |||
def validate(self): | |||
def validate(self) -> None: | |||
for name, (params, exp, _options) in self._definitions.items(): | |||
for i, p in enumerate(params): | |||
if p in self._definitions: | |||
@@ -1195,7 +1196,7 @@ class GrammarBuilder: | |||
if not set(self._definitions).issuperset(self._ignore_names): | |||
raise GrammarError("Terminals %s were marked to ignore but were not defined!" % (set(self._ignore_names) - set(self._definitions))) | |||
def build(self): | |||
def build(self) -> Grammar: | |||
self.validate() | |||
rule_defs = [] | |||
term_defs = [] | |||
@@ -1,11 +1,13 @@ | |||
"""Reconstruct text from a tree, based on Lark grammar""" | |||
from typing import List, Dict, Union, Callable, Iterable | |||
import unicodedata | |||
from .lark import Lark | |||
from .tree import Tree | |||
from .visitors import Transformer_InPlace | |||
from .lexer import Token, PatternStr | |||
from .grammar import Terminal, NonTerminal | |||
from .lexer import Token, PatternStr, TerminalDef | |||
from .grammar import Terminal, NonTerminal, Symbol | |||
from .tree_matcher import TreeMatcher, is_discarded_terminal | |||
from .utils import is_id_continue | |||
@@ -21,7 +23,7 @@ def is_iter_empty(i): | |||
class WriteTokensTransformer(Transformer_InPlace): | |||
"Inserts discarded tokens into their correct place, according to the rules of grammar" | |||
def __init__(self, tokens, term_subs): | |||
def __init__(self, tokens: Dict[str, TerminalDef], term_subs: Dict[str, Callable[[Symbol], str]]) -> None: | |||
self.tokens = tokens | |||
self.term_subs = term_subs | |||
@@ -70,7 +72,7 @@ class Reconstructor(TreeMatcher): | |||
term_subs: a dictionary of [Terminal name as str] to [output text as str] | |||
""" | |||
def __init__(self, parser, term_subs=None): | |||
def __init__(self, parser: Lark, term_subs: Dict[str, Callable[[Symbol], str]]=None) -> None: | |||
TreeMatcher.__init__(self, parser) | |||
self.write_tokens = WriteTokensTransformer({t.name:t for t in self.tokens}, term_subs or {}) | |||
@@ -87,7 +89,7 @@ class Reconstructor(TreeMatcher): | |||
else: | |||
yield item | |||
def reconstruct(self, tree, postproc=None, insert_spaces=True): | |||
def reconstruct(self, tree: Tree, postproc: Callable[[Iterable[str]], Iterable[str]]=None, insert_spaces: bool=True) -> str: | |||
x = self._reconstruct(tree) | |||
if postproc: | |||
x = postproc(x) | |||
@@ -1,3 +1,4 @@ | |||
from abc import ABC | |||
from functools import wraps | |||
from .utils import smart_decorator, combine_alternatives | |||
@@ -7,7 +8,12 @@ from .lexer import Token | |||
###{standalone | |||
from inspect import getmembers, getmro | |||
from typing import TypeVar, Tuple, List, Callable, Generic, Type, Union | |||
_T = TypeVar('_T') | |||
_R = TypeVar('_R') | |||
_FUNC = Callable[..., _T] | |||
_DECORATED = Union[_FUNC, type] | |||
class Discard(Exception): | |||
"""When raising the Discard exception in a transformer callback, | |||
@@ -46,7 +52,7 @@ class _Decoratable: | |||
return cls | |||
class Transformer(_Decoratable): | |||
class Transformer(_Decoratable, ABC, Generic[_T]): | |||
"""Transformers visit each node of the tree, and run the appropriate method on it according to the node's data. | |||
Methods are provided by the user via inheritance, and called according to ``tree.data``. | |||
@@ -74,7 +80,7 @@ class Transformer(_Decoratable): | |||
""" | |||
__visit_tokens__ = True # For backwards compatibility | |||
def __init__(self, visit_tokens=True): | |||
def __init__(self, visit_tokens: bool=True) -> None: | |||
self.__visit_tokens__ = visit_tokens | |||
def _call_userfunc(self, tree, new_children=None): | |||
@@ -125,11 +131,11 @@ class Transformer(_Decoratable): | |||
children = list(self._transform_children(tree.children)) | |||
return self._call_userfunc(tree, children) | |||
def transform(self, tree): | |||
def transform(self, tree: Tree) -> _T: | |||
"Transform the given tree, and return the final result" | |||
return self._transform_tree(tree) | |||
def __mul__(self, other): | |||
def __mul__(self, other: 'Transformer[_T]') -> 'TransformerChain[_T]': | |||
"""Chain two transformers together, returning a new transformer. | |||
""" | |||
return TransformerChain(self, other) | |||
@@ -149,16 +155,16 @@ class Transformer(_Decoratable): | |||
return token | |||
class TransformerChain(object): | |||
class TransformerChain(Generic[_T]): | |||
def __init__(self, *transformers): | |||
self.transformers = transformers | |||
self.transformers: Tuple[Transformer[_T], ...] = transformers | |||
def transform(self, tree): | |||
def transform(self, tree: Tree) -> _T: | |||
for t in self.transformers: | |||
tree = t.transform(tree) | |||
return tree | |||
def __mul__(self, other): | |||
def __mul__(self, other: Transformer[_T]) -> 'TransformerChain[_T]': | |||
return TransformerChain(*self.transformers + (other,)) | |||
@@ -239,19 +245,19 @@ class VisitorBase: | |||
return cls | |||
class Visitor(VisitorBase): | |||
class Visitor(VisitorBase, ABC, Generic[_T]): | |||
"""Tree visitor, non-recursive (can handle huge trees). | |||
Visiting a node calls its methods (provided by the user via inheritance) according to ``tree.data`` | |||
""" | |||
def visit(self, tree): | |||
def visit(self, tree: Tree) -> Tree: | |||
"Visits the tree, starting with the leaves and finally the root (bottom-up)" | |||
for subtree in tree.iter_subtrees(): | |||
self._call_userfunc(subtree) | |||
return tree | |||
def visit_topdown(self,tree): | |||
def visit_topdown(self, tree: Tree) -> Tree: | |||
"Visit the tree, starting at the root, and ending at the leaves (top-down)" | |||
for subtree in tree.iter_subtrees_topdown(): | |||
self._call_userfunc(subtree) | |||
@@ -266,7 +272,7 @@ class Visitor_Recursive(VisitorBase): | |||
Slightly faster than the non-recursive version. | |||
""" | |||
def visit(self, tree): | |||
def visit(self, tree: Tree) -> Tree: | |||
"Visits the tree, starting with the leaves and finally the root (bottom-up)" | |||
for child in tree.children: | |||
if isinstance(child, Tree): | |||
@@ -275,7 +281,7 @@ class Visitor_Recursive(VisitorBase): | |||
self._call_userfunc(tree) | |||
return tree | |||
def visit_topdown(self,tree): | |||
def visit_topdown(self,tree: Tree) -> Tree: | |||
"Visit the tree, starting at the root, and ending at the leaves (top-down)" | |||
self._call_userfunc(tree) | |||
@@ -286,16 +292,7 @@ class Visitor_Recursive(VisitorBase): | |||
return tree | |||
def visit_children_decor(func): | |||
"See Interpreter" | |||
@wraps(func) | |||
def inner(cls, tree): | |||
values = cls.visit_children(tree) | |||
return func(cls, values) | |||
return inner | |||
class Interpreter(_Decoratable): | |||
class Interpreter(_Decoratable, ABC, Generic[_T]): | |||
"""Interpreter walks the tree starting at the root. | |||
Visits the tree, starting with the root and finally the leaves (top-down) | |||
@@ -307,7 +304,7 @@ class Interpreter(_Decoratable): | |||
This allows the user to implement branching and loops. | |||
""" | |||
def visit(self, tree): | |||
def visit(self, tree: Tree) -> _T: | |||
f = getattr(self, tree.data) | |||
wrapper = getattr(f, 'visit_wrapper', None) | |||
if wrapper is not None: | |||
@@ -315,7 +312,7 @@ class Interpreter(_Decoratable): | |||
else: | |||
return f(tree) | |||
def visit_children(self, tree): | |||
def visit_children(self, tree: Tree) -> List[_T]: | |||
return [self.visit(child) if isinstance(child, Tree) else child | |||
for child in tree.children] | |||
@@ -326,6 +323,16 @@ class Interpreter(_Decoratable): | |||
return self.visit_children(tree) | |||
_InterMethod = Callable[[Type[Interpreter], _T], _R] | |||
def visit_children_decor(func: _InterMethod) -> _InterMethod: | |||
"See Interpreter" | |||
@wraps(func) | |||
def inner(cls, tree): | |||
values = cls.visit_children(tree) | |||
return func(cls, values) | |||
return inner | |||
# Decorators | |||
def _apply_decorator(obj, decorator, **kwargs): | |||
@@ -380,7 +387,7 @@ def _vargs_tree(f, data, children, meta): | |||
return f(Tree(data, children, meta)) | |||
def v_args(inline=False, meta=False, tree=False, wrapper=None): | |||
def v_args(inline: bool=False, meta: bool=False, tree: bool=False, wrapper: Callable[[_DECORATED], _DECORATED]=None) -> Callable[[_DECORATED], _DECORATED]: | |||
"""A convenience decorator factory for modifying the behavior of user-supplied visitor methods. | |||
By default, callback methods of transformers/visitors accept one argument - a list of the node's children. | |||