Explicit resolved ASTs

This commit is contained in:
Jesse Bannon 2025-11-27 11:26:41 -08:00
parent 91c45fe176
commit fb51295974
4 changed files with 26 additions and 1 deletions

View file

@ -158,10 +158,15 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
script = entry.script script = entry.script
unresolvable = entry.unresolvable unresolvable = entry.unresolvable
# Update the script internally so long as we are not supplying overrides
# that could alter the script with one-off state
update = function_overrides is None
try: try:
return script.resolve_once( return script.resolve_once(
dict({"tmp_var": formatter.format_string}, **(function_overrides or {})), dict({"tmp_var": formatter.format_string}, **(function_overrides or {})),
unresolvable=unresolvable, unresolvable=unresolvable,
update=update,
)["tmp_var"] )["tmp_var"]
except ScriptVariableNotResolved as exc: except ScriptVariableNotResolved as exc:
raise StringFormattingException( raise StringFormattingException(

View file

@ -10,6 +10,7 @@ from ytdl_sub.script.script_output import ScriptOutput
from ytdl_sub.script.types.resolvable import BuiltInFunctionType from ytdl_sub.script.types.resolvable import BuiltInFunctionType
from ytdl_sub.script.types.resolvable import Lambda from ytdl_sub.script.types.resolvable import Lambda
from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.resolvable import Resolvable
from ytdl_sub.script.types.syntax_tree import ResolvedSyntaxTree
from ytdl_sub.script.types.syntax_tree import SyntaxTree from ytdl_sub.script.types.syntax_tree import SyntaxTree
from ytdl_sub.script.types.variable import FunctionArgument from ytdl_sub.script.types.variable import FunctionArgument
from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable import Variable
@ -273,7 +274,7 @@ class Script:
def _update_internally(self, resolved_variables: Dict[str, Resolvable]) -> None: def _update_internally(self, resolved_variables: Dict[str, Resolvable]) -> None:
for variable_name, resolved in resolved_variables.items(): for variable_name, resolved in resolved_variables.items():
self._variables[variable_name] = SyntaxTree(ast=[resolved]) self._variables[variable_name] = ResolvedSyntaxTree(ast=[resolved])
def _recursive_get_unresolved_output_filter_variables( def _recursive_get_unresolved_output_filter_variables(
self, current_var: SyntaxTree, subset_to_resolve: Set[str], unresolvable: Set[Variable] self, current_var: SyntaxTree, subset_to_resolve: Set[str], unresolvable: Set[Variable]
@ -522,6 +523,7 @@ class Script:
variable_definitions: Dict[str, str], variable_definitions: Dict[str, str],
resolved: Optional[Dict[str, Resolvable]] = None, resolved: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None, unresolvable: Optional[Set[str]] = None,
update: bool = False,
) -> Dict[str, Resolvable]: ) -> Dict[str, Resolvable]:
""" """
Given a new set of variable definitions, resolve them using the Script, but do not Given a new set of variable definitions, resolve them using the Script, but do not
@ -536,6 +538,8 @@ class Script:
unresolvable unresolvable
Optional. Unresolvable variables that will be ignored in resolution, including all Optional. Unresolvable variables that will be ignored in resolution, including all
variables with a dependency to them. variables with a dependency to them.
update
Whether to update the script's state with resolved variables. Defaults to False.
Returns Returns
------- -------
@ -548,6 +552,7 @@ class Script:
pre_resolved=resolved, pre_resolved=resolved,
unresolvable=unresolvable, unresolvable=unresolvable,
output_filter=set(list(variable_definitions.keys())), output_filter=set(list(variable_definitions.keys())),
update=update,
).output ).output
finally: finally:
for name in variable_definitions.keys(): for name in variable_definitions.keys():

View file

@ -50,3 +50,17 @@ class SyntaxTree(VariableDependency):
if len(self.ast) == 1 and isinstance(self.ast[0], Resolvable): if len(self.ast) == 1 and isinstance(self.ast[0], Resolvable):
return self.ast[0] return self.ast[0]
return None return None
@dataclass(frozen=True)
class ResolvedSyntaxTree(SyntaxTree):
def resolve(
self,
resolved_variables: Dict[Variable, Resolvable],
custom_functions: Dict[str, VariableDependency],
) -> Resolvable:
return self.ast[0]
@property
def maybe_resolvable(self) -> Optional[Resolvable]:
return self.ast[0]

View file

@ -246,6 +246,7 @@ def _validate_formatter(
) )
}, },
unresolvable=unresolvable, unresolvable=unresolvable,
update=True,
) )
except RuntimeException as exc: except RuntimeException as exc:
if isinstance(exc, ScriptVariableNotResolved) and is_static_formatter: if isinstance(exc, ScriptVariableNotResolved) and is_static_formatter: