From c9fb4913a6f62deb95d8367ea100efee595a86b9 Mon Sep 17 00:00:00 2001 From: Igor Dejanovic <igor.dejanovic@gmail.com> Date: Mon, 17 Feb 2014 01:14:42 +0100 Subject: [PATCH] refs #2 Support for referencing child node as attributes on NonTerminal This works for rules that are referenced from the rule which created NonTerminal. --- arpeggio/__init__.py | 23 +++++++++++++++++++++++ tests/test_rulename_lookup.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/test_rulename_lookup.py diff --git a/arpeggio/__init__.py b/arpeggio/__init__.py index 267bd58..1319e88 100644 --- a/arpeggio/__init__.py +++ b/arpeggio/__init__.py @@ -615,6 +615,9 @@ class NonTerminal(ParseTreeNode): super(NonTerminal, self).__init__(type, position, error) self.nodes = flatten([nodes]) + # Child nodes cache. Used for lookup by rule name. + self._child_cache = {} + @property def desc(self): return self.name @@ -628,6 +631,26 @@ class NonTerminal(ParseTreeNode): def __repr__(self): return "[ %s ]" % ", ".join([repr(x) for x in self.nodes]) + def __getattr__(self, item): + """ + Find a child (non)terminal by the rule name. + + Args: + item(str): The name of the child node. + """ + # First check the cache + if item in self._child_cache: + return self._child_cache[item] + + # If not found in the cache find it and store it in the + # cache for later. + for n in self.nodes: + if n.type == item: + self._child_cache[item] = n + return n + + raise AttributeError + # ---------------------------------------------------- # Semantic Actions diff --git a/tests/test_rulename_lookup.py b/tests/test_rulename_lookup.py new file mode 100644 index 0000000..2fec9d0 --- /dev/null +++ b/tests/test_rulename_lookup.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +####################################################################### +# Name: test_peg_parser +# Purpose: Test for parser constructed using PEG textual grammars. +# Author: Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com> +# Copyright: (c) 2014 Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com> +# License: MIT License +####################################################################### + +from unittest import TestCase + +# Grammar +from arpeggio import ParserPython, ZeroOrMore + + +def foo(): return "a", bar, "b", baz +def bar(): return "c" +def baz(): return "d" + + + +class TestPEGParser(TestCase): + + def test_lookup_single(self): + + parser = ParserPython(foo) + + result = parser.parse("a c b d") + + self.assertTrue(hasattr(result, "bar")) + self.assertTrue(hasattr(result, "baz")) + self.assertTrue(not hasattr(result, "unexisting")) + -- 2.18.0