value parsing speed up: treat simple refs with a quicker parser
diff --git a/reclass/values/value.py b/reclass/values/value.py
index f90eded..976a35e 100644
--- a/reclass/values/value.py
+++ b/reclass/values/value.py
@@ -20,83 +20,101 @@
_REF = 'REF'
_EXP = 'EXP'
+_ESCAPE = ESCAPE_CHARACTER
+_DOUBLE_ESCAPE = _ESCAPE + _ESCAPE
+
+_REF_OPEN = REFERENCE_SENTINELS[0]
+_REF_CLOSE = REFERENCE_SENTINELS[1]
+_REF_CLOSE_FIRST = _REF_CLOSE[0]
+_REF_ESCAPE_OPEN = _ESCAPE + _REF_OPEN
+_REF_ESCAPE_CLOSE = _ESCAPE + _REF_CLOSE
+_REF_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _REF_OPEN
+_REF_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _REF_CLOSE
+_REF_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE
+
+_EXP_OPEN = EXPORT_SENTINELS[0]
+_EXP_CLOSE = EXPORT_SENTINELS[1]
+_EXP_CLOSE_FIRST = _EXP_CLOSE[0]
+_EXP_ESCAPE_OPEN = _ESCAPE + _EXP_OPEN
+_EXP_ESCAPE_CLOSE = _ESCAPE + _EXP_CLOSE
+_EXP_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _EXP_OPEN
+_EXP_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _EXP_CLOSE
+_EXP_EXCLUDES = _ESCAPE + _EXP_OPEN + _EXP_CLOSE
+
+_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE + _EXP_OPEN + _EXP_CLOSE
+
+def _string(string, location, tokens):
+ token = tokens[0]
+ tokens[0] = (_STR, token)
+
+def _reference(string, location, tokens):
+ token = list(tokens[0])
+ tokens[0] = (_REF, token)
+
+def _export(string, location, tokens):
+ token = list(tokens[0])
+ tokens[0] = (_EXP, token)
+
+def _get_parser():
+ white_space = pp.White()
+ double_escape = pp.Combine(pp.Literal(_DOUBLE_ESCAPE) + pp.MatchFirst([pp.FollowedBy(_REF_OPEN), pp.FollowedBy(_REF_CLOSE)])).setParseAction(pp.replaceWith(_ESCAPE))
+
+ ref_open = pp.Literal(_REF_OPEN).suppress()
+ ref_close = pp.Literal(_REF_CLOSE).suppress()
+ ref_not_open = ~pp.Literal(_REF_OPEN) + ~pp.Literal(_REF_ESCAPE_OPEN) + ~pp.Literal(_REF_DOUBLE_ESCAPE_OPEN)
+ ref_not_close = ~pp.Literal(_REF_CLOSE) + ~pp.Literal(_REF_ESCAPE_CLOSE) + ~pp.Literal(_REF_DOUBLE_ESCAPE_CLOSE)
+ ref_escape_open = pp.Literal(_REF_ESCAPE_OPEN).setParseAction(pp.replaceWith(_REF_OPEN))
+ ref_escape_close = pp.Literal(_REF_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_REF_CLOSE))
+ ref_text = pp.MatchFirst([pp.Word(pp.printables, excludeChars=_REF_EXCLUDES), pp.CharsNotIn(_REF_CLOSE_FIRST, exact=1)])
+ ref_content = pp.Combine(pp.OneOrMore(ref_not_open + ref_not_close + ref_text))
+ ref_string = pp.MatchFirst([double_escape, ref_escape_open, ref_escape_close, ref_content, white_space]).setParseAction(_string)
+ ref_item = pp.Forward()
+ ref_items = pp.OneOrMore(ref_item)
+ reference = (ref_open + pp.Group(ref_items) + ref_close).setParseAction(_reference)
+ ref_item << (reference | ref_string)
+
+ exp_open = pp.Literal(_EXP_OPEN).suppress()
+ exp_close = pp.Literal(_EXP_CLOSE).suppress()
+ exp_not_open = ~pp.Literal(_EXP_OPEN) + ~pp.Literal(_EXP_ESCAPE_OPEN) + ~pp.Literal(_EXP_DOUBLE_ESCAPE_OPEN)
+ exp_not_close = ~pp.Literal(_EXP_CLOSE) + ~pp.Literal(_EXP_ESCAPE_CLOSE) + ~pp.Literal(_EXP_DOUBLE_ESCAPE_CLOSE)
+ exp_escape_open = pp.Literal(_EXP_ESCAPE_OPEN).setParseAction(pp.replaceWith(_EXP_OPEN))
+ exp_escape_close = pp.Literal(_EXP_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_EXP_CLOSE))
+ exp_text = pp.Word(pp.printables, excludeChars=_EXP_CLOSE_FIRST)
+ exp_content = pp.Combine(pp.OneOrMore(exp_not_close + exp_text))
+ exp_string = pp.MatchFirst([double_escape, exp_escape_open, exp_escape_close, exp_content, white_space]).setParseAction(_string)
+ exp_items = pp.OneOrMore(exp_string)
+ export = (exp_open + pp.Group(exp_items) + exp_close).setParseAction(_export)
+
+ text = pp.MatchFirst([pp.Word(pp.printables, excludeChars=_EXCLUDES), pp.CharsNotIn('', exact=1)])
+ content = pp.Combine(pp.OneOrMore(ref_not_open + exp_not_open + text))
+ string = pp.MatchFirst([double_escape, ref_escape_open, exp_escape_open, content, white_space]).setParseAction(_string)
+
+ item = reference | export | string
+ line = pp.OneOrMore(item) + pp.StringEnd()
+ return line
+
+def _get_simple_ref_parser():
+ white_space = pp.White()
+
+ ref_open = pp.Literal(_REF_OPEN).suppress()
+ ref_close = pp.Literal(_REF_CLOSE).suppress()
+ ref_not_open = ~pp.Literal(_REF_OPEN) + ~pp.Literal(_REF_ESCAPE_OPEN) + ~pp.Literal(_REF_DOUBLE_ESCAPE_OPEN)
+ ref_text = pp.Word(pp.printables, excludeChars=_REF_CLOSE_FIRST)
+ ref_content = pp.Combine(pp.OneOrMore(ref_text | white_space)).setParseAction(_string)
+ reference = (ref_open + pp.Group(ref_content) + ref_close).setParseAction(_reference)
+
+ text = pp.MatchFirst([pp.Word(pp.printables, excludeChars=_EXCLUDES), pp.CharsNotIn('', exact=1)])
+ content = pp.OneOrMore(ref_not_open + text)
+ string = pp.Combine(pp.OneOrMore(pp.MatchFirst([content, white_space]))).setParseAction(_string)
+
+ item = reference | string
+ line = pp.OneOrMore(item) + pp.StringEnd()
+ return line
+
class Value(object):
- def _get_parser():
-
- def _string(string, location, tokens):
- token = tokens[0]
- tokens[0] = (_STR, token)
-
- def _reference(string, location, tokens):
- token = list(tokens[0])
- tokens[0] = (_REF, token)
-
- def _export(string, location, tokens):
- token = list(tokens[0])
- tokens[0] = (_EXP, token)
-
- _ESCAPE = ESCAPE_CHARACTER
- _DOUBLE_ESCAPE = _ESCAPE + _ESCAPE
-
- _REF_OPEN = REFERENCE_SENTINELS[0]
- _REF_CLOSE = REFERENCE_SENTINELS[1]
- _REF_CLOSE_FIRST = _REF_CLOSE[0]
- _REF_ESCAPE_OPEN = _ESCAPE + _REF_OPEN
- _REF_ESCAPE_CLOSE = _ESCAPE + _REF_CLOSE
- _REF_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _REF_OPEN
- _REF_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _REF_CLOSE
- _REF_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE
-
- _EXP_OPEN = EXPORT_SENTINELS[0]
- _EXP_CLOSE = EXPORT_SENTINELS[1]
- _EXP_CLOSE_FIRST = _EXP_CLOSE[0]
- _EXP_ESCAPE_OPEN = _ESCAPE + _EXP_OPEN
- _EXP_ESCAPE_CLOSE = _ESCAPE + _EXP_CLOSE
- _EXP_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _EXP_OPEN
- _EXP_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _EXP_CLOSE
- _EXP_EXCLUDES = _ESCAPE + _EXP_OPEN + _EXP_CLOSE
-
- _EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE + _EXP_OPEN + _EXP_CLOSE
-
- white_space = pp.White()
- double_escape = pp.Combine(pp.Literal(_DOUBLE_ESCAPE) + pp.MatchFirst([pp.FollowedBy(_REF_OPEN), pp.FollowedBy(_REF_CLOSE)])).setParseAction(pp.replaceWith(_ESCAPE))
-
- ref_open = pp.Literal(_REF_OPEN).suppress()
- ref_close = pp.Literal(_REF_CLOSE).suppress()
- ref_not_open = ~pp.Literal(_REF_OPEN) + ~pp.Literal(_REF_ESCAPE_OPEN) + ~pp.Literal(_REF_DOUBLE_ESCAPE_OPEN)
- ref_not_close = ~pp.Literal(_REF_CLOSE) + ~pp.Literal(_REF_ESCAPE_CLOSE) + ~pp.Literal(_REF_DOUBLE_ESCAPE_CLOSE)
- ref_escape_open = pp.Literal(_REF_ESCAPE_OPEN).setParseAction(pp.replaceWith(_REF_OPEN))
- ref_escape_close = pp.Literal(_REF_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_REF_CLOSE))
- ref_text = pp.MatchFirst([pp.Word(pp.printables, excludeChars=_REF_EXCLUDES), pp.CharsNotIn(_REF_CLOSE_FIRST, exact=1)])
- ref_content = pp.Combine(pp.OneOrMore(ref_not_open + ref_not_close + ref_text))
- ref_string = pp.MatchFirst([double_escape, ref_escape_open, ref_escape_close, ref_content, white_space]).setParseAction(_string)
- ref_item = pp.Forward()
- ref_items = pp.OneOrMore(ref_item)
- reference = (ref_open + pp.Group(ref_items) + ref_close).setParseAction(_reference)
- ref_item << (reference | ref_string)
-
- exp_open = pp.Literal(_EXP_OPEN).suppress()
- exp_close = pp.Literal(_EXP_CLOSE).suppress()
- exp_not_open = ~pp.Literal(_EXP_OPEN) + ~pp.Literal(_EXP_ESCAPE_OPEN) + ~pp.Literal(_EXP_DOUBLE_ESCAPE_OPEN)
- exp_not_close = ~pp.Literal(_EXP_CLOSE) + ~pp.Literal(_EXP_ESCAPE_CLOSE) + ~pp.Literal(_EXP_DOUBLE_ESCAPE_CLOSE)
- exp_escape_open = pp.Literal(_EXP_ESCAPE_OPEN).setParseAction(pp.replaceWith(_EXP_OPEN))
- exp_escape_close = pp.Literal(_EXP_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_EXP_CLOSE))
- exp_text = pp.Word(pp.printables, excludeChars=_EXP_CLOSE_FIRST)
- exp_content = pp.Combine(pp.OneOrMore(exp_not_close + exp_text))
- exp_string = pp.MatchFirst([double_escape, exp_escape_open, exp_escape_close, exp_content, white_space]).setParseAction(_string)
- exp_items = pp.OneOrMore(exp_string)
- export = (exp_open + pp.Group(exp_items) + exp_close).setParseAction(_export)
-
- text = pp.MatchFirst([pp.Word(pp.printables, excludeChars=_EXCLUDES), pp.CharsNotIn('', exact=1)])
- content = pp.Combine(pp.OneOrMore(ref_not_open + exp_not_open + text))
- string = pp.MatchFirst([double_escape, ref_escape_open, exp_escape_open, content, white_space]).setParseAction(_string)
-
- item = reference | export | string
- line = pp.OneOrMore(item) + pp.StringEnd()
- return line
-
_parser = _get_parser()
+ _simple_ref_parser = _get_simple_ref_parser()
def __init__(self, val, delimiter=PARAMETER_INTERPOLATION_DELIMITER):
self._delimiter = delimiter
@@ -104,19 +122,34 @@
self._allRefs = False
self._container = False
if isinstance(val, str):
- if '$' in val:
+ dollars = val.count('$')
+ if dollars == 0:
# speed up: only use pyparsing if there is a $ in the string
- try:
- tokens = Value._parser.leaveWhitespace().parseString(val).asList()
- except pp.ParseException as e:
- raise ParseError(e.msg, e.line, e.col, e.lineno)
- items = self._createItems(tokens)
- if len(items) is 1:
- self._item = items[0]
- else:
- self._item = CompItem(items)
- else:
self._item = ScaItem(val)
+ else:
+ open_braces = val.count('{')
+ if dollars == 1 and open_braces == 1 and '[' not in val and '\\' not in val:
+ # speed up: simple reference or string
+ try:
+ tokens = Value._simple_ref_parser.leaveWhitespace().parseString(val).asList()
+ except pp.ParseException as e:
+ raise ParseError(e.msg, e.line, e.col, e.lineno)
+ items = self._createItems(tokens)
+ if len(items) is 1:
+ self._item = items[0]
+ else:
+ self._item = CompItem(items)
+ else:
+ # use the full parser
+ try:
+ tokens = Value._parser.leaveWhitespace().parseString(val).asList()
+ except pp.ParseException as e:
+ raise ParseError(e.msg, e.line, e.col, e.lineno)
+ items = self._createItems(tokens)
+ if len(items) is 1:
+ self._item = items[0]
+ else:
+ self._item = CompItem(items)
elif isinstance(val, list):
self._item = ListItem(val)
self._container = True