diff options
| author | Charles Brunet <charles.brunet@optelgroup.com> | 2023-08-23 09:24:05 -0400 |
|---|---|---|
| committer | Charles Brunet <charles.brunet@optelgroup.com> | 2023-09-11 07:51:18 -0400 |
| commit | 35936283d24ed5a0aa76b184a7489d637d3e49c4 (patch) | |
| tree | e6a0d7e95eca06437c15ddb9f89cfaa99c5f43fb /mesonbuild/mparser.py | |
| parent | a730a2fe215ae45c928370b5e28d2a844c082f38 (diff) | |
| download | meson-35936283d24ed5a0aa76b184a7489d637d3e49c4.tar.gz | |
parser: preserve escape chars in strings
use separate Node for multiline strings
Diffstat (limited to 'mesonbuild/mparser.py')
| -rw-r--r-- | mesonbuild/mparser.py | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index f9b896759..614479466 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -193,23 +193,15 @@ class Lexer: elif tid == 'dblquote': raise ParseException('Double quotes are not supported. Use single quotes.', self.getline(line_start), lineno, col) elif tid in {'string', 'fstring'}: - # Handle here and not on the regexp to give a better error message. if match_text.find("\n") != -1: msg = ("Newline character in a string detected, use ''' (three single quotes) " "for multiline strings instead.\n" "This will become a hard error in a future Meson release.") mlog.warning(mlog.code_line(msg, self.getline(line_start), col), location=BaseNode(lineno, col, filename)) value = match_text[2 if tid == 'fstring' else 1:-1] - value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, value) elif tid in {'multiline_string', 'multiline_fstring'}: - # For multiline strings, parse out the value and pass - # through the normal string logic. - # For multiline format strings, we have to emit a - # different AST node so we can add a feature check, - # but otherwise, it follows the normal fstring logic. if tid == 'multiline_string': value = match_text[3:-3] - tid = 'string' else: value = match_text[4:-3] lines = match_text.split('\n') @@ -295,13 +287,30 @@ class NumberNode(ElementaryNode[int]): self.value = int(token.value, base=0) self.bytespan = token.bytespan -class StringNode(ElementaryNode[str]): +class BaseStringNode(ElementaryNode[str]): pass -class FormatStringNode(ElementaryNode[str]): +@dataclass(unsafe_hash=True) +class StringNode(BaseStringNode): + + raw_value: str = field(hash=False) + + 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 -class MultilineFormatStringNode(FormatStringNode): +@dataclass(unsafe_hash=True) +class MultilineStringNode(BaseStringNode): + + def __init__(self, token: Token[str]): + super().__init__(token) + self.value = token.value + +class MultilineFormatStringNode(MultilineStringNode): pass class ContinueNode(ElementaryNode): @@ -819,6 +828,8 @@ class Parser: return StringNode(t) if self.accept('fstring'): return FormatStringNode(t) + if self.accept('multiline_string'): + return MultilineStringNode(t) if self.accept('multiline_fstring'): return MultilineFormatStringNode(t) return EmptyNode(self.current.lineno, self.current.colno, self.current.filename) |
