snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

View File

@@ -0,0 +1,509 @@
import t
import stdio
import string
import testcheck
import linkedlist
import viperlib
import stdlib
# ============================================================
# 子类继承 linkedlist.LinkedNode启用链表/树形能力
# 字段展平,无 vtableOOP 方法通过 _generate_inherited_method_wrappers
# 自动生成子类包装self bitcast 为父类指针后调用父类方法)。
# 从 LinkedNode* 取回 Node* 需显式向下转型:(Node | t.CPtr)(ptr)
# ============================================================
class Node(linkedlist.LinkedNode):
value: t.CInt
# ============================================================
# 测试 1append + child_count
# ============================================================
def test_append():
testcheck.section("Test 1: append")
root: Node = Node()
a: Node = Node()
b: Node = Node()
c: Node = Node()
a.value = 10
b.value = 20
c.value = 30
root.append(a)
root.append(b)
root.append(c)
testcheck.check(root.child_count == 3,
"append count=3",
"append count fail")
# 验证顺序LinkedNode* → Node* 显式向下转型)
c1: Node | t.CPtr = (Node | t.CPtr)(root.child)
c2: Node | t.CPtr = (Node | t.CPtr)(c1.next)
c3: Node | t.CPtr = (Node | t.CPtr)(c2.next)
testcheck.check(c1.value == 10 and c2.value == 20 and c3.value == 30,
"order 10,20,30",
"order fail")
# ============================================================
# 测试 2双向链表 prev 指针
# ============================================================
def test_prev_link():
testcheck.section("Test 2: prev pointer (doubly linked)")
root: Node = Node()
a: Node = Node()
b: Node = Node()
a.value = 1
b.value = 2
root.append(a)
root.append(b)
# b.prev 应指向 a
bp: Node | t.CPtr = (Node | t.CPtr)(b.prev)
testcheck.check(bp is not None and bp.value == 1,
"b.prev.value=1",
"prev link fail")
# a.prev 应为 None第一个子节点
testcheck.check(a.prev is None,
"a.prev=None",
"first prev fail")
# ============================================================
# 测试 3last_child 指针O(1) 追加验证)
# ============================================================
def test_last_child():
testcheck.section("Test 3: last_child pointer")
root: Node = Node()
a: Node = Node()
b: Node = Node()
a.value = 100
b.value = 200
root.append(a)
lc: Node | t.CPtr = (Node | t.CPtr)(root.last_child)
testcheck.check(lc is not None and lc.value == 100,
"last_child=100 after 1 append",
"last_child fail 1")
root.append(b)
lc = (Node | t.CPtr)(root.last_child)
testcheck.check(lc is not None and lc.value == 200,
"last_child=200 after 2 append",
"last_child fail 2")
# ============================================================
# 测试 4detachO(1) 摘除)
# ============================================================
def test_remove():
testcheck.section("Test 4: detach (O(1) unlink)")
root: Node = Node()
a: Node = Node()
b: Node = Node()
c: Node = Node()
a.value = 1
b.value = 2
c.value = 3
root.append(a)
root.append(b)
root.append(c)
# 摘除中间的 b
b.detach()
testcheck.check(root.child_count == 2,
"count=2 after detach",
"detach count fail")
# a.next 应直接指向 c
an: Node | t.CPtr = (Node | t.CPtr)(a.next)
testcheck.check(an is not None and an.value == 3,
"a.next.value=3",
"detach link fail")
# c.prev 应指向 a
cp: Node | t.CPtr = (Node | t.CPtr)(c.prev)
testcheck.check(cp is not None and cp.value == 1,
"c.prev.value=1",
"detach prev fail")
# b 的链接应清空
testcheck.check(b.parent is None and b.next is None and b.prev is None,
"b cleared",
"b not cleared")
# ============================================================
# 测试 5remove_child
# ============================================================
def test_remove_child():
testcheck.section("Test 5: remove_child")
root: Node = Node()
a: Node = Node()
b: Node = Node()
a.value = 10
b.value = 20
root.append(a)
root.append(b)
root.remove_child(a)
testcheck.check(root.child_count == 1,
"count=1 after remove_child",
"remove_child count fail")
fc: Node | t.CPtr = (Node | t.CPtr)(root.child)
testcheck.check(fc is not None and fc.value == 20,
"first child=20",
"remove_child first fail")
# ============================================================
# 测试 6prepend + insert_before + insert_after
# ============================================================
def test_insert_ops():
testcheck.section("Test 6: prepend/insert_before/insert_after")
root: Node = Node()
a: Node = Node()
b: Node = Node()
c: Node = Node()
d: Node = Node()
a.value = 1
b.value = 2
c.value = 3
d.value = 4
root.append(a) # [1]
root.append(c) # [1, 3]
root.insert_before(c, b) # [1, 2, 3] 在 c 前插入 b
root.insert_after(a, d) # [1, 4, 2, 3] 在 a 后插入 d
# 遍历验证顺序
cur: Node | t.CPtr = (Node | t.CPtr)(root.child)
v0: t.CInt = cur.value
cur = (Node | t.CPtr)(cur.next)
v1: t.CInt = cur.value
cur = (Node | t.CPtr)(cur.next)
v2: t.CInt = cur.value
cur = (Node | t.CPtr)(cur.next)
v3: t.CInt = cur.value
testcheck.check(v0 == 1 and v1 == 4 and v2 == 2 and v3 == 3,
"order 1,4,2,3",
"insert order fail")
testcheck.check(root.child_count == 4,
"count=4",
"insert count fail")
# ============================================================
# 测试 7child_at + count_children
# 注意Viper 中 Node() 是栈分配,循环内 n 会被复用(同一地址),
# 导致所有子节点指向同一内存。必须用独立变量保证各节点地址不同。
# ============================================================
def test_index_access():
testcheck.section("Test 7: child_at + count_children")
root: Node = Node()
n0: Node = Node()
n1: Node = Node()
n2: Node = Node()
n3: Node = Node()
n4: Node = Node()
n0.value = 0
n1.value = 10
n2.value = 20
n3.value = 30
n4.value = 40
root.append(n0)
root.append(n1)
root.append(n2)
root.append(n3)
root.append(n4)
# child_at
r0: Node | t.CPtr = (Node | t.CPtr)(root.child_at(0))
r2: Node | t.CPtr = (Node | t.CPtr)(root.child_at(2))
r4: Node | t.CPtr = (Node | t.CPtr)(root.child_at(4))
r5: Node | t.CPtr = (Node | t.CPtr)(root.child_at(5))
testcheck.check(r0 is not None and r0.value == 0,
"child_at(0)=0",
"child_at 0 fail")
testcheck.check(r2 is not None and r2.value == 20,
"child_at(2)=20",
"child_at 2 fail")
testcheck.check(r4 is not None and r4.value == 40,
"child_at(4)=40",
"child_at 4 fail")
testcheck.check(r5 is None,
"child_at(5)=None",
"child_at 5 fail")
# count_children
cc: t.CSizeT = root.count_children()
testcheck.check(cc == 5,
"count_children=5",
"count_children fail")
# ============================================================
# 测试 8has_children + first_sibling/last_sibling
# ============================================================
def test_sibling_traverse():
testcheck.section("Test 8: has_children + sibling traverse")
root: Node = Node()
testcheck.check(root.has_children() == 0,
"empty has_children=0",
"has_children empty fail")
a: Node = Node()
b: Node = Node()
c: Node = Node()
a.value = 1
b.value = 2
c.value = 3
root.append(a)
root.append(b)
root.append(c)
testcheck.check(root.has_children() == 1,
"has_children=1",
"has_children fail")
# 从 b 出发找头尾兄弟
fs: Node | t.CPtr = (Node | t.CPtr)(b.first_sibling())
ls: Node | t.CPtr = (Node | t.CPtr)(b.last_sibling())
testcheck.check(fs is not None and fs.value == 1,
"first_sibling=1",
"first_sibling fail")
testcheck.check(ls is not None and ls.value == 3,
"last_sibling=3",
"last_sibling fail")
# ============================================================
# 测试 9unlink断开所有连接
# ============================================================
def test_unlink():
testcheck.section("Test 9: unlink")
root: Node = Node()
a: Node = Node()
b: Node = Node()
a.value = 1
b.value = 2
root.append(a)
root.append(b)
# unlink a从兄弟链摘除 + 断开父子链接
a.unlink()
testcheck.check(a.next is None and a.prev is None and a.parent is None,
"a links cleared",
"a links not cleared")
testcheck.check(a.child is None and a.last_child is None and a.child_count == 0,
"a child cleared",
"a child not cleared")
# root 应只剩 b
testcheck.check(root.child_count == 1,
"root count=1 after unlink",
"root count fail")
# ============================================================
# 测试 10SListNode 单向链表OOP 方法)
# ============================================================
class SNode(linkedlist.SListNode):
value: t.CInt
def test_slist():
testcheck.section("Test 10: SListNode (singly linked, OOP)")
n0: SNode = SNode()
n1: SNode = SNode()
n2: SNode = SNode()
n0.value = 100
n1.value = 200
n2.value = 300
# append (O(n)) — 直接用 n0 作为 head
head: linkedlist.SListNode | t.CPtr = n0
head = head.append(n1)
head = head.append(n2)
# count
testcheck.check(head.count() == 3,
"count=3",
"count fail")
# at
a0: SNode | t.CPtr = (SNode | t.CPtr)(head.at(0))
a1: SNode | t.CPtr = (SNode | t.CPtr)(head.at(1))
a2: SNode | t.CPtr = (SNode | t.CPtr)(head.at(2))
a3: SNode | t.CPtr = (SNode | t.CPtr)(head.at(3))
testcheck.check(a0 is not None and a0.value == 100,
"at(0)=100",
"at 0 fail")
testcheck.check(a1 is not None and a1.value == 200,
"at(1)=200",
"at 1 fail")
testcheck.check(a2 is not None and a2.value == 300,
"at(2)=300",
"at 2 fail")
testcheck.check(a3 is None,
"at(3)=None",
"at 3 fail")
# remove (移除中间节点 n1)
head = head.remove(n1)
testcheck.check(head.count() == 2,
"after remove count=2",
"remove count fail")
testcheck.check(n1.Next is None,
"n1.Next cleared",
"n1.Next not cleared")
# 移除后 a0.Next 应指向 n2
a0b: SNode | t.CPtr = (SNode | t.CPtr)(a0.Next)
testcheck.check(a0b is not None and a0b.value == 300,
"after remove a0.Next=300",
"a0.Next fail")
# append_after (O(1))
n3: SNode = SNode()
n3.value = 400
tail: linkedlist.SListNode | t.CPtr = n2.append_after(n3)
testcheck.check(tail is n3,
"append_after returns n3",
"append_after fail")
testcheck.check(head.count() == 3,
"after append count=3",
"append count fail")
# ============================================================
# 测试 11viperlib.sprintf *args 转发
# ============================================================
def test_sprintf_vararg():
testcheck.section("Test 11: viperlib.sprintf *args forwarding")
# 测试 %d 单参数
buf: t.CChar | t.CPtr = stdlib.malloc(32)
if buf is None: return
buf[0] = 0
viperlib.sprintf(buf, "key%d", 42)
testcheck.check(string.strcmp(buf, "key42") == 0,
"sprintf key42",
"sprintf key%d fail")
# 测试无参数
buf2: t.CChar | t.CPtr = stdlib.malloc(32)
if buf2 is None: return
buf2[0] = 0
viperlib.sprintf(buf2, "hello")
testcheck.check(string.strcmp(buf2, "hello") == 0,
"sprintf hello",
"sprintf no-arg fail")
# 测试多参数
buf3: t.CChar | t.CPtr = stdlib.malloc(32)
if buf3 is None: return
buf3[0] = 0
viperlib.sprintf(buf3, "%d+%d=%d", 1, 2, 3)
testcheck.check(string.strcmp(buf3, "1+2=3") == 0,
"sprintf 1+2=3",
"sprintf multi-arg fail")
# ============================================================
# 测试 12泛型 GSListNode[T] + GSList[T]
#
# 验证 4 个技术点(为 llvmlite 简化铺路):
# 1. 递归泛型 class GNode(GSListNode[GNode]):
# 2. @t.NoVTable + 泛型组合GNode 无 vptr字段展平
# 3. 泛型类作字段类型 lst: GSList[GNode]
# 4. 泛型方法继承 lst.append(n) / lst.count() / lst.at(i)
# GSList[T] 的方法在特化 GSList[GNode] 后可用)
#
# 注:编译器暂不支持 模块.泛型类[T]() 跨模块构造,故本地定义。
# ============================================================
@t.NoVTable
class GSListNode[T]:
Next: T | t.CPtr
@t.NoVTable
class GSList[T]:
Head: T | t.CPtr
Tail: T | t.CPtr
Count: t.CSizeT
def __init__(self):
self.Head = None
self.Tail = None
self.Count = 0
def append(self, node: T):
if node is None: return
node.Next = None
if self.Head is None:
self.Head = node
else:
self.Tail.Next = node
self.Tail = node
self.Count += 1
def count(self) -> t.CSizeT:
return self.Count
def at(self, index: t.CSizeT) -> T | t.CPtr:
if self.Head is None: return None
cur: T | t.CPtr = self.Head
i: t.CSizeT = 0
while cur is not None:
if i == index: return cur
i += 1
cur = cur.Next
return None
class GNode(GSListNode[GNode]):
Value: t.CInt
def test_generic_slist():
testcheck.section("Test 12: Generic GSListNode[T] + GSList[T]")
# 技术点 3: 泛型类作字段类型 + 构造
lst: GSList[GNode] | t.CPtr = GSList[GNode]()
# 技术点 1+2: 递归泛型 + NoVTable 组合GNode 定义在上方)
n0: GNode = GNode()
n1: GNode = GNode()
n2: GNode = GNode()
n0.Value = 10
n1.Value = 20
n2.Value = 30
# 技术点 4: 泛型方法继承
lst.append(n0)
lst.append(n1)
lst.append(n2)
# count (O(1))
testcheck.check(lst.count() == 3,
"GSList.count()=3",
"GSList count fail")
# at (O(n)) — 返回 GNode|CPtr无需向下转型
a0: GNode | t.CPtr = lst.at(0)
a1: GNode | t.CPtr = lst.at(1)
a2: GNode | t.CPtr = lst.at(2)
a3: GNode | t.CPtr = lst.at(3)
testcheck.check(a0 is not None and a0.Value == 10,
"GSList.at(0)=10",
"GSList at 0 fail")
testcheck.check(a1 is not None and a1.Value == 20,
"GSList.at(1)=20",
"GSList at 1 fail")
testcheck.check(a2 is not None and a2.Value == 30,
"GSList.at(2)=30",
"GSList at 2 fail")
testcheck.check(a3 is None,
"GSList.at(3)=None",
"GSList at 3 fail")
# Next 字段强类型a0.Next 直接是 GNode|CPtr无需转型
testcheck.check(a0.Next is a1,
"a0.Next is a1 (strong type)",
"a0.Next fail")
testcheck.check(a1.Next is a2,
"a1.Next is a2 (strong type)",
"a1.Next fail")
testcheck.check(a2.Next is None,
"a2.Next is None",
"a2.Next fail")
def main() -> t.CInt:
testcheck.begin("NoVTableTest: linkedlist 库(@t.NoVTable OOP 方法 + 字段展平继承)")
test_append()
test_prev_link()
test_last_child()
test_remove()
test_remove_child()
test_insert_ops()
test_index_access()
test_sibling_traverse()
test_unlink()
test_slist()
test_sprintf_vararg()
test_generic_slist()
return testcheck.end()