From e19e9ce6f196f7c127a2668b5df0ada1d50806df Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 1 Aug 2022 23:30:21 -0400 Subject: [PATCH] interpreter: add a special class to track the lifecycle of get_option() strings --- mesonbuild/interpreter/interpreter.py | 6 +++++ mesonbuild/interpreter/primitives/__init__.py | 3 ++- mesonbuild/interpreter/primitives/string.py | 27 ++++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 987388859..8caf010df 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -445,6 +445,7 @@ class Interpreter(InterpreterBase, HoldableObject): str: P_OBJ.StringHolder, P_OBJ.MesonVersionString: P_OBJ.MesonVersionStringHolder, P_OBJ.DependencyVariableString: P_OBJ.DependencyVariableStringHolder, + P_OBJ.OptionString: P_OBJ.OptionStringHolder, # Meson types mesonlib.File: OBJ.FileHolder, @@ -1094,6 +1095,8 @@ class Interpreter(InterpreterBase, HoldableObject): opt.name = optname return opt elif isinstance(opt, coredata.UserOption): + if isinstance(opt.value, str): + return P_OBJ.OptionString(opt.value, f'{{{optname}}}') return opt.value return opt @@ -2845,6 +2848,9 @@ class Interpreter(InterpreterBase, HoldableObject): ret = os.path.join(*parts).replace('\\', '/') if isinstance(parts[0], P_OBJ.DependencyVariableString) and '..' not in other: return P_OBJ.DependencyVariableString(ret) + elif isinstance(parts[0], P_OBJ.OptionString): + name = os.path.join(parts[0].optname, other) + return P_OBJ.OptionString(ret, name) else: return ret diff --git a/mesonbuild/interpreter/primitives/__init__.py b/mesonbuild/interpreter/primitives/__init__.py index 1874d0d81..5bbd959ea 100644 --- a/mesonbuild/interpreter/primitives/__init__.py +++ b/mesonbuild/interpreter/primitives/__init__.py @@ -22,5 +22,6 @@ from .range import RangeHolder from .string import ( StringHolder, MesonVersionString, MesonVersionStringHolder, - DependencyVariableString, DependencyVariableStringHolder + DependencyVariableString, DependencyVariableStringHolder, + OptionString, OptionStringHolder, ) diff --git a/mesonbuild/interpreter/primitives/string.py b/mesonbuild/interpreter/primitives/string.py index 9abca7525..0c635a20a 100644 --- a/mesonbuild/interpreter/primitives/string.py +++ b/mesonbuild/interpreter/primitives/string.py @@ -157,10 +157,14 @@ class StringHolder(ObjectHolder[str]): def version_compare_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: return version_compare(self.held_object, args[0]) + @staticmethod + def _op_div(this: str, other: str) -> str: + return os.path.join(this, other).replace('\\', '/') + @FeatureNew('/ with string arguments', '0.49.0') @typed_operator(MesonOperator.DIV, str) def op_div(self, other: str) -> str: - return os.path.join(self.held_object, other).replace('\\', '/') + return self._op_div(self.held_object, other) @typed_operator(MesonOperator.INDEX, int) def op_index(self, other: int) -> str: @@ -194,3 +198,24 @@ class DependencyVariableStringHolder(StringHolder): if '..' in other: return ret return DependencyVariableString(ret) + + +class OptionString(str): + optname: str + + def __new__(cls, value: str, name: str) -> 'OptionString': + obj = str.__new__(cls, value) + obj.optname = name + return obj + + def __getnewargs__(self) -> T.Tuple[str, str]: # type: ignore # because the entire point of this is to diverge + return (str(self), self.optname) + + +class OptionStringHolder(StringHolder): + held_object: OptionString + + def op_div(self, other: str) -> T.Union[str, OptionString]: + ret = super().op_div(other) + name = self._op_div(self.held_object.optname, other) + return OptionString(ret, name)