diff --git a/ChangeLog b/ChangeLog index e8d986c..77d973e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018.07.09, Version 1.2.2 (Stable) + + * Added export to JavaScript using class (es6) syntax. + + * Use jsleri Ref.set() method instead of Object.assign. + 2018.07.05, Version 1.2.1 (Stable) * Format readme on PyPi diff --git a/pyleri/__init__.py b/pyleri/__init__.py index 6e7ab69..9e095bc 100644 --- a/pyleri/__init__.py +++ b/pyleri/__init__.py @@ -36,4 +36,4 @@ __author__ = 'Jeroen van der Heijden' __maintainer__ = 'Jeroen van der Heijden' __email__ = 'jeroen@transceptor.technology' -__version__ = '1.2.1' +__version__ = '1.2.2' diff --git a/pyleri/choice.py b/pyleri/choice.py index 5485369..287d44b 100644 --- a/pyleri/choice.py +++ b/pyleri/choice.py @@ -48,8 +48,8 @@ def _stop_at_first_match(self, root, tree, rule, s, node): return is_valid, pos - def _run_export_js(self, js_indent, indent, classes): - return self._export_js_elements(js_indent, indent, classes) + def _run_export_js(self, js_indent, indent, classes, cname): + return self._export_js_elements(js_indent, indent, classes, cname) def _run_export_py(self, py_indent, indent, classes): new_indent = indent + 1 diff --git a/pyleri/elements.py b/pyleri/elements.py index 206632c..54055b6 100644 --- a/pyleri/elements.py +++ b/pyleri/elements.py @@ -82,25 +82,26 @@ class NamedElement(Element): __slots__ = ('name',) - def _export_js(self, js_indent, indent, classes): + def _export_js(self, js_indent, indent, classes, cname): classes.add(self.__class__.__name__.lstrip('_')) - if hasattr(self, 'name') and indent: - return self.name - return self._run_export_js(js_indent, indent or 1, classes) + if hasattr(self, 'name') and indent > 0: + return '{}.{}'.format(cname, self.name) if cname else self.name + indent = 0 if indent < 0 else 1 if indent == 0 else indent + return self._run_export_js(js_indent, indent, classes, cname) - def _export_js_elements(self, js_indent, indent, classes): + def _export_js_elements(self, js_indent, indent, classes, cname): new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=js_indent * new_indent, elem=elem._export_js( js_indent, - new_indent, classes)) for elem in self._elements]) + new_indent, classes, cname)) for elem in self._elements]) return '{class_name}(\n{value}\n{indent})'.format( class_name=self.__class__.__name__.lstrip('_'), value=value, indent=js_indent * indent) - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'not_implemented' def _export_py(self, py_indent, indent, classes): diff --git a/pyleri/grammar.py b/pyleri/grammar.py index d419dab..80bec78 100644 --- a/pyleri/grammar.py +++ b/pyleri/grammar.py @@ -162,6 +162,7 @@ class Grammar(metaclass=_OrderedClass): {arguments} {indent}{indent}) {{ {language} +{refs} {indent}window.{name} = Grammar(START, '{re_keywords}'); @@ -181,23 +182,16 @@ class Grammar(metaclass=_OrderedClass): import {{ {classes} }} from 'jsleri'; -class {name} extends Grammar { +class {name} extends Grammar {{ {language} -{indent}constructor() { + +{indent}constructor() {{ {indent}{indent}super({name}.START, '{re_keywords}'); +{indent}}} +}} {refs} -{indent}} -} -(function ( -{arguments} -{indent}{indent}) {{ -{language} -{indent}window.{name} = Grammar(START, '{re_keywords}'); - -}})( -{constructors} -); +export default {name}; '''.lstrip() PY_INDENTATION = ' ' * 4 @@ -349,14 +343,21 @@ def __init__(self): def export_js( self, js_module_name=JS_MODULE_NAME, - js_template=JS_WINDOW_TEMPLATE, + js_template=JS_ES6_IMPORT_EXPORT_TEMPLATE, js_indent=JS_INDENTATION): '''Export the grammar to a JavaScript file which can be - used with the js-lrparsing module.''' + used with the js-lrparsing module. + + Two templates are available: + Grammar.JS_WINDOW_TEMPLATE + Grammar.JS_ES6_IMPORT_EXPORT_TEMPLATE (default) + ''' language = [] + refs = [] classes = {'Grammar'} indent = 0 + cname = self.__class__.__name__ if 'import ' in js_template else None for name in self._order: elem = getattr(self, name, None) @@ -364,21 +365,26 @@ def export_js( continue if not hasattr(elem, '_export_js'): continue - language.append('{indent}var {name} = {value};'.format( + language.append('{indent}{var} {name} = {value};'.format( indent=js_indent, name=name, - value=elem._export_js(js_indent, indent, classes))) + var='static' if cname else 'var', + value=elem._export_js(js_indent, indent, classes, cname))) for name, ref in self._refs.items(): - language.append( - '{indent}Object.assign({name}, {value});' + refs.append( + '{pre}{name}.set({value});' .format( - indent=js_indent, + pre='{}.'.format(cname) if cname else js_indent, name=name, value=ref._element._export_js( js_indent, - indent, - classes))) + -1 if cname else indent, + classes, + cname))) + + if 'Rule' in classes: + classes.remove('Rule') return js_template.format( name=self.__class__.__name__, @@ -386,15 +392,16 @@ def export_js( js_module=js_module_name, datetime=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), language='\n'.join(language), + refs='\n{}'.format('\n'.join(refs)), arguments=',\n'.join(map(lambda s: js_indent * 3 + s, classes)), re_keywords=self.RE_KEYWORDS.pattern.replace('\\', '\\\\'), + classes=', '.join(classes), constructors=',\n'.join( map(lambda s: js_indent + s, - ['.'.join( - [ - 'window', - js_module_name, n]) for n in classes]))) + ['.'.join([ + 'window', + js_module_name, n]) for n in classes]))) def export_py( self, diff --git a/pyleri/keyword.py b/pyleri/keyword.py index 453b17b..218db48 100644 --- a/pyleri/keyword.py +++ b/pyleri/keyword.py @@ -55,7 +55,7 @@ def _get_node_result(self, root, tree, rule, s, node): return is_valid, node.end or node.start - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Keyword(\'{}\'{})'.format( self._keyword, ', true' if self._ign_case else '') diff --git a/pyleri/list.py b/pyleri/list.py index deec425..147f038 100644 --- a/pyleri/list.py +++ b/pyleri/list.py @@ -78,10 +78,10 @@ def _get_node_result(self, root, tree, rule, s, node): return is_valid, pos - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'List({}, {}, {}, {}, {})'.format( - self._element._export_js(js_indent, indent, classes), - self._delimiter._export_js(js_indent, indent, classes), + self._element._export_js(js_indent, indent, classes, cname), + self._delimiter._export_js(js_indent, indent, classes, cname), self._min, self._max or 'undefined', 'true' if self._opt else 'false') diff --git a/pyleri/optional.py b/pyleri/optional.py index 816426b..f070300 100644 --- a/pyleri/optional.py +++ b/pyleri/optional.py @@ -28,9 +28,9 @@ def _get_node_result(self, root, tree, rule, _s, node): return True, node.end or node.start - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Optional({})'.format( - self._element._export_js(js_indent, indent, classes)) + self._element._export_js(js_indent, indent, classes, cname)) def _run_export_py(self, py_indent, indent, classes): return 'Optional({})'.format( diff --git a/pyleri/prio.py b/pyleri/prio.py index 133b797..dc3f9db 100644 --- a/pyleri/prio.py +++ b/pyleri/prio.py @@ -30,8 +30,8 @@ def _get_node_result(self, root, tree, rule, s, node): return rule._tested[node.start] - def _run_export_js(self, js_indent, indent, classes): - return self._export_js_elements(js_indent, indent, classes) + def _run_export_js(self, js_indent, indent, classes, cname): + return self._export_js_elements(js_indent, indent, classes, cname) def _run_export_py(self, py_indent, indent, classes): return self._export_py_elements(py_indent, indent, classes) diff --git a/pyleri/ref.py b/pyleri/ref.py index b46415f..5d75131 100644 --- a/pyleri/ref.py +++ b/pyleri/ref.py @@ -23,7 +23,7 @@ def element(self, element): self._element = self._validate_element(element) self._get_node_result = self._element._get_node_result - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Ref({})'.format(self._element.__class__.__name__) def _run_export_py(self, py_indent, indent, classes): diff --git a/pyleri/regex.py b/pyleri/regex.py index 4844a4f..b843acb 100644 --- a/pyleri/regex.py +++ b/pyleri/regex.py @@ -32,7 +32,7 @@ def _get_node_result(self, root, tree, rule, s, node): return is_valid, node.end or node.start - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Regex(\'{}\'{})'.format( self._compiled.pattern.replace('\\', '\\\\').replace('\'', '\\\''), ', true' if self._compiled.flags & re.IGNORECASE else '') diff --git a/pyleri/repeat.py b/pyleri/repeat.py index 66e6bfb..0a4f9db 100644 --- a/pyleri/repeat.py +++ b/pyleri/repeat.py @@ -50,9 +50,9 @@ def _get_node_result(self, root, tree, rule, s, node): return is_valid, pos - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Repeat({}, {}, {})'.format( - self._element._export_js(js_indent, indent, classes), + self._element._export_js(js_indent, indent, classes, cname), self._min, self._max or 'undefined') diff --git a/pyleri/rule.py b/pyleri/rule.py index 3673fa0..523199b 100644 --- a/pyleri/rule.py +++ b/pyleri/rule.py @@ -25,8 +25,8 @@ def _get_node_result(self, root, tree, rule, _s, node): root._append_tree(tree, node, pos) return is_valid, pos - def _run_export_js(self, js_indent, indent, classes): - return self._element._export_js(js_indent, indent, classes) + def _run_export_js(self, js_indent, indent, classes, cname): + return self._element._export_js(js_indent, indent, classes, cname) def _run_export_py(self, py_indent, indent, classes): return self._element._export_py(py_indent, indent, classes) diff --git a/pyleri/sequence.py b/pyleri/sequence.py index cd581ea..67a5e39 100644 --- a/pyleri/sequence.py +++ b/pyleri/sequence.py @@ -24,8 +24,8 @@ def _get_node_result(self, root, tree, rule, _s, node): return is_valid, pos - def _run_export_js(self, js_indent, indent, classes): - return self._export_js_elements(js_indent, indent, classes) + def _run_export_js(self, js_indent, indent, classes, cname): + return self._export_js_elements(js_indent, indent, classes, cname) def _run_export_py(self, py_indent, indent, classes): return self._export_py_elements(py_indent, indent, classes) diff --git a/pyleri/this.py b/pyleri/this.py index f4ab072..52631fc 100644 --- a/pyleri/this.py +++ b/pyleri/this.py @@ -23,7 +23,7 @@ def _get_node_result(self, root, tree, rule, _s, node): return rule._tested[node.start] - def _export_js(self, js_indent, indent, classes): + def _export_js(self, js_indent, indent, classes, cname): classes.add('THIS') return 'THIS' diff --git a/pyleri/token.py b/pyleri/token.py index e2f5477..b86a477 100644 --- a/pyleri/token.py +++ b/pyleri/token.py @@ -28,7 +28,7 @@ def _get_node_result(self, root, tree, rule, s, node): return is_valid, node.end or node.start - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Token(\'{}\')'.format(self._token) def _run_export_py(self, py_indent, indent, classes): diff --git a/pyleri/tokens.py b/pyleri/tokens.py index 7d692ab..45e17ed 100644 --- a/pyleri/tokens.py +++ b/pyleri/tokens.py @@ -26,7 +26,7 @@ def _get_node_result(self, root, tree, rule, s, node): return False, node.start - def _run_export_js(self, js_indent, indent, classes): + def _run_export_js(self, js_indent, indent, classes, cname): return 'Tokens(\'{}\')'.format(' '.join(self._tokens)) def _run_export_py(self, py_indent, indent, classes): diff --git a/setup.py b/setup.py index 65cd384..a6baf7e 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,10 @@ Upload to PyPI, Thx to: http://peterdowns.com/posts/first-time-with-pypi.html python3 setup.py sdist -twine upload --repository pypitest dist/pyleri-1.2.1c.tar.gz +twine upload --repository pypitest dist/pyleri-x.x.x.tar.gz -python3 setup.py register -r pypitest -python3 setup.py sdist upload -r pypitest +twine upload --repository pypi dist/pyleri-x.x.x.tar.gz -python3 setup.py register -r pypi -python3 setup.py sdist upload -r pypi """ from setuptools import setup from pyleri import __version__ as version diff --git a/test/test_pyleri.py b/test/test_pyleri.py index c7c45a8..aa874c9 100644 --- a/test/test_pyleri.py +++ b/test/test_pyleri.py @@ -1,7 +1,7 @@ import unittest import gc import sys -sys.path.append('..') +sys.path.insert(0, '..') from pyleri import ( Keyword, @@ -195,5 +195,6 @@ def tearDown(self): # print(my_grammar.parse('hi "Iris"').is_valid) # => True # print(my_grammar.parse('bye "Iris"').is_valid) # => False - # # my_grammar = JsonGrammar() - # print(my_grammar.export_go()) + # my_grammar = JsonGrammar() + # print(my_grammar.export_js(js_template=Grammar.JS_WINDOW_TEMPLATE)) + # print(my_grammar.export_js())