Files
Viper_VRTE/ast/base.vp
T
TermiNexus 0055ab7ea7 refactor: rawptr[T] -> T* 与 t.CConst 前缀迁移(R14/R16)
R14:rawptr[X] -> X*(41 文件 / 2037 行改动),X 含模块限定名与嵌套下标(rawptr[GSList[NameEntry]] -> GSList[NameEntry]*)。保留 6 处 rawptr[t.CPtr](规范例外:存纯裸指针);# 注释与字符串里的 rawptr[...] 属元语法描述,未动。 R16(保守子集):t.CConst | str/bytes -> const str/bytes,t.CConst | char | t.CPtr -> const str;typedef 右值位置豁免(const str 在该处无法注册,与 R1 同源)。 验证:TPC 自举三重重编 SUCCESS;TransPyV.exe 全量 77/77 顺序回归通过。
2026-10-05 17:38:21 +08:00

396 lines
14 KiB
Plaintext

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)
# ============================================================
enum ASTKind:
# Core 15 nodes
Module, FunctionDef, ClassDef, Assign
If, For, While, Return
Expr, Name, Constant
BinOp, UnaryOp
Call, Compare
# Module Layer
Expression, Interactive, FunctionType
# Statement
Delete, AugAssign, AnnAssign
With, Raise, Try, Assert
Global, Nonlocal
Pass, Break, Continue
Import, ImportFrom, Match
# Expression Layer
BoolOp, Lambda, IfExp
Dict, Set, ListComp, SetComp, DictComp
GeneratorExp, Await, Yield, YieldFrom
FormattedValue, JoinedStr
Attribute, Subscript
Starred
List, Tuple, Slice
NamedExpr
# Auxiliary Nodes
ExceptHandler
Arguments, Arg
Keyword, Alias
WithItem, Comprehension, OpNode
# Pattern Matching
MatchCase, MatchValue
MatchSingleton, MatchSequence, MatchMapping
MatchClass, MatchStar, MatchAs, MatchOr
# Soft keyword statement (appended last to keep existing enum values unchanged)
FallThrough
# ============================================================
# ASTCtx - Name context (Load/Store/Del)
# ============================================================
enum ASTCtx:
Load, Store, Del
# ============================================================
# OpKind - Operator enum (BinOp/UnaryOp/Compare)
# ============================================================
enum OpKind:
# Binary arithmetic operators
Add, Sub
Mult, MatMult
Div, Mod, Pow
LShift, RShift
BitOr, BitXor, BitAnd
FloorDiv
# Boolean operators
And, Or
# Comparison operators
Eq, Ne, Lt, Le, Gt, Ge
Is, IsNot
In, NotIn
# Unary operators
Not, UAdd, USub
Invert, Deref, AddrOf
# None
NoneOp
# Constant subtype identifiers
define CONST_INT = 1
define CONST_FLOAT = 2
define CONST_STR = 3
define CONST_BOOL = 4
define CONST_NONE = 5
define CONST_CHAR = 6
# Node flags
define FLAG_IS_ASYNC = 1
define FLAG_SIMPLE = 2
define FLAG_HAS_STAR = 4
define FLAG_IS_EXTERN = 8
define FLAG_IS_EXPORT = 16
define FLAG_IS_DEFINE = 32
# ============================================================
# ASTFlag - Node flags enum
# ============================================================
enum ASTFlag:
IsAsync, Simple, HasStar
# ============================================================
# Helper Functions
# ============================================================
def _copy_str(pool: memhub.MemManager*, src: str) -> str:
"""Allocate and copy a C string from pool."""
if src is None: return None
slen: sizet = 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: 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: AST*, ref: 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: AST*, pool: 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[AST*]*, parent: AST*):
"""Set list children parent pointers."""
if lst is None: return
for i in range(lst.__len__()):
child: AST* = lst.get(i)
if child is not None: child.parent = parent
def _append_child(lst: list[AST*]*, node: AST*,
pool: 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: sizet, pos: sizet, text: str) -> sizet:
"""Append literal to buf+pos."""
if buf is None or pos >= size: return pos
cur: str = str(uint64(buf) + pos)
rem: sizet = size - pos
n: int = viperlib.snprintf(cur, rem, "%s", text)
if n < 0: return pos
return pos + sizet(n)
def _emit_str(buf: str, size: sizet, pos: sizet, text: str) -> sizet:
"""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: sizet = size - pos
n: int = viperlib.snprintf(cur, rem, "%s", text)
if n < 0: return pos
return pos + sizet(n)
def _emit_int(buf: str, size: sizet, pos: sizet, val: int64) -> sizet:
"""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: sizet = size - pos
n: int = viperlib.snprintf(cur, rem, "%lld", val)
if n < 0: return pos
return pos + sizet(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[AST*]*, buf: str, size: sizet, pos: sizet) -> sizet:
"""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, "[")
for i in range(lst.__len__()):
if i > 0: pos = _emit(buf, size, pos, ", ")
child: AST* = lst.get(i)
if child is not None: pos = child.dump(buf, size, pos)
pos = _emit(buf, size, pos, "]")
return pos
def _dump_op_list(lst: t.CPtr, buf: str, size: sizet, pos: sizet) -> sizet:
"""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: list[int]* = (list[int]*)(lst)
pos = _emit(buf, size, pos, "[")
for i in range(ops_list.__len__()):
if i > 0: pos = _emit(buf, size, pos, ", ")
op: int = ops_list.get(i)
pos = _emit(buf, size, pos, _op_name(op))
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)
# ============================================================
virtual 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: AST*
pool: memhub.MemManager*
lineno: int
col_offset: int
end_lineno: int
end_col_offset: int
children: list[AST*]*
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: sizet, pos: sizet) -> sizet:
"""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: 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[AST*](self.pool, 8)
node.parent = self
_append_child(self.children, node, self.pool)
# ============================================================
# Stmt - Statement Base Class
#
# All statement nodes (Assign/If/For/While/Return/...) inherit Stmt.
# isinstance(node, ast.Stmt) distinguishes statements from expressions at runtime.
# Does not override kind() (inherits AST's 0); concrete nodes return their ASTKind.
# ============================================================
virtual class Stmt(AST):
"""Statement node base class (Assign/If/For/While/Return/...)"""
# ============================================================
# ExprNode - Expression Base Class
#
# All expression nodes (Name/Constant/Call/BinOp/...) inherit ExprNode.
# isinstance(node, ast.ExprNode) distinguishes expressions from statements at runtime.
# Not named Expr: ASTKind.Expr and the stmts.vp Expr class already mean expression statement.
# ============================================================
virtual class ExprNode(AST):
"""Expression node base class (Name/Constant/Call/BinOp/...)"""
# ============================================================
# Module dump function (for ast.dump(node, buf, size))
# ============================================================
def dump(node: AST*, buf: str, size: sizet):
"""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: sizet = node.dump(buf, size, 0)
# NUL-terminate to prevent printf overflow
buf[final_pos if final_pos < size else size - 1] = '\0'