Add support for basic format strings

pull/8513/head
Laurin-Luis Lehning 4 years ago committed by Xavier Claessens
parent 442416db6f
commit 130adef778
  1. 14
      mesonbuild/interpreterbase.py
  2. 15
      mesonbuild/mparser.py
  3. 9
      test cases/common/238 fstrings/meson.build

@ -708,6 +708,8 @@ class InterpreterBase:
return self.evaluate_indexing(cur)
elif isinstance(cur, mparser.TernaryNode):
return self.evaluate_ternary(cur)
elif isinstance(cur, mparser.FormatStringNode):
return self.evaluate_fstring(cur)
elif isinstance(cur, mparser.ContinueNode):
raise ContinueRequest()
elif isinstance(cur, mparser.BreakNode):
@ -926,6 +928,18 @@ The result of this is undefined and will become a hard error in a future Meson r
else:
return self.evaluate_statement(node.falseblock)
def evaluate_fstring(self, node: mparser.FormatStringNode) -> TYPE_var:
assert(isinstance(node, mparser.FormatStringNode))
def replace(match: T.Match[str]) -> str:
var = str(match.group(1))
try:
return str(self.variables[var])
except KeyError:
raise mesonlib.MesonException(f'Identifier "{var}" does not name a variable.')
return re.sub(r'{([_a-zA-Z][_0-9a-zA-Z]*)}', replace, node.value)
def evaluate_foreach(self, node: mparser.ForeachClauseNode) -> None:
assert(isinstance(node, mparser.ForeachClauseNode))
items = self.evaluate_statement(node.items)

@ -114,6 +114,7 @@ class Lexer:
self.token_specification = [
# Need to be sorted longest to shortest.
('ignore', re.compile(r'[ \t]')),
('fstring', re.compile(r"f'([^'\\]|(\\.))*'")),
('id', re.compile('[_a-zA-Z][_0-9a-zA-Z]*')),
('number', re.compile(r'0[bB][01]+|0[oO][0-7]+|0[xX][0-9a-fA-F]+|0|[1-9]\d*')),
('eol_cont', re.compile(r'\\\n')),
@ -189,7 +190,7 @@ class Lexer:
curl_count -= 1
elif tid == 'dblquote':
raise ParseException('Double quotes are not supported. Use single quotes.', self.getline(line_start), lineno, col)
elif tid == 'string':
elif tid in {'string', 'fstring'}:
# Handle here and not on the regexp to give a better error message.
if match_text.find("\n") != -1:
mlog.warning(textwrap.dedent("""\
@ -200,7 +201,7 @@ class Lexer:
str(lineno),
str(col)
)
value = match_text[1:-1]
value = match_text[2 if tid == 'fstring' else 1:-1]
try:
value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, value)
except MesonUnicodeDecodeError as err:
@ -288,6 +289,14 @@ class StringNode(ElementaryNode[str]):
def __str__(self) -> str:
return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno)
class FormatStringNode(ElementaryNode[str]):
def __init__(self, token: Token[str]):
super().__init__(token)
assert isinstance(self.value, str)
def __str__(self) -> str:
return "Format string node: '{self.value}' ({self.lineno}, {self.colno})."
class ContinueNode(ElementaryNode):
pass
@ -671,6 +680,8 @@ class Parser:
return NumberNode(t)
if self.accept('string'):
return StringNode(t)
if self.accept('fstring'):
return FormatStringNode(t)
return EmptyNode(self.current.lineno, self.current.colno, self.current.filename)
def key_values(self) -> ArgumentNode:

@ -0,0 +1,9 @@
project('meson-test', 'c')
n = 10
m = 'bar'
s = f'test {n} string ({n}): {m}'
if s != 'test 10 string (10): bar'
error('Incorrect string formatting')
endif
Loading…
Cancel
Save