diff options
-rw-r--r-- | mesonbuild/ast/interpreter.py | 6 | ||||
-rw-r--r-- | mesonbuild/ast/introspection.py | 10 | ||||
-rw-r--r-- | mesonbuild/ast/printer.py | 46 | ||||
-rw-r--r-- | mesonbuild/ast/visitor.py | 9 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 2 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/interpreterbase/helpers.py | 4 | ||||
-rw-r--r-- | mesonbuild/interpreterbase/interpreterbase.py | 17 | ||||
-rw-r--r-- | mesonbuild/mintro.py | 4 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 34 | ||||
-rw-r--r-- | mesonbuild/optinterpreter.py | 5 | ||||
-rw-r--r-- | mesonbuild/rewriter.py | 28 | ||||
-rw-r--r-- | unittests/allplatformstests.py | 1 |
13 files changed, 62 insertions, 106 deletions
diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index 0887fa2..53ddc10 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -207,8 +207,8 @@ class AstInterpreter(InterpreterBase): def method_call(self, node: BaseNode) -> bool: return True - def evaluate_fstring(self, node: mparser.FormatStringNode) -> str: - assert isinstance(node, mparser.FormatStringNode) + def evaluate_fstring(self, node: mparser.StringNode) -> str: + assert isinstance(node, mparser.StringNode) return node.value def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> TYPE_var: @@ -231,7 +231,7 @@ class AstInterpreter(InterpreterBase): def evaluate_dictstatement(self, node: mparser.DictNode) -> TYPE_nkwargs: def resolve_key(node: mparser.BaseNode) -> str: - if isinstance(node, mparser.BaseStringNode): + if isinstance(node, mparser.StringNode): return node.value return '__AST_UNKNOWN__' arguments, kwargs = self.reduce_arguments(node.args, key_resolver=resolve_key) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 17eb1d5..5bf7e05 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -16,7 +16,7 @@ from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..compilers import detect_compiler_for from ..interpreterbase import InvalidArguments, SubProject from ..mesonlib import MachineChoice, OptionKey -from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, BaseStringNode +from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode from .interpreter import AstInterpreter if T.TYPE_CHECKING: @@ -118,7 +118,7 @@ class IntrospectionInterpreter(AstInterpreter): if not self.is_subproject() and 'subproject_dir' in kwargs: spdirname = kwargs['subproject_dir'] - if isinstance(spdirname, BaseStringNode): + if isinstance(spdirname, StringNode): assert isinstance(spdirname.value, str) self.subproject_dir = spdirname.value if not self.is_subproject(): @@ -165,7 +165,7 @@ class IntrospectionInterpreter(AstInterpreter): for l in self.flatten_args(raw_langs): if isinstance(l, str): langs.append(l) - elif isinstance(l, BaseStringNode): + elif isinstance(l, StringNode): langs.append(l.value) for lang in sorted(langs, key=compilers.sort_clink): @@ -254,7 +254,7 @@ class IntrospectionInterpreter(AstInterpreter): # Pop the first element if the function is a build target function if isinstance(curr, FunctionNode) and curr.func_name.value in BUILD_TARGET_FUNCTIONS: arg_nodes.pop(0) - elementary_nodes = [x for x in arg_nodes if isinstance(x, (str, BaseStringNode))] + elementary_nodes = [x for x in arg_nodes if isinstance(x, (str, StringNode))] inqueue += [x for x in arg_nodes if isinstance(x, (FunctionNode, ArrayNode, IdNode, ArithmeticNode))] if elementary_nodes: res += [curr] @@ -369,6 +369,6 @@ class IntrospectionInterpreter(AstInterpreter): assert isinstance(kw, IdNode), 'for mypy' if kw.value == 'subproject_dir': # mypy does not understand "and isinstance" - if isinstance(val, BaseStringNode): + if isinstance(val, StringNode): return val.value return None diff --git a/mesonbuild/ast/printer.py b/mesonbuild/ast/printer.py index 004a649..4ce3b3f 100644 --- a/mesonbuild/ast/printer.py +++ b/mesonbuild/ast/printer.py @@ -61,22 +61,13 @@ class AstPrinter(AstVisitor): def visit_StringNode(self, node: mparser.StringNode) -> None: assert isinstance(node.value, str) - self.append("'" + self.escape(node.value) + "'", node) - node.lineno = self.curr_line or node.lineno - - def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: - assert isinstance(node.value, str) - self.append("f'" + self.escape(node.value) + "'", node) - node.lineno = self.curr_line or node.lineno - def visit_MultilineStringNode(self, node: mparser.MultilineStringNode) -> None: - assert isinstance(node.value, str) - self.append("'''" + node.value + "'''", node) - node.lineno = self.curr_line or node.lineno - - def visit_FormatMultilineStringNode(self, node: mparser.MultilineFormatStringNode) -> None: - assert isinstance(node.value, str) - self.append("f'''" + node.value + "'''", node) + if node.is_fstring: + self.append('f', node) + if node.is_multiline: + self.append("'''" + node.value + "'''", node) + else: + self.append("'" + self.escape(node.value) + "'", node) node.lineno = self.curr_line or node.lineno def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: @@ -258,22 +249,12 @@ class RawPrinter(FullAstVisitor): def visit_StringNode(self, node: mparser.StringNode) -> None: self.enter_node(node) - self.result += f"'{node.raw_value}'" - self.exit_node(node) - - def visit_MultilineStringNode(self, node: mparser.MultilineStringNode) -> None: - self.enter_node(node) - self.result += f"'''{node.value}'''" - self.exit_node(node) - - def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: - self.enter_node(node) - self.result += f"f'{node.raw_value}'" - self.exit_node(node) - - def visit_MultilineFormatStringNode(self, node: mparser.MultilineFormatStringNode) -> None: - self.enter_node(node) - self.result += f"f'''{node.value}'''" + if node.is_fstring: + self.result += 'f' + if node.is_multiline: + self.result += f"'''{node.value}'''" + else: + self.result += f"'{node.raw_value}'" self.exit_node(node) def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: @@ -342,9 +323,6 @@ class AstJSONPrinter(AstVisitor): def visit_StringNode(self, node: mparser.StringNode) -> None: self.gen_ElementaryNode(node) - def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: - self.gen_ElementaryNode(node) - def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: self._accept('args', node.args) self.setbase(node) diff --git a/mesonbuild/ast/visitor.py b/mesonbuild/ast/visitor.py index e75755a..57a60bb 100644 --- a/mesonbuild/ast/visitor.py +++ b/mesonbuild/ast/visitor.py @@ -30,15 +30,6 @@ class AstVisitor: def visit_StringNode(self, node: mparser.StringNode) -> None: self.visit_default_func(node) - def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: - self.visit_default_func(node) - - def visit_MultilineStringNode(self, node: mparser.MultilineStringNode) -> None: - self.visit_default_func(node) - - def visit_FormatMultilineStringNode(self, node: mparser.MultilineFormatStringNode) -> None: - self.visit_default_func(node) - def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: self.visit_default_func(node) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index b12ec82..eeeb8d1 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -1142,7 +1142,7 @@ class MachineFileParser(): return section def _evaluate_statement(self, node: mparser.BaseNode) -> T.Union[str, bool, int, T.List[str]]: - if isinstance(node, (mparser.BaseStringNode)): + if isinstance(node, (mparser.StringNode)): return node.value elif isinstance(node, mparser.BooleanNode): return node.value diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index f88f407..6e38c57 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -529,7 +529,7 @@ class Interpreter(InterpreterBase, HoldableObject): assert isinstance(kw, mparser.IdNode), 'for mypy' if kw.value == 'meson_version': # mypy does not understand "and isinstance" - if isinstance(val, mparser.BaseStringNode): + if isinstance(val, mparser.StringNode): self.handle_meson_version(val.value, val) def get_build_def_files(self) -> mesonlib.OrderedSet[str]: diff --git a/mesonbuild/interpreterbase/helpers.py b/mesonbuild/interpreterbase/helpers.py index 0ded85b..3942f2c 100644 --- a/mesonbuild/interpreterbase/helpers.py +++ b/mesonbuild/interpreterbase/helpers.py @@ -15,7 +15,7 @@ if T.TYPE_CHECKING: from .baseobjects import TYPE_var, TYPE_kwargs, SubProject def flatten(args: T.Union['TYPE_var', T.List['TYPE_var']]) -> T.List['TYPE_var']: - if isinstance(args, mparser.BaseStringNode): + if isinstance(args, mparser.StringNode): assert isinstance(args.value, str) return [args.value] if not isinstance(args, collections.abc.Sequence): @@ -25,7 +25,7 @@ def flatten(args: T.Union['TYPE_var', T.List['TYPE_var']]) -> T.List['TYPE_var'] if isinstance(a, list): rest = flatten(a) result = result + rest - elif isinstance(a, mparser.BaseStringNode): + elif isinstance(a, mparser.StringNode): result.append(a.value) else: result.append(a) diff --git a/mesonbuild/interpreterbase/interpreterbase.py b/mesonbuild/interpreterbase/interpreterbase.py index 47dd46f..ccc3349 100644 --- a/mesonbuild/interpreterbase/interpreterbase.py +++ b/mesonbuild/interpreterbase/interpreterbase.py @@ -198,11 +198,12 @@ class InterpreterBase: self.assignment(cur) elif isinstance(cur, mparser.MethodNode): return self.method_call(cur) - elif isinstance(cur, mparser.BaseStringNode): - if isinstance(cur, mparser.MultilineFormatStringNode): - return self.evaluate_multiline_fstring(cur) - elif isinstance(cur, mparser.FormatStringNode): - return self.evaluate_fstring(cur) + elif isinstance(cur, mparser.StringNode): + if cur.is_fstring: + if cur.is_multiline: + return self.evaluate_multiline_fstring(cur) + else: + return self.evaluate_fstring(cur) else: return self._holderify(cur.value) elif isinstance(cur, mparser.BooleanNode): @@ -256,7 +257,7 @@ class InterpreterBase: @FeatureNew('dict', '0.47.0') def evaluate_dictstatement(self, cur: mparser.DictNode) -> InterpreterObject: def resolve_key(key: mparser.BaseNode) -> str: - if not isinstance(key, mparser.BaseStringNode): + if not isinstance(key, mparser.StringNode): FeatureNew.single_use('Dictionary entry using non literal key', '0.53.0', self.subproject) key_holder = self.evaluate_statement(key) if key_holder is None: @@ -424,11 +425,11 @@ class InterpreterBase: return self.evaluate_statement(node.falseblock) @FeatureNew('multiline format strings', '0.63.0') - def evaluate_multiline_fstring(self, node: mparser.MultilineFormatStringNode) -> InterpreterObject: + def evaluate_multiline_fstring(self, node: mparser.StringNode) -> InterpreterObject: return self.evaluate_fstring(node) @FeatureNew('format strings', '0.58.0') - def evaluate_fstring(self, node: T.Union[mparser.FormatStringNode, mparser.MultilineFormatStringNode]) -> InterpreterObject: + def evaluate_fstring(self, node: mparser.StringNode) -> InterpreterObject: def replace(match: T.Match[str]) -> str: var = str(match.group(1)) try: diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 81b15d2..bdbb59e 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -26,7 +26,7 @@ from .dependencies import Dependency from . import environment from .interpreterbase import ObjectHolder from .mesonlib import OptionKey -from .mparser import FunctionNode, ArrayNode, ArgumentNode, BaseStringNode +from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode if T.TYPE_CHECKING: import argparse @@ -185,7 +185,7 @@ def list_targets_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[st elif isinstance(n, ArgumentNode): args = n.arguments for j in args: - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): assert isinstance(j.value, str) res += [Path(j.value)] elif isinstance(j, str): diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index c1bceb2..0e26b9e 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -298,31 +298,25 @@ class NumberNode(ElementaryNode[int]): self.value = int(token.value, base=0) self.bytespan = token.bytespan -class BaseStringNode(ElementaryNode[str]): - pass - @dataclass(unsafe_hash=True) -class StringNode(BaseStringNode): +class StringNode(ElementaryNode[str]): raw_value: str = field(hash=False) + is_multiline: bool + is_fstring: bool def __init__(self, token: Token[str], escape: bool = True): super().__init__(token) - self.value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, token.value) if escape else token.value - self.raw_value = token.value -class FormatStringNode(StringNode): - pass - -@dataclass(unsafe_hash=True) -class MultilineStringNode(BaseStringNode): + self.is_multiline = 'multiline' in token.tid + self.is_fstring = 'fstring' in token.tid + self.raw_value = token.value - def __init__(self, token: Token[str]): - super().__init__(token) - self.value = token.value + if escape and not self.is_multiline: + self.value = self.escape() -class MultilineFormatStringNode(MultilineStringNode): - pass + def escape(self) -> str: + return ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, self.raw_value) class ContinueNode(ElementaryNode): pass @@ -930,14 +924,8 @@ class Parser: return self.create_node(IdNode, t) if self.accept('number'): return self.create_node(NumberNode, t) - if self.accept('string'): + if self.accept_any(('string', 'fstring', 'multiline_string', 'multiline_fstring')): return self.create_node(StringNode, t) - if self.accept('fstring'): - return self.create_node(FormatStringNode, t) - if self.accept('multiline_string'): - return self.create_node(MultilineStringNode, t) - if self.accept('multiline_fstring'): - return self.create_node(MultilineFormatStringNode, t) return EmptyNode(self.current.lineno, self.current.colno, self.current.filename) def key_values(self) -> ArgumentNode: diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 9da355a..980dadd 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -105,15 +105,14 @@ class OptionInterpreter: return arg if isinstance(arg, mparser.ParenthesizedNode): return self.reduce_single(arg.inner) - elif isinstance(arg, (mparser.BaseStringNode, mparser.BooleanNode, - mparser.NumberNode)): + elif isinstance(arg, (mparser.StringNode, mparser.BooleanNode, mparser.NumberNode)): return arg.value elif isinstance(arg, mparser.ArrayNode): return [self.reduce_single(curarg) for curarg in arg.args.arguments] elif isinstance(arg, mparser.DictNode): d = {} for k, v in arg.args.kwargs.items(): - if not isinstance(k, mparser.BaseStringNode): + if not isinstance(k, mparser.StringNode): raise OptionException('Dictionary keys must be a string literal') d[k.value] = self.reduce_single(v) return d diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index fd5413a..0a40a71 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -13,7 +13,7 @@ from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionL from mesonbuild.mesonlib import MesonException, setup_vsenv from . import mlog, environment from functools import wraps -from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseStringNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, StringNode, SymbolNode +from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, StringNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, SymbolNode import json, os, re, sys import typing as T @@ -142,7 +142,7 @@ class MTypeStr(MTypeBase): def new_node(cls, value=None): if value is None: value = '' - return StringNode(Token('', '', 0, 0, 0, None, str(value))) + return StringNode(Token('string', '', 0, 0, 0, None, str(value))) @classmethod def supported_nodes(cls): @@ -259,17 +259,17 @@ class MTypeStrList(MTypeList): @classmethod def _new_element_node(cls, value): - return StringNode(Token('', '', 0, 0, 0, None, str(value))) + return StringNode(Token('string', '', 0, 0, 0, None, str(value))) @staticmethod def _check_is_equal(node, value) -> bool: - if isinstance(node, BaseStringNode): + if isinstance(node, StringNode): return node.value == value return False @staticmethod def _check_regex_matches(node, regex: str) -> bool: - if isinstance(node, BaseStringNode): + if isinstance(node, StringNode): return re.match(regex, node.value) is not None return False @@ -293,7 +293,7 @@ class MTypeIDList(MTypeList): @staticmethod def _check_regex_matches(node, regex: str) -> bool: - if isinstance(node, BaseStringNode): + if isinstance(node, StringNode): return re.match(regex, node.value) is not None return False @@ -657,7 +657,7 @@ class Rewriter: src_list = [] for i in target['sources']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): src_list += [j.value] # Generate the new String nodes @@ -691,7 +691,7 @@ class Rewriter: def find_node(src): for i in target['sources']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): if j.value == src: return i, j return None, None @@ -750,7 +750,7 @@ class Rewriter: extra_files_list = [] for i in target['extra_files']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): extra_files_list += [j.value] # Generate the new String nodes @@ -781,7 +781,7 @@ class Rewriter: def find_node(src): for i in target['extra_files']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): if j.value == src: return i, j return None, None @@ -850,12 +850,12 @@ class Rewriter: src_list = [] for i in target['sources']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): src_list += [j.value] extra_files_list = [] for i in target['extra_files']: for j in arg_list_from_node(i): - if isinstance(j, BaseStringNode): + if isinstance(j, StringNode): extra_files_list += [j.value] test_data = { 'name': target['name'], @@ -870,8 +870,8 @@ class Rewriter: alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)] path_sorter = lambda key: ([(key.count('/') <= idx, alphanum_key(x)) for idx, x in enumerate(key.split('/'))]) - unknown = [x for x in i.arguments if not isinstance(x, BaseStringNode)] - sources = [x for x in i.arguments if isinstance(x, BaseStringNode)] + unknown = [x for x in i.arguments if not isinstance(x, StringNode)] + sources = [x for x in i.arguments if isinstance(x, StringNode)] sources = sorted(sources, key=lambda x: path_sorter(x.value)) i.arguments = unknown + sources diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 0e56375..60a3a8a 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -3583,7 +3583,6 @@ class AllPlatformTests(BasePlatformTests): 'IdNode': [('value', None, str)], 'NumberNode': [('value', None, int)], 'StringNode': [('value', None, str)], - 'FormatStringNode': [('value', None, str)], 'ContinueNode': [], 'BreakNode': [], 'ArgumentNode': [('positional', accept_node_list), ('kwargs', accept_kwargs)], |