将 ast 英化

This commit is contained in:
TermiNexus committed 2026-08-07 18:49:53 +08:00
1 parent 752f3ddb70
commit c5570dc8b1
9 files changed
+424 -413

No files matched your search

+29 -21
View File
@@ -3,34 +3,34 @@ from stdint import *
import memhub
import string
# 导入子模块
# Import submodule
from .tokens import (
Token, TokenType, Keyword, TokOp, _init_tables,
)
# 公共部分:基类、枚举、常量、辅助函数、dump
# Common Section: Base Classes, Enums, Constants, Helper Functions, Dump
from .base import (
AST, ASTKind, ASTCtx, OpKind, ASTFlag,
# 常量
# Constants
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR,
# 辅助函数
# Helper Functions
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,
_binop_from_op, _augop_from_op, _cmpop_from_op,
_emit, _emit_str, _emit_int, _dump_list,
dump, _op_name,
)
# 语句节点
# Statement Nodes: Module, Expression, Interactive, FunctionType
from .stmts import (
# 模块层
# Module Layer
Module, Expression, Interactive, FunctionType,
# 语句
# Statement
FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign,
For, While, If, With, Raise, Try, Assert, Global, Nonlocal,
Pass, Break, Continue, Expr, Import, ImportFrom, Match,
)
# 表达式节点
# Expression Nodes: BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set
from .exprs import (
# 表达式
# Expression Layer
BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set,
ListComp, SetComp, DictComp, GeneratorExp,
Await, Yield, YieldFrom, FormattedValue, JoinedStr,
@@ -38,12 +38,12 @@ from .exprs import (
List, Tuple, Slice,
Call, Compare, OpNode,
)
# 辅助节点
# Auxiliary Nodes
from .astaux import (
ExceptHandler, Arguments, Arg, Keyword, Alias, WithItem,
Comprehension,
)
# 模式匹配
# Pattern Matching
from .match import (
MatchCase, MatchValue, MatchSingleton, MatchSequence,
MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr,
@@ -54,25 +54,25 @@ from .parser import Parser, _parser_init, parse_tokens, new_parser
from .parser import _parse_test
# ============================================================
# 全局内存池指针(遵循项目规则:声明 _mbuddy)
# 用户在 main 中初始化:ast._mbuddy = memhub.MemBuddy(arena, size)
# Global Memory Pool Pointer (follows project rules: declare _mbuddy)
# User initializes in main: ast._mbuddy = memhub.MemBuddy(arena, size)
# ============================================================
_mbuddy: memhub.MemBuddy | t.CPtr
# ============================================================
# 公共 API: parse
# Common API: parse
# ============================================================
def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
"""解析 Python 源代码,返回 AST Module 节点。
"""Parse Python source code, return the AST Module node.
参数:
src: NUL 结尾的源代码字符串
pool: memhub.MemManager 实例,用于分配 AST 节点
Parameters:
src: NUL source code string, terminated with NUL
pool: memhub.MemManager instance, to allocate AST nodes
返回:
AST Module 节点,失败返回 None
Returns:
AST Module node, or None
"""
if src is None or pool is None:
return None
@@ -89,7 +89,15 @@ def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
def parse_expression(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
"""解析单个表达式,返回 Expression 节点"""
"""Parse a single expression, return the Expression node.
Parameters:
src: NUL expression string, terminated with NUL
pool: memhub.MemManager instance, to allocate AST nodes
Returns:
Expression node, or None
"""
if src is None or pool is None:
return None
_init_tables(pool)
+7 -7
View File
@@ -10,7 +10,7 @@ from .base import (
# ============================================================
# ExceptHandler 节点
# ExceptHandler Node
# ============================================================
class ExceptHandler(AST):
@@ -53,7 +53,7 @@ class ExceptHandler(AST):
# ============================================================
# Arguments 节点
# Arguments Node
# ============================================================
class Arguments(AST):
@@ -119,7 +119,7 @@ class Arguments(AST):
# ============================================================
# Arg 节点
# Arg Node
# ============================================================
class Arg(AST):
@@ -160,7 +160,7 @@ class Arg(AST):
# ============================================================
# Keyword 节点
# Keyword Node
# ============================================================
class Keyword(AST):
@@ -201,7 +201,7 @@ class Keyword(AST):
# ============================================================
# Alias 节点
# Alias Node
# ============================================================
class Alias(AST):
@@ -239,7 +239,7 @@ class Alias(AST):
# ============================================================
# WithItem 节点
# WithItem Node
# ============================================================
class WithItem(AST):
@@ -283,7 +283,7 @@ class WithItem(AST):
# ============================================================
# Comprehension 节点
# Comprehension Node
# ============================================================
class Comprehension(AST):
+56 -57
View File
@@ -7,11 +7,11 @@ from .tokens import TokOp
# ============================================================
# ASTKind - 节点类型枚举(kind() 虚函数返回值)
# ASTKind - Node type enum (kind() virtual function return value)
# ============================================================
class ASTKind(t.CEnum):
# 核心 15 节点
# Core 15 nodes
Module: t.State
FunctionDef: t.State
ClassDef: t.State
@@ -27,11 +27,11 @@ class ASTKind(t.CEnum):
UnaryOp: t.State
Call: t.State
Compare: t.State
# 模块层
# Module Layer
Expression: t.State
Interactive: t.State
FunctionType: t.State
# 语句
# Statement
Delete: t.State
AugAssign: t.State
AnnAssign: t.State
@@ -47,7 +47,7 @@ class ASTKind(t.CEnum):
Import: t.State
ImportFrom: t.State
Match: t.State
# 表达式
# Expression Layer
BoolOp: t.State
Lambda: t.State
IfExp: t.State
@@ -69,7 +69,7 @@ class ASTKind(t.CEnum):
Tuple: t.State
Slice: t.State
NamedExpr: t.State
# 辅助节点
# Auxiliary Nodes
ExceptHandler: t.State
Arguments: t.State
Arg: t.State
@@ -78,7 +78,7 @@ class ASTKind(t.CEnum):
WithItem: t.State
Comprehension: t.State
OpNode: t.State
# 模式匹配
# Pattern Matching
MatchCase: t.State
MatchValue: t.State
MatchSingleton: t.State
@@ -91,7 +91,7 @@ class ASTKind(t.CEnum):
# ============================================================
# ASTCtx - 名称上下文(Load/Store/Del)
# ASTCtx - Name context (Load/Store/Del)
# ============================================================
class ASTCtx(t.CEnum):
@@ -101,11 +101,11 @@ class ASTCtx(t.CEnum):
# ============================================================
# OpKind - 运算符枚举(BinOp/UnaryOp/Compare 共用)
# OpKind - Operator enum (BinOp/UnaryOp/Compare)
# ============================================================
class OpKind(t.CEnum):
# 二元算术/位运算
# Binary arithmetic operators
Add: t.State
Sub: t.State
Mult: t.State
@@ -119,10 +119,10 @@ class OpKind(t.CEnum):
BitXor: t.State
BitAnd: t.State
FloorDiv: t.State
# 布尔运算
# Boolean operators
And: t.State
Or: t.State
# 比较运算
# Comparison operators
Eq: t.State
Ne: t.State
Lt: t.State
@@ -133,16 +133,16 @@ class OpKind(t.CEnum):
IsNot: t.State
In: t.State
NotIn: t.State
# 一元运算
# Unary operators
Not: t.State
UAdd: t.State
USub: t.State
Invert: t.State
# 空
# None
NoneOp: t.State
# Constant 子类型标识
# Constant subtype identifiers
CONST_INT: t.CDefine = 1
CONST_FLOAT: t.CDefine = 2
CONST_STR: t.CDefine = 3
@@ -150,14 +150,14 @@ CONST_BOOL: t.CDefine = 4
CONST_NONE: t.CDefine = 5
CONST_CHAR: t.CDefine = 6
# 标志位
# Node flags
FLAG_IS_ASYNC: t.CDefine = 1
FLAG_SIMPLE: t.CDefine = 2
FLAG_HAS_STAR: t.CDefine = 4
# ============================================================
# ASTFlag - 节点标志位枚举
# ASTFlag - Node flags enum
# ============================================================
class ASTFlag(t.CEnum):
@@ -167,11 +167,11 @@ class ASTFlag(t.CEnum):
# ============================================================
# 辅助函数
# Helper Functions
# ============================================================
def _copy_str(pool: memhub.MemManager | t.CPtr, src: str) -> str:
"""从 pool 分配并复制 C 字符串"""
"""Allocate and copy a C string from pool."""
if src is None: return None
slen: t.CSizeT = string.strlen(src)
buf: str = pool.alloc(slen + 1)
@@ -199,7 +199,7 @@ def _inherit_pos(node: AST | t.CPtr, ref: AST | t.CPtr):
def _init_ast(node: AST | t.CPtr, pool: memhub.MemManager | t.CPtr,
lineno: t.CInt, col: t.CInt):
"""初始化 AST 基类字段"""
"""Initialize AST base fields."""
node.parent = None
node.pool = pool
node.lineno = lineno
@@ -210,7 +210,7 @@ def _init_ast(node: AST | t.CPtr, pool: memhub.MemManager | t.CPtr,
def _set_parent_list(lst: list[AST | t.CPtr] | t.CPtr, parent: AST | t.CPtr):
"""为 list 中的每个子节点设置 parent 指针"""
"""Set list children parent pointers."""
if lst is None: return
n: t.CSizeT = lst.__len__()
i: t.CSizeT = 0
@@ -223,17 +223,16 @@ def _set_parent_list(lst: list[AST | t.CPtr] | t.CPtr, parent: AST | t.CPtr):
def _append_child(lst: list[AST | t.CPtr] | t.CPtr, node: AST | t.CPtr,
pool: memhub.MemManager | t.CPtr):
"""向 list 追加子节点(模块级函数,避免与 AST.append 方法名冲突)。
"""Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name).
在 AST.append 方法中调用此函数,绕过编译器把 list.append 误解析为
AST.append 虚函数调用的类型推断问题。"""
Call this function within the AST.append method to bypass the compiler mistaking list.append for a virtual function call to AST.append when doing type inference."""
if lst is None or node is None:
return
lst.append(node)
# ============================================================
# 运算符映射:TokOp -> OpKind
# Operator Mapping: TokOp -> OpKind
# ============================================================
def _binop_from_op(op_id: t.CInt) -> t.CInt:
@@ -281,12 +280,12 @@ def _cmpop_from_op(op_id: t.CInt) -> t.CInt:
# ============================================================
# dump 辅助函数
# dump Helper Functions
# ============================================================
def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""追加字面量到 buf+pos,返回新 pos"""
"""Append literal to buf+pos."""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
@@ -299,7 +298,7 @@ def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
def _emit_str(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""追加字符串值到 buf+pos(用 %s 格式)"""
"""Append a string value to buf pos (using %s format)"""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
@@ -312,7 +311,7 @@ def _emit_str(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
def _emit_int(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
val: t.CInt64T) -> t.CSizeT:
"""追加整数值到 buf+pos"""
"""Append an integer value to buf pos (using %lld format)."""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
@@ -324,7 +323,7 @@ def _emit_int(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
def _op_name(op: t.CInt) -> str:
"""返回 OpKind 的字符串名称"""
"""Return the string name of an OpKind."""
if op == OpKind.Add: return "Add"
if op == OpKind.Sub: return "Sub"
if op == OpKind.Mult: return "Mult"
@@ -359,7 +358,7 @@ def _op_name(op: t.CInt) -> str:
def _dump_list(lst: list[AST | t.CPtr] | t.CPtr, buf: t.CChar | t.CPtr,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""遍历 list[AST | CPtr] 容器,多态 dump 每个元素"""
"""Traverse a list[AST | CPtr] container, polymorphically dump each element."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
@@ -379,7 +378,7 @@ def _dump_list(lst: list[AST | t.CPtr] | t.CPtr, buf: t.CChar | t.CPtr,
def _dump_op_list(lst: t.CPtr, buf: t.CChar | t.CPtr,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""遍历 list[CInt] (OpKind 值),输出 op 名称列表"""
"""Traverse a list[CInt] (OpKind values), output a list of op names."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
@@ -398,23 +397,23 @@ def _dump_op_list(lst: t.CPtr, buf: t.CChar | t.CPtr,
# ============================================================
# AST - 多态基类
#
# @t.CVTable 启用 vtable,支持 kind()/type_name()/dump()/accept() 虚函数
# 子节点用 list[AST | CPtr] 容器存储(O(1) 随机访问,比链表高效)
# parent 字段维护父指针(用于向上遍历)
# AST - Polymorphic Base Class
# @t.CVTable enables vtable, supporting virtual functions like kind()/type_name()/dump()/accept()
# Child nodes are stored in a list[AST | CPtr] container (O(1) random access, more efficient than linked lists)
# The parent field maintains a pointer to the parent (used for upward traversal)
# ============================================================
@t.CVTable
class AST:
"""AST 节点基类。所有具体节点类继承此类。
"""AST node base class. All specific node classes inherit from this.
字段:
parent: 父节点指针(向上遍历)
pool: 分配器(用于子节点/字符串分配)
lineno/col_offset: 起始位置
end_lineno/end_col_offset: 结束位置
children: 子节点列表(body 语句块,通过 append 添加)
Fields:
parent: Pointer to the parent node (for upward traversal)
pool: Allocator (used for allocating child nodes/strings)
lineno/col_offset: Starting position
end_lineno/end_col_offset: Ending position
children: List of child nodes (body block, added via append)
"""
parent: AST | t.CPtr
pool: memhub.MemManager | t.CPtr
@@ -425,31 +424,31 @@ class AST:
children: list[AST | t.CPtr] | t.CPtr
def kind(self) -> t.CInt:
"""返回节点类型(ASTKind 值),子类覆盖"""
"""Returns the node type (ASTKind value), overridden by subclasses"""
return 0
def type_name(self) -> str:
"""返回节点类型名,子类覆盖"""
"""Return the node type name, subclasses override"""
return "AST"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
"""多态 dump:子类覆盖以自定义格式。返回写入后的 pos"""
"""Polymorphic dump: subclasses override to define custom format. Returns the written pos"""
return pos
def accept(self, visitor: t.CPtr):
"""访问者模式入口(待实现):ASTVisitor 在 __visitor.py 定义后,
子类覆盖此方法分派到 visitor.visit_X(self)。当前为空实现。"""
"""Visitor pattern entry point: subclasses override to dispatch to ASTVisitor in the visitor pattern.
Current implementation is empty. override this method to dispatch to visitor.visit_X(self)"""
pass
def append(self, node: AST | t.CPtr):
"""将 node 追加为子节点(添加到 children 列表),设置 parent 指针。
"""Append node to the children list.
用于 parser 构建语句块:module.append(stmt), if_node.append(stmt) 等。
首次调用时懒初始化 children 列表。
Used for parser to build statement blocks: module.append(stmt), if_node.append(stmt), etc.
The children list is lazily initialized on first call.
注意:list[AST|CPtr] 当前按值复制存储(编译器限制),所以必须先设置
node.parent 再 append,这样副本中的 parent 才是正确的。"""
Note: list[AST|CPtr] is currently stored by value (compiler limitation), so you must set
node.parent before appending, so the parent in the copy is correct."""
if self is None or node is None:
return
if self.children is None:
@@ -459,16 +458,16 @@ class AST:
# ============================================================
# 模块级 dump 函数(供 ast.dump(node, buf, size) 调用)
# Module dump function (for ast.dump(node, buf, size))
# ============================================================
def dump(node: AST | t.CPtr, buf: t.CChar | t.CPtr, size: t.CSizeT):
"""将 AST 节点序列化到 buf(容量 size)"""
"""Serialize AST node to buf (with capacity size)"""
if node is None or buf is None or size == 0:
return
buf[0] = '\0'
final_pos: t.CSizeT = node.dump(buf, size, 0)
# NUL 终止,防止 printf 越界
# NUL-terminate to prevent printf overflow
if final_pos < size:
buf[final_pos] = '\0'
else:
+29 -29
View File
@@ -11,7 +11,7 @@ from .base import (
# ============================================================
# Name 节点
# Name node
# ============================================================
class Name(AST):
@@ -54,7 +54,7 @@ class Name(AST):
# ============================================================
# Constant 节点(用 const_kind 标识子类型)
# Constant nodes (subtype marked by const_kind)
# ============================================================
class Constant(AST):
@@ -107,7 +107,7 @@ class Constant(AST):
pos = _emit(buf, size, pos, "(null)")
pos = _emit(buf, size, pos, "'")
elif self.const_kind == CONST_CHAR:
# 单引号单字符 → 显示为字符 ASCII 值
# Single character → display as character ASCII value
pos = _emit(buf, size, pos, "char(")
pos = _emit_int(buf, size, pos, self.int_val)
pos = _emit(buf, size, pos, ")")
@@ -123,7 +123,7 @@ class Constant(AST):
# ============================================================
# BinOp 节点
# BinOp Node
# ============================================================
class BinOp(AST):
@@ -171,7 +171,7 @@ class BinOp(AST):
# ============================================================
# UnaryOp 节点
# UnaryOp Node
# ============================================================
class UnaryOp(AST):
@@ -212,7 +212,7 @@ class UnaryOp(AST):
# ============================================================
# Compare 节点
# Compare Node
# ============================================================
class Compare(AST):
@@ -262,7 +262,7 @@ class Compare(AST):
# ============================================================
# Call 节点
# Call Node
# ============================================================
class Call(AST):
@@ -311,7 +311,7 @@ class Call(AST):
# ============================================================
# BoolOp 节点
# BoolOp Node
# ============================================================
class BoolOp(AST):
@@ -352,7 +352,7 @@ class BoolOp(AST):
# ============================================================
# Lambda 节点
# Lambda Node
# ============================================================
class Lambda(AST):
@@ -396,7 +396,7 @@ class Lambda(AST):
# ============================================================
# IfExp 节点
# IfExp Node
# ============================================================
class IfExp(AST):
@@ -449,7 +449,7 @@ class IfExp(AST):
# ============================================================
# Dict 节点
# Dict Node
# ============================================================
class Dict(AST):
@@ -491,7 +491,7 @@ class Dict(AST):
# ============================================================
# Set 节点
# Set Node
# ============================================================
class Set(AST):
@@ -526,7 +526,7 @@ class Set(AST):
# ============================================================
# ListComp 节点
# ListComp Node
# ============================================================
class ListComp(AST):
@@ -570,7 +570,7 @@ class ListComp(AST):
# ============================================================
# SetComp 节点
# SetComp Node
# ============================================================
class SetComp(AST):
@@ -614,7 +614,7 @@ class SetComp(AST):
# ============================================================
# DictComp 节点
# DictComp Node
# ============================================================
class DictComp(AST):
@@ -665,7 +665,7 @@ class DictComp(AST):
# ============================================================
# GeneratorExp 节点
# GeneratorExp Node
# ============================================================
class GeneratorExp(AST):
@@ -709,7 +709,7 @@ class GeneratorExp(AST):
# ============================================================
# Await 节点
# Await Node
# ============================================================
class Await(AST):
@@ -744,7 +744,7 @@ class Await(AST):
# ============================================================
# Yield 节点
# Yield Node
# ============================================================
class Yield(AST):
@@ -779,7 +779,7 @@ class Yield(AST):
# ============================================================
# YieldFrom 节点
# YieldFrom Node
# ============================================================
class YieldFrom(AST):
@@ -814,7 +814,7 @@ class YieldFrom(AST):
# ============================================================
# FormattedValue 节点
# FormattedValue Node
# ============================================================
class FormattedValue(AST):
@@ -864,7 +864,7 @@ class FormattedValue(AST):
# ============================================================
# JoinedStr 节点
# JoinedStr Node
# ============================================================
class JoinedStr(AST):
@@ -899,7 +899,7 @@ class JoinedStr(AST):
# ============================================================
# Attribute 节点
# Attribute Node
# ============================================================
class Attribute(AST):
@@ -944,7 +944,7 @@ class Attribute(AST):
# ============================================================
# Subscript 节点
# Subscript Node
# ============================================================
class Subscript(AST):
@@ -992,7 +992,7 @@ class Subscript(AST):
# ============================================================
# Starred 节点
# Starred Node
# ============================================================
class Starred(AST):
@@ -1033,7 +1033,7 @@ class Starred(AST):
# ============================================================
# List 节点
# List Node
# ============================================================
class List(AST):
@@ -1072,7 +1072,7 @@ class List(AST):
# ============================================================
# Tuple 节点
# Tuple Node
# ============================================================
class Tuple(AST):
@@ -1111,7 +1111,7 @@ class Tuple(AST):
# ============================================================
# Slice 节点
# Slice Node
# ============================================================
class Slice(AST):
@@ -1164,7 +1164,7 @@ class Slice(AST):
# ============================================================
# NamedExpr 节点
# NamedExpr Node
# ============================================================
class NamedExpr(AST):
@@ -1208,7 +1208,7 @@ class NamedExpr(AST):
# ============================================================
# OpNode 节点
# OpNode Node
# ============================================================
class OpNode(AST):
+91 -90
View File
@@ -8,27 +8,27 @@ from .tokens import (
)
# 缩进栈最大深度
# Maximum Indentation Stack Depth
LEXER_MAX_INDENT: t.CDefine = 256
# ============================================================
# Lexer 状态结构体
# Lexer State Structure
# ============================================================
class Lexer:
src: str # 源代码(NUL 结尾)
pos: t.CSizeT # 当前位置
len: t.CSizeT # 源代码长度
lineno: t.CInt # 当前行号(从 1 开始)
col: t.CInt # 当前列号(从 0 开始)
pool: memhub.MemManager | t.CPtr # 内存池
indent_stack: t.CInt | t.CPtr # 缩进栈(int 数组,从 pool 分配)
indent_top: t.CInt # 栈顶索引(-1 表示空栈)
paren_depth: t.CInt # 括号深度(>0 时不产生 TokenType.NewLine)
tokens_head: Token | t.CPtr # token 链表头
tokens_tail: Token | t.CPtr # token 链表尾
at_line_start: t.CInt # 1=行首(需处理缩进)
error_count: t.CInt # 错误计数
src: str # Source code (NUL-terminated)
pos: t.CSizeT # Current position
len: t.CSizeT # Source code length
lineno: t.CInt # Current line number (1-based)
col: t.CInt # Current column number (0-based)
pool: memhub.MemManager | t.CPtr # Memory pool
indent_stack: t.CInt | t.CPtr # Indent stack (int array, allocated from pool)
indent_top: t.CInt # Stack top (-1 for empty stack)
paren_depth: t.CInt # Paren depth (>0 for no TokenType.NewLine)
tokens_head: Token | t.CPtr # token list head
tokens_tail: Token | t.CPtr # token list tail
at_line_start: t.CInt # 1=line start (need indent)
error_count: t.CInt # Error count
def __new__(self, pool: memhub.MemManager | t.CPtr):
ptr: Lexer | t.CPtr = pool.alloc(Lexer.__sizeof__())
@@ -38,13 +38,13 @@ class Lexer:
def new_lexer(pool: memhub.MemManager | t.CPtr) -> Lexer | t.CPtr:
"""从 pool 分配并返回 Lexer(跨模块安全包装)"""
"""Allocate from the pool and return a Lexer (cross-module safe wrapper)"""
return Lexer(pool)
def _lexer_init(lx: Lexer | t.CPtr, src: str,
pool: memhub.MemManager | t.CPtr):
"""初始化 Lexer"""
"""Initialize Lexer"""
if lx == None: return
lx.src = src
lx.pos = 0
@@ -52,12 +52,12 @@ def _lexer_init(lx: Lexer | t.CPtr, src: str,
lx.lineno = 1
lx.col = 0
lx.pool = pool
# 分配缩进栈
# Allocate indentation stack
lx.indent_stack = pool.alloc(LEXER_MAX_INDENT * 8)
if lx.indent_stack != None:
string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8)
lx.indent_top = -1
# 栈底压入 0(基础缩进)
# Push 0 (base indent)
if lx.indent_stack != None:
lx.indent_stack[0] = 0
lx.indent_top = 0
@@ -70,11 +70,11 @@ def _lexer_init(lx: Lexer | t.CPtr, src: str,
# ============================================================
# 辅助函数
# Auxiliary Functions
# ============================================================
def _peek(lx: Lexer | t.CPtr, offset: t.CSizeT) -> t.CChar:
"""查看 pos+offset 处字符,越界返回 '\0'"""
"""Peek character at position pos+offset, return '\0' if out of bounds"""
p: t.CSizeT = lx.pos + offset
if p >= lx.len:
return '\0'
@@ -88,7 +88,7 @@ def _peek_cur(lx: Lexer | t.CPtr) -> t.CChar:
def _advance(lx: Lexer | t.CPtr) -> t.CChar:
"""前进一个字符,返回该字符"""
"""Advance one character, return the character"""
if lx.pos >= lx.len:
return '\0'
ch: t.CChar = lx.src[lx.pos]
@@ -136,7 +136,7 @@ def _is_space(ch: t.CChar) -> t.CInt:
def _emit(lx: Lexer | t.CPtr, tok: Token | t.CPtr):
"""将 token 追加到链表"""
"""Append token to token list"""
if tok == None: return
if lx.tokens_head == None:
lx.tokens_head = tok
@@ -156,25 +156,25 @@ def _make_op_token(lx: Lexer | t.CPtr, op_id: t.CInt, length: t.CInt,
# ============================================================
# 缩进处理
# Indent Handling
# ============================================================
def _handle_indent(lx: Lexer | t.CPtr):
"""处理行首缩进,生成 TokenType.Indent/TokenType.Dedent。
跳过空行和注释行(不产生缩进变化)。"""
# 先跳过空行和注释行
"""Handle line start indent, generate TokenType.Indent/TokenType.Dedent.
Skip empty lines and comment lines."""
# Skip empty lines and comment lines
while lx.pos < lx.len:
# 记住行首位置,用于非空行回退
# Save line start position for non-empty lines
line_start_pos: t.CSizeT = lx.pos
line_start_col: t.CInt = lx.col
# 跳过空白(不跨行)
# Skip whitespace, not across lines
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == ' ' or ch == '\t' or ch == '\f' or ch == '\v':
lx.pos += 1
lx.col += 1
elif ch == '\r':
# CRLF 行尾符的 \r,跳过(让 \n 触发空行处理)
# CRLF line end \r, skip \n to trigger empty line processing
lx.pos += 1
else:
break
@@ -182,13 +182,13 @@ def _handle_indent(lx: Lexer | t.CPtr):
break
ch = lx.src[lx.pos]
if ch == '\n':
# 空行,跳过
# Empty line, skip
lx.pos += 1
lx.lineno += 1
lx.col = 0
continue
if ch == '\r':
# CRLF 空行(\r 后跟 \n),跳过 \r
# CRLF line end \r, skip \n to trigger empty line processing
lx.pos += 1
if lx.pos < lx.len and lx.src[lx.pos] == '\n':
lx.pos += 1
@@ -196,21 +196,21 @@ def _handle_indent(lx: Lexer | t.CPtr):
lx.col = 0
continue
if ch == '#':
# 注释行,跳过到行尾
# Comment line, skip to end of line
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
lx.pos += 1
continue
# 非空行:回退到行首,让后续缩进计算能读到前导空格
# Non-empty line: backtrack to line start to allow indent calculation
lx.pos = line_start_pos
lx.col = line_start_col
break
if lx.pos >= lx.len:
# 文件末尾,不再处理缩进
# End of file, no indent to handle
lx.at_line_start = 0
return
# 计算当前行缩进
# Calculate current line indent
indent: t.CInt = 0
save_pos: t.CSizeT = lx.pos
save_col: t.CInt = lx.col
@@ -227,17 +227,17 @@ def _handle_indent(lx: Lexer | t.CPtr):
else:
break
# 如果行尾(空行),不处理
# If line end (empty line), skip indent calculation
if lx.pos < lx.len:
ch = lx.src[lx.pos]
if ch == '\n' or ch == '\r' or ch == '#':
# 空行或注释行,回退位置让主循环处理
# Empty line or comment line, backtrack position to allow loop to handle indent
lx.pos = save_pos
lx.col = save_col
lx.at_line_start = 0
return
# 与缩进栈比较
# Compare indent with top of indent stack
top_indent: t.CInt = lx.indent_stack[lx.indent_top]
if indent > top_indent:
# TokenType.Indent
@@ -257,7 +257,7 @@ def _handle_indent(lx: Lexer | t.CPtr):
# ============================================================
# 标识符/关键字
# Identifier/Keyword Handling
# ============================================================
def _read_name(lx: Lexer | t.CPtr):
@@ -277,7 +277,7 @@ def _read_name(lx: Lexer | t.CPtr):
token_set_str(lx.pool, tok, lx.src, start, length)
tok.end_lineno = lx.lineno
tok.end_col_offset = start_col + t.CInt(length)
# 查找关键字
# Look up keyword if any
kw_id: t.CInt = _kw_lookup(tok.str_val)
if kw_id:
tok.kw_subtype = kw_id
@@ -285,7 +285,7 @@ def _read_name(lx: Lexer | t.CPtr):
# ============================================================
# 数字
# Number Handling
# ============================================================
def _read_number(lx: Lexer | t.CPtr):
@@ -296,7 +296,7 @@ def _read_number(lx: Lexer | t.CPtr):
is_complex: t.CInt = 0
ch0: t.CChar = lx.src[lx.pos]
# 处理 0x/0o/0b 前缀
# Handle 0x/0o/0b prefix
if ch0 == '0' and lx.pos + 1 < lx.len:
ch1: t.CChar = lx.src[lx.pos + 1]
if ch1 == 'x' or ch1 == 'X':
@@ -339,7 +339,7 @@ def _read_number(lx: Lexer | t.CPtr):
_emit_number(lx, start, start_lineno, start_col, 0, 0, 0)
return
# 十进制整数/浮点
# Decimal integer/float
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_digit(ch) or ch == '_':
@@ -348,7 +348,7 @@ def _read_number(lx: Lexer | t.CPtr):
else:
break
# 小数部分
# Decimal part
if lx.pos < lx.len and lx.src[lx.pos] == '.':
is_float = 1
lx.pos += 1
@@ -361,7 +361,7 @@ def _read_number(lx: Lexer | t.CPtr):
else:
break
# 指数部分
# Exponent part
if lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == 'e' or ch == 'E':
@@ -381,7 +381,7 @@ def _read_number(lx: Lexer | t.CPtr):
else:
break
# 虚数后缀
# Complex suffix part
if lx.pos < lx.len and lx.src[lx.pos] == 'j':
is_complex = 1
is_float = 1
@@ -402,7 +402,7 @@ def _emit_number(lx: Lexer | t.CPtr, start: t.CSizeT,
tok.is_complex = is_complex
tok.end_lineno = lx.lineno
tok.end_col_offset = start_col + t.CInt(length)
# 解析数值
# Parse number
if is_float:
tok.float_val = string.atof(tok.str_val)
else:
@@ -411,18 +411,19 @@ def _emit_number(lx: Lexer | t.CPtr, start: t.CSizeT,
# ============================================================
# 字符串
# String Handling
# ============================================================
def _read_string(lx: Lexer | t.CPtr):
"""读取字符串字面量。
支持前缀: r, b, u, f, rb, br, rf, fr(大小写不敏感)
支持引号: ', ", ''', """
"""Read string literal.
Supports prefixes: r, b, u, f, rb, br, rf, fr (case insensitive)
Supports quotes: ', ", ''',
Later we need to support string prefixes like i16/i24"""
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
prefix_start: t.CSizeT = lx.pos
# 读取前缀(r/b/u/f)
# Read prefix (r/b/u/f)
is_raw: t.CInt = 0
is_bytes: t.CInt = 0
is_fstring: t.CInt = 0
@@ -450,13 +451,13 @@ def _read_string(lx: Lexer | t.CPtr):
lx.error_count += 1
return
# 确定引号
# Determine quote type
quote: t.CChar = lx.src[lx.pos]
if quote != '\'' and quote != '"':
lx.error_count += 1
return
# 检查三引号
# Check triple quote
is_triple: t.CInt = 0
if lx.pos + 2 < lx.len:
if lx.src[lx.pos] == quote and lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote:
@@ -470,7 +471,7 @@ def _read_string(lx: Lexer | t.CPtr):
lx.pos += 1
lx.col += 1
# 读取字符串内容
# Read string content
content_buf_start: t.CSizeT = lx.pos
while lx.pos < lx.len:
ch = lx.src[lx.pos]
@@ -500,7 +501,7 @@ def _read_string(lx: Lexer | t.CPtr):
if ch == quote:
break
if ch == '\n':
# 单引号字符串不能跨行(除非续行)
# Single quote string cannot span multiple lines (unless continued)
lx.error_count += 1
return
if ch == '\\' and not is_raw:
@@ -514,7 +515,7 @@ def _read_string(lx: Lexer | t.CPtr):
lx.col += 1
content_end: t.CSizeT = lx.pos
# 跳过结束引号
# Skip the closing quote
if is_triple:
if lx.pos + 2 < lx.len:
lx.pos += 3
@@ -526,16 +527,16 @@ def _read_string(lx: Lexer | t.CPtr):
lx.pos += 1
lx.col += 1
# 创建 token
# Create token
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: Actual bytes after escaping (used to check single character)
esc_len: t.CSizeT = content_len
# 处理转义序列(非 raw 字符串)
# Handle escape sequences (non-raw strings)
if is_raw == 0 and content_len > 0:
# 分配转换缓冲区(最大情况:每个字符都是普通字符,无需扩展)
# Allocate conversion buffer (max case: each char is plain, no extension)
conv_buf: str = lx.pool.alloc(content_len + 1)
if conv_buf == None:
token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len)
@@ -570,7 +571,7 @@ def _read_string(lx: Lexer | t.CPtr):
elif next_ch == '0':
conv_buf[wpos] = '\0'
else:
# 未知转义,保留原样(包括 \xNN 等以后再处理)
# Unknown escape sequence, keep original (includes \xNN)
conv_buf[wpos] = '\\'
wpos += 1
conv_buf[wpos] = next_ch
@@ -587,37 +588,37 @@ def _read_string(lx: Lexer | t.CPtr):
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, bit4=dquote, bit5=单字符候选
# flags field: bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=single char candidate
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=双引号)
# bit4 (16) = double quote=single quote
if quote == '"': tok.kw_subtype = tok.kw_subtype | 16
# bit5 (32) = 单字符候选(非三引号、非 fstring、转义后正好 1 字节)
# 用于 CONST_CHAR 判定,避免 '\0' 等含 NUL 字节被 strlen 误判为空字符串
# bit5 (32) = single-character candidate (not triple quotes, not f-string, exactly 1 byte after escaping)
# Used for CONST_CHAR checks to prevent '0' and other NUL bytes from being mistaken as empty strings by strlen
if is_triple == 0 and is_fstring == 0 and esc_len == 1:
tok.kw_subtype = tok.kw_subtype | 32
_emit(lx, tok)
# ============================================================
# 运算符
# Operator Matching
# ============================================================
def _read_operator(lx: Lexer | t.CPtr):
"""贪婪匹配运算符"""
"""Greedy match operator"""
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
remaining: t.CSizeT = lx.len - lx.pos
# 遍历运算符表,找最长匹配
# Traverse operator table, find longest match
best_entry: OpEntry | t.CPtr = None
best_len: t.CInt = 0
cur: OpEntry | t.CPtr = _op_head
while cur != None:
if cur.length <= t.CInt(remaining):
# 比较 cur.name 与 src[pos:pos+cur.length]
# Compare cur.name with src[pos:pos+cur.length]
match: t.CInt = 1
i: t.CSizeT = 0
while i < t.CSizeT(cur.length):
@@ -632,13 +633,13 @@ def _read_operator(lx: Lexer | t.CPtr):
cur = cur.next
if best_entry == None:
# 未知字符,报错并跳过
# Unknown character, report error and skip
lx.error_count += 1
lx.pos += 1
lx.col += 1
return
# 更新括号深度
# Update parenthesis depth
if best_entry.op_id == TokOp.LPar or best_entry.op_id == TokOp.Lsqb or best_entry.op_id == TokOp.LBrace:
lx.paren_depth += 1
elif best_entry.op_id == TokOp.RPar or best_entry.op_id == TokOp.Rsqb or best_entry.op_id == TokOp.RBrace:
@@ -655,14 +656,14 @@ def _read_operator(lx: Lexer | t.CPtr):
# ============================================================
# 主词法分析入口
# Main Lexical Analysis Entry Point
# ============================================================
def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
"""执行词法分析,返回 token 链表头"""
"""Execute tokenization, return token list head"""
if lx == None: return None
while lx.pos < lx.len:
# 行首缩进处理
# Handle line start indent
if lx.at_line_start and lx.paren_depth == 0:
_handle_indent(lx)
if lx.pos >= lx.len:
@@ -672,14 +673,14 @@ def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
if ch == '\0':
break
# 换行
# New line
if ch == '\n':
if lx.paren_depth > 0:
# 括号内,产生 TokenType.Nl
# # In bi brackets, generates TokenType.Nl
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Nl, lx.lineno, lx.col)
_emit(lx, tok)
else:
# 逻辑换行
# Logical new line
tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col)
_emit(lx, tok)
lx.at_line_start = 1
@@ -688,30 +689,30 @@ def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
lx.col = 0
continue
# 反斜线续行
# Backslash continuation line
if ch == '\\' and lx.pos + 1 < lx.len and lx.src[lx.pos + 1] == '\n':
lx.pos += 2
lx.lineno += 1
lx.col = 0
continue
# 空白
# Whitespace
if _is_space(ch):
lx.pos += 1
lx.col += 1
continue
# 注释
# Comment
if ch == '#':
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
lx.pos += 1
continue
# 字符串前缀(如 r"...")或字符串
# String prefixes (like r"...") or strings
if ch == '\'' or ch == '"':
_read_string(lx)
continue
# 字符串前缀字母后跟引号(必须在 _is_alpha 之前检测,否则 f/r/b/u 会被当作 TokenType.Name)
# A string prefix letter followed by a quote (must be checked before _is_alpha, otherwise f/r/b/u will be treated as TokenType.Name)
if (ch == 'r' or ch == 'R' or ch == 'b' or ch == 'B' or
ch == 'u' or ch == 'U' or ch == 'f' or ch == 'F'):
if lx.pos + 1 < lx.len:
@@ -719,7 +720,7 @@ def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
if ch1 == '\'' or ch1 == '"':
_read_string(lx)
continue
# 双前缀如 rb, br, rf, fr
# Double prefixes like rb, br, rf, fr
if lx.pos + 2 < lx.len:
ch2: t.CChar = lx.src[lx.pos + 2]
if ((ch1 == 'r' or ch1 == 'R' or ch1 == 'b' or ch1 == 'B' or
@@ -728,26 +729,26 @@ def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
_read_string(lx)
continue
# 标识符/关键字
# Identifier/keyword
if _is_alpha(ch):
_read_name(lx)
continue
# 数字
# Number
if _is_digit(ch):
_read_number(lx)
continue
# 运算符
# Operator
_read_operator(lx)
# 文件结尾:产生 TokenType.NewLine(如果有内容)
# End of file: generate TokenType.NewLine (if there's content)
if lx.tokens_tail != None:
if lx.tokens_tail.type != TokenType.NewLine and lx.tokens_tail.type != TokenType.Nl:
tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col)
_emit(lx, tok)
# 产生剩余 TokenType.Dedent
# Generate remaining remaining TokenType.Dedent
while lx.indent_top > 0:
lx.indent_top -= 1
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0)
+9 -9
View File
@@ -10,7 +10,7 @@ from .base import (
# ============================================================
# MatchCase 节点
# MatchCase 节点Node
# ============================================================
class MatchCase(AST):
@@ -52,7 +52,7 @@ class MatchCase(AST):
# ============================================================
# MatchValue 节点
# MatchValue Node
# ============================================================
class MatchValue(AST):
@@ -85,7 +85,7 @@ class MatchValue(AST):
# ============================================================
# MatchSingleton 节点
# MatchSingleton Node
# ============================================================
class MatchSingleton(AST):
@@ -118,7 +118,7 @@ class MatchSingleton(AST):
# ============================================================
# MatchSequence 节点
# MatchSequence Node
# ============================================================
class MatchSequence(AST):
@@ -153,7 +153,7 @@ class MatchSequence(AST):
# ============================================================
# MatchMapping 节点
# MatchMapping Node
# ============================================================
class MatchMapping(AST):
@@ -201,7 +201,7 @@ class MatchMapping(AST):
# ============================================================
# MatchClass 节点
# MatchClass Node
# ============================================================
class MatchClass(AST):
@@ -258,7 +258,7 @@ class MatchClass(AST):
# ============================================================
# MatchStar 节点
# MatchStar Node
# ============================================================
class MatchStar(AST):
@@ -290,7 +290,7 @@ class MatchStar(AST):
# ============================================================
# MatchAs 节点
# MatchAs Node
# ============================================================
class MatchAs(AST):
@@ -329,7 +329,7 @@ class MatchAs(AST):
# ============================================================
# MatchOr 节点
# MatchOr Node
# ============================================================
class MatchOr(AST):
+132 -129
View File
@@ -34,14 +34,14 @@ from .lexer import Lexer, _lexer_init, tokenize, new_lexer
# ============================================================
# Parser 状态
# Parser State
# ============================================================
class Parser:
tokens: Token | t.CPtr # token 链表头
cur: Token | t.CPtr # 当前 token
pool: memhub.MemManager | t.CPtr # 内存池
error_count: t.CInt # 错误计数
pending_decorators: list[AST | t.CPtr] | t.CPtr # 待处理的装饰器 list
tokens: Token | t.CPtr # token linked list head
cur: Token | t.CPtr # current token
pool: memhub.MemManager | t.CPtr # memory pool
error_count: t.CInt # error count
pending_decorators: list[AST | t.CPtr] | t.CPtr # pending decorators list
def __new__(self, pool: memhub.MemManager | t.CPtr):
ptr: Parser | t.CPtr = pool.alloc(Parser.__sizeof__())
@@ -51,7 +51,7 @@ class Parser:
def new_parser(pool: memhub.MemManager | t.CPtr) -> Parser | t.CPtr:
"""从 pool 分配并返回 Parser(跨模块安全包装)"""
"""Allocate from the pool and return the Parser (cross-module safe wrapper)"""
return Parser(pool)
@@ -66,11 +66,11 @@ def _parser_init(ps: Parser | t.CPtr, tokens: Token | t.CPtr,
# ============================================================
# Token 导航辅助
# Token Navigation Helpers
# ============================================================
def _advance(ps: Parser | t.CPtr):
"""前进到下一个 token"""
"""Advance to the next token"""
if ps.cur is None: return
if ps.cur.next is not None:
ps.cur = ps.cur.next
@@ -107,13 +107,13 @@ def _cur_col(ps: Parser | t.CPtr) -> t.CInt:
def _skip_nl(ps: Parser | t.CPtr):
"""跳过 TokenType.Nl token"""
"""Skip TokenType.Nl token"""
while ps.cur is not None and ps.cur.type == TokenType.Nl:
ps.cur = ps.cur.next
def _skip_nls_and_newlines(ps: Parser | t.CPtr):
"""跳过 TokenType.Nl 和 TokenType.NewLine(用于续行)"""
"""Skip TokenType.Nl and TokenType.NewLine (used for line continuation)"""
while ps.cur is not None:
if ps.cur.type == TokenType.Nl or ps.cur.type == TokenType.NewLine:
ps.cur = ps.cur.next
@@ -122,7 +122,7 @@ def _skip_nls_and_newlines(ps: Parser | t.CPtr):
def _expect_type(ps: Parser | t.CPtr, ttype: t.CInt) -> t.CInt:
"""期望当前 token 是指定类型,是则前进并返回 1,否则返回 0"""
"""Expect the current token to be of the specified type, advance and return 1, otherwise return 0"""
if _cur_type(ps) == ttype:
_advance(ps)
return 1
@@ -131,7 +131,7 @@ def _expect_type(ps: Parser | t.CPtr, ttype: t.CInt) -> t.CInt:
def _expect_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt:
"""期望当前是某个运算符"""
"""Expecting the current one to be some operator"""
if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id:
_advance(ps)
return 1
@@ -140,14 +140,14 @@ def _expect_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt:
def _match_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt:
"""检查但不消耗"""
"""Check but not consume the current token"""
if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id:
return 1
return 0
def _accept_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt:
"""如果匹配则消耗并返回 1"""
"""If match, consume and return 1"""
if _match_op(ps, op_id):
_advance(ps)
return 1
@@ -155,7 +155,7 @@ def _accept_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt:
# ============================================================
# 常量构造辅助(新 API:Constant 直接接受 lineno/col)
# Constant Construction Helper (New API: Constant directly accepts lineno/col)
# ============================================================
def _new_const_int(pool: memhub.MemManager | t.CPtr, val: t.CInt64T,
@@ -173,26 +173,26 @@ def _new_const_str(pool: memhub.MemManager | t.CPtr, val: str,
is_dquote: t.CInt = 1,
is_triple: t.CInt = 0,
is_char: t.CInt = 0) -> AST | t.CPtr:
"""创建字符串/字符常量节点
"""Create a string/character constant node
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* 指针)
is_dquote: 0 = single quote, non-0 = double quote (default double quote)
is_triple: non-0 = triple-quoted string
is_char: non-0 = single-character candidate (lexer has confirmed that after escaping it's exactly 1 byte, including '0')
Semantic distinctions:
- 'x' (single quote, single character, not triple-quoted) → CONST_CHAR (i8 value)
- "x" (double quote, includes 0 terminator) → CONST_STR (i8* pointer, i8 x 2)
- 'ab' (single quotes, multiple characters) → CONST_STR (i8* pointer)
- '''x''' / \"\"\"x\"\"\" (triple quotes) → CONST_STR (i8* pointer)
- '' / "" (empty string) → CONST_STR (i8* pointer)
"""
# 单引号、非三引号、lexer 标记的单字符候选 → CONST_CHAR
# 用 is_char 标记而非 strlen(val),因为 '\0' 转义后是 NUL 字节,strlen 会返回 0
# Single quotes, non-triple quotes, single-character candidates marked by lexer → CONST_CHAR
# Mark with is_char instead of strlen(val), because '0' becomes a NUL byte after escaping, strlen would return 0
if is_dquote == 0 and is_triple == 0 and is_char != 0:
# 单字符 → CONST_CHAR,int_val 存储字符 ASCII 值
# val[0] 即使是 NUL 也是合法值 0
# Single quote # Single character → CONST_CHAR, int_val stores the character's ASCII value
# val[0] is a legal value of 0 even if it's NUL
ch_val: t.CInt64T = val[0]
return Constant(pool, CONST_CHAR, ch_val, 0.0, val, lineno, col)
# 其他情况 → CONST_STR
# Other situations → CONST_STR
return Constant(pool, CONST_STR, 0, 0.0, val, lineno, col)
@@ -207,11 +207,11 @@ def _new_const_none(pool: memhub.MemManager | t.CPtr,
# ============================================================
# ctx 辅助(递归修正赋值目标的 ctx)
# ctx Helper (Recursive Fixing Store Context)
# ============================================================
def _set_ctx(node: AST | t.CPtr, ctx: t.CInt):
"""设置节点的 ctx 字段(按 kind 转型后赋值)"""
"""Set ctx field of node (based on kind conversion)"""
if node is None: return
k: t.CInt = node.kind()
if k == ASTKind.Name:
@@ -235,7 +235,7 @@ def _set_ctx(node: AST | t.CPtr, ctx: t.CInt):
def _fix_store_ctx(node: AST | t.CPtr):
"""递归修正赋值目标的 ctx 为 Store"""
"""Fix ctx of store targets to be Store"""
if node is None: return
_set_ctx(node, ASTCtx.Store)
k: t.CInt = node.kind()
@@ -260,7 +260,7 @@ def _fix_store_ctx(node: AST | t.CPtr):
# ============================================================
# 表达式解析
# Expression Parser
# ============================================================
def _parse_expr(ps: Parser | t.CPtr) -> AST | t.CPtr:
@@ -371,8 +371,8 @@ def _parse_not_test(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""comparison: bitor_expr (comp_op bitor_expr)*
单比较设计:a < b → Compare(left=a, op=Lt, right=b)
链式比较 a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c)])
Single comparison design: a < b → Compare(left=a, op=Lt, right=b)
Chained comparison a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c)])
"""
left: AST | t.CPtr = _parse_bitor(ps)
if left is None: return None
@@ -382,7 +382,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr:
return left
_advance_comp_op(ps)
right: AST | t.CPtr = _parse_bitor(ps)
# 单比较:构造 ops 和 comparators list
# Single comparison: construct ops and comparators list
ops: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8)
ops.append(op_id)
comparators: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -390,12 +390,12 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr:
first_cmp: AST | t.CPtr = Compare(ps.pool, left, ops, comparators)
_set_pos(first_cmp, left.lineno, left.col_offset, 0, 0)
# 检查链式比较
# Check chained comparison
next_op: t.CInt = _match_comp_op(ps)
if next_op == OpKind.NoneOp:
return first_cmp
# 链式:a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c), ...])
# Single comparison with chained conditions: a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c), ...])
values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
values.append(first_cmp)
cur_left: AST | t.CPtr = right
@@ -417,7 +417,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _match_comp_op(ps: Parser | t.CPtr) -> t.CInt:
"""检查当前是否是比较运算符,返回 OP_* 或 OpKind.NoneOp"""
"""Check if the current one is a comparison operator, return OP_* or OpKind.NoneOp"""
if _cur_type(ps) == TokenType.Op:
op_id: t.CInt = _cur_op(ps)
if op_id == TokOp.EqEq: return OpKind.Eq
@@ -439,7 +439,7 @@ def _match_comp_op(ps: Parser | t.CPtr) -> t.CInt:
def _advance_comp_op(ps: Parser | t.CPtr):
"""消耗比较运算符 token"""
"""Consume comparison operator token"""
if _cur_type(ps) == TokenType.Op:
_advance(ps)
return
@@ -595,7 +595,7 @@ def _parse_atom_expr(ps: Parser | t.CPtr) -> AST | t.CPtr:
return node
base: AST | t.CPtr = _parse_atom(ps)
if base is None: return None
# trailer 循环
# trailer loop
while True:
if _match_op(ps, TokOp.Dot):
_advance(ps)
@@ -623,11 +623,11 @@ def _parse_atom_expr(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_call(ps: Parser | t.CPtr, func: AST | t.CPtr) -> AST | t.CPtr:
"""解析函数调用 trailer。args 和 keywords 均为 list。"""
"""Parse function call trailer. Both args and keywords are lists."""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # (
_skip_nls_and_newlines(ps) # 跳过 ( 后的换行
_skip_nls_and_newlines(ps) # Skip the line break after '('
args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
keywords: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -668,11 +668,11 @@ def _parse_call(ps: Parser | t.CPtr, func: AST | t.CPtr) -> AST | t.CPtr:
else:
val = _parse_expr(ps)
args.append(val)
_skip_nls_and_newlines(ps) # 跳过参数后的换行
_skip_nls_and_newlines(ps) # Skip the line break after the parameter
if not _accept_op(ps, TokOp.Comma):
break
_skip_nls_and_newlines(ps) # 跳过逗号后的换行
_skip_nls_and_newlines(ps) # 跳过 ) 前的换行
_skip_nls_and_newlines(ps) # Skip the line break after the comma
_skip_nls_and_newlines(ps) # Skip the line break before ')'
_expect_op(ps, TokOp.RPar)
node: AST | t.CPtr = Call(ps.pool, func, args, keywords)
_set_pos(node, lineno, col, 0, 0)
@@ -680,7 +680,7 @@ def _parse_call(ps: Parser | t.CPtr, func: AST | t.CPtr) -> AST | t.CPtr:
def _parse_subscript(ps: Parser | t.CPtr, value: AST | t.CPtr) -> AST | t.CPtr:
"""解析下标 trailer"""
"""Parse subscript trailer."""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # [
@@ -696,19 +696,19 @@ def _parse_subscript(ps: Parser | t.CPtr, value: AST | t.CPtr) -> AST | t.CPtr:
def _parse_slice(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""解析 slice:[expr] ':' [expr] [':' [expr]] | expr | expr, expr, ..."""
"""Parse slice: [expr] ':' [expr] [':' [expr]] | expr | expr, expr, ..."""
lower: AST | t.CPtr = None
if not _match_op(ps, TokOp.Colon):
lower = _parse_expr(ps)
# 检查是否有逗号(元组语法: a[x, y, ...])
# Check if there’s a comma (tuple syntax: a[x, y, ...])
if _match_op(ps, TokOp.Comma):
elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
if lower is not None:
elts.append(lower)
while _accept_op(ps, TokOp.Comma):
if _match_op(ps, TokOp.Rsqb):
break # 尾随逗号
break # Trailing comma
elem: AST | t.CPtr = _parse_expr(ps)
if elem is not None:
elts.append(elem)
@@ -742,7 +742,7 @@ def _parse_slice(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""atom: 最小表达式单元"""
"""atom: the smallest unit of expression"""
ttype: t.CInt = _cur_type(ps)
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
@@ -798,14 +798,14 @@ def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""括号表达式: () | (expr) | (expr,) | (expr, ...) | (yield)"""
"""Parenthesis expressions: () | (expr) | (expr,) | (expr, ...) | (yield)"""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # (
_skip_nl(ps) # 跳过 ( 后的换行(多行元组)
_skip_nl(ps) # Skip the line break after '(' (multi-line tuple)
if _match_op(ps, TokOp.RPar):
_advance(ps)
# 空元组
# Empty tuple
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = Tuple(ps.pool, empty, ASTCtx.Load)
_set_pos(node, lineno, col, 0, 0)
@@ -817,7 +817,7 @@ def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr:
return y
first: AST | t.CPtr = _parse_expr(ps)
if _match_op(ps, TokOp.Comma):
# 元组
# Tuple
elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
elts.append(first)
while _accept_op(ps, TokOp.Comma):
@@ -831,18 +831,18 @@ def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr:
_set_pos(node, lineno, col, 0, 0)
return node
_expect_op(ps, TokOp.RPar)
# 检查推导式
# Check for generator expression
if _cur_kw(ps) == Keyword.For:
return _parse_comprehension(ps, first, ASTKind.GeneratorExp, lineno, col)
return first
def _parse_list(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""列表: [] | [expr_list] | [expr_list comp_for]"""
"""List expressions: [] | [expr_list] | [expr_list comp_for]"""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # [
_skip_nl(ps) # 跳过 [ 后的换行(多行列表)
_skip_nl(ps) # Skip the line break after '[' (multi-line list)
if _match_op(ps, TokOp.Rsqb):
_advance(ps)
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -869,11 +869,11 @@ def _parse_list(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""花括号: {} | {set_items} | {dict_items} | {comp_for}"""
"""Brace expressions: {} | {set_items} | {dict_items} | {comp_for}"""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # {
_skip_nl(ps)
_skip_nl(ps) # Skip the line break after '{' (multi-line dict)
if _match_op(ps, TokOp.RBrace):
_advance(ps)
empty_k: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -929,11 +929,11 @@ def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr:
# ============================================================
# f-string 解析
# f-string parsing
# ============================================================
def _parse_sub_expr(ps: Parser | t.CPtr, src: str) -> AST | t.CPtr:
"""创建子 lexer + parser 解析表达式(用于 f-string 内的 {expr})"""
"""Create a sub-lexer and parser to parse expressions (used for {expr} inside f-strings)"""
pool: memhub.MemManager | t.CPtr = ps.pool
lx: Lexer | t.CPtr = new_lexer(pool)
if lx is None: return None
@@ -948,12 +948,12 @@ def _parse_sub_expr(ps: Parser | t.CPtr, src: str) -> AST | t.CPtr:
def _parse_fstring(ps: Parser | t.CPtr, content: str,
lineno: t.CInt, col: t.CInt) -> AST | t.CPtr:
"""解析 f-string 内容,构建 JoinedStr 或 FormattedValue。"""
"""Parse f-string content, building JoinedStr or FormattedValue nodes"""
pool: memhub.MemManager | t.CPtr = ps.pool
values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8)
i: t.CSizeT = 0
content_len: t.CSizeT = string.strlen(content)
# 字面量文本缓冲区
# Literal text buffer for f-string content
lit_buf: str = pool.alloc(content_len + 1)
if lit_buf is None: return None
lit_pos: t.CSizeT = 0
@@ -961,13 +961,13 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
while i < content_len:
ch: t.CChar = content[i]
if ch == '{':
# {{ → 字面量 {
# {{ → Literal {
if i + 1 < content_len and content[i + 1] == '{':
lit_buf[lit_pos] = '{'
lit_pos += 1
i += 2
continue
# 刷新字面量缓冲区
# Refresh literal buffer
if lit_pos > 0:
lit_buf[lit_pos] = '\0'
lit_node: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col)
@@ -975,7 +975,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
lit_buf = pool.alloc(content_len + 1)
if lit_buf is None: break
lit_pos = 0
# 查找匹配的 },同时跟踪嵌套 {} 和字符串字面量
# Find matching closing '}' while tracking nested '{}' and string literals inside the f-string
j: t.CSizeT = i + 1
depth: t.CInt = 1
conv_pos: t.CSizeT = 0
@@ -1005,7 +1005,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
if depth != 0:
ps.error_count += 1
break
# 提取表达式文本
# Extract expression text
expr_end: t.CSizeT = j
if conv_pos > 0:
expr_end = conv_pos
@@ -1020,9 +1020,9 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
if expr_buf is None: break
string.memcpy(expr_buf, content + i + 1, expr_len)
expr_buf[expr_len] = '\0'
# 解析表达式
# Parse expression text
expr_node: AST | t.CPtr = _parse_sub_expr(ps, expr_buf)
# 转换符
# Conversion specifier
conversion: t.CInt = -1
if conv_pos > 0:
conv_char: t.CChar = content[conv_pos + 1]
@@ -1032,7 +1032,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
conversion = 114
elif conv_char == 'a':
conversion = 97
# 格式说明符
# Format specifier
format_spec: AST | t.CPtr = None
if fmt_pos > 0:
spec_len: t.CSizeT = j - fmt_pos - 1
@@ -1059,16 +1059,16 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
lit_pos += 1
i += 1
# 刷新剩余字面量
# Refresh remaining literal buffer
if lit_pos > 0:
lit_buf[lit_pos] = '\0'
lit_node2: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col)
values.append(lit_node2)
# 如果没有内容,返回空字符串
# If no content, return empty string
if values.__len__() == 0:
return _new_const_str(pool, "", lineno, col)
# 如果只有一个 FormattedValue 且无字面量,返回 FormattedValue
# If only one FormattedValue and no literal, return FormattedValue
if values.__len__() == 1:
first: AST | t.CPtr = values.get(0)
if first.kind() == ASTKind.FormattedValue:
@@ -1080,7 +1080,7 @@ def _parse_fstring(ps: Parser | t.CPtr, content: str,
def _parse_comprehension(ps: Parser | t.CPtr, elt: AST | t.CPtr,
vtype: t.CInt, lineno: t.CInt, col: t.CInt) -> AST | t.CPtr:
"""通用推导式:elt comp_for"""
"""General comprehension: elt comp_for"""
gens: list[AST | t.CPtr] | t.CPtr = _parse_comp_for(ps)
node: AST | t.CPtr = None
if vtype == ASTKind.ListComp:
@@ -1095,7 +1095,7 @@ def _parse_comprehension(ps: Parser | t.CPtr, elt: AST | t.CPtr,
def _parse_comp_for(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
"""comp_for: ['async'] 'for' exprlist 'in' or_test [comp_if] (comp_for)*
返回 generators list。"""
Returns generators list。"""
gens: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
while True:
is_async: t.CInt = 0
@@ -1113,7 +1113,7 @@ def _parse_comp_for(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
break
_advance(ps)
iter_: AST | t.CPtr = _parse_or_test(ps)
# 收集 ifs 到 list
# Collect ifs to list
ifs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
while _cur_kw(ps) == Keyword.If:
_advance(ps)
@@ -1126,7 +1126,7 @@ def _parse_comp_for(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
def _parse_target_list(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""解析赋值目标列表(用逗号分隔)"""
"""Parse assignment target list (comma-separated)"""
first: AST | t.CPtr = _parse_target(ps)
if _match_op(ps, TokOp.Comma):
elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -1143,7 +1143,7 @@ def _parse_target_list(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_target(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""解析单个赋值目标"""
"""Parse assignment target"""
if _match_op(ps, TokOp.Star):
_advance(ps)
inner: AST | t.CPtr = _parse_atom_expr(ps)
@@ -1173,7 +1173,7 @@ def _parse_target(ps: Parser | t.CPtr) -> AST | t.CPtr:
node = List(ps.pool, elts, ASTCtx.Store)
_set_pos(node, first.lineno, first.col_offset, 0, 0)
return node
# 普通 atom_expr,但 ctx=Store
# Normal atom_expr, ctx=Store
node = _parse_atom_expr(ps)
if node is not None:
_set_ctx(node, ASTCtx.Store)
@@ -1202,8 +1202,8 @@ def _parse_yield(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr:
"""函数参数列表解析(lambda 和 def 共用)
新 API:args/defaults/kw_defaults 为 list,vararg/kwarg 为字段。"""
"""Parse function parameter list
New API: args/defaults/kw_defaults are lists, vararg/kwarg are fields."""
args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
vararg: AST | t.CPtr = None
kwarg: AST | t.CPtr = None
@@ -1214,7 +1214,7 @@ def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CP
_skip_nl(ps)
if _match_op(ps, TokOp.RPar):
break
# *args 或 * (kwonly 分隔)
# *args 或 * (kwonly separated)
if _match_op(ps, TokOp.Star):
_advance(ps)
_skip_nl(ps)
@@ -1233,14 +1233,14 @@ def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CP
break
_skip_nl(ps)
continue
# / 分隔符(posonly 结束)— 新 API 中 posonly/regular 不区分
# / Delimiter (posonly end)— New API: posonly/regular are not distinguished
if _match_op(ps, TokOp.Slash):
_advance(ps)
if not _accept_op(ps, TokOp.Comma):
break
_skip_nl(ps)
continue
# 普通参数
# Normal parameter
a: AST | t.CPtr = _parse_arg_def(ps, is_lambda)
if a is None: break
args.append(a)
@@ -1273,11 +1273,11 @@ def _parse_arg_def(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr:
# ============================================================
# 语句解析(设计:直接 append 到 parent,不返回 list)
# Statement parsing (Design: directly append to parent, do not return a list)
# ============================================================
def _parse_suite_into_children(ps: Parser | t.CPtr, parent: AST | t.CPtr):
"""解析语句块,直接 append 为 parent 的子节点。
"""Parse statement suite, directly append to parent's children.
suite: TokenType.NewLine TokenType.Indent stmt+ TokenType.Dedent | simple_stmt"""
_skip_nl(ps)
if _cur_type(ps) == TokenType.NewLine:
@@ -1290,24 +1290,24 @@ def _parse_suite_into_children(ps: Parser | t.CPtr, parent: AST | t.CPtr):
sidx: t.CInt = 0
while _cur_type(ps) != TokenType.Dedent and _cur_type(ps) != TokenType.EndMarker:
sidx += 1
# 装饰器(类体内方法也可以有装饰器)
# Decorator (class body methods can have decorators)
if _match_op(ps, TokOp.At):
ps.pending_decorators = _parse_decorators(ps)
before_cur: Token | t.CPtr = ps.cur
_parse_statement_into(ps, parent)
# 防御:若解析未前进 token,强制前进以避免死循环
# Defensive: if parse did not advance token, force advance to avoid infinite loop
if ps.cur is before_cur:
ps.error_count += 1
_advance(ps)
_skip_nl(ps)
_expect_type(ps, TokenType.Dedent)
return
# 单行 suite
# Single-line suite
_parse_simple_stmt_into(ps, parent)
def _parse_statement_into(ps: Parser | t.CPtr, parent: AST | t.CPtr):
"""解析一条语句(复合或简单),append 到 parent。"""
"""Parse statement (compound or simple), append to the parent."""
ttype: t.CInt = _cur_type(ps)
kw: t.CInt = _cur_kw(ps)
if ttype == TokenType.Name:
@@ -1346,7 +1346,7 @@ def _parse_simple_stmt_into(ps: Parser | t.CPtr, parent: AST | t.CPtr):
def _parse_small_stmt(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""small_stmt: 各种简单语句"""
"""small_stmt: various simple statements"""
kw: t.CInt = _cur_kw(ps)
if kw == Keyword.Pass:
lineno: t.CInt = _cur_lineno(ps)
@@ -1387,12 +1387,12 @@ def _parse_small_stmt(ps: Parser | t.CPtr) -> AST | t.CPtr:
return _parse_assert(ps)
if kw == Keyword.Yield:
return _parse_expr_stmt(ps, _parse_yield(ps))
# 表达式语句 / 赋值 / augassign / annassign
# Expression statement / assignment / augassign / annassign
return _parse_expr_stmt(ps, None)
def _maybe_tuple(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr:
"""如果 first 后面有逗号,收集逗号分隔的表达式为 Tuple。"""
"""If there is a comma after first, collect the comma-separated expressions into a Tuple."""
if first is None: return None
if not _match_op(ps, TokOp.Comma):
return first
@@ -1420,13 +1420,13 @@ def _maybe_tuple(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr:
def _parse_testlist(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""解析逗号分隔的表达式列表,多于1个则形成 Tuple。"""
"""Parse a comma-separated list of expressions, if there’s more than one, form a tuple."""
first: AST | t.CPtr = _parse_expr(ps)
return _maybe_tuple(ps, first)
def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr:
"""表达式语句,处理赋值/augassign/annassign"""
"""Expression statement, handle assignment/augassign/annassign"""
if first is None:
first = _parse_testlist(ps)
else:
@@ -1435,7 +1435,7 @@ def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr:
return None
lineno: t.CInt = first.lineno
col: t.CInt = first.col_offset
# 赋值
# Assignment
if _match_op(ps, TokOp.Equal):
targets: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
targets.append(first)
@@ -1479,7 +1479,7 @@ def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr:
node3: AST | t.CPtr = AnnAssign(ps.pool, first, annotation, value3, 1)
_set_pos(node3, lineno, col, 0, 0)
return node3
# 表达式语句
# Expression statement
node4: AST | t.CPtr = Expr(ps.pool, first)
_set_pos(node4, lineno, col, 0, 0)
return node4
@@ -1571,7 +1571,7 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps)
# 解析 module(可能带点号)
# Parse module (possibly with dots)
level: t.CInt = 0
while _match_op(ps, TokOp.Dot):
level += 1
@@ -1580,9 +1580,12 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
level += 3
_advance(ps)
module_name: str = None
# 关键字(如 import)的 token type 也是 Name,必须通过 kw_subtype 排除,
# 否则 `from . import` 中的 `import` 会被误认为 module_name
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword:
# The token type for keywords (like import) is also Name, so they must be excluded using kw_subtype,
# otherwise the `import` in `from . import` would be mistakenly treated as a module_name.
# Note: only `import` itself should be excluded. Module names can be keywords (like in `from .match import ...`,
# where match is a Viper match statement keyword), requiring NotKeyword would cause
# `from .match import` to fail parsing and the dependency scan would miss that module.
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) != Keyword.Import:
module_name = _cur_str(ps)
_advance(ps)
while _match_op(ps, TokOp.Dot):
@@ -1628,7 +1631,7 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_alias_list(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
"""返回 alias list。"""
"""Parse alias list."""
names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
while True:
if _cur_type(ps) != TokenType.Name:
@@ -1697,7 +1700,7 @@ def _parse_assert(ps: Parser | t.CPtr) -> AST | t.CPtr:
# ============================================================
# 复合语句
# Compound statements
# ============================================================
def _parse_compound(ps: Parser | t.CPtr) -> AST | t.CPtr:
@@ -1738,7 +1741,7 @@ def _parse_if(ps: Parser | t.CPtr) -> AST | t.CPtr:
_advance(ps) # if
test: AST | t.CPtr = _parse_test(ps)
_expect_op(ps, TokOp.Colon)
# 先用空 orelse 构造,后面填充
# First construct with empty orelse, then fill it in later
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: If | t.CPtr = If(ps.pool, test, empty)
_parse_suite_into_children(ps, node)
@@ -1779,7 +1782,7 @@ def _parse_if_tail(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
# ============================================================
# 复合语句解析(续)
# Parsing Compound Statements (Continued)
# ============================================================
def _parse_while(ps: Parser | t.CPtr) -> AST | t.CPtr:
@@ -1891,7 +1894,7 @@ def _parse_with(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
items.append(item)
if not _accept_op(ps, TokOp.Comma):
break
# 检查是否可以续行(with (...): 形式)
# Check if we can continue with a newline (with (...): form)
if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.Nl:
break
_expect_op(ps, TokOp.Colon)
@@ -1951,7 +1954,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr:
return None
name: str = _cur_str(ps)
_advance(ps)
# 解析类型参数 [T] 或 [T, U](PEP 695 泛型类语法)
# Parse type parameters [T] or [T, U] (PEP 695 generic class syntax)
type_params: list[str] | t.CPtr = None
if _accept_op(ps, TokOp.Lsqb):
type_params = list[str](ps.pool, 8)
@@ -1960,7 +1963,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr:
if _cur_type(ps) == TokenType.Name:
tp_name: str = _cur_str(ps)
_advance(ps)
# 跳过可选的 bound/constraint: [T: bound] 或 [T: (A, B)]
# Skip optional bound/constraint: [T: bound] or [T: (A, B)]
if _match_op(ps, TokOp.Colon):
_advance(ps)
_parse_test(ps)
@@ -1976,7 +1979,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr:
if _cur_type(ps) == TokenType.EndMarker: break
# base 或 keyword=value
if _cur_type(ps) == TokenType.Name:
# 解析为表达式,若后跟 = 则作为 keyword
# Parse as expression, if followed by '=', then as keyword=value
e: AST | t.CPtr = _parse_or_test(ps)
if _match_op(ps, TokOp.Equal):
_advance(ps)
@@ -1998,7 +2001,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr:
def _parse_match(ps: Parser | t.CPtr) -> AST | t.CPtr:
"""match 语句:match subject ':' NewLine Indent case+ Dedent"""
"""match statement: match subject ':' NewLine Indent case+ Dedent"""
lineno: t.CInt = _cur_lineno(ps)
col: t.CInt = _cur_col(ps)
_advance(ps) # match
@@ -2006,8 +2009,8 @@ def _parse_match(ps: Parser | t.CPtr) -> AST | t.CPtr:
_expect_op(ps, TokOp.Colon)
cases: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = Match(ps.pool, subject, cases)
# 解析 body:与 _parse_suite_into_children 相同的 NewLine/Indent/Dedent 模式,
# 但解析 case 子句到 cases 列表而非普通语句到 children
# Parsing body: Same NewLine/Indent/Dedent pattern as _parse_suite_into_children,
# but parses case clauses into a cases list instead of normal statements into children
_skip_nl(ps)
if _cur_type(ps) == TokenType.NewLine:
_advance(ps)
@@ -2020,18 +2023,18 @@ def _parse_match(ps: Parser | t.CPtr) -> AST | t.CPtr:
if case_node is not None:
cases.append(case_node)
else:
_advance(ps) # 跳过非 case token,避免死循环
_advance(ps) # Skip non-case token to avoid infinite loop
_expect_type(ps, TokenType.Dedent)
_set_pos(node, lineno, col, 0, 0)
return node
# ============================================================
# Match pattern 解析
# Match pattern parsing
# ============================================================
def _make_name_ast(pool: memhub.MemManager | t.CPtr, node: Name | t.CPtr) -> AST | t.CPtr:
"""将 Name* 转换为 AST*(解决 TransPyC 类型推断问题)"""
# Analysis: "Convert Name* to AST* (Solving the TransPyC Type Inference Problem)"
return node
@@ -2075,7 +2078,7 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
tok: Token | t.CPtr
sval: str
# 数字字面量 pattern
# Number literal pattern
if ttype == TokenType.Number:
tok = ps.cur
_advance(ps)
@@ -2087,7 +2090,7 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
_set_pos(node, lineno, col, 0, 0)
return node
# 字符串字面量 pattern
# String literal pattern
if ttype == TokenType.String:
sval = _cur_str(ps)
is_dquote_m: t.CInt = ps.cur.kw_subtype & 16
@@ -2097,7 +2100,7 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
_set_pos(node, lineno, col, 0, 0)
return node
# 负数字面量 pattern: -1, -1.5
# Negative number literal pattern: -1, -1.5
if _match_op(ps, TokOp.Minus):
_advance(ps)
if _cur_type(ps) == TokenType.Number:
@@ -2129,14 +2132,14 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
_set_pos(node, lineno, col, 0, 0)
return node
name_str: str = _cur_str(ps)
# 通配符 _
# Wildcard pattern: _
if string.strcmp(name_str, "_") == 0:
_advance(ps)
node = MatchAs(ps.pool, None, None)
_set_pos(node, lineno, col, 0, 0)
return node
_advance(ps)
# 检查 dotted name(value pattern 或 class pattern)
# Check dotted name(value pattern 或 class pattern)
if _match_op(ps, TokOp.Dot):
name_node: Name | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load)
_set_pos(name_node, lineno, col, 0, 0)
@@ -2349,7 +2352,7 @@ def _parse_decorators(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
# ============================================================
# 模块入口
# Module entry
# ============================================================
def _parse_module_body(ps: Parser | t.CPtr, module_node: AST | t.CPtr):
@@ -2358,14 +2361,14 @@ def _parse_module_body(ps: Parser | t.CPtr, module_node: AST | t.CPtr):
stmt_idx: t.CInt = 0
while _cur_type(ps) != TokenType.EndMarker:
stmt_idx += 1
# 装饰器
# Decorator
if _match_op(ps, TokOp.At):
ps.pending_decorators = _parse_decorators(ps)
# 记录解析前的 token 指针,用于检测未前进的死循环
# Record current token pointer to check for infinite loop
before_cur: Token | t.CPtr = ps.cur
_parse_statement_into(ps, module_node)
# 防御:若解析未前进 token(如 _parse_atom 遇到无法识别的 token 返回 None),
# 强制前进以避免主循环死循环;累计 error_count 供调用方诊断
# Defense: If parsing doesn't advance the token (like when _parse_atom encounters an unrecognized token and returns None),
# force it to move forward to avoid an infinite loop in the main loop; accumulate error_count for the caller to diagnose
if ps.cur is before_cur:
ps.error_count += 1
_advance(ps)
@@ -2374,7 +2377,7 @@ def _parse_module_body(ps: Parser | t.CPtr, module_node: AST | t.CPtr):
def parse_tokens(pool: memhub.MemManager | t.CPtr,
tokens: Token | t.CPtr) -> AST | t.CPtr:
"""从 token 链表解析 AST Module。"""
"""Parse an AST Module from a token list."""
if pool is None or tokens is None:
return None
ps: Parser | t.CPtr = new_parser(pool)
+27 -27
View File
@@ -11,7 +11,7 @@ from .base import (
# ============================================================
# Module 节点
# Module Node
# ============================================================
@t.CVTable
@@ -42,7 +42,7 @@ class Module(AST):
# ============================================================
# Assign 节点
# Assign Node
# ============================================================
class Assign(AST):
@@ -84,7 +84,7 @@ class Assign(AST):
# ============================================================
# If 节点
# If Node
# ============================================================
class If(AST):
@@ -130,7 +130,7 @@ class If(AST):
# ============================================================
# For 节点
# For Node
# ============================================================
class For(AST):
@@ -188,7 +188,7 @@ class For(AST):
# ============================================================
# While 节点
# While Node
# ============================================================
class While(AST):
@@ -232,7 +232,7 @@ class While(AST):
# ============================================================
# Return 节点
# Return Node
# ============================================================
class Return(AST):
@@ -267,7 +267,7 @@ class Return(AST):
# ============================================================
# Expr 节点(表达式语句)
# Expr Node (expression statement)
# ============================================================
class Expr(AST):
@@ -302,7 +302,7 @@ class Expr(AST):
# ============================================================
# FunctionDef 节点
# FunctionDef Node
# ============================================================
class FunctionDef(AST):
@@ -367,7 +367,7 @@ class FunctionDef(AST):
# ============================================================
# Expression 节点
# Expression Node
# ============================================================
class Expression(AST):
@@ -404,7 +404,7 @@ class Expression(AST):
# ============================================================
# Interactive 节点
# Interactive Node
# ============================================================
class Interactive(AST):
@@ -441,7 +441,7 @@ class Interactive(AST):
# ============================================================
# FunctionType 节点
# FunctionType Node
# ============================================================
class FunctionType(AST):
@@ -484,7 +484,7 @@ class FunctionType(AST):
# ============================================================
# ClassDef 节点
# ClassDef Node
# ============================================================
class ClassDef(AST):
@@ -547,7 +547,7 @@ class ClassDef(AST):
# ============================================================
# Delete 节点
# Delete Node
# ============================================================
class Delete(AST):
@@ -582,7 +582,7 @@ class Delete(AST):
# ============================================================
# AugAssign 节点
# AugAssign Node
# ============================================================
class AugAssign(AST):
@@ -630,7 +630,7 @@ class AugAssign(AST):
# ============================================================
# AnnAssign 节点
# AnnAssign Node
# ============================================================
class AnnAssign(AST):
@@ -687,7 +687,7 @@ class AnnAssign(AST):
# ============================================================
# With 节点
# With Node
# ============================================================
class With(AST):
@@ -731,7 +731,7 @@ class With(AST):
# ============================================================
# Raise 节点
# Raise Node
# ============================================================
class Raise(AST):
@@ -775,7 +775,7 @@ class Raise(AST):
# ============================================================
# Try 节点
# Try Node
# ============================================================
class Try(AST):
@@ -827,7 +827,7 @@ class Try(AST):
# ============================================================
# Assert 节点
# Assert Node
# ============================================================
class Assert(AST):
@@ -871,7 +871,7 @@ class Assert(AST):
# ============================================================
# Global 节点
# Global Node
# ============================================================
class Global(AST):
@@ -906,7 +906,7 @@ class Global(AST):
# ============================================================
# Nonlocal 节点
# Nonlocal Node
# ============================================================
class Nonlocal(AST):
@@ -941,7 +941,7 @@ class Nonlocal(AST):
# ============================================================
# Pass 节点
# Pass Node
# ============================================================
class Pass(AST):
@@ -969,7 +969,7 @@ class Pass(AST):
# ============================================================
# Break 节点
# Break Node
# ============================================================
class Break(AST):
@@ -997,7 +997,7 @@ class Break(AST):
# ============================================================
# Continue 节点
# Continue Node
# ============================================================
class Continue(AST):
@@ -1025,7 +1025,7 @@ class Continue(AST):
# ============================================================
# Import 节点
# Import Node
# ============================================================
class Import(AST):
@@ -1060,7 +1060,7 @@ class Import(AST):
# ============================================================
# ImportFrom 节点
# ImportFrom Node
# ============================================================
class ImportFrom(AST):
@@ -1107,7 +1107,7 @@ class ImportFrom(AST):
# ============================================================
# Match 节点
# Match Node
# ============================================================
class Match(AST):
+44 -44
View File
@@ -5,8 +5,8 @@ import string
# ============================================================
# Token 类型枚举(参考 CPython Lib/token.py)
# 用 t.CEnum 组织为类型安全枚举;旧名 XXX 保留为兼容别名
# Token type enumeration (refer to CPython Lib/token.py)
# Organized as a type-safe enum using t.CEnum; old names XXX retained as compatible aliases
# ============================================================
class TokenType(t.CEnum):
@@ -27,9 +27,9 @@ class TokenType(t.CEnum):
# ============================================================
# 关键字枚举(参考 CPython Lib/keyword.py)
# 用 t.CEnum 组织为类型安全枚举;旧名 KW_XXX 保留为兼容别名
# NotKeyword(0) 表示非关键字(哨兵,避免 False_=0 与 kw_subtype=0 冲突)
# Keyword enumeration (refer to CPython Lib/keyword.py)
# Organized as a type-safe enum using t.CEnum; old names KW_XXX are kept as compatible aliases
# NotKeyword(0) represents a non-keyword (sentinel to avoid conflict between False_=0 and kw_subtype=0)
# ============================================================
class Keyword(t.CEnum):
@@ -75,9 +75,9 @@ class Keyword(t.CEnum):
# ============================================================
# 运算符/分隔符枚举
# 用 t.CEnum 组织为类型安全枚举;旧名 OP_XXX 保留为兼容别名
# 存储在 token.op_subtype 字段
# Operator/Separator Enumeration
# Organized as a type-safe enum using t.CEnum; old names OP_XXX retained as compatible aliases
# Stored in the token.op_subtype field
# ============================================================
class TokOp(t.CEnum):
@@ -128,29 +128,29 @@ class TokOp(t.CEnum):
Tilde: t.State # ~
ColonEq: t.State # :=
Ellipsis: t.State # ...
Bang: t.State # ! (非标准,用于解析容错)
Bang: t.State # !(Non-standard, used for parsing tolerance)
# ============================================================
# Token 结构体
# Token stucture
# ============================================================
class Token:
type: t.CInt # Token 类型(TokenType.EndMarker/TokenType.NewLine/TokenType.Name/...)
op_subtype: t.CInt # 运算符子类型(OP_*),仅 type==TokenType.Op 时有效
kw_subtype: t.CInt # 关键字子类型(KW_*),仅 type==TokenType.Name 且是关键字时有效
str_val: str # token 文本(NUL 结尾,从 pool 分配)
int_val: t.CInt64T # 整数值(TokenType.Number 用)
float_val: t.CDouble # 浮点值(TokenType.Number 用)
is_float: t.CInt # 1=浮点数, 0=整数
is_complex: t.CInt # 1=复数, 0=实数
lineno: t.CInt # 起始行号
col_offset: t.CInt # 起始列偏移
end_lineno: t.CInt # 结束行号
end_col_offset: t.CInt # 结束列偏移
next: Token | t.CPtr # 链表下一个 token
type: t.CInt # Token type (TokenType.EndMarker / TokenType.NewLine / TokenType.Name / ...)
op_subtype: t.CInt # Operator subtype (OP_*). Only valid when type == TokenType.Op
kw_subtype: t.CInt # Keyword subtype (KW_*). Only valid when type == TokenType.Name and it is a keyword
str_val: str # Token text (NUL‑terminated, allocated from pool)
int_val: t.CInt64T # Integer value (used by TokenType.Number)
float_val: t.CDouble # Floating‑point value (used by TokenType.Number)
is_float: t.CInt # 1 = floating‑point number, 0 = integer
is_complex: t.CInt # 1 = complex number, 0 = real number
lineno: t.CInt # Starting line number
col_offset: t.CInt # Starting column offset
end_lineno: t.CInt # Ending line number
end_col_offset: t.CInt # Ending column offset
next: Token | t.CPtr # Next token in linked list
def __new__(self, pool: memhub.MemManager | t.CPtr):
"""从 mpool 分配 Token 结构体内存并零初始化"""
"""Allocate zero‑initialized Token struct memory from mpool"""
ptr: Token | t.CPtr = pool.alloc(Token.__sizeof__())
if ptr:
string.memset(ptr, 0, Token.__sizeof__())
@@ -158,8 +158,8 @@ class Token:
# ============================================================
# 关键字查找表
# 由于 TransPyC 无 dict 字面量,用链表实现
# Keyword lookup table
# Since TransPyC has no dict literals, implemented with linked lists
# ============================================================
class KwEntry:
name: str
@@ -173,13 +173,13 @@ class KwEntry:
return ptr
# 全局关键字链表头(懒初始化)
# Global keyword linked list head (lazy initialization)
_kw_head: KwEntry | t.CPtr = None
_kw_pool: memhub.MemManager | t.CPtr = None
def _kw_intern(pool: memhub.MemManager | t.CPtr, name: str, kw_id: t.CInt):
"""将关键字名注册到链表"""
"""Register keyword name in the linked list"""
global _kw_head
entry: KwEntry | t.CPtr = KwEntry(pool)
if entry == None: return
@@ -194,7 +194,7 @@ def _kw_intern(pool: memhub.MemManager | t.CPtr, name: str, kw_id: t.CInt):
def _kw_lookup(name: str) -> t.CInt:
"""查找关键字,返回 kw_id(0 表示非关键字)"""
"""Look up keyword name in the linked list, return the kw_id (0 if not keyword)"""
cur: KwEntry | t.CPtr = _kw_head
while cur != None:
if string.strcmp(cur.name, name) == 0:
@@ -204,7 +204,7 @@ def _kw_lookup(name: str) -> t.CInt:
def _init_keywords(pool: memhub.MemManager | t.CPtr):
"""初始化关键字表(仅一次)"""
"""Initialize keyword linked list (only once)"""
global _kw_head, _kw_pool
if _kw_head != None: return
_kw_pool = pool
@@ -249,12 +249,12 @@ def _init_keywords(pool: memhub.MemManager | t.CPtr):
# ============================================================
# 运算符查找表
# 由于 TransPyC 无 dict,用数组+线性查找
# 运算符按长度降序排列,以便贪婪匹配
# Operator lookup table
# Since TransPyC doesn't have dict, use an array with linear search
# Operators are sorted by descending length for greedy matching
# ============================================================
class OpEntry:
name: str # 运算符文本(如 "==", "+=")
name: str # Operator text (e.g. "==", "+=")
op_id: t.CInt
length: t.CInt
next: OpEntry | t.CPtr
@@ -285,16 +285,16 @@ def _op_intern(pool: memhub.MemManager | t.CPtr, name: str, op_id: t.CInt):
def _init_operators(pool: memhub.MemManager | t.CPtr):
"""初始化运算符表(按长度降序注册,便于贪婪匹配)"""
"""Initialize the operator table (register in descending length order for easy greedy matching)"""
global _op_head
if _op_head != None: return
# 3 字符运算符
# 3-character operators
_op_intern(pool, "**=", TokOp.StarEqEq)
_op_intern(pool, "//=", TokOp.DSlashEq)
_op_intern(pool, ">>=", TokOp.GtGtEq)
_op_intern(pool, "<<=", TokOp.LtLtEq)
_op_intern(pool, "...", TokOp.Ellipsis)
# 2 字符运算符
# 2-character operators
_op_intern(pool, "->", TokOp.RArrow)
_op_intern(pool, "+=", TokOp.PlusEq)
_op_intern(pool, "-=", TokOp.MinusEq)
@@ -314,7 +314,7 @@ def _init_operators(pool: memhub.MemManager | t.CPtr):
_op_intern(pool, "==", TokOp.EqEq)
_op_intern(pool, "!=", TokOp.ExclaimEq)
_op_intern(pool, ":=", TokOp.ColonEq)
# 1 字符运算符
# 1-character operators
_op_intern(pool, "(", TokOp.LPar)
_op_intern(pool, ")", TokOp.RPar)
_op_intern(pool, "[", TokOp.Lsqb)
@@ -341,18 +341,18 @@ def _init_operators(pool: memhub.MemManager | t.CPtr):
def _init_tables(pool: memhub.MemManager | t.CPtr):
"""初始化所有查找表(幂等)"""
"""Initialize all lookup tables (idempotent)"""
_init_keywords(pool)
_init_operators(pool)
# ============================================================
# Token 创建辅助函数
# Token creation helper functions
# ============================================================
def new_token(pool: memhub.MemManager | t.CPtr, ttype: t.CInt, lineno: t.CInt,
col_offset: t.CInt) -> Token | t.CPtr:
"""创建一个空 Token,调用方填充字段"""
"""Create a new empty Token and fill in fields later"""
tok: Token | t.CPtr = Token(pool)
if tok == None: return None
tok.type = ttype
@@ -365,9 +365,9 @@ def new_token(pool: memhub.MemManager | t.CPtr, ttype: t.CInt, lineno: t.CInt,
def token_set_str(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr,
src: str, start: t.CSizeT, length: t.CSizeT):
"""从 src[start:start+length] 复制文本到 token.str_val
"""Copy text from src[start:start + length] to token.str_val
注意:length == 0 时也分配 1 字节存 NUL,让空字符串与 NULL 指针区分开。
Note: When length == 0, still allocate 1 byte for NUL, so that an empty string is distinguished from a NULL pointer.
"""
if tok == None: return
buf: str = pool.alloc(length + 1)
@@ -382,7 +382,7 @@ def token_set_str(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr,
def token_set_str_literal(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr,
text: str):
"""直接复制一个 C 字符串到 token.str_val"""
"""Copy a C string to token.str_val"""
if tok == None or text == None: return
slen: t.CSizeT = string.strlen(text)
buf: str = pool.alloc(slen + 1)