fix(tpv): 支持 PEP 701 同引号嵌套 f-string 并记录解析错误位置
- lexer.vp: _read_string 增加 f-string {} 深度跟踪,跳过表达式块内嵌套字符串字面量(含 {{/}} 转义、跨行报错)
- parser.vp: _parse_fstring 表达式扫描同步跳过块内嵌套字符串,三条 error_count 路径补 _record_parse_err(消除'第 0 行 0 列'不可读错误)
This commit is contained in:
1 parent
bc017d0a61
commit
90a74e4e2c
2 files changed
+64
No files matched your search
@@ -473,6 +473,8 @@ def _read_string(lx: Lexer | t.CPtr):
|
|||||||
|
|
||||||
# Read string content
|
# Read string content
|
||||||
content_buf_start: t.CSizeT = lx.pos
|
content_buf_start: t.CSizeT = lx.pos
|
||||||
|
# f-string {} 表达式块嵌套深度(PEP 701 同引号嵌套字符串支持用)
|
||||||
|
fstr_depth: t.CInt = 0
|
||||||
while lx.pos < lx.len:
|
while lx.pos < lx.len:
|
||||||
ch = lx.src[lx.pos]
|
ch = lx.src[lx.pos]
|
||||||
if is_triple:
|
if is_triple:
|
||||||
@@ -498,6 +500,50 @@ def _read_string(lx: Lexer | t.CPtr):
|
|||||||
lx.pos += 1
|
lx.pos += 1
|
||||||
lx.col += 1
|
lx.col += 1
|
||||||
else:
|
else:
|
||||||
|
if is_fstring:
|
||||||
|
# {{ 与 }} 是转义字面量,不参与深度计数
|
||||||
|
if ch == '{' and lx.pos + 1 < lx.len and lx.src[lx.pos + 1] == '{':
|
||||||
|
lx.pos += 2
|
||||||
|
lx.col += 2
|
||||||
|
continue
|
||||||
|
if ch == '}' and lx.pos + 1 < lx.len and lx.src[lx.pos + 1] == '}':
|
||||||
|
lx.pos += 2
|
||||||
|
lx.col += 2
|
||||||
|
continue
|
||||||
|
if ch == '{':
|
||||||
|
fstr_depth += 1
|
||||||
|
lx.pos += 1
|
||||||
|
lx.col += 1
|
||||||
|
continue
|
||||||
|
if ch == '}':
|
||||||
|
if fstr_depth > 0:
|
||||||
|
fstr_depth -= 1
|
||||||
|
lx.pos += 1
|
||||||
|
lx.col += 1
|
||||||
|
continue
|
||||||
|
if fstr_depth > 0 and (ch == '\'' or ch == '"'):
|
||||||
|
# {} 表达式块内允许嵌套字符串字面量(PEP 701 同引号嵌套):
|
||||||
|
# 跳过到匹配引号,块内引号不终止外层 f-string。
|
||||||
|
nq: t.CChar = ch
|
||||||
|
lx.pos += 1
|
||||||
|
lx.col += 1
|
||||||
|
while lx.pos < lx.len:
|
||||||
|
c2: t.CChar = lx.src[lx.pos]
|
||||||
|
if c2 == '\\':
|
||||||
|
lx.pos += 2
|
||||||
|
lx.col += 2
|
||||||
|
continue
|
||||||
|
if c2 == nq:
|
||||||
|
lx.pos += 1
|
||||||
|
lx.col += 1
|
||||||
|
break
|
||||||
|
if c2 == '\n':
|
||||||
|
# 单行字符串不能跨行
|
||||||
|
lx.error_count += 1
|
||||||
|
return
|
||||||
|
lx.pos += 1
|
||||||
|
lx.col += 1
|
||||||
|
continue
|
||||||
if ch == quote:
|
if ch == quote:
|
||||||
break
|
break
|
||||||
if ch == '\n':
|
if ch == '\n':
|
||||||
|
|||||||
@@ -1286,6 +1286,21 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
|
|||||||
fmt_pos: t.CSizeT = 0
|
fmt_pos: t.CSizeT = 0
|
||||||
while j < content_len and depth > 0:
|
while j < content_len and depth > 0:
|
||||||
c: t.CChar = content[j]
|
c: t.CChar = content[j]
|
||||||
|
if c == '\'' or c == '"':
|
||||||
|
# 跳过表达式块内的嵌套字符串字面量(PEP 701 同引号嵌套),
|
||||||
|
# 避免其内部字符干扰 {} 深度/转换/格式分隔符定位
|
||||||
|
nq: t.CChar = c
|
||||||
|
j += 1
|
||||||
|
while j < content_len:
|
||||||
|
c2: t.CChar = content[j]
|
||||||
|
if c2 == '\\':
|
||||||
|
j += 2
|
||||||
|
continue
|
||||||
|
if c2 == nq:
|
||||||
|
j += 1
|
||||||
|
break
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
if c == '{':
|
if c == '{':
|
||||||
depth += 1
|
depth += 1
|
||||||
elif c == '}':
|
elif c == '}':
|
||||||
@@ -1307,6 +1322,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
|
|||||||
fmt_pos = j
|
fmt_pos = j
|
||||||
j += 1
|
j += 1
|
||||||
if depth != 0:
|
if depth != 0:
|
||||||
|
_record_parse_err(ps)
|
||||||
ps.error_count += 1
|
ps.error_count += 1
|
||||||
break
|
break
|
||||||
# Extract expression text
|
# Extract expression text
|
||||||
@@ -1317,6 +1333,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
|
|||||||
expr_end = fmt_pos
|
expr_end = fmt_pos
|
||||||
expr_len: t.CSizeT = expr_end - i - 1
|
expr_len: t.CSizeT = expr_end - i - 1
|
||||||
if expr_len == 0:
|
if expr_len == 0:
|
||||||
|
_record_parse_err(ps)
|
||||||
ps.error_count += 1
|
ps.error_count += 1
|
||||||
i = j + 1
|
i = j + 1
|
||||||
continue
|
continue
|
||||||
@@ -1356,6 +1373,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
|
|||||||
lit_pos += 1
|
lit_pos += 1
|
||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
|
_record_parse_err(ps)
|
||||||
ps.error_count += 1
|
ps.error_count += 1
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in new issue
Block a user