Some simple information syncing

This commit is contained in:
2026-07-28 21:08:58 +08:00
parent 1837339f69
commit 3633be1995
65 changed files with 1132 additions and 368581 deletions

View File

@@ -11,7 +11,7 @@ from .tokens import (
from .base import (
AST, ASTKind, ASTCtx, OpKind, ASTFlag,
# 常量
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR,
# 辅助函数
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,

View File

@@ -148,6 +148,7 @@ CONST_FLOAT: t.CDefine = 2
CONST_STR: t.CDefine = 3
CONST_BOOL: t.CDefine = 4
CONST_NONE: t.CDefine = 5
CONST_CHAR: t.CDefine = 6
# 标志位
FLAG_IS_ASYNC: t.CDefine = 1

View File

@@ -6,7 +6,7 @@ from .base import (
AST, ASTKind, ASTCtx, OpKind,
_init_ast, _copy_str, _set_parent_list,
_emit, _emit_str, _emit_int, _dump_list, _dump_op_list, _op_name,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR
)
@@ -106,6 +106,11 @@ class Constant(AST):
else:
pos = _emit(buf, size, pos, "(null)")
pos = _emit(buf, size, pos, "'")
elif self.const_kind == CONST_CHAR:
# 单引号单字符 → 显示为字符 ASCII 值
pos = _emit(buf, size, pos, "char(")
pos = _emit_int(buf, size, pos, self.int_val)
pos = _emit(buf, size, pos, ")")
elif self.const_kind == CONST_BOOL:
if self.int_val != 0:
pos = _emit(buf, size, pos, "True")

View File

@@ -530,6 +530,8 @@ def _read_string(lx: Lexer | t.CPtr):
tok: Token | t.CPtr = new_token(lx.pool, TokenType.String, start_lineno, start_col)
if tok == None: return
content_len: t.CSizeT = content_end - content_buf_start
# esc_len: 转义后实际字节数(用于判断单字符)
esc_len: t.CSizeT = content_len
# 处理转义序列(非 raw 字符串)
if is_raw == 0 and content_len > 0:
@@ -572,15 +574,22 @@ def _read_string(lx: Lexer | t.CPtr):
rpos += 1
conv_buf[wpos] = '\0'
token_set_str_literal(lx.pool, tok, conv_buf)
esc_len = wpos
else:
token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len)
tok.end_lineno = lx.lineno
tok.end_col_offset = lx.col
# flags 字段复用bit0=raw, bit1=bytes, bit2=fstring, bit3=triple
# flags 字段复用bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=单字符候选
if is_raw: tok.kw_subtype = tok.kw_subtype | 1
if is_bytes: tok.kw_subtype = tok.kw_subtype | 2
if is_fstring: tok.kw_subtype = tok.kw_subtype | 4
if is_triple: tok.kw_subtype = tok.kw_subtype | 8
# bit4 (16) = 双引号0=单引号, 1=双引号)
if quote == '"': tok.kw_subtype = tok.kw_subtype | 16
# bit5 (32) = 单字符候选(非三引号、非 fstring、转义后正好 1 字节)
# 用于 CONST_CHAR 判定,避免 '\0' 等含 NUL 字节被 strlen 误判为空字符串
if is_triple == 0 and is_fstring == 0 and esc_len == 1:
tok.kw_subtype = tok.kw_subtype | 32
_emit(lx, tok)

View File

@@ -7,7 +7,7 @@ from .base import (
AST, ASTCtx, ASTKind, OpKind, ASTFlag,
_set_pos, _binop_from_op, _augop_from_op, _cmpop_from_op, _copy_str, _inherit_pos,
_init_ast,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC,
)
from .exprs import (
@@ -169,7 +169,30 @@ def _new_const_float(pool: memhub.MemManager | t.CPtr, val: t.CDouble,
def _new_const_str(pool: memhub.MemManager | t.CPtr, val: str,
lineno: t.CInt, col: t.CInt) -> AST | t.CPtr:
lineno: t.CInt, col: t.CInt,
is_dquote: t.CInt = 1,
is_triple: t.CInt = 0,
is_char: t.CInt = 0) -> AST | t.CPtr:
"""创建字符串/字符常量节点
is_dquote: 0=单引号, 非0=双引号(默认双引号)
is_triple: 非0=三引号字符串
is_char: 非0=单字符候选lexer 已确认转义后正好 1 字节, 含 '\\0'
语义区分:
- 'x' (单引号单字符, 非三引号) → CONST_CHAR (i8 值)
- "x" (双引号, 含\\0终止符) → CONST_STR (i8* 指针, i8 x 2)
- 'ab' (单引号多字符) → CONST_STR (i8* 指针)
- '''x''' / \"\"\"x\"\"\" (三引号) → CONST_STR (i8* 指针)
- '' / \"\" (空字符串) → CONST_STR (i8* 指针)
"""
# 单引号、非三引号、lexer 标记的单字符候选 → CONST_CHAR
# 用 is_char 标记而非 strlen(val),因为 '\0' 转义后是 NUL 字节strlen 会返回 0
if is_dquote == 0 and is_triple == 0 and is_char != 0:
# 单字符 → CONST_CHARint_val 存储字符 ASCII 值
# val[0] 即使是 NUL 也是合法值 0
ch_val: t.CInt64T = val[0]
return Constant(pool, CONST_CHAR, ch_val, 0.0, val, lineno, col)
# 其他情况 → CONST_STR
return Constant(pool, CONST_STR, 0, 0.0, val, lineno, col)
@@ -751,10 +774,13 @@ def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr:
if ttype == TokenType.String:
sval: str = _cur_str(ps)
is_fstr: t.CInt = ps.cur.kw_subtype & 4
is_triple: t.CInt = ps.cur.kw_subtype & 8
is_dquote: t.CInt = ps.cur.kw_subtype & 16
is_char: t.CInt = ps.cur.kw_subtype & 32
_advance(ps)
if is_fstr:
return _parse_fstring(ps, sval, lineno, col)
return _new_const_str(ps.pool, sval, lineno, col)
return _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char)
if _match_op(ps, TokOp.Ellipsis):
_advance(ps)
@@ -1551,12 +1577,14 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
level += 3
_advance(ps)
module_name: str = None
if _cur_type(ps) == TokenType.Name:
# 关键字(如 import的 token type 也是 Name必须通过 kw_subtype 排除,
# 否则 `from . import` 中的 `import` 会被误认为 module_name
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword:
module_name = _cur_str(ps)
_advance(ps)
while _match_op(ps, TokOp.Dot):
_advance(ps)
if _cur_type(ps) == TokenType.Name:
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword:
next_name: str = _cur_str(ps)
mlen: t.CInt = string.strlen(module_name)
nlen: t.CInt = string.strlen(next_name)
@@ -1571,6 +1599,7 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
ps.error_count += 1
return None
_advance(ps)
_skip_nl(ps)
# import *
if _match_op(ps, TokOp.Star):
_advance(ps)
@@ -2058,8 +2087,9 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
# 字符串字面量 pattern
if ttype == TokenType.String:
sval = _cur_str(ps)
is_dquote_m: t.CInt = ps.cur.kw_subtype & 16
_advance(ps)
val = _new_const_str(ps.pool, sval, lineno, col)
val = _new_const_str(ps.pool, sval, lineno, col, is_dquote_m)
node = MatchValue(ps.pool, val)
_set_pos(node, lineno, col, 0, 0)
return node