Honor whitespace in funcparser unparsed strings. Resolve #2927

This commit is contained in:
Griatch 2022-11-06 16:38:35 +01:00
parent b37ce26005
commit 443aae7f20
2 changed files with 30 additions and 8 deletions

View file

@ -85,6 +85,7 @@ class _ParsedFunc:
# state storage
fullstr: str = ""
infuncstr: str = ""
rawstr: str = ""
double_quoted: int = -1
current_kwarg: str = ""
open_lparens: int = 0
@ -96,7 +97,7 @@ class _ParsedFunc:
return self.funcname, self.args, self.kwargs
def __str__(self):
return self.fullstr + self.infuncstr
return self.prefix + self.rawstr + self.infuncstr
class ParsingError(RuntimeError):
@ -369,6 +370,8 @@ class FuncParser:
curr_func.open_lparens = open_lparens
curr_func.open_lsquare = open_lsquare
curr_func.open_lcurly = open_lcurly
# we must strip the remaining funcstr so it's not counted twice
curr_func.rawstr = curr_func.rawstr[: -len(infuncstr)]
current_kwarg = ""
infuncstr = ""
double_quoted = -1
@ -392,6 +395,8 @@ class FuncParser:
# in a function def (can be nested)
curr_func.rawstr += char
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
@ -552,8 +557,15 @@ class FuncParser:
# these are malformed (no closing bracket) and we should get their
# strings as-is.
callstack.append(curr_func)
for _ in range(len(callstack)):
infuncstr = str(callstack.pop()) + infuncstr
for inum, _ in enumerate(range(len(callstack))):
funcstr = str(callstack.pop())
if inum == 0 and funcstr.endswith(infuncstr):
# avoid double-echo of nested function calls. This should
# produce a good result most of the time, but it's not 100%
# guaranteed to, since it can ignore genuine duplicates
infuncstr = funcstr
else:
infuncstr = funcstr + infuncstr
if not return_str and exec_return != "":
# return explicit return

View file

@ -82,6 +82,12 @@ def _raises_callable(*args, **kwargs):
raise RuntimeError("Test exception raised by test callable")
def _pass_callable(*args, **kwargs):
kwargs.pop("funcparser", None)
kwargs.pop("raise_errors", None)
return str(args) + str(kwargs)
_test_callables = {
"foo": _test_callable,
"bar": _test_callable,
@ -95,6 +101,7 @@ _test_callables = {
"lit": _lit_callable,
"sum": _lsum_callable,
"raise": _raises_callable,
"pass": _pass_callable,
}
@ -184,8 +191,8 @@ class TestFuncParser(TestCase):
("Test with color |r$foo(a,b)|n is ok", "Test with color |r_test(a, b)|n is ok"),
("Test malformed1 This is $foo( and $bar(", "Test malformed1 This is $foo( and $bar("),
(
"Test malformed2 This is $foo( and $bar()",
"Test malformed2 This is $foo( and _test()",
"Test malformed2 This is $foo( and $bar()",
"Test malformed2 This is $foo( and _test()",
),
("Test malformed3 $", "Test malformed3 $"),
(
@ -304,11 +311,14 @@ class TestFuncParser(TestCase):
ret = self.parser.parse(string, strip=True)
self.assertEqual("Test and things", ret)
@unittest.skip("broken due to https://github.com/evennia/evennia/issues/2927")
def test_parse_whitespace_preserved(self):
string = "The answer is $add(1, x)"
string = "The answer is $foobar(1, x)" # not found, so should be preserved
ret = self.parser.parse(string)
self.assertEqual("The answer is $add(1, x)", ret)
self.assertEqual("The answer is $foobar(1, x)", ret)
string = 'The $pass(testing, bar= $dum(b = "test2" , a), ) $pass('
ret = self.parser.parse(string)
self.assertEqual("The ('testing',){'bar': '$dum(b = \"test2\" , a)'} $pass(", ret)
def test_parse_escape(self):
"""