forked from cesbit/pyleri
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
146 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
'''JSON Grammar.''' | ||
"""JSON Grammar.""" | ||
from pyleri import ( | ||
Ref, | ||
Choice, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
'''Py-LeRi (pyleri) Python LR-parsing module. | ||
"""Py-LeRi (pyleri) Python LR-parsing module. | ||
This module is inspired by lrparsing (http://lrparsing.sourceforge.net/), | ||
a Python parser written by Russell Stuart, 2014-05-29. | ||
|
@@ -10,7 +10,7 @@ | |
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
:license: MIT | ||
''' | ||
""" | ||
|
||
from .choice import Choice | ||
from .endofstatement import end_of_statement | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,29 @@ | ||
'''pyleri.Choice Class. | ||
"""pyleri.Choice Class. | ||
Choose one of the given elements. When most_greedy is True we will choose | ||
the 'longest' element when multiple elements are valid. If most_greedy is | ||
False we will return the first match. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
|
||
from .elements import NamedElement, c_export, go_export, java_export | ||
""" | ||
from .elements import Element, NamedElement, c_export, go_export, java_export | ||
|
||
|
||
class Choice(NamedElement): | ||
|
||
__slots__ = ('_elements', '_get_node_result') | ||
|
||
def __init__(self, *elements, most_greedy=True): | ||
def __init__( | ||
self, | ||
*elements: Element, | ||
most_greedy: bool = True): | ||
self._elements = self._validate_elements(elements) | ||
self._get_node_result = \ | ||
self._most_greedy_result if most_greedy else \ | ||
self._stop_at_first_match | ||
|
||
@property | ||
def most_greedy(self): | ||
def most_greedy(self) -> bool: | ||
return self._get_node_result == self._most_greedy_result | ||
|
||
def _most_greedy_result(self, root, tree, rule, s, node): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
'''Element and NamedElement Class. | ||
"""Element and NamedElement Class. | ||
These are the base classes used for all other elements. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
import typing as t | ||
|
||
|
||
def camel_case(s): | ||
def camel_case(s: str) -> str: | ||
return ''.join( | ||
p[0].upper() + p[1:] if n else p | ||
for n, p in enumerate(s.split('_'))) | ||
|
||
|
||
def cap_case(s): | ||
def cap_case(s: str) -> str: | ||
return ''.join(p[0].upper() + p[1:] for p in s.split('_') if p) | ||
|
||
|
||
|
@@ -63,26 +64,33 @@ class Element: | |
|
||
__slots__ = tuple() | ||
|
||
name: t.Optional[str] | ||
|
||
@staticmethod | ||
def _validate_element(element): | ||
def _validate_element(element: 'Element') -> 'Element': | ||
if isinstance(element, str): | ||
return Token(element) | ||
if isinstance(element, Element): | ||
return element | ||
raise TypeError( | ||
'Expecting an element or string but received type: {}'.format( | ||
type(element))) | ||
'Expecting an element or string ' | ||
'but received type: {}'.format(type(element))) | ||
|
||
@classmethod | ||
def _validate_elements(cls, elements): | ||
def _validate_elements(cls, elements) -> t.List['Element']: | ||
return [cls._validate_element(elem) for elem in elements] | ||
|
||
|
||
class NamedElement(Element): | ||
|
||
__slots__ = ('name',) | ||
|
||
def _export_js(self, js_indent, indent, classes, cname): | ||
def _export_js( | ||
self, | ||
js_indent: int, | ||
indent: int, | ||
classes, | ||
cname) -> str: | ||
classes.add(self.__class__.__name__.lstrip('_')) | ||
if hasattr(self, 'name') and indent > 0: | ||
return '{}.{}'.format(cname, self.name) if cname else self.name | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
'''end_of_statement Variable. | ||
"""end_of_statement Variable. | ||
end_of_statement is an instance of _EndOfStatement and will be added to | ||
an 'expecting' in a node result when an 'End of Statement' is possible. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
|
||
|
||
class _EndOfStatement: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
'''Exceptions. | ||
"""Exceptions. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
|
||
|
||
class CompileError(Exception): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,27 @@ | ||
'''Expecting Class. | ||
"""Expecting Class. | ||
Expecting Class is used to return possible elements at a position when a given | ||
statement is not correct. This helps building auto-completion, suggestions or | ||
returning nice messages to the user. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
import typing as t | ||
if t.TYPE_CHECKING: | ||
from .elements import Element | ||
|
||
|
||
class Expecting: | ||
|
||
__slots__ = ('required', 'optional', 'pos', '_modes') | ||
|
||
def __init__(self): | ||
self.required = set() | ||
self.optional = set() | ||
self.pos = 0 | ||
self._modes = {self.pos: self.required} | ||
self.required: t.Set['Element'] = set() | ||
self.optional: t.Set['Element'] = set() | ||
self.pos: int = 0 | ||
self._modes: t.Dict[int, t.Set['Element']] = {self.pos: self.required} | ||
|
||
def set_mode_required(self, pos, is_required): | ||
def set_mode_required(self, pos: int, is_required: bool): | ||
# do nothing when mode is already set to optional | ||
if pos in self._modes and self._modes[pos] is self.optional: | ||
return | ||
|
@@ -29,13 +32,13 @@ def empty(self): | |
self.required.clear() | ||
self.optional.clear() | ||
|
||
def update(self, element, pos): | ||
def update(self, element: 'Element', pos: int): | ||
if pos > self.pos: | ||
self.empty() | ||
self.pos = pos | ||
|
||
if pos == self.pos: | ||
self._modes[pos].add(element) | ||
|
||
def get_expecting(self): | ||
def get_expecting(self) -> t.Set['Element']: | ||
return self.required | self.optional |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
'''pyleri.Grammar Class. | ||
"""pyleri.Grammar Class. | ||
When creating a new grammar this class should be used as the base class. | ||
|
@@ -9,7 +9,7 @@ class MyGrammar(Grammar): | |
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
|
||
|
||
import re | ||
|
@@ -328,11 +328,11 @@ class {name}(Grammar): | |
'''.lstrip() | ||
|
||
def __init__(self): | ||
'''Initialize the grammar. | ||
"""Initialize the grammar. | ||
Note: usually you should only initialize a Grammar instance | ||
once in a project. | ||
''' | ||
""" | ||
self._element = self.START | ||
self._string = None | ||
self._expecting = None | ||
|
@@ -343,13 +343,13 @@ def export_js( | |
js_module_name=JS_MODULE_NAME, | ||
js_template=JS_ES6_IMPORT_EXPORT_TEMPLATE, | ||
js_indent=JS_INDENTATION): | ||
'''Export the grammar to a JavaScript file which can be | ||
"""Export the grammar to a JavaScript file which can be | ||
used with the js-lrparsing module. | ||
Two templates are available: | ||
Grammar.JS_WINDOW_TEMPLATE | ||
Grammar.JS_ES6_IMPORT_EXPORT_TEMPLATE (default) | ||
''' | ||
""" | ||
|
||
language = [] | ||
refs = [] | ||
|
@@ -406,10 +406,10 @@ def export_py( | |
py_module_name=PY_MODULE_NAME, | ||
py_template=PY_TEMPLATE, | ||
py_indent=PY_INDENTATION): | ||
'''Export the grammar to a python file which can be | ||
"""Export the grammar to a python file which can be | ||
used with the pyleri module. This can be useful when python code | ||
if used to auto-create a grammar and an export of the final result is | ||
required.''' | ||
required.""" | ||
|
||
language = [] | ||
classes = {'Grammar'} | ||
|
@@ -450,8 +450,8 @@ def export_py( | |
for n in classes if n != 'Rule']))) | ||
|
||
def export_c(self, target=C_TARGET, c_indent=C_INDENTATION, headerf=None): | ||
'''Export the grammar to a c (source and header) file which can be | ||
used with the libcleri module.''' | ||
"""Export the grammar to a c (source and header) file which can be | ||
used with the libcleri module.""" | ||
language = [] | ||
indent = 0 | ||
enums = set() | ||
|
@@ -518,8 +518,8 @@ def export_go( | |
go_template=GO_TEMPLATE, | ||
go_indent=GO_INDENTATION, | ||
go_package=GO_PACKAGE): | ||
'''Export the grammar to a Go file which can be | ||
used with the goleri module.''' | ||
"""Export the grammar to a Go file which can be | ||
used with the goleri module.""" | ||
|
||
language = [] | ||
enums = set() | ||
|
@@ -569,8 +569,8 @@ def export_java( | |
java_indent=JAVA_INDENTATION, | ||
java_package=JAVA_PACKAGE, | ||
is_public=True): | ||
'''Export the grammar to a Java file which can be | ||
used with the jleri module.''' | ||
"""Export the grammar to a Java file which can be | ||
used with the jleri module.""" | ||
|
||
language = [] | ||
enums = set() | ||
|
@@ -630,7 +630,7 @@ def export_java( | |
public='public ' if is_public else '') | ||
|
||
def parse(self, string): | ||
'''Parse some string to the Grammar. | ||
"""Parse some string to the Grammar. | ||
Returns a nodeResult with the following attributes: | ||
- is_valid: True when the string is successfully parsed | ||
|
@@ -641,7 +641,7 @@ def parse(self, string): | |
'pos' in the string. | ||
- tree: the parse_tree containing a structured | ||
result for the given string. | ||
''' | ||
""" | ||
self._string = string | ||
self._expecting = Expecting() | ||
self._cached_kw_match.clear() | ||
|
@@ -653,7 +653,8 @@ def parse(self, string): | |
0, | ||
tree.children, | ||
self._element, | ||
True)) | ||
True), | ||
tree) | ||
|
||
# get rest if anything | ||
rest = self._string[node_res.pos:].lstrip() | ||
|
@@ -673,8 +674,6 @@ def parse(self, string): | |
if not node_res.is_valid: | ||
node_res.pos = self._expecting.pos | ||
|
||
node_res.tree = tree | ||
|
||
return node_res | ||
|
||
def _append_tree(self, tree, node, pos): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
'''pyleri.Keyword Class. | ||
"""pyleri.Keyword Class. | ||
Try matching a given keyword string. The keyword should match | ||
Grammer.RE_KEYWORDS otherwise the keyword will not be found. It's possible | ||
however to overwrite the default RE_KEYWORDS in you own Grammar class. | ||
:copyright: 2021, Jeroen van der Heijden <[email protected]> | ||
''' | ||
""" | ||
from .elements import NamedElement, c_export, go_export, java_export | ||
|
||
|
||
class Keyword(NamedElement): | ||
|
||
__slots__ = ('_keyword', '_ign_case') | ||
|
||
def __init__(self, keyword, ign_case=False): | ||
def __init__(self, keyword: str, ign_case: bool = False): | ||
|
||
if not isinstance(keyword, str): | ||
raise TypeError( | ||
|
@@ -23,7 +23,7 @@ def __init__(self, keyword, ign_case=False): | |
self._ign_case = bool(ign_case) | ||
|
||
@property | ||
def ign_case(self): | ||
def ign_case(self) -> bool: | ||
return self._ign_case | ||
|
||
def __repr__(self): | ||
|
Oops, something went wrong.