Browse Source

Merge branch 'Rogdham-import-rule-rename'

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.6.6
Erez Shinan 5 years ago
parent
commit
c6d41f4bb4
16 changed files with 189 additions and 6 deletions
  1. +10
    -1
      docs/grammar.md
  2. +2
    -2
      examples/lark.lark
  3. +3
    -0
      examples/lark_grammar.py
  4. +1
    -0
      examples/relative-imports/multiple2.lark
  5. +5
    -0
      examples/relative-imports/multiple3.lark
  6. +5
    -0
      examples/relative-imports/multiples.lark
  7. +28
    -0
      examples/relative-imports/multiples.py
  8. +3
    -3
      lark/load_grammar.py
  9. +10
    -0
      tests/grammars/ab.lark
  10. +78
    -0
      tests/test_parser.py
  11. +7
    -0
      tests/test_relative_import_rename.lark
  12. +7
    -0
      tests/test_relative_rule_import.lark
  13. +7
    -0
      tests/test_relative_rule_import_drop_ignore.lark
  14. +7
    -0
      tests/test_relative_rule_import_rename.lark
  15. +7
    -0
      tests/test_relative_rule_import_subrule.lark
  16. +9
    -0
      tests/test_relative_rule_import_subrule_no_conflict.lark

+ 10
- 1
docs/grammar.md View File

@@ -133,20 +133,29 @@ When importing rules, all their dependencies will be imported into a namespace,
**Syntax:**
```html
%import <module>.<TERMINAL>
%import <module> (<TERM1> <TERM2>)
%import <module>.<rule>
%import <module>.<TERMINAL> -> <NEWTERMINAL>
%import <module>.<rule> -> <newrule>
%import <module> (<TERM1> <TERM2> <rule1> <rule2>)
```

If the module path is absolute, Lark will attempt to load it from the built-in directory (currently, only `common.lark` is available).

If the module path is relative, such as `.path.to.file`, Lark will attempt to load it from the current working directory. Grammars must have the `.lark` extension.

The rule or terminal can be imported under an other name with the `->` syntax.

**Example:**
```perl
%import common.NUMBER

%import .terminals_file (A B C)

%import .rules_file.rulea -> ruleb
```

Note that `%ignore` directives cannot be imported. Imported rules will abide by the `%ignore` directives declared in the main grammar.

### %declare

Declare a terminal without defining it. Useful for plugins.

+ 2
- 2
examples/lark.lark View File

@@ -10,10 +10,10 @@ token: TOKEN priority? ":" expansions _NL
priority: "." NUMBER

statement: "%ignore" expansions _NL -> ignore
| "%import" import_args ["->" TOKEN] _NL -> import
| "%import" import_args ["->" name] _NL -> import
| "%declare" name+ -> declare

import_args: name ("." name)*
import_args: "."? name ("." name)*

?expansions: alias (_VBAR alias)*



+ 3
- 0
examples/lark_grammar.py View File

@@ -6,6 +6,9 @@ grammar_files = [
'examples/python2.lark',
'examples/python3.lark',
'examples/lark.lark',
'examples/relative-imports/multiples.lark',
'examples/relative-imports/multiple2.lark',
'examples/relative-imports/multiple3.lark',
'lark/grammars/common.lark',
]



+ 1
- 0
examples/relative-imports/multiple2.lark View File

@@ -0,0 +1 @@
start: ("0" | "1")* "0"

+ 5
- 0
examples/relative-imports/multiple3.lark View File

@@ -0,0 +1,5 @@
start: mod0mod0+

mod0mod0: "0" | "1" mod1mod0
mod1mod0: "1" | "0" mod2mod1 mod1mod0
mod2mod1: "0" | "1" mod2mod1

+ 5
- 0
examples/relative-imports/multiples.lark View File

@@ -0,0 +1,5 @@
start: "2:" multiple2
| "3:" multiple3

%import .multiple2.start -> multiple2
%import .multiple3.start -> multiple3

+ 28
- 0
examples/relative-imports/multiples.py View File

@@ -0,0 +1,28 @@
#
# This example demonstrates relative imports with rule rewrite
# see multiples.lark
#

#
# if b is a number written in binary, and m is either 2 or 3,
# the grammar aims to recognise m:b iif b is a multiple of m
#
# for example, 3:1001 is recognised
# because 9 (0b1001) is a multiple of 3
#

from lark import Lark, UnexpectedInput

parser = Lark.open('multiples.lark', parser='lalr')

def is_in_grammar(data):
try:
parser.parse(data)
except UnexpectedInput:
return False
return True

for n_dec in range(100):
n_bin = bin(n_dec)[2:]
assert is_in_grammar('2:{}'.format(n_bin)) == (n_dec % 2 == 0)
assert is_in_grammar('3:{}'.format(n_bin)) == (n_dec % 3 == 0)

+ 3
- 3
lark/load_grammar.py View File

@@ -139,7 +139,7 @@ RULES = {
'declare': ['_DECLARE _declare_args _NL'],
'import': ['_IMPORT _import_path _NL',
'_IMPORT _import_path _LPAR name_list _RPAR _NL',
'_IMPORT _import_path _TO TERMINAL _NL'],
'_IMPORT _import_path _TO name _NL'],

'_import_path': ['import_lib', 'import_rel'],
'import_lib': ['_import_args'],
@@ -586,7 +586,7 @@ def import_from_grammar_into_namespace(grammar, namespace, aliases):
try:
return aliases[name].value
except KeyError:
return '%s.%s' % (namespace, name)
return '%s__%s' % (namespace, name)

to_import = list(bfs(aliases, rule_dependencies))
for symbol in to_import:
@@ -745,7 +745,7 @@ class GrammarLoader:
g = import_grammar(grammar_path, base_paths=[base_path])

aliases_dict = dict(zip(names, aliases))
new_td, new_rd = import_from_grammar_into_namespace(g, '.'.join(dotted_path), aliases_dict)
new_td, new_rd = import_from_grammar_into_namespace(g, '__'.join(dotted_path), aliases_dict)

term_defs += new_td
rule_defs += new_rd


+ 10
- 0
tests/grammars/ab.lark View File

@@ -0,0 +1,10 @@
startab: expr

expr: A B
| A expr B

A: "a"
B: "b"

%import common.WS
%ignore WS

+ 78
- 0
tests/test_parser.py View File

@@ -998,11 +998,89 @@ def _make_parser_test(LEXER, PARSER):
self.assertEqual(x.children, ['12', 'elephants'])


def test_import_rename(self):
grammar = """
start: N W

%import common.NUMBER -> N
%import common.WORD -> W
%import common.WS
%ignore WS

"""
l = _Lark(grammar)
x = l.parse('12 elephants')
self.assertEqual(x.children, ['12', 'elephants'])


def test_relative_import(self):
l = _Lark_open('test_relative_import.lark', rel_to=__file__)
x = l.parse('12 lions')
self.assertEqual(x.children, ['12', 'lions'])


def test_relative_import_rename(self):
l = _Lark_open('test_relative_import_rename.lark', rel_to=__file__)
x = l.parse('12 lions')
self.assertEqual(x.children, ['12', 'lions'])


def test_relative_rule_import(self):
l = _Lark_open('test_relative_rule_import.lark', rel_to=__file__)
x = l.parse('xaabby')
self.assertEqual(x.children, [
'x',
Tree('expr', ['a', Tree('expr', ['a', 'b']), 'b']),
'y'])


def test_relative_rule_import_drop_ignore(self):
# %ignore rules are dropped on import
l = _Lark_open('test_relative_rule_import_drop_ignore.lark',
rel_to=__file__)
self.assertRaises((ParseError, UnexpectedInput),
l.parse, 'xa abby')


def test_relative_rule_import_subrule(self):
l = _Lark_open('test_relative_rule_import_subrule.lark',
rel_to=__file__)
x = l.parse('xaabby')
self.assertEqual(x.children, [
'x',
Tree('startab', [
Tree('grammars__ab__expr', [
'a', Tree('grammars__ab__expr', ['a', 'b']), 'b',
]),
]),
'y'])


def test_relative_rule_import_subrule_no_conflict(self):
l = _Lark_open(
'test_relative_rule_import_subrule_no_conflict.lark',
rel_to=__file__)
x = l.parse('xaby')
self.assertEqual(x.children, [Tree('expr', [
'x',
Tree('startab', [
Tree('grammars__ab__expr', ['a', 'b']),
]),
'y'])])
self.assertRaises((ParseError, UnexpectedInput),
l.parse, 'xaxabyby')


def test_relative_rule_import_rename(self):
l = _Lark_open('test_relative_rule_import_rename.lark',
rel_to=__file__)
x = l.parse('xaabby')
self.assertEqual(x.children, [
'x',
Tree('ab', ['a', Tree('ab', ['a', 'b']), 'b']),
'y'])


def test_multi_import(self):
grammar = """
start: NUMBER WORD


+ 7
- 0
tests/test_relative_import_rename.lark View File

@@ -0,0 +1,7 @@
start: N WORD

%import .grammars.test.NUMBER -> N
%import common.WORD
%import common.WS
%ignore WS


+ 7
- 0
tests/test_relative_rule_import.lark View File

@@ -0,0 +1,7 @@
start: X expr Y

X: "x"
Y: "y"

%import .grammars.ab.expr


+ 7
- 0
tests/test_relative_rule_import_drop_ignore.lark View File

@@ -0,0 +1,7 @@
start: X expr Y

X: "x"
Y: "y"

%import .grammars.ab.expr


+ 7
- 0
tests/test_relative_rule_import_rename.lark View File

@@ -0,0 +1,7 @@
start: X ab Y

X: "x"
Y: "y"

%import .grammars.ab.expr -> ab


+ 7
- 0
tests/test_relative_rule_import_subrule.lark View File

@@ -0,0 +1,7 @@
start: X startab Y

X: "x"
Y: "y"

%import .grammars.ab.startab


+ 9
- 0
tests/test_relative_rule_import_subrule_no_conflict.lark View File

@@ -0,0 +1,9 @@
start: expr

expr: X startab Y

X: "x"
Y: "y"

%import .grammars.ab.startab


Loading…
Cancel
Save