| @@ -100,7 +100,7 @@ See more [examples here](https://github.com/lark-parser/lark/tree/master/example | |||||
| - **Python 2 & 3** compatible | - **Python 2 & 3** compatible | ||||
| - Automatic line & column tracking | - Automatic line & column tracking | ||||
| - Standard library of terminals (strings, numbers, names, etc.) | - Standard library of terminals (strings, numbers, names, etc.) | ||||
| - Import grammars from Nearley.js | |||||
| - Import grammars from Nearley.js ([read more](/docs/nearley.md)) | |||||
| - Extensive test suite [](https://codecov.io/gh/erezsh/lark) | - Extensive test suite [](https://codecov.io/gh/erezsh/lark) | ||||
| - MyPy support using type stubs | - MyPy support using type stubs | ||||
| - And much more! | - And much more! | ||||
| @@ -159,25 +159,6 @@ Check out the [JSON tutorial](/docs/json_tutorial.md#conclusion) for more detail | |||||
| Using Lark? Send me a message and I'll add your project! | Using Lark? Send me a message and I'll add your project! | ||||
| ### How to use Nearley grammars in Lark | |||||
| Lark comes with a tool to convert grammars from [Nearley](https://github.com/Hardmath123/nearley), a popular Earley library for Javascript. It uses [Js2Py](https://github.com/PiotrDabkowski/Js2Py) to convert and run the Javascript postprocessing code segments. | |||||
| Here's an example: | |||||
| ```bash | |||||
| git clone https://github.com/Hardmath123/nearley | |||||
| python -m lark.tools.nearley nearley/examples/calculator/arithmetic.ne main nearley > ncalc.py | |||||
| ``` | |||||
| You can use the output as a regular python module: | |||||
| ```python | |||||
| >>> import ncalc | |||||
| >>> ncalc.parse('sin(pi/4) ^ e') | |||||
| 0.38981434460254655 | |||||
| ``` | |||||
| ## License | ## License | ||||
| Lark uses the [MIT license](LICENSE). | Lark uses the [MIT license](LICENSE). | ||||
| @@ -21,7 +21,7 @@ | |||||
| # Extra features | # Extra features | ||||
| - Import rules and tokens from other Lark grammars, for code reuse and modularity. | - Import rules and tokens from other Lark grammars, for code reuse and modularity. | ||||
| - Import grammars from Nearley.js | |||||
| - Import grammars from Nearley.js ([read more](/docs/nearley.md)) | |||||
| - CYK parser | - CYK parser | ||||
| ### Experimental features | ### Experimental features | ||||
| @@ -49,6 +49,7 @@ $ pip install lark-parser | |||||
| * [Visitors & Transformers](visitors.md) | * [Visitors & Transformers](visitors.md) | ||||
| * [Classes](classes.md) | * [Classes](classes.md) | ||||
| * [Cheatsheet (PDF)](lark_cheatsheet.pdf) | * [Cheatsheet (PDF)](lark_cheatsheet.pdf) | ||||
| * [Importing grammars from Nearley](nearley.md) | |||||
| * Discussion | * Discussion | ||||
| * [Gitter](https://gitter.im/lark-parser/Lobby) | * [Gitter](https://gitter.im/lark-parser/Lobby) | ||||
| * [Forum (Google Groups)](https://groups.google.com/forum/#!forum/lark-parser) | * [Forum (Google Groups)](https://groups.google.com/forum/#!forum/lark-parser) | ||||
| @@ -0,0 +1,47 @@ | |||||
| # Importing grammars from Nearley | |||||
| Lark comes with a tool to convert grammars from [Nearley](https://github.com/Hardmath123/nearley), a popular Earley library for Javascript. It uses [Js2Py](https://github.com/PiotrDabkowski/Js2Py) to convert and run the Javascript postprocessing code segments. | |||||
| ## Requirements | |||||
| 1. Install Lark with the `nearley` component: | |||||
| ```bash | |||||
| pip install lark-parser[nearley] | |||||
| ``` | |||||
| 2. Acquire a copy of the nearley codebase. This can be done using: | |||||
| ```bash | |||||
| git clone https://github.com/Hardmath123/nearley | |||||
| ``` | |||||
| ## Usage | |||||
| Here's an example of how to import nearley's calculator example into Lark: | |||||
| ```bash | |||||
| git clone https://github.com/Hardmath123/nearley | |||||
| python -m lark.tools.nearley nearley/examples/calculator/arithmetic.ne main nearley > ncalc.py | |||||
| ``` | |||||
| You can use the output as a regular python module: | |||||
| ```python | |||||
| >>> import ncalc | |||||
| >>> ncalc.parse('sin(pi/4) ^ e') | |||||
| 0.38981434460254655 | |||||
| ``` | |||||
| The Nearley converter also supports an experimental converter for newer JavaScript (ES6+), using the `--es6` flag: | |||||
| ```bash | |||||
| git clone https://github.com/Hardmath123/nearley | |||||
| python -m lark.tools.nearley nearley/examples/calculator/arithmetic.ne main nearley --es6 > ncalc.py | |||||
| ``` | |||||
| ## Notes | |||||
| - Lark currently cannot import templates from Nearley | |||||
| - Lark currently cannot export grammars to Nearley | |||||
| These might get added in the future, if enough users ask for them. | |||||
| @@ -1,8 +1,9 @@ | |||||
| "Converts between Lark and Nearley grammars. Work in progress!" | |||||
| "Converts Nearley grammars to Lark" | |||||
| import os.path | import os.path | ||||
| import sys | import sys | ||||
| import codecs | import codecs | ||||
| import argparse | |||||
| from lark import Lark, InlineTransformer | from lark import Lark, InlineTransformer | ||||
| @@ -137,7 +138,7 @@ def _nearley_to_lark(g, builtin_path, n2l, js_code, folder_path, includes): | |||||
| return rule_defs | return rule_defs | ||||
| def create_code_for_nearley_grammar(g, start, builtin_path, folder_path): | |||||
| def create_code_for_nearley_grammar(g, start, builtin_path, folder_path, es6=False): | |||||
| import js2py | import js2py | ||||
| emit_code = [] | emit_code = [] | ||||
| @@ -160,7 +161,10 @@ def create_code_for_nearley_grammar(g, start, builtin_path, folder_path): | |||||
| for alias, code in n2l.alias_js_code.items(): | for alias, code in n2l.alias_js_code.items(): | ||||
| js_code.append('%s = (%s);' % (alias, code)) | js_code.append('%s = (%s);' % (alias, code)) | ||||
| emit(js2py.translate_js('\n'.join(js_code))) | |||||
| if es6: | |||||
| emit(js2py.translate_js6('\n'.join(js_code))) | |||||
| else: | |||||
| emit(js2py.translate_js('\n'.join(js_code))) | |||||
| emit('class TransformNearley(Transformer):') | emit('class TransformNearley(Transformer):') | ||||
| for alias in n2l.alias_js_code: | for alias in n2l.alias_js_code: | ||||
| emit(" %s = var.get('%s').to_python()" % (alias, alias)) | emit(" %s = var.get('%s').to_python()" % (alias, alias)) | ||||
| @@ -173,18 +177,20 @@ def create_code_for_nearley_grammar(g, start, builtin_path, folder_path): | |||||
| return ''.join(emit_code) | return ''.join(emit_code) | ||||
| def main(fn, start, nearley_lib): | |||||
| def main(fn, start, nearley_lib, es6=False): | |||||
| with codecs.open(fn, encoding='utf8') as f: | with codecs.open(fn, encoding='utf8') as f: | ||||
| grammar = f.read() | grammar = f.read() | ||||
| return create_code_for_nearley_grammar(grammar, start, os.path.join(nearley_lib, 'builtin'), os.path.abspath(os.path.dirname(fn))) | |||||
| return create_code_for_nearley_grammar(grammar, start, os.path.join(nearley_lib, 'builtin'), os.path.abspath(os.path.dirname(fn)), es6=es6) | |||||
| def get_arg_parser(): | |||||
| parser = argparse.ArgumentParser('Reads Nearley grammar (with js functions) outputs an equivalent lark parser.') | |||||
| parser.add_argument('nearley_grammar', help='Path to the file containing the nearley grammar') | |||||
| parser.add_argument('start_rule', help='Rule within the nearley grammar to make the base rule') | |||||
| parser.add_argument('nearley_lib', help='') | |||||
| parser.add_argument('--es6', help='Enable experimental ES6 support', action='store_true') | |||||
| return parser | |||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||
| if len(sys.argv) < 4: | |||||
| print("Reads Nearley grammar (with js functions) outputs an equivalent lark parser.") | |||||
| print("Usage: %s <nearley_grammar_path> <start_rule> <nearley_lib_path>" % sys.argv[0]) | |||||
| sys.exit(1) | |||||
| fn, start, nearley_lib = sys.argv[1:] | |||||
| print(main(fn, start, nearley_lib)) | |||||
| parser = get_arg_parser() | |||||
| args = parser.parse_args() | |||||
| print(main(fn=args.nearley_grammar, start=args.start_rule, nearley_lib=args.nearley_lib, es6=args.es6)) | |||||
| @@ -15,7 +15,8 @@ setup( | |||||
| install_requires = [], | install_requires = [], | ||||
| extras_require = { | extras_require = { | ||||
| "regex": ["regex"] | |||||
| "regex": ["regex"], | |||||
| "nearley": ["js2py"] | |||||
| }, | }, | ||||
| package_data = {'': ['*.md', '*.lark'], 'lark-stubs': ['*.pyi']}, | package_data = {'': ['*.md', '*.lark'], 'lark-stubs': ['*.pyi']}, | ||||