summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/ast/interpreter.py104
-rw-r--r--mesonbuild/ast/introspection.py40
-rw-r--r--mesonbuild/mintro.py6
-rw-r--r--mesonbuild/rewriter.py2
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)