mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
Parse escape sequences instead of using replace
That way we can warn about invalid sequences. Also, the previous code had at least one subtle bug (`\\\\'`).
This commit is contained in:
parent
bc798c544c
commit
ea92838cf3
7 changed files with 76 additions and 21 deletions
|
@ -23,7 +23,7 @@ from dataclasses import dataclass
|
|||
from enum import Enum
|
||||
|
||||
from .gir import *
|
||||
from .utils import Colors
|
||||
from .utils import Colors, escape_quote
|
||||
from .xml_reader import Element, parse, parse_string
|
||||
|
||||
__all__ = ["decompile"]
|
||||
|
@ -253,15 +253,6 @@ def decompiler(tag, cdata=False):
|
|||
return decorator
|
||||
|
||||
|
||||
def escape_quote(string: str) -> str:
|
||||
return (
|
||||
string.replace("\\", "\\\\")
|
||||
.replace("'", "\\'")
|
||||
.replace('"', '\\"')
|
||||
.replace("\n", "\\n")
|
||||
)
|
||||
|
||||
|
||||
@decompiler("interface")
|
||||
def decompile_interface(ctx, gir):
|
||||
return gir
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import typing as T
|
||||
from enum import Enum
|
||||
|
||||
from . import utils
|
||||
from .ast_utils import AstNode
|
||||
from .errors import (
|
||||
CompileError,
|
||||
|
@ -573,14 +574,19 @@ class UseQuoted(ParseNode):
|
|||
if token.type != TokenType.QUOTED:
|
||||
return False
|
||||
|
||||
string = (
|
||||
str(token)[1:-1]
|
||||
.replace("\\n", "\n")
|
||||
.replace('\\"', '"')
|
||||
.replace("\\\\", "\\")
|
||||
.replace("\\'", "'")
|
||||
)
|
||||
ctx.set_group_val(self.key, string, token)
|
||||
unescaped = None
|
||||
|
||||
try:
|
||||
unescaped = utils.unescape_quote(str(token))
|
||||
except utils.UnescapeError as e:
|
||||
start = ctx.tokens[ctx.index - 1].start
|
||||
range = Range(start + e.start, start + e.end, ctx.text)
|
||||
ctx.errors.append(
|
||||
CompileError(f"Invalid escape sequence '{range.text}'", range)
|
||||
)
|
||||
|
||||
ctx.set_group_val(self.key, unescaped, token)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import typing as T
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
class Colors:
|
||||
|
@ -98,3 +99,54 @@ def idxs_to_range(start: int, end: int, text: str):
|
|||
"character": end_c,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class UnescapeError(Exception):
|
||||
start: int
|
||||
end: int
|
||||
|
||||
|
||||
def escape_quote(string: str) -> str:
|
||||
return (
|
||||
string.replace("\\", "\\\\")
|
||||
.replace("'", "\\'")
|
||||
.replace('"', '\\"')
|
||||
.replace("\n", "\\n")
|
||||
.replace("\t", "\\t")
|
||||
)
|
||||
|
||||
|
||||
def unescape_quote(string: str) -> str:
|
||||
string = string[1:-1]
|
||||
|
||||
REPLACEMENTS = {
|
||||
"\\": "\\",
|
||||
"n": "\n",
|
||||
"t": "\t",
|
||||
'"': '"',
|
||||
"'": "'",
|
||||
}
|
||||
|
||||
result = ""
|
||||
i = 0
|
||||
while i < len(string):
|
||||
c = string[i]
|
||||
if c == "\\":
|
||||
i += 1
|
||||
|
||||
if i >= len(string):
|
||||
from .errors import CompilerBugError
|
||||
|
||||
raise CompilerBugError()
|
||||
|
||||
if r := REPLACEMENTS.get(string[i]):
|
||||
result += r
|
||||
else:
|
||||
raise UnescapeError(i, i + 2)
|
||||
else:
|
||||
result += c
|
||||
|
||||
i += 1
|
||||
|
||||
return result
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue