diff --git a/mesonpy/_substitutions.py b/mesonpy/_substitutions.py new file mode 100644 index 000000000..fceef23e7 --- /dev/null +++ b/mesonpy/_substitutions.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2023 The meson-python developers +# +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +import ast +import functools +import operator + +from typing import Any, Dict + + +class Interpreter: + + _operators = { + ast.Add: operator.add, + ast.Sub: operator.sub, + ast.Mult: operator.mul, + ast.Div: operator.truediv, + } + + def __init__(self, variables: Dict[str, Any]): + self._variables = variables + + def eval(self, string: str) -> Any: + expr = ast.parse(string, mode='eval') + return self._eval(expr) + + __getitem__ = eval + + @functools.singledispatchmethod + def _eval(self, node: ast.Node) -> Any: + print(node, type(node)) + raise ValueError + + @_eval.register + def _expression(self, node: ast.Expression) -> Any: + return self._eval(node.body) + + @_eval.register + def _binop(self, node: ast.BinOp) -> Any: + func = self._operators.get(type(node.op)) + if func is None: + raise ValueError(node.op) + return func(self._eval(node.left), self._eval(node.right)) + + @_eval.register + def _constant(self, node: ast.Constant) -> Any: + return node.value + + @_eval.register + def _variable(self, node: ast.Name) -> Any: + value = self._variables.get(node.id) + if value is None: + raise ValueError + return value + + +def interpolate(string, **variables): + return string % Interpreter(variables)