Files
Viper_VRTE/ast/base.vp
T
TermiNexus 2992674783 feat(types): rowptr/REnum 迁移工作区快照 + GSList/PrintModule 临时 DBGCHAIN 护栏
把此前未提交的 rowptr 迁移整体入库(42 文件,含 ast/llvmlite/hashlib/json/zlib 等签名 rowptr 化)。临时诊断(用后移除):linkedlist.vp GSList[T].append 链完整性四检、__module.vp PrintModule Function.Params/param 指针野值护栏([DBGCHAIN] 前缀 + fflush + exit)。
2026-09-05 14:51:40 +08:00

511 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import memhub
import string
import viperlib
from .tokens import TokOp
# ============================================================
# ASTKind - Node type enum (kind() virtual function return value)
# ============================================================
class ASTKind(t.CEnum):
# Core 15 nodes
Module: t.State
FunctionDef: t.State
ClassDef: t.State
Assign: t.State
If: t.State
For: t.State
While: t.State
Return: t.State
Expr: t.State
Name: t.State
Constant: t.State
BinOp: t.State
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
With: t.State
Raise: t.State
Try: t.State
Assert: t.State
Global: t.State
Nonlocal: t.State
Pass: t.State
Break: t.State
Continue: t.State
Import: t.State
ImportFrom: t.State
Match: t.State
# Expression Layer
BoolOp: t.State
Lambda: t.State
IfExp: t.State
Dict: t.State
Set: t.State
ListComp: t.State
SetComp: t.State
DictComp: t.State
GeneratorExp: t.State
Await: t.State
Yield: t.State
YieldFrom: t.State
FormattedValue: t.State
JoinedStr: t.State
Attribute: t.State
Subscript: t.State
Starred: t.State
List: t.State
Tuple: t.State
Slice: t.State
NamedExpr: t.State
# Auxiliary Nodes
ExceptHandler: t.State
Arguments: t.State
Arg: t.State
Keyword: t.State
Alias: t.State
WithItem: t.State
Comprehension: t.State
OpNode: t.State
# Pattern Matching
MatchCase: t.State
MatchValue: t.State
MatchSingleton: t.State
MatchSequence: t.State
MatchMapping: t.State
MatchClass: t.State
MatchStar: t.State
MatchAs: t.State
MatchOr: t.State
# ============================================================
# ASTCtx - Name context (Load/Store/Del)
# ============================================================
class ASTCtx(t.CEnum):
Load: t.State
Store: t.State
Del: t.State
# ============================================================
# OpKind - Operator enum (BinOp/UnaryOp/Compare)
# ============================================================
class OpKind(t.CEnum):
# Binary arithmetic operators
Add: t.State
Sub: t.State
Mult: t.State
MatMult: t.State
Div: t.State
Mod: t.State
Pow: t.State
LShift: t.State
RShift: t.State
BitOr: t.State
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
Le: t.State
Gt: t.State
Ge: t.State
Is: t.State
IsNot: t.State
In: t.State
NotIn: t.State
# Unary operators
Not: t.State
UAdd: t.State
USub: t.State
Invert: t.State
Deref: t.State
AddrOf: t.State
# None
NoneOp: t.State
# Constant subtype identifiers
CONST_INT: t.CDefine = 1
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
# Node flags
FLAG_IS_ASYNC: t.CDefine = 1
FLAG_SIMPLE: t.CDefine = 2
FLAG_HAS_STAR: t.CDefine = 4
FLAG_IS_EXTERN: t.CDefine = 8
FLAG_IS_EXPORT: t.CDefine = 16
FLAG_IS_DEFINE: t.CDefine = 32
# ============================================================
# ASTFlag - Node flags enum
# ============================================================
class ASTFlag(t.CEnum):
IsAsync: t.State
Simple: t.State
HasStar: t.State
# ============================================================
# Helper Functions
# ============================================================
def _copy_str(pool: rowptr[memhub.MemManager], src: str) -> str:
"""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)
if buf is None: return None
string.memcpy(buf, src, slen + 1)
return buf
def _set_pos(node: rowptr[AST], lineno: int, col_offset: int,
end_lineno: int, end_col_offset: int):
if node is None: return
node.lineno = lineno
node.col_offset = col_offset
node.end_lineno = end_lineno
node.end_col_offset = end_col_offset
def _inherit_pos(node: rowptr[AST], ref: rowptr[AST]):
if node is None or ref is None: return
node.lineno = ref.lineno
node.col_offset = ref.col_offset
node.end_lineno = ref.end_lineno
node.end_col_offset = ref.end_col_offset
def _init_ast(node: rowptr[AST], pool: rowptr[memhub.MemManager],
lineno: int, col: int):
"""Initialize AST base fields."""
node.parent = None
node.pool = pool
node.lineno = lineno
node.col_offset = col
node.end_lineno = lineno
node.end_col_offset = col
node.children = None
def _set_parent_list(lst: list[rowptr[AST]] | t.CPtr, parent: rowptr[AST]):
"""Set list children parent pointers."""
if lst is None: return
n: t.CSizeT = lst.__len__()
i: t.CSizeT = 0
while i < n:
child: rowptr[AST] = lst.get(i)
if child is not None:
child.parent = parent
i += 1
def _append_child(lst: list[rowptr[AST]] | t.CPtr, node: rowptr[AST],
pool: rowptr[memhub.MemManager]):
"""Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name).
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)
# ============================================================
# Operator Mapping: TokOp -> OpKind
# ============================================================
def _binop_from_op(op_id: int) -> int:
if op_id == TokOp.Plus: return OpKind.Add
if op_id == TokOp.Minus: return OpKind.Sub
if op_id == TokOp.Star: return OpKind.Mult
if op_id == TokOp.At: return OpKind.MatMult
if op_id == TokOp.Slash: return OpKind.Div
if op_id == TokOp.Percent: return OpKind.Mod
if op_id == TokOp.StarStar: return OpKind.Pow
if op_id == TokOp.LtLt: return OpKind.LShift
if op_id == TokOp.GtGt: return OpKind.RShift
if op_id == TokOp.VBar: return OpKind.BitOr
if op_id == TokOp.Caret: return OpKind.BitXor
if op_id == TokOp.Amp: return OpKind.BitAnd
if op_id == TokOp.DSlash: return OpKind.FloorDiv
return OpKind.NoneOp
def _augop_from_op(op_id: int) -> int:
if op_id == TokOp.PlusEq: return OpKind.Add
if op_id == TokOp.MinusEq: return OpKind.Sub
if op_id == TokOp.StarEq: return OpKind.Mult
if op_id == TokOp.AtEq: return OpKind.MatMult
if op_id == TokOp.SlashEq: return OpKind.Div
if op_id == TokOp.PercentEq: return OpKind.Mod
if op_id == TokOp.StarEqEq: return OpKind.Pow
if op_id == TokOp.LtLtEq: return OpKind.LShift
if op_id == TokOp.GtGtEq: return OpKind.RShift
if op_id == TokOp.VBarEq: return OpKind.BitOr
if op_id == TokOp.CaretEq: return OpKind.BitXor
if op_id == TokOp.AmpEq: return OpKind.BitAnd
if op_id == TokOp.DSlashEq: return OpKind.FloorDiv
return OpKind.NoneOp
def _cmpop_from_op(op_id: int) -> int:
if op_id == TokOp.EqEq: return OpKind.Eq
if op_id == TokOp.ExclaimEq: return OpKind.Ne
if op_id == TokOp.Less: return OpKind.Lt
if op_id == TokOp.LessEq: return OpKind.Le
if op_id == TokOp.Greater: return OpKind.Gt
if op_id == TokOp.GreaterEq: return OpKind.Ge
return OpKind.NoneOp
# ============================================================
# dump Helper Functions
# ============================================================
def _emit(buf: str, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""Append literal to buf+pos."""
if buf is None or pos >= size:
return pos
cur: str = str(uint64(buf) + pos)
rem: t.CSizeT = size - pos
n: int = viperlib.snprintf(cur, rem, "%s", text)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _emit_str(buf: str, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""Append a string value to buf pos (using %s format)"""
if buf is None or pos >= size:
return pos
cur: str = str(uint64(buf) + pos)
rem: t.CSizeT = size - pos
n: int = viperlib.snprintf(cur, rem, "%s", text)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _emit_int(buf: str, size: t.CSizeT, pos: t.CSizeT,
val: int64) -> t.CSizeT:
"""Append an integer value to buf pos (using %lld format)."""
if buf is None or pos >= size:
return pos
cur: str = str(uint64(buf) + pos)
rem: t.CSizeT = size - pos
n: int = viperlib.snprintf(cur, rem, "%lld", val)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _op_name(op: int) -> str:
"""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"
if op == OpKind.MatMult: return "MatMult"
if op == OpKind.Div: return "Div"
if op == OpKind.Mod: return "Mod"
if op == OpKind.Pow: return "Pow"
if op == OpKind.LShift: return "LShift"
if op == OpKind.RShift: return "RShift"
if op == OpKind.BitOr: return "BitOr"
if op == OpKind.BitXor: return "BitXor"
if op == OpKind.BitAnd: return "BitAnd"
if op == OpKind.FloorDiv: return "FloorDiv"
if op == OpKind.And: return "And"
if op == OpKind.Or: return "Or"
if op == OpKind.Eq: return "Eq"
if op == OpKind.Ne: return "Ne"
if op == OpKind.Lt: return "Lt"
if op == OpKind.Le: return "Le"
if op == OpKind.Gt: return "Gt"
if op == OpKind.Ge: return "Ge"
if op == OpKind.Is: return "Is"
if op == OpKind.IsNot: return "IsNot"
if op == OpKind.In: return "In"
if op == OpKind.NotIn: return "NotIn"
if op == OpKind.Not: return "Not"
if op == OpKind.UAdd: return "UAdd"
if op == OpKind.USub: return "USub"
if op == OpKind.Invert: return "Invert"
if op == OpKind.Deref: return "Deref"
if op == OpKind.AddrOf: return "AddrOf"
return "NoneOp"
def _dump_list(lst: list[rowptr[AST]] | t.CPtr, buf: str,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""Traverse a list[AST | CPtr] container, polymorphically dump each element."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
pos = _emit(buf, size, pos, "[")
n: t.CSizeT = lst.__len__()
i: t.CSizeT = 0
while i < n:
if i > 0:
pos = _emit(buf, size, pos, ", ")
child: rowptr[AST] = lst.get(i)
if child is not None:
pos = child.dump(buf, size, pos)
i += 1
pos = _emit(buf, size, pos, "]")
return pos
def _dump_op_list(lst: t.CPtr, buf: str,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""Traverse a list[CInt] (OpKind values), output a list of op names."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
ops_list: rowptr[list[int]] = (rowptr[list[int]])(lst)
pos = _emit(buf, size, pos, "[")
n: t.CSizeT = ops_list.__len__()
i: t.CSizeT = 0
while i < n:
if i > 0:
pos = _emit(buf, size, pos, ", ")
op: int = ops_list.get(i)
pos = _emit(buf, size, pos, _op_name(op))
i += 1
pos = _emit(buf, size, pos, "]")
return pos
# ============================================================
# 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 node base class. All specific node classes inherit from this.
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: rowptr[AST]
pool: rowptr[memhub.MemManager]
lineno: int
col_offset: int
end_lineno: int
end_col_offset: int
children: list[rowptr[AST]] | t.CPtr
def kind(self) -> int:
"""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: str, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
"""Polymorphic dump: subclasses override to define custom format. Returns the written pos"""
return pos
def accept(self, visitor: t.CPtr):
"""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: rowptr[AST]):
"""Append node to the children list.
Used for parser to build statement blocks: module.append(stmt), if_node.append(stmt), etc.
The children list is lazily initialized on first call.
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:
self.children = list[rowptr[AST]](self.pool, 8)
node.parent = self
_append_child(self.children, node, self.pool)
# ============================================================
# Stmt - Statement Base Class
#
# 所有语句节点(Assign/If/For/While/Return/...)继承 Stmt。
# isinstance(node, ast.Stmt) 可在运行时区分"语句"与"表达式"
# (依赖 TPV isinstance 子类集合判定 + 三层 vtable 继承)。
# 不 override kind()(继承 AST 的 0),具体节点各自返回 ASTKind 值。
# ============================================================
@t.CVTable
class Stmt(AST):
"""语句节点基类(Assign/If/For/While/Return/...)"""
# ============================================================
# ExprNode - Expression Base Class
#
# 所有表达式节点(Name/Constant/Call/BinOp/...)继承 ExprNode。
# isinstance(node, ast.ExprNode) 可在运行时区分"表达式"与"语句"。
#
# 命名说明:不能叫 Expr——ASTKind.Expr(base.vp L23)与 stmts.vp 的
# Expr 类已是"表达式语句"(Expression Statement)的既有语义。
# ============================================================
@t.CVTable
class ExprNode(AST):
"""表达式节点基类(Name/Constant/Call/BinOp/...)"""
# ============================================================
# Module dump function (for ast.dump(node, buf, size))
# ============================================================
def dump(node: rowptr[AST], buf: str, size: t.CSizeT):
"""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-terminate to prevent printf overflow
if final_pos < size:
buf[final_pos] = '\0'
else:
buf[size - 1] = '\0'