Skip to content

Commit

Permalink
parser: revert to single StringNode type
Browse files Browse the repository at this point in the history
this will allow transforming string types in the formater
  • Loading branch information
bruchar1 committed Oct 2, 2023
1 parent 1229def commit 2a0b569
Show file tree
Hide file tree
Showing 13 changed files with 62 additions and 106 deletions.
6 changes: 3 additions & 3 deletions mesonbuild/ast/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ def func_subdir(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[st
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_nvar:
Expand All @@ -241,7 +241,7 @@ def evaluate_ternary(self, node: TernaryNode) -> None:

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)
Expand Down
10 changes: 5 additions & 5 deletions mesonbuild/ast/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ..compilers import detect_compiler_for
from ..interpreterbase import InvalidArguments
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:
Expand Down Expand Up @@ -128,7 +128,7 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[s

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():
Expand Down Expand Up @@ -174,7 +174,7 @@ def _add_languages(self, raw_langs: T.List[TYPE_nvar], required: bool, for_machi
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):
Expand Down Expand Up @@ -263,7 +263,7 @@ def traverse_nodes(inqueue: T.List[BaseNode]) -> T.List[BaseNode]:
# 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]
Expand Down Expand Up @@ -378,6 +378,6 @@ def extract_subproject_dir(self) -> T.Optional[str]:
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
46 changes: 12 additions & 34 deletions mesonbuild/ast/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,13 @@ def escape(self, val: str) -> str:

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:
Expand Down Expand Up @@ -270,22 +261,12 @@ def visit_NumberNode(self, node: mparser.NumberNode) -> None:

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:
Expand Down Expand Up @@ -354,9 +335,6 @@ def visit_NumberNode(self, node: mparser.NumberNode) -> None:
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)
Expand Down
9 changes: 0 additions & 9 deletions mesonbuild/ast/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,6 @@ def visit_NumberNode(self, node: mparser.NumberNode) -> None:
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)

Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ def _parse_section(self, s: str) -> T.Dict[str, T.Union[str, bool, int, T.List[s
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
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ def handle_meson_version_from_ast(self) -> None:
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]:
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/interpreterbase/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
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):
Expand All @@ -35,7 +35,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)
Expand Down
17 changes: 9 additions & 8 deletions mesonbuild/interpreterbase/interpreterbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,12 @@ def evaluate_statement(self, cur: mparser.BaseNode) -> T.Optional[InterpreterObj
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):
Expand Down Expand Up @@ -256,7 +257,7 @@ def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> InterpreterObject:
@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:
Expand Down Expand Up @@ -424,11 +425,11 @@ def evaluate_ternary(self, node: mparser.TernaryNode) -> T.Optional[InterpreterO
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:
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/mintro.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
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
Expand Down Expand Up @@ -194,7 +194,7 @@ def nodes_to_paths(node_list: T.List[BaseNode]) -> T.List[Path]:
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):
Expand Down
34 changes: 11 additions & 23 deletions mesonbuild/mparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,31 +304,25 @@ def __init__(self, token: Token[str]):
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
Expand Down Expand Up @@ -937,14 +931,8 @@ def e9(self) -> BaseNode:
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:
Expand Down
5 changes: 2 additions & 3 deletions mesonbuild/optinterpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@ def reduce_single(self, arg: T.Union[str, mparser.BaseNode]) -> 'TYPE_var':
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
Expand Down
Loading

0 comments on commit 2a0b569

Please sign in to comment.