Commit c2bfe117 authored by Igor Dejanovic's avatar Igor Dejanovic

Support for default semantic actions.

SemanticAction now have a default behaviour which will reduce overhead
in some common cases.
parent 30b13fc0
...@@ -11,9 +11,10 @@ ...@@ -11,9 +11,10 @@
# notation. # notation.
################################################################################ ################################################################################
from __future__ import print_function from __future__ import print_function, unicode_literals
import re import re
import bisect import bisect
from arpeggio.utils import isstr
DEFAULT_WS = '\t\n\r ' DEFAULT_WS = '\t\n\r '
...@@ -697,8 +698,30 @@ class SemanticAction(object): ...@@ -697,8 +698,30 @@ class SemanticAction(object):
def first_pass(self, parser, node, nodes): def first_pass(self, parser, node, nodes):
""" """
Called in the first pass of tree walk. Called in the first pass of tree walk.
This is the default implementation used if no semantic action is defined.
""" """
raise NotImplementedError() # Special case. If only one child exist return it.
if len(nodes)==1:
retval = nodes[0]
else:
# If there is only one non-string child return
# that by default. This will support e.g. bracket
# removals.
last_non_str = None
for c in nodes:
if not isstr(c):
if last_non_str is None:
last_non_str = c
else:
# If there is multiple non-string objects
# by default convert non-terminal to unicode
retval = str(node)
break
else:
# Return the only non-string child
retval = last_non_str
return retval
# ---------------------------------------------------- # ----------------------------------------------------
...@@ -777,8 +800,12 @@ class Parser(object): ...@@ -777,8 +800,12 @@ class Parser(object):
if hasattr(sem_actions[node.rule], "second_pass"): if hasattr(sem_actions[node.rule], "second_pass"):
for_second_pass.append((node.rule, retval)) for_second_pass.append((node.rule, retval))
else: else:
if isinstance(node, NonTerminal): # If no rule is present use some sane defaults
retval = NonTerminal(node.rule, node.position, children) if isinstance(node, Terminal):
# Convert Terminal node to str
retval = str(node)
elif isinstance(node, NonTerminal):
retval = SemanticAction().first_pass(self, node, children)
else: else:
retval = node retval = node
......
"""
Various utilities.
"""
# isstr check if object is of string type.
# This works for both python 2 and 3
# Taken from http://stackoverflow.com/questions/11301138/how-to-check-if-variable-is-string-with-python-2-and-3-compatibility
try:
basestring # attempt to evaluate basestring
def isstr(s):
return isinstance(s, basestring)
except NameError:
def isstr(s):
return isinstance(s, str)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment