multiple lists work :o
This commit is contained in:
parent
870b3ee018
commit
ec62c7fe67
6 changed files with 54 additions and 14 deletions
|
|
@ -1,9 +1,10 @@
|
|||
from typing import Optional
|
||||
|
||||
from ytdl_sub.script.functions.array_functions import ArrayFunctions
|
||||
from ytdl_sub.script.functions.numeric_functions import NumericFunctions
|
||||
from ytdl_sub.script.functions.special_functions import SpecialFunctions
|
||||
from ytdl_sub.script.functions.string_functions import StringFunctions
|
||||
|
||||
|
||||
class Functions(StringFunctions, NumericFunctions, SpecialFunctions):
|
||||
class Functions(StringFunctions, NumericFunctions, SpecialFunctions, ArrayFunctions):
|
||||
pass
|
||||
|
|
|
|||
14
src/ytdl_sub/script/functions/array_functions.py
Normal file
14
src/ytdl_sub/script/functions/array_functions.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from typing import List
|
||||
|
||||
from ytdl_sub.script.types.resolvable import Array
|
||||
from ytdl_sub.script.types.resolvable import Resolvable
|
||||
|
||||
|
||||
class ArrayFunctions:
|
||||
@staticmethod
|
||||
def extend(*arrays: Array) -> Array:
|
||||
output: List[Resolvable] = []
|
||||
for array in arrays:
|
||||
output.extend(array.value)
|
||||
|
||||
return Array(output)
|
||||
|
|
@ -4,6 +4,7 @@ from typing import Optional
|
|||
from ytdl_sub.script.syntax_tree import SyntaxTree
|
||||
from ytdl_sub.script.types.function import ArgumentType
|
||||
from ytdl_sub.script.types.function import Function
|
||||
from ytdl_sub.script.types.resolvable import Array
|
||||
from ytdl_sub.script.types.resolvable import Boolean
|
||||
from ytdl_sub.script.types.resolvable import Float
|
||||
from ytdl_sub.script.types.resolvable import Integer
|
||||
|
|
@ -48,7 +49,7 @@ class _Parser:
|
|||
if ch.isspace() and not var_name:
|
||||
self._pos += 1
|
||||
continue
|
||||
if ch in ["}", ",", ")"] or ch.isspace():
|
||||
if ch in ["}", ",", ")", "]"] or ch.isspace():
|
||||
break
|
||||
|
||||
is_lower = ch.isascii() and ch.islower()
|
||||
|
|
@ -115,6 +116,9 @@ class _Parser:
|
|||
return Boolean(value=False)
|
||||
if self._read(increment_pos=False) in ["'", '"']:
|
||||
return self._parse_string()
|
||||
if self._read(increment_pos=False) == "[":
|
||||
self._pos += 1
|
||||
return self._parse_array()
|
||||
if self._read(increment_pos=False).isascii() and self._read(increment_pos=False).islower():
|
||||
return self._parse_variable()
|
||||
raise StringFormattingException(
|
||||
|
|
@ -122,7 +126,7 @@ class _Parser:
|
|||
"string, boolean, or variable without brackets"
|
||||
)
|
||||
|
||||
def _parse_function_args(self) -> List[ArgumentType]:
|
||||
def _parse_args(self, breaking_char: str = ")") -> List[ArgumentType]:
|
||||
"""
|
||||
Begin parsing function args after the first ``(``, i.e. ``function_name(``
|
||||
"""
|
||||
|
|
@ -131,7 +135,7 @@ class _Parser:
|
|||
|
||||
arguments: List[ArgumentType] = []
|
||||
while ch := self._read(increment_pos=False):
|
||||
if ch == ")":
|
||||
if ch == breaking_char:
|
||||
break
|
||||
|
||||
if ch.isspace():
|
||||
|
|
@ -162,7 +166,22 @@ class _Parser:
|
|||
if ch != "(":
|
||||
function_name += ch
|
||||
else:
|
||||
function_args = self._parse_function_args()
|
||||
function_args = self._parse_args()
|
||||
|
||||
raise StringFormattingException("Invalid function")
|
||||
|
||||
def _parse_array(self) -> Array:
|
||||
"""
|
||||
Begin parsing an array after reading the first ``[``
|
||||
"""
|
||||
function_args: List[String | Variable | "Function"] = []
|
||||
|
||||
while ch := self._read(increment_pos=False):
|
||||
if ch == "]":
|
||||
self._pos += 1
|
||||
return Array(value=function_args)
|
||||
else:
|
||||
function_args = self._parse_args(breaking_char="]")
|
||||
|
||||
raise StringFormattingException("Invalid function")
|
||||
|
||||
|
|
@ -193,6 +212,9 @@ class _Parser:
|
|||
if ch1 == "%":
|
||||
self._pos += 1
|
||||
self._ast.append(self._parse_function())
|
||||
elif ch1 == "[":
|
||||
self._pos += 1
|
||||
self._ast.append(self._parse_array())
|
||||
else:
|
||||
self._ast.append(self._parse_variable())
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from typing import final
|
|||
from typing import get_origin
|
||||
|
||||
from ytdl_sub.script.functions import Functions
|
||||
from ytdl_sub.script.types.resolvable import Array
|
||||
from ytdl_sub.script.types.resolvable import Boolean
|
||||
from ytdl_sub.script.types.resolvable import Float
|
||||
from ytdl_sub.script.types.resolvable import Integer
|
||||
|
|
@ -26,7 +27,7 @@ from ytdl_sub.script.types.resolvable import String
|
|||
from ytdl_sub.script.types.variable import Variable
|
||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||
|
||||
ArgumentType = Union[Integer, Float, String, Boolean, Variable, "Function"]
|
||||
ArgumentType = Union[Integer, Float, String, Boolean, Variable, "Function", Array]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
|||
|
|
@ -61,13 +61,8 @@ class String(ResolvableT[str]):
|
|||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class _List(Resolvable, Generic[T], ABC):
|
||||
value: List[T]
|
||||
class Array(Resolvable):
|
||||
value: List[Resolvable]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"[{', '.join([str(val) for val in self.value])}]"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StringList(_List[String]):
|
||||
pass
|
||||
return f"[{', '.join([val.value for val in self.value])}]"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ class TestParser:
|
|||
]
|
||||
)
|
||||
|
||||
def test_array(self):
|
||||
parsed = parse("hello {['elem1', 'elem2']}")
|
||||
parsed_empty = parse("hello {[]}")
|
||||
parsed_with_var = parse("hello {['elem1', variable_name]}")
|
||||
parsed_extend = parse("hi {%extend(['elem1', 'elem2'], ['elem3'], [], ['elem4'])}")
|
||||
assert False
|
||||
|
||||
def test_conditional(self):
|
||||
parsed = parse("hello {%if(True, 'hi', 3.4)}")
|
||||
assert parsed == SyntaxTree(
|
||||
|
|
|
|||
Loading…
Reference in a new issue