Make funcparser able to handle non-string returns
This commit is contained in:
parent
73eb9a935d
commit
06c2b6d477
2 changed files with 73 additions and 25 deletions
|
|
@ -72,6 +72,7 @@ class ParsedFunc:
|
||||||
open_lparens: int = 0
|
open_lparens: int = 0
|
||||||
open_lsquate: int = 0
|
open_lsquate: int = 0
|
||||||
open_lcurly: int = 0
|
open_lcurly: int = 0
|
||||||
|
exec_return = ""
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.funcname, self.args, self.kwargs
|
return self.funcname, self.args, self.kwargs
|
||||||
|
|
@ -214,7 +215,7 @@ class FuncParser:
|
||||||
kwargs = {**self.default_kwargs, **kwargs, **reserved_kwargs}
|
kwargs = {**self.default_kwargs, **kwargs, **reserved_kwargs}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return str(func(*args, **kwargs))
|
return func(*args, **kwargs)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
if raise_errors:
|
if raise_errors:
|
||||||
|
|
@ -267,6 +268,7 @@ class FuncParser:
|
||||||
open_lcurly = 0 # open {
|
open_lcurly = 0 # open {
|
||||||
escaped = False
|
escaped = False
|
||||||
current_kwarg = ""
|
current_kwarg = ""
|
||||||
|
exec_return = ""
|
||||||
|
|
||||||
curr_func = None
|
curr_func = None
|
||||||
fullstr = '' # final string
|
fullstr = '' # final string
|
||||||
|
|
@ -316,6 +318,7 @@ class FuncParser:
|
||||||
open_lparens = 0
|
open_lparens = 0
|
||||||
open_lsquare = 0
|
open_lsquare = 0
|
||||||
open_lcurly = 0
|
open_lcurly = 0
|
||||||
|
exec_return = ""
|
||||||
callstack.append(curr_func)
|
callstack.append(curr_func)
|
||||||
|
|
||||||
# start a new func
|
# start a new func
|
||||||
|
|
@ -329,6 +332,13 @@ class FuncParser:
|
||||||
|
|
||||||
# in a function def (can be nested)
|
# in a function def (can be nested)
|
||||||
|
|
||||||
|
if exec_return != '' and char not in (",=)"):
|
||||||
|
# if exec_return is followed by any other character
|
||||||
|
# than one demarking an arg,kwarg or function-end
|
||||||
|
# it must immediately merge as a string
|
||||||
|
infuncstr += str(exec_return)
|
||||||
|
exec_return = ''
|
||||||
|
|
||||||
if char == "'": # note that this is the same as "\'"
|
if char == "'": # note that this is the same as "\'"
|
||||||
# a single quote - flip status
|
# a single quote - flip status
|
||||||
single_quoted = not single_quoted
|
single_quoted = not single_quoted
|
||||||
|
|
@ -342,7 +352,7 @@ class FuncParser:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if double_quoted or single_quoted:
|
if double_quoted or single_quoted:
|
||||||
# inside a string escape - this escapes everything else
|
# inside a string definition - this escapes everything else
|
||||||
infuncstr += char
|
infuncstr += char
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -374,6 +384,8 @@ class FuncParser:
|
||||||
|
|
||||||
if char == '=':
|
if char == '=':
|
||||||
# beginning of a keyword argument
|
# beginning of a keyword argument
|
||||||
|
if exec_return != '':
|
||||||
|
infuncstr = exec_return
|
||||||
current_kwarg = infuncstr.strip()
|
current_kwarg = infuncstr.strip()
|
||||||
curr_func.kwargs[current_kwarg] = ""
|
curr_func.kwargs[current_kwarg] = ""
|
||||||
curr_func.fullstr += infuncstr + char
|
curr_func.fullstr += infuncstr + char
|
||||||
|
|
@ -396,16 +408,28 @@ class FuncParser:
|
||||||
infuncstr += char
|
infuncstr += char
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# end current arg/kwarg one way or another
|
if exec_return != '':
|
||||||
if current_kwarg:
|
# store the execution return as-received
|
||||||
curr_func.kwargs[current_kwarg] = infuncstr.strip()
|
if current_kwarg:
|
||||||
current_kwarg = ""
|
curr_func.kwargs[current_kwarg] = exec_return
|
||||||
elif infuncstr.strip():
|
else:
|
||||||
curr_func.args.append(infuncstr.strip())
|
curr_func.args.append(exec_return)
|
||||||
|
else:
|
||||||
|
# store a string instead
|
||||||
|
if current_kwarg:
|
||||||
|
curr_func.kwargs[current_kwarg] = infuncstr.strip()
|
||||||
|
elif infuncstr.strip():
|
||||||
|
# don't store the empty string
|
||||||
|
curr_func.args.append(infuncstr.strip())
|
||||||
|
|
||||||
# we need to store the full string so we can print it 'raw' in
|
# note that at this point either exec_return or infuncstr will
|
||||||
# case this funcdef turns out to e.g. lack an ending paranthesis
|
# be empty. We need to store the full string so we can print
|
||||||
curr_func.fullstr += infuncstr + char
|
# it 'raw' in case this funcdef turns out to e.g. lack an
|
||||||
|
# ending paranthesis
|
||||||
|
curr_func.fullstr += str(exec_return) + infuncstr + char
|
||||||
|
|
||||||
|
current_kwarg = ""
|
||||||
|
exec_return = ''
|
||||||
infuncstr = ''
|
infuncstr = ''
|
||||||
|
|
||||||
if char == ')':
|
if char == ')':
|
||||||
|
|
@ -415,13 +439,14 @@ class FuncParser:
|
||||||
|
|
||||||
if strip:
|
if strip:
|
||||||
# remove function as if it returned empty
|
# remove function as if it returned empty
|
||||||
infuncstr = ''
|
exec_return = ''
|
||||||
elif escape:
|
elif escape:
|
||||||
# get function and set it as escaped
|
# get function and set it as escaped
|
||||||
infuncstr = escape_char + curr_func.fullstr
|
exec_return = escape_char + curr_func.fullstr
|
||||||
else:
|
else:
|
||||||
# execute the function
|
# execute the function - the result may be a string or
|
||||||
infuncstr = self.execute(
|
# something else
|
||||||
|
exec_return = self.execute(
|
||||||
curr_func, raise_errors=raise_errors, **reserved_kwargs)
|
curr_func, raise_errors=raise_errors, **reserved_kwargs)
|
||||||
|
|
||||||
if callstack:
|
if callstack:
|
||||||
|
|
@ -429,7 +454,11 @@ class FuncParser:
|
||||||
# and continue where we were
|
# and continue where we were
|
||||||
curr_func = callstack.pop()
|
curr_func = callstack.pop()
|
||||||
current_kwarg = curr_func.current_kwarg
|
current_kwarg = curr_func.current_kwarg
|
||||||
infuncstr = curr_func.infuncstr + infuncstr
|
if curr_func.infuncstr:
|
||||||
|
# if we have an ongoing string, we must merge the
|
||||||
|
# exec into this as a part of that string
|
||||||
|
infuncstr = curr_func.infuncstr + str(exec_return)
|
||||||
|
exec_return = ''
|
||||||
curr_func.infuncstr = ''
|
curr_func.infuncstr = ''
|
||||||
single_quoted = curr_func.single_quoted
|
single_quoted = curr_func.single_quoted
|
||||||
double_quoted = curr_func.double_quoted
|
double_quoted = curr_func.double_quoted
|
||||||
|
|
@ -437,13 +466,14 @@ class FuncParser:
|
||||||
open_lsquare = curr_func.open_lsquare
|
open_lsquare = curr_func.open_lsquare
|
||||||
open_lcurly = curr_func.open_lcurly
|
open_lcurly = curr_func.open_lcurly
|
||||||
else:
|
else:
|
||||||
# back to the top-level string
|
# back to the top-level string - this means the
|
||||||
|
# exec_return should always be converted to a string.
|
||||||
curr_func = None
|
curr_func = None
|
||||||
fullstr += infuncstr
|
fullstr += str(exec_return)
|
||||||
|
exec_return = ''
|
||||||
infuncstr = ''
|
infuncstr = ''
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# no special char
|
|
||||||
infuncstr += char
|
infuncstr += char
|
||||||
|
|
||||||
if curr_func:
|
if curr_func:
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,27 @@ def _clr_callable(*args, **kwargs):
|
||||||
return f"|{clr}{string}|n"
|
return f"|{clr}{string}|n"
|
||||||
|
|
||||||
def _typ_callable(*args, **kwargs):
|
def _typ_callable(*args, **kwargs):
|
||||||
if args:
|
try:
|
||||||
return type(literal_eval(args[0]))
|
if isinstance(args[0], str):
|
||||||
return ''
|
return type(literal_eval(args[0]))
|
||||||
|
else:
|
||||||
|
return type(args[0])
|
||||||
|
except (SyntaxError, ValueError):
|
||||||
|
return type("")
|
||||||
|
|
||||||
def _add_callable(*args, **kwargs):
|
def _add_callable(*args, **kwargs):
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
return literal_eval(args[0]) + literal_eval(args[1])
|
return literal_eval(args[0]) + literal_eval(args[1])
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def _lit_callable(*args, **kwargs):
|
||||||
|
return literal_eval(args[0])
|
||||||
|
|
||||||
|
def _lsum_callable(*args, **kwargs):
|
||||||
|
if isinstance(args[0], (list, tuple)):
|
||||||
|
return sum(val for val in args[0])
|
||||||
|
return ''
|
||||||
|
|
||||||
_test_callables = {
|
_test_callables = {
|
||||||
"foo": _test_callable,
|
"foo": _test_callable,
|
||||||
"bar": _test_callable,
|
"bar": _test_callable,
|
||||||
|
|
@ -63,6 +75,8 @@ _test_callables = {
|
||||||
"clr": _clr_callable,
|
"clr": _clr_callable,
|
||||||
"typ": _typ_callable,
|
"typ": _typ_callable,
|
||||||
"add": _add_callable,
|
"add": _add_callable,
|
||||||
|
"lit": _lit_callable,
|
||||||
|
"sum": _lsum_callable,
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestFuncParser(TestCase):
|
class TestFuncParser(TestCase):
|
||||||
|
|
@ -147,17 +161,21 @@ class TestFuncParser(TestCase):
|
||||||
("Test type6 $typ('1'), $typ(\"1.0\")", "Test type6 <class 'str'>, <class 'str'>"),
|
("Test type6 $typ('1'), $typ(\"1.0\")", "Test type6 <class 'str'>, <class 'str'>"),
|
||||||
("Test add1 $add(1, 2)", "Test add1 3"),
|
("Test add1 $add(1, 2)", "Test add1 3"),
|
||||||
("Test add2 $add([1,2,3,4], [5,6])", "Test add2 [1, 2, 3, 4, 5, 6]"),
|
("Test add2 $add([1,2,3,4], [5,6])", "Test add2 [1, 2, 3, 4, 5, 6]"),
|
||||||
|
("Test literal1 $sum($lit([1,2,3,4,5,6]))", "Test literal1 21"),
|
||||||
|
("Test literal2 $typ($lit(1))", "Test literal2 <class 'int'>"),
|
||||||
|
("Test literal3 $typ($lit(1)aaa)", "Test literal3 <class 'str'>"),
|
||||||
|
("Test literal4 $typ(aaa$lit(1))", "Test literal4 <class 'str'>"),
|
||||||
])
|
])
|
||||||
def test_parse(self, string, expected):
|
def test_parse(self, string, expected):
|
||||||
"""
|
"""
|
||||||
Test parsing of string.
|
Test parsing of string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
t0 = time.time()
|
# t0 = time.time()
|
||||||
# from evennia import set_trace;set_trace()
|
# from evennia import set_trace;set_trace()
|
||||||
ret = self.parser.parse(string, raise_errors=True)
|
ret = self.parser.parse(string, raise_errors=True)
|
||||||
t1 = time.time()
|
# t1 = time.time()
|
||||||
print(f"time: {(t1-t0)*1000} ms")
|
# print(f"time: {(t1-t0)*1000} ms")
|
||||||
self.assertEqual(expected, ret)
|
self.assertEqual(expected, ret)
|
||||||
|
|
||||||
def test_parse_raise(self):
|
def test_parse_raise(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue