diff --git a/src/ytdl_sub/script/parser.py b/src/ytdl_sub/script/parser.py index 85dd77a7..3fc91e8b 100644 --- a/src/ytdl_sub/script/parser.py +++ b/src/ytdl_sub/script/parser.py @@ -27,6 +27,7 @@ from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments from ytdl_sub.script.utils.exceptions import InvalidSyntaxException from ytdl_sub.script.utils.exceptions import UserException +from ytdl_sub.script.utils.exceptions import VariableDoesNotExist from ytdl_sub.utils.exceptions import StringFormattingException from ytdl_sub.validators.string_formatter_validators import is_valid_source_variable_name @@ -163,6 +164,7 @@ class _Parser: def _parse_variable(self) -> Variable: var_name = "" + variable_start_pos = self._pos while ch := self._read(increment_pos=False): if ch.isspace() and not var_name: self._pos += 1 @@ -183,7 +185,13 @@ class _Parser: if not var_name: raise StringFormattingException("invalid var name") - assert is_valid_source_variable_name(var_name, raise_exception=False) + if not is_valid_source_variable_name(var_name, raise_exception=False): + raise UNREACHABLE + + if self._variable_names is not None and var_name not in self._variable_names: + self._set_highlight_position(variable_start_pos) + raise VariableDoesNotExist(f"Variable {var_name} does not exist.") + return Variable(var_name) def _parse_custom_function_argument(self) -> FunctionArgument: diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index 55c41454..8523cbd8 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -9,7 +9,6 @@ from ytdl_sub.script.types.syntax_tree import SyntaxTree from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.utils.exceptions import UNREACHABLE from ytdl_sub.script.utils.exceptions import CycleDetected -from ytdl_sub.script.utils.exceptions import VariableDoesNotExist # pylint: disable=missing-raises-doc @@ -41,9 +40,7 @@ class Script: ) -> None: for dep in variable_dependency.variables: if dep.name not in self._variables: - raise VariableDoesNotExist( - f"{variable_name} uses the variable {dep.name} which does not exist." - ) + continue # does not exist, will throw downstream in parser if variable_name in deps + [dep.name]: cycle_deps = [variable_name] + deps + [dep.name] @@ -72,7 +69,7 @@ class Script: ) -> None: for dep in custom_function_dependency.custom_functions: if dep.name not in self._functions: - continue # does not exist, will throw downstream + continue # does not exist, will throw downstream in parser if custom_function_name in deps + [dep.name]: cycle_deps = [custom_function_name] + deps + [dep.name] diff --git a/src/ytdl_sub/script/types/function.py b/src/ytdl_sub/script/types/function.py index a1427a75..73ce1ef8 100644 --- a/src/ytdl_sub/script/types/function.py +++ b/src/ytdl_sub/script/types/function.py @@ -27,7 +27,6 @@ from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable_dependency import VariableDependency from ytdl_sub.script.utils.exception_formatters import FunctionArgumentsExceptionFormatter from ytdl_sub.script.utils.exceptions import UNREACHABLE -from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist from ytdl_sub.script.utils.exceptions import FunctionRuntimeException from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError from ytdl_sub.script.utils.type_checking import FunctionInputSpec diff --git a/tests/unit/script/types/test_variable.py b/tests/unit/script/types/test_variable.py index 91f47f6c..79ad14c0 100644 --- a/tests/unit/script/types/test_variable.py +++ b/tests/unit/script/types/test_variable.py @@ -47,6 +47,6 @@ class TestVariable: def test_undefined_variable(self): with pytest.raises( VariableDoesNotExist, - match=re.escape("b uses the variable c which does not exist."), + match=re.escape("Variable c does not exist."), ): Script({"a": "a", "b": "{c}"}).resolve()