| @@ -0,0 +1,6 @@ | |||||
| v1.0 | |||||
| - `maybe_placeholders` is now True by default | |||||
| - `use_accepts` in `UnexpectedInput.match_examples()` is now True by default | |||||
| @@ -72,7 +72,11 @@ class UnexpectedInput(LarkError): | |||||
| after = text[pos:end].split(b'\n', 1)[0] | after = text[pos:end].split(b'\n', 1)[0] | ||||
| return (before + after + b'\n' + b' ' * len(before.expandtabs()) + b'^\n').decode("ascii", "backslashreplace") | return (before + after + b'\n' + b' ' * len(before.expandtabs()) + b'^\n').decode("ascii", "backslashreplace") | ||||
| def match_examples(self, parse_fn: 'Callable[[str], Tree]', examples: Union[Dict[T, Iterable[str]], Iterable[Tuple[T, Iterable[str]]]], token_type_match_fallback: bool=False, use_accepts: bool=False) -> Optional[T]: | |||||
| def match_examples(self, parse_fn: 'Callable[[str], Tree]', | |||||
| examples: Union[Dict[T, Iterable[str]], Iterable[Tuple[T, Iterable[str]]]], | |||||
| token_type_match_fallback: bool=False, | |||||
| use_accepts: bool=True | |||||
| ) -> Optional[T]: | |||||
| """Allows you to detect what's wrong in the input text by matching | """Allows you to detect what's wrong in the input text by matching | ||||
| against example errors. | against example errors. | ||||
| @@ -87,8 +91,7 @@ class UnexpectedInput(LarkError): | |||||
| Parameters: | Parameters: | ||||
| parse_fn: parse function (usually ``lark_instance.parse``) | parse_fn: parse function (usually ``lark_instance.parse``) | ||||
| examples: dictionary of ``{'example_string': value}``. | examples: dictionary of ``{'example_string': value}``. | ||||
| use_accepts: Recommended to call this with ``use_accepts=True``. | |||||
| The default is ``False`` for backwards compatibility. | |||||
| use_accepts: Recommended to keep this as ``use_accepts=True``. | |||||
| """ | """ | ||||
| assert self.state is not None, "Not supported for this exception" | assert self.state is not None, "Not supported for this exception" | ||||
| @@ -104,7 +107,7 @@ class UnexpectedInput(LarkError): | |||||
| parse_fn(malformed) | parse_fn(malformed) | ||||
| except UnexpectedInput as ut: | except UnexpectedInput as ut: | ||||
| if ut.state == self.state: | if ut.state == self.state: | ||||
| if use_accepts and hasattr(self, 'accepts') and ut.accepts != self.accepts: | |||||
| if use_accepts and hasattr(self, 'accepts') and hasattr(ut, 'accepts') and ut.accepts != self.accepts: | |||||
| logger.debug("Different accepts with same state[%d]: %s != %s at example [%s][%s]" % | logger.debug("Different accepts with same state[%d]: %s != %s at example [%s][%s]" % | ||||
| (self.state, self.accepts, ut.accepts, i, j)) | (self.state, self.accepts, ut.accepts, i, j)) | ||||
| continue | continue | ||||
| @@ -82,9 +82,8 @@ class LarkOptions(Serialize): | |||||
| Accepts ``False``, ``True``, or a callable, which will filter which nodes to ignore when propagating. | Accepts ``False``, ``True``, or a callable, which will filter which nodes to ignore when propagating. | ||||
| maybe_placeholders | maybe_placeholders | ||||
| When ``True``, the ``[]`` operator returns ``None`` when not matched. | When ``True``, the ``[]`` operator returns ``None`` when not matched. | ||||
| When ``False``, ``[]`` behaves like the ``?`` operator, and returns no value at all. | When ``False``, ``[]`` behaves like the ``?`` operator, and returns no value at all. | ||||
| (default= ``False``. Recommended to set to ``True``) | |||||
| (default= ``True``) | |||||
| cache | cache | ||||
| Cache the results of the Lark grammar analysis, for x2 to x3 faster loading. LALR only for now. | Cache the results of the Lark grammar analysis, for x2 to x3 faster loading. LALR only for now. | ||||
| @@ -164,7 +163,7 @@ class LarkOptions(Serialize): | |||||
| 'regex': False, | 'regex': False, | ||||
| 'propagate_positions': False, | 'propagate_positions': False, | ||||
| 'lexer_callbacks': {}, | 'lexer_callbacks': {}, | ||||
| 'maybe_placeholders': False, | |||||
| 'maybe_placeholders': True, | |||||
| 'edit_terminals': None, | 'edit_terminals': None, | ||||
| 'g_regex_flags': 0, | 'g_regex_flags': 0, | ||||
| 'use_bytes': False, | 'use_bytes': False, | ||||
| @@ -303,8 +302,8 @@ class Lark(Serialize): | |||||
| else: | else: | ||||
| if self.options.cache is not True: | if self.options.cache is not True: | ||||
| raise ConfigurationError("cache argument must be bool or str") | raise ConfigurationError("cache argument must be bool or str") | ||||
| # Python2.7 doesn't support * syntax in tuples | |||||
| cache_fn = tempfile.gettempdir() + '/.lark_cache_%s_%s_%s.tmp' % ((cache_md5,) + sys.version_info[:2]) | |||||
| cache_fn = tempfile.gettempdir() + '/.lark_cache_%s_%s_%s.tmp' % (cache_md5, *sys.version_info[:2]) | |||||
| if FS.exists(cache_fn): | if FS.exists(cache_fn): | ||||
| logger.debug('Loading grammar from cache: %s', cache_fn) | logger.debug('Loading grammar from cache: %s', cache_fn) | ||||
| @@ -368,7 +367,6 @@ class Lark(Serialize): | |||||
| if self.options.priority not in _VALID_PRIORITY_OPTIONS: | if self.options.priority not in _VALID_PRIORITY_OPTIONS: | ||||
| raise ConfigurationError("invalid priority option: %r. Must be one of %r" % (self.options.priority, _VALID_PRIORITY_OPTIONS)) | raise ConfigurationError("invalid priority option: %r. Must be one of %r" % (self.options.priority, _VALID_PRIORITY_OPTIONS)) | ||||
| assert self.options.ambiguity not in ('resolve__antiscore_sum', ), 'resolve__antiscore_sum has been replaced with the option priority="invert"' | |||||
| if self.options.ambiguity not in _VALID_AMBIGUITY_OPTIONS: | if self.options.ambiguity not in _VALID_AMBIGUITY_OPTIONS: | ||||
| raise ConfigurationError("invalid ambiguity option: %r. Must be one of %r" % (self.options.ambiguity, _VALID_AMBIGUITY_OPTIONS)) | raise ConfigurationError("invalid ambiguity option: %r. Must be one of %r" % (self.options.ambiguity, _VALID_AMBIGUITY_OPTIONS)) | ||||
| @@ -387,7 +385,6 @@ class Lark(Serialize): | |||||
| self._terminals_dict = {t.name: t for t in self.terminals} | self._terminals_dict = {t.name: t for t in self.terminals} | ||||
| # If the user asked to invert the priorities, negate them all here. | # If the user asked to invert the priorities, negate them all here. | ||||
| # This replaces the old 'resolve__antiscore_sum' option. | |||||
| if self.options.priority == 'invert': | if self.options.priority == 'invert': | ||||
| for rule in self.rules: | for rule in self.rules: | ||||
| if rule.options.priority is not None: | if rule.options.priority is not None: | ||||
| @@ -6,7 +6,6 @@ from collections import namedtuple | |||||
| from copy import copy, deepcopy | from copy import copy, deepcopy | ||||
| import pkgutil | import pkgutil | ||||
| from ast import literal_eval | from ast import literal_eval | ||||
| from numbers import Integral | |||||
| from contextlib import suppress | from contextlib import suppress | ||||
| from typing import List, Tuple, Union, Callable, Dict, Optional | from typing import List, Tuple, Union, Callable, Dict, Optional | ||||
| @@ -1067,8 +1066,7 @@ class GrammarBuilder: | |||||
| if self._is_term(name): | if self._is_term(name): | ||||
| if options is None: | if options is None: | ||||
| options = 1 | options = 1 | ||||
| # if we don't use Integral here, we run into python2.7/python3 problems with long vs int | |||||
| elif not isinstance(options, Integral): | |||||
| elif not isinstance(options, int): | |||||
| raise GrammarError("Terminal require a single int as 'options' (e.g. priority), got %s" % (type(options),)) | raise GrammarError("Terminal require a single int as 'options' (e.g. priority), got %s" % (type(options),)) | ||||
| else: | else: | ||||
| if options is None: | if options is None: | ||||
| @@ -385,7 +385,7 @@ def _vargs_inline(f, _data, children, _meta): | |||||
| def _vargs_meta_inline(f, _data, children, meta): | def _vargs_meta_inline(f, _data, children, meta): | ||||
| return f(meta, *children) | return f(meta, *children) | ||||
| def _vargs_meta(f, _data, children, meta): | def _vargs_meta(f, _data, children, meta): | ||||
| return f(children, meta) # TODO swap these for consistency? Backwards incompatible! | |||||
| return f(meta, children) | |||||
| def _vargs_tree(f, data, children, meta): | def _vargs_tree(f, data, children, meta): | ||||
| return f(Tree(data, children, meta)) | return f(Tree(data, children, meta)) | ||||
| @@ -208,11 +208,11 @@ class TestParsers(unittest.TestCase): | |||||
| @v_args(meta=True) | @v_args(meta=True) | ||||
| class T1(Transformer): | class T1(Transformer): | ||||
| def a(self, children, meta): | |||||
| def a(self, meta, children): | |||||
| assert not children | assert not children | ||||
| return meta.line | return meta.line | ||||
| def start(self, children, meta): | |||||
| def start(self, meta, children): | |||||
| return children | return children | ||||
| @v_args(meta=True, inline=True) | @v_args(meta=True, inline=True) | ||||
| @@ -183,8 +183,8 @@ class TestReconstructor(TestCase): | |||||
| keyword x += y | keyword x += y | ||||
| """ | """ | ||||
| l1 = Lark(g1, parser='lalr') | |||||
| l2 = Lark(g2, parser='lalr') | |||||
| l1 = Lark(g1, parser='lalr', maybe_placeholders=False) | |||||
| l2 = Lark(g2, parser='lalr', maybe_placeholders=False) | |||||
| r = Reconstructor(l2) | r = Reconstructor(l2) | ||||
| tree = l1.parse(code) | tree = l1.parse(code) | ||||