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