diff options
| -rw-r--r-- | mesonbuild/ast/interpreter.py | 104 | ||||
| -rw-r--r-- | mesonbuild/ast/introspection.py | 40 | ||||
| -rw-r--r-- | mesonbuild/mintro.py | 6 | ||||
| -rw-r--r-- | mesonbuild/rewriter.py | 2 |
4 files changed, 31 insertions, 121 deletions
diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index e66decf60..0d53873ca 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -40,7 +40,6 @@ from ..mparser import ( ArrayNode, AssignmentNode, BaseNode, - ElementaryNode, EmptyNode, IdNode, MethodNode, @@ -76,9 +75,9 @@ def _symbol(val: str) -> SymbolNode: # `IntrospectionDependency` is to the `IntrospectionInterpreter` what `Dependency` is to the normal `Interpreter`. @dataclass class IntrospectionDependency(MesonInterpreterObject): - name: str - required: T.Union[bool] - version: T.List[str] + name: T.Union[str, UnknownValue] + required: T.Union[bool, UnknownValue] + version: T.Union[T.List[str], UnknownValue] has_fallback: bool conditional: bool node: FunctionNode @@ -612,96 +611,7 @@ class AstInterpreter(InterpreterBase): val = self.get_cur_value(var_name) self.dataflow_dag.add_edge(val, node) - def resolve_node(self, node: BaseNode, include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.Optional[T.Any]: - def quick_resolve(n: BaseNode, loop_detect: T.Optional[T.List[str]] = None) -> T.Any: - if loop_detect is None: - loop_detect = [] - if isinstance(n, IdNode): - assert isinstance(n.value, str) - if n.value in loop_detect or n.value not in self.cur_assignments: - return [] - return quick_resolve(self.get_cur_value(n.value), loop_detect = loop_detect + [n.value]) - elif isinstance(n, ElementaryNode): - return n.value - else: - return n - - if id_loop_detect is None: - id_loop_detect = [] - result = None - - if not isinstance(node, BaseNode): - return None - - assert node.ast_id - if node.ast_id in id_loop_detect: - return None # Loop detected - id_loop_detect += [node.ast_id] - - # Try to evaluate the value of the node - if isinstance(node, IdNode): - result = quick_resolve(node) - - elif isinstance(node, ElementaryNode): - result = node.value - - elif isinstance(node, NotNode): - result = self.resolve_node(node.value, include_unknown_args, id_loop_detect) - if isinstance(result, bool): - result = not result - - elif isinstance(node, ArrayNode): - result = node.args.arguments.copy() - - elif isinstance(node, ArgumentNode): - result = node.arguments.copy() - - elif isinstance(node, ArithmeticNode): - if node.operation != 'add': - return None # Only handle string and array concats - l = self.resolve_node(node.left, include_unknown_args, id_loop_detect) - r = self.resolve_node(node.right, include_unknown_args, id_loop_detect) - if isinstance(l, str) and isinstance(r, str): - result = l + r # String concatenation detected - else: - result = self.flatten_args(l, include_unknown_args, id_loop_detect) + self.flatten_args(r, include_unknown_args, id_loop_detect) - - elif isinstance(node, MethodNode): - src = quick_resolve(node.source_object) - margs = self.flatten_args(node.args.arguments, include_unknown_args, id_loop_detect) - mkwargs: T.Dict[str, TYPE_var] = {} - method_name = node.name.value - try: - if isinstance(src, str): - result = StringHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) - elif isinstance(src, bool): - result = BooleanHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) - elif isinstance(src, int): - result = IntegerHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) - elif isinstance(src, list): - result = ArrayHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) - elif isinstance(src, dict): - result = DictHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) - except mesonlib.MesonException: - return None - - # Ensure that the result is fully resolved (no more nodes) - if isinstance(result, BaseNode): - result = self.resolve_node(result, include_unknown_args, id_loop_detect) - elif isinstance(result, list): - new_res: T.List[TYPE_var] = [] - for i in result: - if isinstance(i, BaseNode): - resolved = self.resolve_node(i, include_unknown_args, id_loop_detect) - if resolved is not None: - new_res += self.flatten_args(resolved, include_unknown_args, id_loop_detect) - else: - new_res += [i] - result = new_res - - return result - - def flatten_args(self, args_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_var]: + def flatten_args(self, args_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], include_unknown_args: bool = False) -> T.List[TYPE_var]: # Make sure we are always dealing with lists if isinstance(args_raw, list): args = args_raw @@ -713,13 +623,15 @@ class AstInterpreter(InterpreterBase): # Resolve the contents of args for i in args: if isinstance(i, BaseNode): - resolved = self.resolve_node(i, include_unknown_args, id_loop_detect) + resolved = self.node_to_runtime_value(i) if resolved is not None: if not isinstance(resolved, list): resolved = [resolved] flattened_args += resolved - elif isinstance(i, (str, bool, int, float)) or include_unknown_args: + elif isinstance(i, (str, bool, int, float, UnknownValue)) or include_unknown_args: flattened_args += [i] + else: + raise NotImplementedError return flattened_args def evaluate_testcase(self, node: TestCaseClauseNode) -> Disabler | None: diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index c74a76835..7dc4281cf 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -198,18 +198,16 @@ class IntrospectionInterpreter(AstInterpreter): if not args: return name = args[0] - assert isinstance(name, str) + assert isinstance(name, (str, UnknownValue)) has_fallback = 'fallback' in kwargs required = kwargs.get('required', True) version = kwargs.get('version', []) - if not isinstance(version, list): - version = [version] - assert all(isinstance(el, str) for el in version) - version = T.cast(T.List[str], version) - if isinstance(required, ElementaryNode): - required = required.value - if not isinstance(required, bool): - required = False + if not isinstance(version, UnknownValue): + if not isinstance(version, list): + version = [version] + assert all(isinstance(el, str) for el in version) + version = T.cast(T.List[str], version) + assert isinstance(required, (bool, UnknownValue)) newdep = IntrospectionDependency( name=name, required=required, @@ -219,11 +217,11 @@ class IntrospectionInterpreter(AstInterpreter): node=node) self.dependencies += [newdep] - def build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs_raw: T.Dict[str, TYPE_var], targetclass: T.Type[BuildTarget]) -> IntrospectionBuildTarget: + def build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs_raw: T.Dict[str, TYPE_var], targetclass: T.Type[BuildTarget]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: assert isinstance(node, FunctionNode) args = self.flatten_args(args) if not args or not isinstance(args[0], str): - return None + return UnknownValue() name = args[0] srcqueue: T.List[BaseNode] = [node] extra_queue = [] @@ -303,7 +301,7 @@ class IntrospectionInterpreter(AstInterpreter): self.targets += [new_target] return new_target - def build_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def build_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: default_library = self.coredata.optstore.get_value_for(OptionKey('default_library')) if default_library == 'shared': return self.build_target(node, args, kwargs, SharedLibrary) @@ -313,28 +311,28 @@ class IntrospectionInterpreter(AstInterpreter): return self.build_target(node, args, kwargs, SharedLibrary) return None - def func_executable(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_executable(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, Executable) - def func_static_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_static_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, StaticLibrary) - def func_shared_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_shared_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, SharedLibrary) - def func_both_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_both_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, SharedLibrary) - def func_shared_module(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_shared_module(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, SharedModule) - def func_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_library(node, args, kwargs) - def func_jar(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_jar(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: return self.build_target(node, args, kwargs, Jar) - def func_build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> IntrospectionBuildTarget: + def func_build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: if 'target_type' not in kwargs: return None target_type = kwargs.pop('target_type') @@ -386,7 +384,7 @@ class IntrospectionInterpreter(AstInterpreter): flattened_kwargs = {} for key, val in kwargs.items(): if isinstance(val, BaseNode): - resolved = self.resolve_node(val, include_unknown_args) + resolved = self.node_to_runtime_value(val) if resolved is not None: flattened_kwargs[key] = resolved elif isinstance(val, (str, bool, int, float)) or include_unknown_args: diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 94ecaf9d0..09d373652 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -24,7 +24,7 @@ from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionL from .backend import backends from .dependencies import Dependency from . import environment -from .interpreterbase import ObjectHolder +from .interpreterbase import ObjectHolder, UnknownValue from .options import OptionKey from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode @@ -380,8 +380,8 @@ def list_compilers(coredata: cdata.CoreData) -> T.Dict[str, T.Dict[str, T.Dict[s } return compilers -def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool, T.List[str]]]]: - result: T.List[T.Dict[str, T.Union[str, bool, T.List[str]]]] = [] +def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool, T.List[str], UnknownValue]]]: + result: T.List[T.Dict[str, T.Union[str, bool, T.List[str], UnknownValue]]] = [] for i in intr.dependencies: result += [{ 'name': i.name, diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index c8f6c864a..2ddc52d2e 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -456,7 +456,7 @@ class Rewriter: node = self.interpreter.get_cur_value(dependency) if isinstance(node, FunctionNode): if node.func_name.value == 'dependency': - name = self.interpreter.flatten_args(node.args)[0] + name = self.interpreter.node_to_runtime_value(node.args.arguments[0]) assert isinstance(name, str) dep = check_list(name) |
