no more escaping strings, triple quote

This commit is contained in:
Jesse Bannon 2023-12-10 22:19:55 -08:00
parent 94e028536f
commit 70876dc123
3 changed files with 33 additions and 22 deletions

View file

@ -104,10 +104,18 @@ def _is_numeric_start(char: str) -> bool:
return char.isnumeric() or char == "-" return char.isnumeric() or char == "-"
def _is_string_start(char: str) -> bool: def _is_string_start_single_char(char: Optional[str]) -> bool:
return char in ["'", '"'] return char in ["'", '"']
def _is_string_start_multi_char(string: Optional[str]) -> bool:
return string in ["'''", '"""']
def _is_null(string: Optional[str]) -> bool:
return string and string.lower() == "null"
def _is_breakable(char: str) -> bool: def _is_breakable(char: str) -> bool:
return char in ["}", ",", ")", "]"] or char.isspace() return char in ["}", ",", ")", "]"] or char.isspace()
@ -120,10 +128,6 @@ def _is_boolean_false(string: Optional[str]) -> bool:
return string and string.lower() == "false" return string and string.lower() == "false"
def _is_null(string: Optional[str]) -> bool:
return string and string.lower() == "null"
def _is_custom_function_argument_start(char: str) -> bool: def _is_custom_function_argument_start(char: str) -> bool:
return char == "$" return char == "$"
@ -273,28 +277,25 @@ class _Parser:
return Float(value=numeric_float) return Float(value=numeric_float)
def _parse_string(self) -> String: def _parse_string(self, str_open_token: str) -> String:
""" """
Begin parsing a string, including the quotation value Begin parsing a string, including the quotation value
""" """
self._set_highlight_position() self._set_highlight_position()
string_value = "" string_value = ""
open_quotation_char = self._read()
if not _is_string_start(open_quotation_char): if not _is_string_start_single_char(str_open_token) and not _is_string_start_multi_char(
str_open_token
):
raise UNREACHABLE raise UNREACHABLE
is_escaped = False while ch := self._read(increment_pos=False):
while ch := self._read(): if self._read(increment_pos=False, length=len(str_open_token)) == str_open_token:
if ch == open_quotation_char and not is_escaped: self._pos += len(str_open_token)
return String(value=string_value) return String(value=string_value)
if ch == "\\" and not is_escaped: self._pos += 1
is_escaped = True
continue
string_value += ch string_value += ch
is_escaped = False
raise STRINGS_NOT_CLOSED raise STRINGS_NOT_CLOSED
@ -313,8 +314,12 @@ class _Parser:
if _is_null(self._read(increment_pos=False, length=4)): if _is_null(self._read(increment_pos=False, length=4)):
self._pos += 4 self._pos += 4
return String(value="") return String(value="")
if _is_string_start(self._read(increment_pos=False)): if _is_string_start_multi_char(str_open_token := self._read(increment_pos=False, length=3)):
return self._parse_string() self._pos += 3
return self._parse_string(str_open_token)
if _is_string_start_single_char(str_open_token := self._read(increment_pos=False)):
self._pos += 1
return self._parse_string(str_open_token)
if self._read(increment_pos=False) == "[": if self._read(increment_pos=False) == "[":
self._pos += 1 self._pos += 1
return self._parse_array() return self._parse_array()
@ -535,7 +540,11 @@ class _Parser:
self._ast.append(self._parse_variable()) self._ast.append(self._parse_variable())
elif _is_numeric_start(ch1): elif _is_numeric_start(ch1):
raise NUMERICS_ONLY_ARGS raise NUMERICS_ONLY_ARGS
elif _is_string_start(ch1) or _is_null(self._read(increment_pos=False, length=4)): elif (
_is_string_start_single_char(ch1)
or _is_string_start_multi_char(self._read(increment_pos=False, length=3))
or _is_null(self._read(increment_pos=False, length=4))
):
raise STRINGS_ONLY_ARGS raise STRINGS_ONLY_ARGS
elif _is_boolean_true( elif _is_boolean_true(
self._read(increment_pos=False, length=4) self._read(increment_pos=False, length=4)

View file

@ -1,6 +1,7 @@
import pytest import pytest
from unit.script.conftest import single_variable_output from unit.script.conftest import single_variable_output
class TestNumericFunctions: class TestNumericFunctions:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"values, expected_output", "values, expected_output",

View file

@ -31,6 +31,7 @@ class TestString:
[ [
("{%string('')}", ""), ("{%string('')}", ""),
('{%string("")}', ""), ('{%string("")}', ""),
('{%string("\\")}', "\\"),
("{%string('323')}", "323"), ("{%string('323')}", "323"),
('{%string( "4253" )}', "4253"), ('{%string( "4253" )}', "4253"),
('{%string("hi")}', "hi"), ('{%string("hi")}', "hi"),
@ -41,9 +42,9 @@ class TestString:
("{%string('in function')} out of function", "in function out of function"), ("{%string('in function')} out of function", "in function out of function"),
("{%string('supports \" in string')}", 'supports " in string'), ("{%string('supports \" in string')}", 'supports " in string'),
('{%string("supports \' in string")}', "supports ' in string"), ('{%string("supports \' in string")}', "supports ' in string"),
('{%string("\\" in string with open \\"")}', '" in string with open "'), ("{%string('backslash \\\\')}", "backslash \\\\"),
("{%string('\\' in string with open \\'')}", "' in string with open '"), ("{%string('''triple quote with \" ' \\''')}", "triple quote with \" ' \\"),
("{%string('backslash \\\\')}", "backslash \\"), ('{%string("""triple quote with " \' \\""")}', "triple quote with \" ' \\"),
], ],
) )
def test_string(self, string: str, expected_string: str): def test_string(self, string: str, expected_string: str):