chore(ViperOS): 合并落库内核侧在途改动并移除 vpsdk wiki 拷贝

VKernel / vpsdk / Apps / Libs 共 30 个源文件:内核与 SDK 侧的新语法适配及编译修正(含 bootinfo.vp / main.vp 位宽改 uint64、gfx.vp 前向引用改指针、devfs.vp 指针解引用赋值、elf.vp 跨模块函数取值等)。删除 vpsdk/wiki/*.md(14 文件,约 -8100 行):与仓库根 wiki 重复的拷贝,统一以根 wiki 为唯一来源。
This commit is contained in:
TermiNexus committed 2026-10-07 19:04:33 +08:00
1 parent 753512ecf7
commit 5b4bab59cc
44 files changed
+483 -8155

No files matched your search

+78 -84
View File
@@ -10,23 +10,23 @@ from stdint import *
import memhub
import t, c
GW: t.CDefine = 160
GH: t.CDefine = 90
GW_F: t.CDefine = 160.0
GH_F: t.CDefine = 90.0
MAX_STEPS: t.CDefine = 100
ESCAPE_R: t.CDefine = 60.0
DISK_IN: t.CDefine = 2.6
DISK_OUT: t.CDefine = 11.0
CAM_DIST: t.CDefine = 22.0
CAM_ELEV: t.CDefine = 9.0
FOVF: t.CDefine = 0.55
YIELD_ROWS: t.CDefine = 4
V3_POOL_SIZE: t.CDefine = 8192
V3_POOL_BYTES: t.CDefine = V3_POOL_SIZE * 24 + 512
define GW = 160
define GH = 90
define GW_F = 160.0
define GH_F = 90.0
define MAX_STEPS = 100
define ESCAPE_R = 60.0
define DISK_IN = 2.6
define DISK_OUT = 11.0
define CAM_DIST = 22.0
define CAM_ELEV = 9.0
define FOVF = 0.55
define YIELD_ROWS = 4
define V3_POOL_SIZE = 8192
define V3_POOL_BYTES = V3_POOL_SIZE * 24 + 512
_v3_mem: t.CArray[uint8, V3_POOL_BYTES]
_v3_pool: memhub.MemPool | t.CPtr
_v3_pool: memhub.MemPool*
_fb_mem: t.CArray[uint32, GW * GH]
class V3:
@@ -34,39 +34,39 @@ class V3:
y: t.CFloat64T
z: t.CFloat64T
def __new__() -> 'V3' | t.CPtr:
return uint64(_v3_pool.alloc(24))
def __new__() -> V3*:
return V3*(_v3_pool.alloc(24))
def __init__(self, x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T):
self.x = x
self.y = y
self.z = z
def __add__(self, b: 'V3' | t.CPtr) -> 'V3' | t.CPtr:
def __add__(self, b: V3*) -> V3*:
return V3(self.x + b.x, self.y + b.y, self.z + b.z)
def __sub__(self, b: 'V3' | t.CPtr) -> 'V3' | t.CPtr:
def __sub__(self, b: V3*) -> V3*:
return V3(self.x - b.x, self.y - b.y, self.z - b.z)
def __mul__(self, s: t.CFloat64T) -> 'V3' | t.CPtr:
def __mul__(self, s: t.CFloat64T) -> V3*:
return V3(self.x * s, self.y * s, self.z * s)
def __neg__(self) -> 'V3' | t.CPtr:
def __neg__(self) -> V3*:
return V3(-self.x, -self.y, -self.z)
def dot(self, b: 'V3' | t.CPtr) -> t.CFloat64T:
def dot(self, b: V3*) -> t.CFloat64T:
return self.x * b.x + self.y * b.y + self.z * b.z
def cross(self, b: 'V3' | t.CPtr) -> 'V3' | t.CPtr:
def cross(self, b: V3*) -> V3*:
return V3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def nrm(self) -> 'V3' | t.CPtr:
def nrm(self) -> V3*:
l: t.CFloat64T = vm.sqrt(self.dot(self))
if l > 1e-12:
return self * (1.0 / l)
return V3(0.0, 0.0, 0.0)
def lerp(self, b: 'V3' | t.CPtr, t_val: t.CFloat64T) -> 'V3' | t.CPtr:
def lerp(self, b: V3*, t_val: t.CFloat64T) -> V3*:
return self * (1.0 - t_val) + b * t_val
_g_cam: t.CArray[t.CFloat64T, 3]
@@ -74,10 +74,10 @@ _g_fwd: t.CArray[t.CFloat64T, 3]
_g_right: t.CArray[t.CFloat64T, 3]
_g_up: t.CArray[t.CFloat64T, 3]
CAM: V3 | t.CPtr
FWD: V3 | t.CPtr
RIGHT: V3 | t.CPtr
UP: V3 | t.CPtr
CAM: V3*
FWD: V3*
RIGHT: V3*
UP: V3*
def v3_pool_reset():
_v3_pool.reset()
@@ -94,26 +94,26 @@ def smoothstep(a: t.CFloat64T, b: t.CFloat64T, x: t.CFloat64T) -> t.CFloat64T:
def setup_camera():
global CAM, FWD, RIGHT, UP
e: t.CFloat64T = CAM_ELEV * 3.14159265358979323846 / 180.0
CAM = c.Addr(_g_cam)
CAM = &_g_cam
CAM.x = CAM_DIST * vm.cos(e)
CAM.y = CAM_DIST * vm.sin(e)
CAM.z = 0.0
tmp0: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
FWD = c.Addr(_g_fwd)
tmp1: V3 | t.CPtr = tmp0 - CAM
n1: V3 | t.CPtr = tmp1.nrm()
tmp0: V3* = V3(0.0, 0.0, 0.0)
FWD = &_g_fwd
tmp1: V3* = tmp0 - CAM
n1: V3* = tmp1.nrm()
FWD.x = n1.x
FWD.y = n1.y
FWD.z = n1.z
tmp2: V3 | t.CPtr = V3(0.0, 1.0, 0.0)
RIGHT = c.Addr(_g_right)
tmp3: V3 | t.CPtr = FWD.cross(tmp2)
tmp4: V3 | t.CPtr = tmp3.nrm()
tmp2: V3* = V3(0.0, 1.0, 0.0)
RIGHT = &_g_right
tmp3: V3* = FWD.cross(tmp2)
tmp4: V3* = tmp3.nrm()
RIGHT.x = tmp4.x
RIGHT.y = tmp4.y
RIGHT.z = tmp4.z
UP = c.Addr(_g_up)
tmp5: V3 | t.CPtr = RIGHT.cross(FWD)
UP = &_g_up
tmp5: V3* = RIGHT.cross(FWD)
UP.x = tmp5.x
UP.y = tmp5.y
UP.z = tmp5.z
@@ -122,10 +122,9 @@ def hash3(x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T) -> t.CFloat64T:
n: t.CFloat64T = vm.sin(x * 127.1 + y * 311.7 + z * 74.7) * 43758.5453
return n - vm.floor(n)
def stars(d: V3 | t.CPtr) -> V3 | t.CPtr:
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
i: int = 0
while i < 3:
def stars(d: V3*) -> V3*:
col: V3* = V3(0.0, 0.0, 0.0)
for i in range(3):
s: t.CFloat64T = 80.0 + t.CFloat64T(i) * 90.0
px: t.CFloat64T = d.x * s
py: t.CFloat64T = d.y * s
@@ -141,7 +140,7 @@ def stars(d: V3 | t.CPtr) -> V3 | t.CPtr:
d2: t.CFloat64T = fx * fx + fy * fy + fz * fz
br: t.CFloat64T = (h - 0.991) / 0.009 * vm.exp(-d2 * 9.0) * 1.4
tv: t.CFloat64T = hash3(iy, iz, ix)
tint: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
tint: V3* = V3(0.0, 0.0, 0.0)
if tv < 0.3:
tint = V3(0.7, 0.8, 1.0)
elif tv > 0.8:
@@ -149,10 +148,9 @@ def stars(d: V3 | t.CPtr) -> V3 | t.CPtr:
else:
tint = V3(1.0, 1.0, 1.0)
col = col + tint * br
i += 1
return col
def disk_shade(cp: V3 | t.CPtr, rr: t.CFloat64T, gT: t.CFloat64T) -> V3 | t.CPtr:
def disk_shade(cp: V3*, rr: t.CFloat64T, gT: t.CFloat64T) -> V3*:
tt: t.CFloat64T = (rr - DISK_IN) / (DISK_OUT - DISK_IN)
edge: t.CFloat64T = smoothstep(0.0, 0.07, tt) * smoothstep(0.0, 0.18, 1.0 - tt)
ang: t.CFloat64T = vm.atan2(cp.z, cp.x)
@@ -162,31 +160,30 @@ def disk_shade(cp: V3 | t.CPtr, rr: t.CFloat64T, gT: t.CFloat64T) -> V3 | t.CPtr
n2: t.CFloat64T = 0.5 + 0.5 * vm.sin(ph * 13.0 + rr * 0.8 + 1.7)
dens: t.CFloat64T = (0.35 + 0.65 * n) * (0.55 + 0.45 * n2)
bright: t.CFloat64T = (0.45 + 1.7 * vm.pow(1.0 - tt, 1.8)) * edge
vdir: V3 | t.CPtr = V3(-cp.z, 0.0, cp.x).nrm()
vdir: V3* = V3(-cp.z, 0.0, cp.x).nrm()
beta: t.CFloat64T = 0.46 / vm.sqrt(rr)
to_cam: V3 | t.CPtr = (CAM - cp).nrm()
to_cam: V3* = (CAM - cp).nrm()
mu: t.CFloat64T = vdir.dot(to_cam)
dop: t.CFloat64T = 1.0 / (1.0 - beta * mu)
beam: t.CFloat64T = vm.pow(dop, 3.0)
c1: V3 | t.CPtr = V3(1.0, 0.92, 0.68)
c2: V3 | t.CPtr = V3(1.0, 0.42, 0.13)
base: V3 | t.CPtr = c1.lerp(c2, tt)
c1: V3* = V3(1.0, 0.92, 0.68)
c2: V3* = V3(1.0, 0.42, 0.13)
base: V3* = c1.lerp(c2, tt)
base.z += (dop - 1.0) * 0.35
base.x -= (dop - 1.0) * 0.05
inten: t.CFloat64T = bright * dens * beam * 1.25
return base * inten
def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
def trace(dir_v: V3*, gT: t.CFloat64T) -> V3*:
v3_pool_reset()
pos: V3 | t.CPtr = V3(CAM.x, CAM.y, CAM.z)
vel: V3 | t.CPtr = V3(dir_v.x, dir_v.y, dir_v.z)
hvec: V3 | t.CPtr = pos.cross(vel)
pos: V3* = V3(CAM.x, CAM.y, CAM.z)
vel: V3* = V3(dir_v.x, dir_v.y, dir_v.z)
hvec: V3* = pos.cross(vel)
h2: t.CFloat64T = hvec.dot(hvec)
T: t.CFloat64T = 1.0
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
col: V3* = V3(0.0, 0.0, 0.0)
i: int = 0
while i < MAX_STEPS:
for i in range(MAX_STEPS):
r2: t.CFloat64T = pos.dot(pos)
r: t.CFloat64T = vm.sqrt(r2)
if r < 1.0:
@@ -199,34 +196,34 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
r5: t.CFloat64T = vm.pow(r2, 2.5)
coeff: t.CFloat64T = -1.5 * h2 / r5
k1v: V3 | t.CPtr = pos * coeff
k2p_a: V3 | t.CPtr = vel + k1v * (dt * 0.5)
k2v_a: V3 | t.CPtr = pos + vel * (dt * 0.5)
k1v: V3* = pos * coeff
k2p_a: V3* = vel + k1v * (dt * 0.5)
k2v_a: V3* = pos + vel * (dt * 0.5)
r2_a: t.CFloat64T = k2v_a.dot(k2v_a)
coeff_a: t.CFloat64T = -1.5 * h2 / vm.pow(r2_a, 2.5)
k2v: V3 | t.CPtr = k2v_a * coeff_a
k2v: V3* = k2v_a * coeff_a
k3p_a: V3 | t.CPtr = vel + k2v * (dt * 0.5)
k3v_a: V3 | t.CPtr = pos + k2p_a * (dt * 0.5)
k3p_a: V3* = vel + k2v * (dt * 0.5)
k3v_a: V3* = pos + k2p_a * (dt * 0.5)
r2_b: t.CFloat64T = k3v_a.dot(k3v_a)
coeff_b: t.CFloat64T = -1.5 * h2 / vm.pow(r2_b, 2.5)
k3v: V3 | t.CPtr = k3v_a * coeff_b
k3v: V3* = k3v_a * coeff_b
k4p_a: V3 | t.CPtr = vel + k3v * dt
k4v_a: V3 | t.CPtr = pos + k3p_a * dt
k4p_a: V3* = vel + k3v * dt
k4v_a: V3* = pos + k3p_a * dt
r2_c: t.CFloat64T = k4v_a.dot(k4v_a)
coeff_c: t.CFloat64T = -1.5 * h2 / vm.pow(r2_c, 2.5)
k4v: V3 | t.CPtr = k4v_a * coeff_c
k4v: V3* = k4v_a * coeff_c
npos: V3 | t.CPtr = pos + (vel + k2p_a * 2.0 + k3p_a * 2.0 + k4p_a) * (dt / 6.0)
nvel: V3 | t.CPtr = vel + (k1v + k2v * 2.0 + k3v * 2.0 + k4v) * (dt / 6.0)
npos: V3* = pos + (vel + k2p_a * 2.0 + k3p_a * 2.0 + k4p_a) * (dt / 6.0)
nvel: V3* = vel + (k1v + k2v * 2.0 + k3v * 2.0 + k4v) * (dt / 6.0)
if pos.y * npos.y < 0.0:
f: t.CFloat64T = pos.y / (pos.y - npos.y)
cp: V3 | t.CPtr = pos.lerp(npos, f)
cp: V3* = pos.lerp(npos, f)
rr: t.CFloat64T = vm.sqrt(cp.x * cp.x + cp.z * cp.z)
if rr > DISK_IN and rr < DISK_OUT:
emit: V3 | t.CPtr = disk_shade(cp, rr, gT)
emit: V3* = disk_shade(cp, rr, gT)
col = col + emit * T
a: t.CFloat64T = clmp(smoothstep(0.0, 0.07, (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * smoothstep(0.0, 0.18, 1.0 - (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * 0.92, 0.0, 1.0)
T = T * (1.0 - a)
@@ -235,15 +232,14 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
pos = npos
vel = nvel
i += 1
return col
def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
aspect: t.CFloat64T = GW_F / GH_F
sx: t.CFloat64T = (2.0 * (t.CFloat64T(px) + 0.5) / GW_F - 1.0) * aspect * FOVF
sy: t.CFloat64T = (1.0 - 2.0 * (t.CFloat64T(py) + 0.5) / GH_F) * FOVF
dir_v: V3 | t.CPtr = (FWD + RIGHT * sx + UP * sy).nrm()
c: V3 | t.CPtr = trace(dir_v, gT)
dir_v: V3* = (FWD + RIGHT * sx + UP * sy).nrm()
c: V3* = trace(dir_v, gT)
ex: t.CFloat64T = 1.15
c = c * ex
c.x = c.x / (1.0 + c.x)
@@ -260,19 +256,19 @@ def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
global _v3_pool
_v3_pool = memhub.MemPool(c.Addr(_v3_mem), V3_POOL_BYTES)
_v3_pool = memhub.MemPool(&_v3_mem, V3_POOL_BYTES)
setup_camera()
root: vpui.Tk = vpui.Tk()
root.title("Gargantua")
root.set_style(window.STYLE_WIN7)
root.bg_color = uint32(0x000000)
master: vpui.Tk | t.CPtr = c.Addr(root)
master: vpui.Tk* = &root
canvas: vpui.FBCanvas = vpui.FBCanvas(master, GW, GH)
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
fb: UINT32PTR = c.Addr(_fb_mem)
fb: UINT32PTR = &_fb_mem
string.memset(fb, 0, GW * GH * 4)
canvas.set_fb(fb, GW, GH)
@@ -283,7 +279,7 @@ def _start() -> int | t.CExport:
evt: window.InputEvent
while window.is_active(root.win_id):
result: int = window.poll_event(c.Addr(evt))
result: int = window.poll_event(&evt)
if result != 0:
if evt.type == window.EVENT_TYPE_PING:
window.flush(root.win_id)
@@ -296,16 +292,14 @@ def _start() -> int | t.CExport:
if rendered == 0:
y: int = 0
while y < GH:
x: int = 0
while x < GW:
for x in range(GW):
pixel: uint32 = shade_pixel(x, y, gT)
fb[y * GW + x] = pixel
x += 1
y += 1
if y % YIELD_ROWS == 0:
root.redraw()
process.yield_cpu()
result2: int = window.poll_event(c.Addr(evt))
result2: int = window.poll_event(&evt)
if result2 != 0:
if evt.type == window.EVENT_TYPE_PING:
window.flush(root.win_id)
+6 -6
View File
@@ -7,8 +7,8 @@ import vpsdk.stdio as stdio
from stdint import *
import t, c
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
@__attribute__(section(".text.startup"), aligned(16))
export def _start() -> int:
base: uint64 = dynlib.load_so("/LIBS/SLOG.SO")
if base != 0:
dynlib.so_call1("log_info", "Hello from dynamic library!")
@@ -18,7 +18,7 @@ def _start() -> int | t.CExport:
root.set_style(window.STYLE_WIN7)
root.geometry(290, 30, 300, 200)
root.bg_color = uint32(0x1E1E32)
master: vpui.Tk | t.CPtr = c.Addr(root)
master: vpui.Tk* = &root
entry: vpui.Entry = vpui.Entry(master, 260, 28)
root.pack(0, vpui.PACK_TOP, vpui.FILL_X, 0, 20, 10)
@@ -26,14 +26,14 @@ def _start() -> int | t.CExport:
root.pack(1, vpui.PACK_BOTTOM, 0, 0, 0, 10)
def _on_submit() -> int:
text: t.CConst | str = entry.get()
text: const str = entry.get()
result.config(text)
entry.delete(0, -1)
return 0
lbl: vpui.Label = vpui.Label(master, "Name:", 0xFFFFFFFF)
root.pack(2, vpui.PACK_TOP, 0, 0, 20, 0)
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", c.Addr(_on_submit))
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", &_on_submit)
root.pack(3, vpui.PACK_TOP, 0, 0, 0, 10)
root2: vpui.Tk = vpui.Tk()
@@ -41,7 +41,7 @@ def _start() -> int | t.CExport:
root2.set_style(window.STYLE_WIN10)
root2.geometry(200, 50, 300, 150)
root2.bg_color = uint32(0x1E1E32)
master2: vpui.Tk | t.CPtr = c.Addr(root2)
master2: vpui.Tk* = &root2
lbl2: vpui.Label = vpui.Label(master2, "This window will NOT respond!", 0xFFFFFFFF)
lbl2.place(10, 10)
+25 -25
View File
@@ -4,11 +4,11 @@ import string
import t, c
PI: t.CDefine = float(3.14159265358979323846)
define PI = float(3.14159265358979323846)
SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
define SPHERE_SLICES = (24 * 1)
define SPHERE_STACKS = (16 * 1)
define SIN_WAVE_GRID = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@@ -22,35 +22,35 @@ class Vec3:
self.x = x
self.y = y
self.z = z
def Sub(self, b: 'Vec3') -> 'Vec3':
def Sub(self, b: Vec3) -> Vec3*:
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
def Cross(self, b: 'Vec3') -> 'Vec3':
def Cross(self, b: Vec3) -> Vec3*:
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def Dot(self, b: 'Vec3') -> float:
def Dot(self, b: Vec3) -> float:
return self.x * b.x + self.y * b.y + self.z * b.z
def Norm(self) -> 'Vec3':
def Norm(self) -> Vec3*:
l = vipermath.sqrtf(self.Dot(self))
return Vec3(self.x / l, self.y / l, self.z / l)
class Mat4:
m: t.CArray[t.CArray[float, 4], 4]
def Mat4_Identity() -> Mat4:
def Mat4_Identity() -> Mat4*:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
string.memset(&m, 0, Mat4.__sizeof__())
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
return m
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4*:
res: Mat4 = Mat4()
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
string.memset(&res, 0, Mat4.__sizeof__())
for i in range(4):
for j in range(4):
for k in range(4):
res.m[i][j] += a.m[i][k] * b.m[k][j]
return res
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3*:
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
@@ -59,15 +59,15 @@ def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
x /= w; y /= w; z /= w
return Vec3(x, y, z)
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4*:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
string.memset(&m, 0, Mat4.__sizeof__())
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
m.m[0][0] = f / aspect; m.m[1][1] = f
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
return m
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4*:
zaxis: Vec3 = eye.Sub(target).Norm()
xaxis: Vec3 = up.Cross(zaxis).Norm()
yaxis: Vec3 = zaxis.Cross(xaxis)
@@ -78,12 +78,12 @@ def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
m.m[3][3] = 1
return m
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
def Mat4_Translate(x: float, y: float, z: float) -> Mat4*:
m: Mat4 = Mat4_Identity()
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
return m
def Mat4_RotateY(a: float) -> Mat4:
def Mat4_RotateY(a: float) -> Mat4*:
m: Mat4 = Mat4_Identity()
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
@@ -93,10 +93,10 @@ def Mat4_RotateY(a: float) -> Mat4:
@t.Object
class Surface:
fb: UINT32PTR
zb: float | t.CPtr
zb: float*
w: int
h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
def __init__(self, fb: UINT32PTR, zb: float*, w: int, h: int):
self.fb = fb
self.zb = zb
self.w = w
@@ -105,11 +105,11 @@ class Surface:
@t.Object
class Renderer:
_fb: UINT32PTR
_zb: float | t.CPtr
_zb: float*
_w: int
_h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
def __init__(self, fb: UINT32PTR, zb: float*, w: int, h: int):
self._fb = fb
self._zb = zb
self._w = w
@@ -117,7 +117,7 @@ class Renderer:
def Clear(self, color: uint32):
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
zb: float* = self._zb
size: int = self._w * self._h
for i in range(size):
fb[i] = color
@@ -143,7 +143,7 @@ class Renderer:
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
zb: float* = self._zb
w: int = self._w
h: int = self._h
@@ -221,7 +221,7 @@ class Renderer:
class Scene3D:
renderer: Renderer
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
def __init__(self, fb: UINT32PTR, zb: float*, w: int, h: int):
self.renderer = Renderer(fb, zb, w, h)
def Render(self, time: float):
+14 -14
View File
@@ -9,21 +9,21 @@ from stdint import *
import gfx
import t, c
SCENE_W: t.CDefine = 640
SCENE_H: t.CDefine = 360
define SCENE_W = 640
define SCENE_H = 360
_zbuf_mem: t.CArray[uint8, SCENE_W * SCENE_H * 8]
_fb_mem: t.CArray[uint32, SCENE_W * SCENE_H]
_root_ptr: vpui.Tk | t.CPtr
_canvas_ptr: vpui.FBCanvas | t.CPtr
_s3d_ptr: gfx.Scene3D | t.CPtr
_root_ptr: vpui.Tk*
_canvas_ptr: vpui.FBCanvas*
_s3d_ptr: gfx.Scene3D*
_time_val: float = float(0.0)
def _render_thread(arg: t.CPtr):
root: vpui.Tk | t.CPtr = _root_ptr
canvas: vpui.FBCanvas | t.CPtr = _canvas_ptr
s3d: gfx.Scene3D | t.CPtr = _s3d_ptr
root: vpui.Tk* = _root_ptr
canvas: vpui.FBCanvas* = _canvas_ptr
s3d: gfx.Scene3D* = _s3d_ptr
while root.winfo_exists():
s3d.Render(_time_val)
_time_val += float(0.02)
@@ -36,15 +36,15 @@ def _start() -> int | t.CExport:
root.title("3D Scene")
root.set_style(window.STYLE_WIN11)
root.bg_color = uint32(0x0F0F19)
master: vpui.Tk | t.CPtr = c.Addr(root)
master: vpui.Tk* = &root
canvas: vpui.FBCanvas = vpui.FBCanvas(master, SCENE_W, SCENE_H)
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
zbuf: float | t.CPtr = c.Addr(_zbuf_mem)
zbuf: float* = &_zbuf_mem
string.memset(zbuf, 0, SCENE_W * SCENE_H * 8)
fb: UINT32PTR = c.Addr(_fb_mem)
fb: UINT32PTR = &_fb_mem
string.memset(fb, 0, SCENE_W * SCENE_H * 4)
canvas.set_fb(fb, SCENE_W, SCENE_H)
@@ -54,9 +54,9 @@ def _start() -> int | t.CExport:
global _root_ptr, _canvas_ptr, _s3d_ptr
_root_ptr = c.Addr(root)
_canvas_ptr = c.Addr(canvas)
_s3d_ptr = c.Addr(s3d)
_root_ptr = &root
_canvas_ptr = &canvas
_s3d_ptr = &s3d
process.thread_create(_render_thread, None)
+70 -70
View File
@@ -17,14 +17,14 @@ def _start() -> int | t.CExport:
root.set_style(window.STYLE_WIN7)
root.geometry(80, 30, 640, 480)
root.bg_color = uint32(0x0C0C0C)
master: vpui.Tk | t.CPtr = c.Addr(root)
master: vpui.Tk* = &root
def _sdbg(msg: str):
_syscall._syscall1(uint64(18), uint64(msg))
_sdbg("[term] start\n")
_cwd: t.CArray[t.CChar, 64]
_cwd: t.CArray[char, 64]
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
@@ -63,130 +63,130 @@ def _start() -> int | t.CExport:
if term.scroll_offset > max_off: term.scroll_offset = max_off
term._update_scrollbar()
sbar.command = c.Addr(_on_scroll)
sbar.command = &_on_scroll
def _startswith(s: str, prefix: str) -> int:
plen: t.CSizeT = string.strlen(prefix)
plen: sizet = string.strlen(prefix)
if string.strncmp(s, prefix, plen) == 0:
return 1
return 0
def _build_path(out: str, out_size: int, rel: str):
if c.Deref(rel) == 47:
if *rel == 47:
string.strncpy(out, rel, out_size - 1)
else:
i: int = 0
for i in range(63):
ch: t.CChar = _cwd[i]
ch: char = _cwd[i]
c.DerefAs(out + i, ch)
if ch == 0: break
cwd_len: int = i
if cwd_len > 0 and _cwd[cwd_len - 1] != 47:
c.DerefAs(out + cwd_len, t.CChar(47))
c.DerefAs(out + cwd_len, char(47))
cwd_len += 1
j: int = 0
for j in range(out_size - 1 - cwd_len):
ch2: t.CChar = c.Deref(rel + j)
ch2: char = *(rel + j)
c.DerefAs(out + cwd_len + j, ch2)
if ch2 == 0: break
c.DerefAs(out + out_size - 1, t.CChar(0))
c.DerefAs(out + out_size - 1, char(0))
def _print_dir_entry(name: str, is_dir: int):
buf: t.CArray[t.CChar, 80]
buf: t.CArray[char, 80]
j: int = 0
for j in range(78):
ch: t.CChar = c.Deref(name + j)
ch: char = *(name + j)
buf[j] = ch
if ch == 0: break
if is_dir and j < 78:
buf[j] = 47
j += 1
buf[j] = 0
term.insert_ptr(c.Addr(buf[0]))
term.insert_ptr(&buf[0])
def _cmd_cd(path: str):
if path is None or c.Deref(path) == 0:
if path is None or *path == 0:
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
return
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
dd: int = fs.opendir(c.Addr(full[0]))
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
dd: int = fs.opendir(&full[0])
if dd < 0:
term.insert("Error: dir not found")
return
fs.closedir(dd)
string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63)
string.strncpy(&_cwd[0], &full[0], 63)
_cwd[63] = 0
def _cmd_ls():
dd: int = fs.opendir(c.Addr(_cwd[0]))
dd: int = fs.opendir(&_cwd[0])
if dd < 0:
term.insert("Error: cannot open dir")
return
info: t.CArray[t.CChar, 320]
string.memset(c.Addr(info[0]), 0, 320)
info: t.CArray[char, 320]
string.memset(&info[0], 0, 320)
while True:
result: int = fs.readdir(dd, c.Addr(info[0]))
result: int = fs.readdir(dd, &info[0])
if result != 0: break
attr_val: uint8 = uint8(c.Deref(c.Addr(info[4])))
attr_val: uint8 = uint8(*(&info[4]))
name_off: int = 16
name_ptr: str = c.Addr(info[name_off])
if c.Deref(name_ptr) == 0: break
if c.Deref(name_ptr) == 46:
if c.Deref(name_ptr + 1) == 0:
string.memset(c.Addr(info[0]), 0, 320)
name_ptr: str = &info[name_off]
if *name_ptr == 0: break
if *name_ptr == 46:
if *(name_ptr + 1) == 0:
string.memset(&info[0], 0, 320)
continue
if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0:
string.memset(c.Addr(info[0]), 0, 320)
if *(name_ptr + 1) == 46 and *(name_ptr + 2) == 0:
string.memset(&info[0], 0, 320)
continue
if (attr_val & 0x10) != 0:
_print_dir_entry(name_ptr, 1)
else:
_print_dir_entry(name_ptr, 0)
string.memset(c.Addr(info[0]), 0, 320)
string.memset(&info[0], 0, 320)
fs.closedir(dd)
def _cmd_cat(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
fd: int = fs.open(&full[0], fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
buf: t.CArray[t.CChar, 80]
buf: t.CArray[char, 80]
while True:
string.memset(c.Addr(buf[0]), 0, 80)
n: int = fs.read(fd, c.Addr(buf[0]), 78)
string.memset(&buf[0], 0, 80)
n: int = fs.read(fd, &buf[0], 78)
if n <= 0: break
if n > 78: n = 78
buf[n] = 0
term.insert_ptr(c.Addr(buf[0]))
term.insert_ptr(&buf[0])
fs.close(fd)
def _cmd_mkdir(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: int = fs.mkdir(c.Addr(full[0]))
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
result: int = fs.mkdir(&full[0])
if result < 0:
term.insert("Error: mkdir failed")
else:
term.insert("Directory created")
def _cmd_rm(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: int = fs.remove(c.Addr(full[0]))
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
result: int = fs.remove(&full[0])
if result < 0:
term.insert("Error: remove failed")
else:
term.insert("Removed")
def _cmd_touch(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT)
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
fd: int = fs.open(&full[0], fs.O_WRONLY | fs.O_CREAT)
if fd < 0:
term.insert("Error: touch failed")
return
@@ -199,22 +199,22 @@ def _start() -> int | t.CExport:
term.insert("Compiler: TransPyC")
def _cmd_hexdump(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
fd: int = fs.open(&full[0], fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
offset: int = 0
buf: t.CArray[t.CChar, 16]
buf: t.CArray[char, 16]
while True:
string.memset(c.Addr(buf[0]), 0, 16)
n: int = fs.read(fd, c.Addr(buf[0]), 16)
string.memset(&buf[0], 0, 16)
n: int = fs.read(fd, &buf[0], 16)
if n <= 0: break
if n > 16: n = 16
line: t.CArray[t.CChar, 80]
string.memset(c.Addr(line[0]), 0, 80)
viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset)
line: t.CArray[char, 80]
string.memset(&line[0], 0, 80)
viperlib.snprintf(&line[0], 80, "%08x: ", offset)
pos: int = 10
j: int = 0
for j in range(16):
@@ -223,14 +223,14 @@ def _start() -> int | t.CExport:
hi: int = int(ub >> 4)
lo: int = int(ub & 0xF)
if hi < 10:
line[pos] = t.CChar(48 + hi)
line[pos] = char(48 + hi)
else:
line[pos] = t.CChar(65 + hi - 10)
line[pos] = char(65 + hi - 10)
pos += 1
if lo < 10:
line[pos] = t.CChar(48 + lo)
line[pos] = char(48 + lo)
else:
line[pos] = t.CChar(65 + lo - 10)
line[pos] = char(65 + lo - 10)
pos += 1
else:
line[pos] = 32
@@ -247,27 +247,27 @@ def _start() -> int | t.CExport:
for j in range(n):
b2: uint32 = uint32(buf[j]) & 0xFF
if b2 >= 32 and b2 < 127:
line[pos] = t.CChar(b2)
line[pos] = char(b2)
else:
line[pos] = 46
pos += 1
line[pos] = 0
term.insert_ptr(c.Addr(line[0]))
term.insert_ptr(&line[0])
offset += n
fs.close(fd)
def _cmd_run(path: str, blocking: int):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
pid: int = process.spawn(c.Addr(full[0]), blocking)
full: t.CArray[char, 256]
_build_path(&full[0], 256, path)
pid: int = process.spawn(&full[0], blocking)
if pid < 0:
term.insert("Error: cannot spawn")
elif blocking:
term.insert("Process exited")
else:
msg: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid)
term.insert_ptr(c.Addr(msg[0]))
msg: t.CArray[char, 32]
viperlib.snprintf(&msg[0], 32, "Spawned pid=%d", pid)
term.insert_ptr(&msg[0])
def _on_command() -> int:
_sdbg("[cmd] enter\n")
@@ -290,7 +290,7 @@ def _start() -> int | t.CExport:
elif string.samestr(text, "about"):
term.insert("ViperOS - A tiny OS in Viper lang")
elif string.samestr(text, "pwd"):
term.insert_ptr(c.Addr(_cwd[0]))
term.insert_ptr(&_cwd[0])
elif string.samestr(text, "ls"):
_cmd_ls()
elif string.samestr(text, "cd"):
@@ -316,11 +316,11 @@ def _start() -> int | t.CExport:
elif _startswith(text, "runb "):
_cmd_run(text + 5, 1)
else:
if text is not None and c.Deref(text) != 0:
if text is not None and *text != 0:
term.insert("Unknown command. Type 'help'.")
return 0
term.on_command = c.Addr(_on_command)
term.on_command = &_on_command
root.mainloop()
process.exit(0)
+2 -2
View File
@@ -1,12 +1,12 @@
import vpsdk.syscall as syscall
import t, c
export def log_info(msg: t.CConst | str):
export def log_info(msg: const str):
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger] "))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
export def log_warn(msg: t.CConst | str):
export def log_warn(msg: const str):
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger:WARN] "))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
+1 -1
View File
@@ -1,7 +1,7 @@
import t
import vpsdk.syscall as syscall
UINT32PTR: t.CTypedef = uint32 | t.CPtr
UINT32PTR: t.CTypedef = uint32*
def color_rgb(r: uint8, g: uint8, b: uint8) -> uint32:
return uint32(r) | (uint32(g) << 8) | (uint32(b) << 16)
+15 -15
View File
@@ -14,20 +14,20 @@ MEMORY_TYPE_BAD_MEMORY: uint64 = 8
class memory_map_entry:
type: uint
_pad: uint
physical_start: ulong
virtual_start: ulong
num_pages: ulong
attribute: ulong
physical_start: uint64
virtual_start: uint64
num_pages: uint64
attribute: uint64
class bootinfo:
MemmapAddr: ulong
MemmapSize: ulong
MemmapDescSize: ulong
kernel_PhysAddr: ulong
framebuffer_addr: ulong
framebuffer_size: ulong
framebuffer_width: ulong
framebuffer_height: ulong
framebuffer_pitch: ulong
framebuffer_format: ulong
system_table: ulong
MemmapAddr: uint64
MemmapSize: uint64
MemmapDescSize: uint64
kernel_PhysAddr: uint64
framebuffer_addr: uint64
framebuffer_size: uint64
framebuffer_width: uint64
framebuffer_height: uint64
framebuffer_pitch: uint64
framebuffer_format: uint64
system_table: uint64
+1 -1
View File
@@ -202,7 +202,7 @@ class _DevFSObject:
string.strcpy(file_ptr.name, file_name)
file_ptr.private_data = private_data
file_ptr.parent_dir = dir_ptr
files[file_count] = file_ptr
files[file_count] = *file_ptr
else:
new_file: devfs_file* = &files[file_count]
string.strcpy(new_file.name, file_name)
@@ -45,7 +45,7 @@ def _write_boot_sector(pdrv: uint8, total_sectors: uint64, sec_per_clus: uint8,
buf[64] = 0x80
buf[66] = 0x29
types._write32(&buf[0], 67, vol_id)
vol_label: t.CArray[t.CChar, 11]
vol_label: t.CArray[char, 11]
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
@@ -3,14 +3,14 @@ import fat32_types as types
import fat32_diskio as diskio
MAX_VOLUMES: t.CDefine = 4
MAX_PARTITIONS: t.CDefine = 4
define MAX_VOLUMES = 4
define MAX_PARTITIONS = 4
MBR_SIGNATURE: t.CDefine = 0xAA55
PART_TYPE_FAT32: t.CDefine = 0x0C
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
PART_TYPE_FAT16: t.CDefine = 0x06
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
define MBR_SIGNATURE = 0xAA55
define PART_TYPE_FAT32 = 0x0C
define PART_TYPE_FAT32_LBA = 0x0B
define PART_TYPE_FAT16 = 0x06
define PART_TYPE_FAT16_LBA = 0x0E
class partition_entry:
boot_flag: uint8
@@ -720,8 +720,8 @@ class volinfo:
match_found: int = 1
i: int
for i in range(11):
a: t.CChar = self.win[entry_offset_in_sector + i]
b: t.CChar = sfn[i]
a: char = self.win[entry_offset_in_sector + i]
b: char = sfn[i]
if a >= 'a' and a <= 'z': a = a - 32
if b >= 'a' and b <= 'z': b = b - 32
if a != b:
@@ -87,7 +87,7 @@ def read_scancode() -> uint8:
asm.sti()
return code
def scancode_to_ascii(scancode: uint8) -> t.CChar:
def scancode_to_ascii(scancode: uint8) -> char:
code: uint8 = scancode & ~uint8(KEY_RELEASED)
if code >= 128: return '\0'
shifted: bool = (shift_l or shift_r) != 0
+1 -1
View File
@@ -82,7 +82,7 @@ def irq_handler() -> int:
pack_count += 1
return 0
def read_packet(out: mouse_packet | t.CPtr) -> int:
def read_packet(out: mouse_packet*) -> int:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
+1 -1
View File
@@ -76,7 +76,7 @@ def delay(count: int):
def isTransmitEmpty(port: uint16) -> int:
return asm.inb(port + UART_LSR) & UART_LSR_THRE
def putchar(port: uint16, cr: t.CChar):
def putchar(port: uint16, cr: char):
# 1. 处理换行符:串口终端需要\r\n才会正确换行,只发\n会错位
if cr == '\n':
# 直接发送\r,避免递归调用
+2 -2
View File
@@ -35,7 +35,7 @@ def init() -> int:
return -2
kbd_initialized = 1
serial.puts("[usb_kbd] initialized\n")
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
kbd_slot_id = uhci.register_int_callback(&_on_int_complete)
if kbd_slot_id < 0:
serial.puts("[usb_kbd] register callback failed\n")
kbd_initialized = 0
@@ -106,7 +106,7 @@ def poll() -> int:
if kbd_buf_count > 0: return 1
return 0
def read_event(out: usb_kbd_event | t.CPtr) -> int:
def read_event(out: usb_kbd_event*) -> int:
global kbd_buf_head, kbd_buf_count
if kbd_buf_count == 0: return -1
out.modifier = kbd_buf[kbd_buf_head].modifier
+19 -19
View File
@@ -5,9 +5,9 @@ import string
define PI: float = 3.14159265358979323846
SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
define SPHERE_SLICES = (24 * 1)
define SPHERE_STACKS = (16 * 1)
define SIN_WAVE_GRID = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@@ -20,26 +20,26 @@ class Vec3:
self.x = x
self.y = y
self.z = z
def Sub(self, b: 'Vec3') -> 'Vec3':
def Sub(self, b: Vec3) -> Vec3*:
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
def Cross(self, b: 'Vec3') -> 'Vec3':
def Cross(self, b: Vec3) -> Vec3*:
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def Dot(self, b: 'Vec3') -> float:
def Dot(self, b: Vec3) -> float:
return self.x * b.x + self.y * b.y + self.z * b.z
def Norm(self) -> 'Vec3':
def Norm(self) -> Vec3*:
l = math.sqrtf(self.Dot(self))
return Vec3(self.x / l, self.y / l, self.z / l)
class Mat4:
m: [4][4]float
def Mat4_Identity() -> Mat4:
def Mat4_Identity() -> Mat4*:
m: Mat4 = Mat4()
string.memset(&m, 0, Mat4.__sizeof__())
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
return m
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4*:
res: Mat4 = Mat4()
string.memset(&res, 0, Mat4.__sizeof__())
for i in range(4):
@@ -48,7 +48,7 @@ def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
res.m[i][j] += a.m[i][k] * b.m[k][j]
return res
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3*:
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
@@ -57,7 +57,7 @@ def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
x /= w; y /= w; z /= w
return Vec3(x, y, z)
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4*:
m: Mat4 = Mat4()
string.memset(&m, 0, Mat4.__sizeof__())
f: float = float(1.0) / math.tanf(fov / float(2.0))
@@ -65,7 +65,7 @@ def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
return m
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4*:
zaxis: Vec3 = eye.Sub(target).Norm()
xaxis: Vec3 = up.Cross(zaxis).Norm()
yaxis: Vec3 = zaxis.Cross(xaxis)
@@ -76,12 +76,12 @@ def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
m.m[3][3] = 1
return m
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
def Mat4_Translate(x: float, y: float, z: float) -> Mat4*:
m: Mat4 = Mat4_Identity()
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
return m
def Mat4_RotateY(a: float) -> Mat4:
def Mat4_RotateY(a: float) -> Mat4*:
m: Mat4 = Mat4_Identity();
m.m[0][0] = math.cosf(a); m.m[0][2] = math.sinf(a)
m.m[2][0] = -math.sinf(a); m.m[2][2] = math.cosf(a)
@@ -259,12 +259,12 @@ class Scene3D:
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
]
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
for i in range(8): v[i] = *Mat4_MulVec(mvp, &v[i])
faces: t.CArray[t.CArray[int, 3], 12] = [
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
]
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
for i in range(12): self.renderer.DrawTriangle(&v[faces[i][0]], &v[faces[i][1]], &v[faces[i][2]], col)
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: uint32):
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
@@ -277,9 +277,9 @@ class Scene3D:
v[1] = Vec3(center.x+radius*math.sinf(theta1)*math.cosf(phi2), center.y+radius*math.cosf(theta1), center.z+radius*math.sinf(theta1)*math.sinf(phi2))
v[2] = Vec3(center.x+radius*math.sinf(theta2)*math.cosf(phi1), center.y+radius*math.cosf(theta2), center.z+radius*math.sinf(theta2)*math.sinf(phi1))
v[3] = Vec3(center.x+radius*math.sinf(theta2)*math.cosf(phi2), center.y+radius*math.cosf(theta2), center.z+radius*math.sinf(theta2)*math.sinf(phi2))
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
for k in range(4): v[k] = *Mat4_MulVec(mvp, &v[k])
self.renderer.DrawTriangle(&v[0], &v[1], &v[2], col)
self.renderer.DrawTriangle(&v[1], &v[3], &v[2], col)
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
+1 -1
View File
@@ -527,7 +527,7 @@ def _resolve_symbol(name: const str) -> rawptr:
if cmp_name[i] != "serial_puts"[i]:
Matched = 0
if Matched != 0:
return &serial.puts
return serial.puts
return None
_so_strtab: rawptr
+3 -7
View File
@@ -150,11 +150,9 @@ class ViperKernel:
if BootInfo is not None:
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
fb_pages: uint64 = (fb_size + uint64(0xFFF)) >> uint64(12)
fpi: uint64 = 0
while fpi < fb_pages:
for fpi in range(fb_pages):
fva: uint64 = uint64(fb) + fpi * uint64(0x1000)
paging.MapPage(fva, fva, paging.PTE_WRITABLE | paging.PTE_PCD)
fpi += 1
mm.init(BootInfo.MemmapAddr, BootInfo.MemmapSize, BootInfo.MemmapDescSize, BootInfo.framebuffer_addr, fb_size)
pt_pool_buf: rawptr = mm.malloc(uint64(513) * uint64(4096))
paging.init_pool(pt_pool_buf, uint64(513) * uint64(4096))
@@ -212,8 +210,7 @@ class ViperKernel:
apps_res: int = fat32.opendir("/APPS", &dp_apps)
if apps_res == 0:
serial.puts("[main] APPS dir listing:\n")
ac: int = 0
while ac < 20:
for ac in range(20):
ai: fat32_types.fileinfo
ar: int = fat32.readdir(&dp_apps, &ai)
if ar != 0: break
@@ -221,7 +218,6 @@ class ViperKernel:
ae: [300]char
viperlib.snprintf(&ae, 300, " %s size=%lu\n", &ai.fname[0], ai.file_size)
serial.puts(&ae)
ac = ac + 1
fat32.closedir(&dp_apps)
else:
serial.puts("[main] APPS dir not found\n")
@@ -347,7 +343,7 @@ VKP: ViperKernel*
@__attribute__(section(".text.startup"), aligned(16), stackrealign)
def _start() -> int:
global VKP, BootInfo
saved_rdi: ulong
saved_rdi: uint64
__asm__(f"mov {asmout(saved_rdi, ASM_DESCR.OUTPUT_REG)}, rdi",
op = [ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RDI])
asm.BSSClean()
+2 -6
View File
@@ -114,10 +114,8 @@ def MapPage(VirtAddr: uint64, PhysAddr: uint64, flags: uint64):
inherit_flags: uint64 = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
pt = AllocPage()
if not pt: return
split_i: int = 0
while split_i < 512:
for split_i in range(512):
pt.entries[split_i] = (big_phys + uint64(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd.entries[PdIndex] = (uint64(pt) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
# PD entry exists as a regular PT (e.g. cloned identity mapping).
@@ -280,10 +278,8 @@ def MakeRangeRO(vaddr_start: uint64, vaddr_end: uint64):
if not pt_split:
va += 0x1000
continue
split_i: int = 0
while split_i < 512:
for split_i in range(512):
pt_split.entries[split_i] = (big_phys + uint64(split_i) * uint64(0x1000)) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd_r.entries[pd_idx] = (uint64(pt_split) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (pd_r.entries[pd_idx] & PTE_USER)
__asm__(f"invlpg [{asminp(va, ASM_DESCR.REG_ANY)}]")
# 分裂后落入下方 4KB 常规路径,继续清当前页 W 位
+1 -3
View File
@@ -99,8 +99,7 @@ class Scheduler:
if next_tid >= s.thread_count:
next_tid = 0
found: int = 0
count: int = 0
while count < s.thread_count:
for count in range(s.thread_count):
st: int = s.threads[next_tid].state
if st == THREAD_READY or st == THREAD_RUNNING:
found = 1
@@ -108,7 +107,6 @@ class Scheduler:
next_tid += 1
if next_tid >= s.thread_count:
next_tid = 0
count += 1
if found == 0:
_yield_lock = 0
if _if_saved:
+1 -3
View File
@@ -1820,10 +1820,8 @@ def desktop_thread(arg: rawptr) -> int:
# 校验和不变 → 疑似 printf/串口输出伪影,走另一条排查线。
_perf_fmt_str: str = "[perf] fps=%u wall=%lu work=%lu mouse=%lu kbd=%lu render=%lu(bg=%lu win=%lu cur=%lu fb=%lu) dirty=%d vsync=%d sh=%d dc=%d ki=%lu mi=%lu\n"
_fmt_sum: uint32 = 0
_fi: int = 0
while _fi < 110:
for _fi in range(110):
_fmt_sum = _fmt_sum + uint32(uint8(_perf_fmt_str[_fi]))
_fi += 1
_chk_buf: [48]char
viperlib.snprintf(&_chk_buf, 48, "[chk] sum=%u\n", _fmt_sum)
serial.puts(&_chk_buf)
+2 -2
View File
@@ -1,8 +1,8 @@
import t, c
from . import syscall as syscall
def load_so(path: t.CConst | t.CChar | t.CPtr) -> uint64:
def load_so(path: const str) -> uint64:
return syscall._syscall1(uint64(syscall.LOAD_SO), uint64(path))
def so_call1(sym_name: t.CConst | t.CChar | t.CPtr, arg1: t.CPtr) -> int:
def so_call1(sym_name: const str, arg1: t.CPtr) -> int:
return int(syscall._syscall2(uint64(syscall.SO_CALL1), uint64(sym_name), uint64(arg1)))
+19 -19
View File
@@ -1,22 +1,22 @@
import t, c
from . import syscall as syscall
O_RDONLY: t.CDefine = 0x01
O_WRONLY: t.CDefine = 0x02
O_RDWR: t.CDefine = 0x03
O_CREAT: t.CDefine = 0x04
O_TRUNC: t.CDefine = 0x08
O_APPEND: t.CDefine = 0x30
define O_RDONLY = 0x01
define O_WRONLY = 0x02
define O_RDWR = 0x03
define O_CREAT = 0x04
define O_TRUNC = 0x08
define O_APPEND = 0x30
SEEK_SET: t.CDefine = 0
SEEK_CUR: t.CDefine = 1
SEEK_END: t.CDefine = 2
define SEEK_SET = 0
define SEEK_CUR = 1
define SEEK_END = 2
DT_UNKNOWN: t.CDefine = 0
DT_FILE: t.CDefine = 1
DT_DIR: t.CDefine = 2
define DT_UNKNOWN = 0
define DT_FILE = 1
define DT_DIR = 2
def open(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> int:
def open(path: const str, flags: uint32) -> int:
return int(syscall._syscall3(uint64(syscall.OPEN), uint64(path), uint64(flags), 0))
def close(fd: int) -> int:
@@ -37,13 +37,13 @@ def tell(fd: int) -> uint32:
def fsize(fd: int) -> uint32:
return uint32(syscall._syscall1(uint64(syscall.SIZE), uint64(fd)))
def mkdir(path: t.CConst | t.CChar | t.CPtr) -> int:
def mkdir(path: const str) -> int:
return int(syscall._syscall3(uint64(syscall.MKDIR), uint64(path), 0, 0))
def remove(path: t.CConst | t.CChar | t.CPtr) -> int:
def remove(path: const str) -> int:
return int(syscall._syscall3(uint64(syscall.REMOVE), uint64(path), 0, 0))
def opendir(path: t.CConst | t.CChar | t.CPtr) -> int:
def opendir(path: const str) -> int:
return int(syscall._syscall3(uint64(syscall.OPENDIR), uint64(path), 0, 0))
def readdir(dd: int, info: t.CPtr) -> int:
@@ -52,7 +52,7 @@ def readdir(dd: int, info: t.CPtr) -> int:
def closedir(dd: int) -> int:
return int(syscall._syscall1(uint64(syscall.CLOSEDIR), uint64(dd)))
def stat(path: t.CConst | t.CChar | t.CPtr, info: t.CPtr) -> int:
def stat(path: const str, info: t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.STAT), uint64(path), uint64(info), 0))
@t.Object
@@ -128,13 +128,13 @@ class DirIO:
def is_closed(self) -> int:
return self._closed
def open_file(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> FileIO | t.CPtr:
def open_file(path: const str, flags: uint32) -> FileIO*:
fd: int = open(path, flags)
if fd < 0:
return None
return FileIO(fd, flags)
def open_dir(path: t.CConst | t.CChar | t.CPtr) -> DirIO | t.CPtr:
def open_dir(path: const str) -> DirIO*:
dd: int = opendir(path)
if dd < 0:
return None
+5 -5
View File
@@ -7,7 +7,7 @@ def exit(code: int):
def yield_cpu():
syscall._syscall2(uint64(syscall.WAIT_WINDOW), uint64(0), uint64(2))
def spawn(path: t.CConst | t.CChar | t.CPtr, blocking: int = 0) -> int:
def spawn(path: const str, blocking: int = 0) -> int:
return int(syscall._syscall2(uint64(syscall.SPAWN), uint64(path), uint64(blocking)))
def thread_create(func: t.CPtr, arg: t.CPtr = None) -> int:
@@ -42,9 +42,9 @@ class Thread:
@t.Object
class Process:
_pid: int
_path: t.CArray[t.CChar, 128]
_path: t.CArray[char, 128]
def __init__(self, path: t.CConst | t.CChar | t.CPtr):
def __init__(self, path: const str):
self._pid = -1
i: int = 0
for ch in path:
@@ -54,11 +54,11 @@ class Process:
self._path[i] = 0
def start(self) -> int:
self._pid = spawn(c.Addr(self._path[0]), 0)
self._pid = spawn(&self._path[0], 0)
return self._pid
def start_blocking(self) -> int:
self._pid = spawn(c.Addr(self._path[0]), 1)
self._pid = spawn(&self._path[0], 1)
return self._pid
def get_pid(self) -> int:
+5 -5
View File
@@ -10,13 +10,13 @@ import viperlib
# syscall 输出到串口;exit 走 EXIT syscall 通知内核销毁本进程窗口。
# ============================================================
export def printf(fmt: t.CConst | str, *args) -> int:
export def printf(fmt: const str, *args) -> int:
"""格式化输出到串口(SERIAL_PUTS syscall),返回输出字节数"""
if fmt is None:
return 0
buf: t.CArray[t.CChar, 1024]
n: int = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(c.Addr(buf)))
buf: t.CArray[char, 1024]
n: int = viperlib.vsnprintf(&buf, 1024, fmt, args)
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(&buf))
return n
export def exit(status: int):
@@ -24,7 +24,7 @@ export def exit(status: int):
_syscall._syscall1(uint64(_syscall.EXIT), uint64(status))
export def fflush(stream: t.CConst | t.CPtr) -> int:
export def fflush(stream: const t.CPtr) -> int:
"""刷新输出流:串口/控制台输出都是直写,无缓冲可刷,空操作返回 0
覆盖 libc fflush 的裸机缺失(includes/memhub.vp 的诊断/终止路径 call @fflush);
+14 -14
View File
@@ -2,7 +2,7 @@ import vpsdk.syscall as _sc
import string
import t, c
HEAP_BLOCK_MAGIC: t.CDefine = 0x48454150
define HEAP_BLOCK_MAGIC = 0x48454150
@t.Object
class _heap_hdr:
@@ -15,45 +15,45 @@ def _heap_init():
global _heap_inited
_heap_inited = 1
def malloc(size: t.CSizeT) -> t.CPtr | t.CExport:
def malloc(size: sizet) -> t.CPtr | t.CExport:
global _heap_inited
if size == 0: return None
if _heap_inited == 0:
_heap_init()
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
total: t.CSizeT = hdr_size + size
hdr_size: sizet = _heap_hdr.__sizeof__()
total: sizet = hdr_size + size
ptr: uint64 = _sc._syscall1(uint64(_sc.SYSCALL_MMAP), uint64(total))
if ptr == 0: return None
hdr: _heap_hdr | t.CPtr = t.CPtr(ptr)
hdr: _heap_hdr* = t.CPtr(ptr)
hdr.magic = HEAP_BLOCK_MAGIC
hdr.size = uint32(size)
return t.CPtr(ptr + hdr_size)
def free(ptr: t.CPtr) -> t.CExport:
if ptr is None: return
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CPtr(uint64(ptr) - hdr_size)
hdr_size: sizet = _heap_hdr.__sizeof__()
hdr: _heap_hdr* = t.CPtr(uint64(ptr) - hdr_size)
if hdr.magic != HEAP_BLOCK_MAGIC: return
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CPtr | t.CExport:
total: t.CSizeT = nmemb * size
def calloc(nmemb: sizet, size: sizet) -> t.CPtr | t.CExport:
total: sizet = nmemb * size
p: t.CPtr = malloc(total)
if p:
string.memset(p, 0, total)
return p
def realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.CExport:
def realloc(ptr: t.CPtr, size: sizet) -> t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CPtr(uint64(ptr) - hdr_size)
hdr_size: sizet = _heap_hdr.__sizeof__()
hdr: _heap_hdr* = t.CPtr(uint64(ptr) - hdr_size)
if hdr.magic != HEAP_BLOCK_MAGIC: return None
old_size: t.CSizeT = hdr.size
old_size: sizet = hdr.size
new_ptr: t.CPtr = malloc(size)
if new_ptr is None: return None
copy_size: t.CSizeT = old_size if old_size < size else size
copy_size: sizet = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
+40 -40
View File
@@ -1,48 +1,48 @@
import t, c
CREATE_WINDOW: t.CDefine = 1
DRAW_TEXT: t.CDefine = 2
EXIT: t.CDefine = 3
OPEN: t.CDefine = 4
CLOSE: t.CDefine = 5
READ: t.CDefine = 6
WRITE: t.CDefine = 7
SEEK: t.CDefine = 8
TELL: t.CDefine = 9
SIZE: t.CDefine = 10
MKDIR: t.CDefine = 11
REMOVE: t.CDefine = 12
OPENDIR: t.CDefine = 13
READDIR: t.CDefine = 14
CLOSEDIR: t.CDefine = 15
STAT: t.CDefine = 16
WAIT_WINDOW: t.CDefine = 17
SERIAL_PUTS: t.CDefine = 18
LOAD_SO: t.CDefine = 19
SO_CALL1: t.CDefine = 20
GET_WINBUF: t.CDefine = 21
WIN_FLUSH: t.CDefine = 22
POLL_EVENT: t.CDefine = 23
SET_CURSOR: t.CDefine = 24
define CREATE_WINDOW = 1
define DRAW_TEXT = 2
define EXIT = 3
define OPEN = 4
define CLOSE = 5
define READ = 6
define WRITE = 7
define SEEK = 8
define TELL = 9
define SIZE = 10
define MKDIR = 11
define REMOVE = 12
define OPENDIR = 13
define READDIR = 14
define CLOSEDIR = 15
define STAT = 16
define WAIT_WINDOW = 17
define SERIAL_PUTS = 18
define LOAD_SO = 19
define SO_CALL1 = 20
define GET_WINBUF = 21
define WIN_FLUSH = 22
define POLL_EVENT = 23
define SET_CURSOR = 24
YIELD: t.CDefine = 25
SET_TITLE: t.CDefine = 26
SET_GEOMETRY: t.CDefine = 27
SPAWN: t.CDefine = 28
MMAP: t.CDefine = 29
MUNMAP: t.CDefine = 30
SET_RESIZABLE: t.CDefine = 31
GET_WIN_SIZE: t.CDefine = 32
THREAD_CREATE: t.CDefine = 33
define YIELD = 25
define SET_TITLE = 26
define SET_GEOMETRY = 27
define SPAWN = 28
define MMAP = 29
define MUNMAP = 30
define SET_RESIZABLE = 31
define GET_WIN_SIZE = 32
define THREAD_CREATE = 33
# SYSCALL_* 别名(vpsdk.stdlib 等模块引用;数值与内核 VKernel/intr/syscall.vp 一致)
SYSCALL_MMAP: t.CDefine = 29
define SYSCALL_MMAP = 29
def _syscall0(num: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11])
return ret
@@ -52,7 +52,7 @@ def _syscall1(num: uint64, a1: uint64) -> uint64:
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI])
return ret
@@ -63,7 +63,7 @@ def _syscall2(num: uint64, a1: uint64, a2: uint64) -> uint64:
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI])
@@ -76,7 +76,7 @@ def _syscall3(num: uint64, a1: uint64, a2: uint64, a3: uint64) -> uint64:
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX])
@@ -91,7 +91,7 @@ def _syscall5(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: u
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
@@ -108,7 +108,7 @@ def _syscall6(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: u
mov r9, {c.AsmInp(a6, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
out=[asmout(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
+109 -141
View File
@@ -5,38 +5,38 @@ from stdint import *
import t, c
import string
TITLE_H: t.CDefine = 32
MAX_WIDGETS: t.CDefine = 24
CHAR_W: t.CDefine = 8
CHAR_H: t.CDefine = 16
define TITLE_H = 32
define MAX_WIDGETS = 24
define CHAR_W = 8
define CHAR_H = 16
WIDGET_LABEL: t.CDefine = 1
WIDGET_BUTTON: t.CDefine = 2
WIDGET_ENTRY: t.CDefine = 3
WIDGET_TEXT: t.CDefine = 4
WIDGET_SCROLLBAR: t.CDefine = 5
WIDGET_FBCANVAS: t.CDefine = 6
define WIDGET_LABEL = 1
define WIDGET_BUTTON = 2
define WIDGET_ENTRY = 3
define WIDGET_TEXT = 4
define WIDGET_SCROLLBAR = 5
define WIDGET_FBCANVAS = 6
VERTICAL: t.CDefine = 1
HORIZONTAL: t.CDefine = 2
TEXT_MAX_LINES: t.CDefine = 200
define VERTICAL = 1
define HORIZONTAL = 2
define TEXT_MAX_LINES = 200
PACK_TOP: t.CDefine = 1
PACK_BOTTOM: t.CDefine = 2
PACK_LEFT: t.CDefine = 3
PACK_RIGHT: t.CDefine = 4
define PACK_TOP = 1
define PACK_BOTTOM = 2
define PACK_LEFT = 3
define PACK_RIGHT = 4
FILL_NONE: t.CDefine = 0
FILL_X: t.CDefine = 1
FILL_Y: t.CDefine = 2
FILL_BOTH: t.CDefine = 3
define FILL_NONE = 0
define FILL_X = 1
define FILL_Y = 2
define FILL_BOTH = 3
STICKY_NONE: t.CDefine = 0
STICKY_W: t.CDefine = 1
STICKY_E: t.CDefine = 2
STICKY_N: t.CDefine = 4
STICKY_S: t.CDefine = 8
STICKY_NSEW: t.CDefine = 15
define STICKY_NONE = 0
define STICKY_W = 1
define STICKY_E = 2
define STICKY_N = 4
define STICKY_S = 8
define STICKY_NSEW = 15
_g_wl_type: t.CArray[int, MAX_WIDGETS]
_g_wl_side: t.CArray[int, MAX_WIDGETS]
@@ -51,10 +51,10 @@ _g_wl_colspan: t.CArray[int, MAX_WIDGETS]
_g_wl_sticky: t.CArray[int, MAX_WIDGETS]
_g_layout_init: int
_hex_tbl: t.CArray[t.CChar, 17] = "0123456789ABCDEF"
_hex_buf: t.CArray[t.CChar, 20] = "0000000000000000000"
_hex_tbl: t.CArray[char, 17] = "0123456789ABCDEF"
_hex_buf: t.CArray[char, 20] = "0000000000000000000"
def _serial_puts(s: t.CConst | t.CChar | t.CPtr):
def _serial_puts(s: const str):
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(s))
def _ptr_to_hex(val: uint64, buf: t.CPtr):
@@ -243,7 +243,7 @@ font: t.CArray[t.CArray[uint8, 16], 256] = [
{0x00,0x00,0x70,0x13,0x24,0x26,0x24,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
]
def _draw_char(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, ch: t.CChar, color: uint32):
def _draw_char(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, ch: char, color: uint32):
if not buf: return
if bw <= 0 or bh <= 0: return
ci: uint8 = uint8(ch)
@@ -257,23 +257,21 @@ def _draw_char(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, ch: t.CChar, co
if row == 0:
fy += 1
continue
fx: int = 0
while fx < CHAR_W:
for fx in range(CHAR_W):
if row & (0x80 >> fx):
px: int = x + fx
if px >= 0 and px < bw:
buf[(y + fy) * bw + px] = color
fx += 1
fy += 1
def _draw_text(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, s: t.CConst | str, color: uint32):
def _draw_text(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, s: const str, color: uint32):
if not buf: return
if bw <= 0 or bh <= 0: return
cx: int = x
cy: int = y
i: int = 0
while True:
ch: t.CChar = s[i]
ch: char = s[i]
if ch == 0: break
if ch == 10:
cy += 16
@@ -283,8 +281,8 @@ def _draw_text(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, s: t.CConst | s
cx += 8
i += 1
def _register_widget(master: t.CPtr, widget: Widget | t.CPtr) -> int:
tk: Tk | t.CPtr = t.CType(master, Tk, t.CPtr)
def _register_widget(master: t.CPtr, widget: Widget*) -> int:
tk: Tk* = t.CType(master, Tk, t.CPtr)
idx: int = tk.widget_count
if idx < MAX_WIDGETS:
tk.widgets[idx] = widget
@@ -307,7 +305,7 @@ class Widget:
def draw(self, fb: UINT32PTR, fw: int, fh: int):
pass
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
return 0
def contains(self, px: int, py: int) -> int:
@@ -326,7 +324,7 @@ class Widget:
@t.Object
@t.CVTable
class Label(Widget):
text: t.CArray[t.CChar, 64]
text: t.CArray[char, 64]
color: uint32
def __init__(self, master: t.CPtr, text: str, color: uint32):
@@ -349,16 +347,16 @@ class Label(Widget):
_register_widget(master, t.CType(self, Widget, t.CPtr))
def draw(self, fb: UINT32PTR, fw: int, fh: int):
_draw_text(fb, fw, fh, self.x, self.y, c.Addr(self.text[0]), self.color)
_draw_text(fb, fw, fh, self.x, self.y, &self.text[0], self.color)
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
return 0
def config(self, text: t.CConst | t.CChar | t.CPtr = None, color: uint32 = None):
def config(self, text: const str = None, color: uint32 = None):
if text is not None:
i: int = 0
while i < 63:
ch: t.CChar = c.Deref(text + i)
ch: char = *(text + i)
self.text[i] = ch
if ch == 0: break
i += 1
@@ -369,7 +367,7 @@ class Label(Widget):
@t.Object
@t.CVTable
class Button(Widget):
text: t.CArray[t.CChar, 32]
text: t.CArray[char, 32]
fill_color: uint32
text_color: uint32
pressed: int
@@ -424,12 +422,12 @@ class Button(Widget):
_draw_hline(fb, fw, fh, self.x - 1, self.y + self.h, self.w + 2, border)
_draw_vline(fb, fw, fh, self.x - 1, self.y - 1, self.h + 2, border)
_draw_vline(fb, fw, fh, self.x + self.w, self.y - 1, self.h + 2, border)
tl: int = string.strlen(c.Addr(self.text[0]))
tl: int = string.strlen(&self.text[0])
tx: int = self.x + (self.w - 8 * tl) / 2
ty: int = self.y + (self.h - CHAR_H) / 2
_draw_text(fb, fw, fh, tx, ty, c.Addr(self.text[0]), self.text_color)
_draw_text(fb, fw, fh, tx, ty, &self.text[0], self.text_color)
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
etype: uint32 = evt.type
ex: int = evt.x
ey: int = evt.y
@@ -472,11 +470,11 @@ pop r12""",
return 1
return 0
def config(self, text: t.CConst | t.CChar | t.CPtr = None, fill_color: uint32 = None, text_color: uint32 = None, callback: t.CPtr = None):
def config(self, text: const str = None, fill_color: uint32 = None, text_color: uint32 = None, callback: t.CPtr = None):
if text is not None:
i: int = 0
while i < 31:
ch: t.CChar = c.Deref(text + i)
ch: char = *(text + i)
self.text[i] = ch
if ch == 0: break
i += 1
@@ -491,7 +489,7 @@ pop r12""",
@t.Object
@t.CVTable
class Entry(Widget):
text: t.CArray[t.CChar, 64]
text: t.CArray[char, 64]
text_len: int
cursor_pos: int
max_len: int
@@ -538,7 +536,7 @@ class Entry(Widget):
tc: uint32 = self.text_color
if not self.focused:
tc = uint32(0xCCCCCC)
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, c.Addr(self.text[0]), tc)
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, &self.text[0], tc)
elif not self.focused:
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, "Type here...", uint32(0x888888))
if self.focused:
@@ -546,7 +544,7 @@ class Entry(Widget):
if cx_pos < self.x + self.w - 2:
_draw_vline(fb, fw, fh, cx_pos, self.y + 5, self.h - 10, self.cursor_color)
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
etype: uint32 = evt.type
ex: int = evt.x
ey: int = evt.y
@@ -554,26 +552,26 @@ class Entry(Widget):
if self.contains(ex, ey):
if not self.hovered:
self.hovered = 1
tk: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk: Tk* = t.CType(self.master, Tk, t.CPtr)
window.set_cursor_type(tk.win_id, window.CURSOR_IBEAM)
return 1
else:
if self.hovered:
self.hovered = 0
tk2: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk2: Tk* = t.CType(self.master, Tk, t.CPtr)
window.set_cursor_type(tk2.win_id, window.CURSOR_DEFAULT)
return 1
elif etype == window.EVENT_TYPE_HOVER_LEAVE:
if self.hovered:
self.hovered = 0
tk3: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk3: Tk* = t.CType(self.master, Tk, t.CPtr)
window.set_cursor_type(tk3.win_id, window.CURSOR_DEFAULT)
return 1
elif etype == window.EVENT_TYPE_CLICK:
if self.contains(ex, ey):
if not self.focused:
self.focused = 1
tk4: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk4: Tk* = t.CType(self.master, Tk, t.CPtr)
tk4.focused_widget = t.CType(self, Widget, t.CPtr)
rel_x: int = ex - self.x - 6
if rel_x < 0: rel_x = 0
@@ -584,7 +582,7 @@ class Entry(Widget):
else:
if self.focused:
self.focused = 0
tk5: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk5: Tk* = t.CType(self.master, Tk, t.CPtr)
tk5.focused_widget = None
return 1
elif etype == window.EVENT_TYPE_KEY:
@@ -628,15 +626,15 @@ class Entry(Widget):
while i > self.cursor_pos:
self.text[i] = self.text[i - 1]
i -= 1
self.text[self.cursor_pos] = t.CChar(ch)
self.text[self.cursor_pos] = char(ch)
self.text_len += 1
self.cursor_pos += 1
self.text[self.text_len] = 0
return 1
return 0
def get(self) -> t.CConst | t.CChar | t.CPtr:
return c.Addr(self.text[0])
def get(self) -> const str:
return &self.text[0]
def delete(self, start: int, end: int):
self.text_len = 0
@@ -750,7 +748,7 @@ class Scrollbar(Widget):
_fill_rect(fb, fw, fh, cx - 2, cy, 5, 1, self.arrow_color)
_fill_rect(fb, fw, fh, cx - 1, cy + 1, 3, 1, self.arrow_color)
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
etype: uint32 = evt.type
ex: int = evt.x
ey: int = evt.y
@@ -899,7 +897,7 @@ class FBCanvas(Widget):
if tx < 0 or tx >= fw: continue
fb[ty * fw + tx] = self._fb[py * self._cw + px]
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
return 0
def set_fb(self, fb: UINT32PTR, cw: int, ch: int):
@@ -919,9 +917,9 @@ class FBCanvas(Widget):
@t.Object
@t.CVTable
class Text(Widget):
lines: t.CArray[t.CArray[t.CChar, 80], TEXT_MAX_LINES]
lines: t.CArray[t.CArray[char, 80], TEXT_MAX_LINES]
line_count: int
input_buf: t.CArray[t.CChar, 80]
input_buf: t.CArray[char, 80]
input_len: int
cursor_pos: int
bg_color: uint32
@@ -930,7 +928,7 @@ class Text(Widget):
cursor_color: uint32
border_color: uint32
on_command: t.CPtr
history: t.CArray[t.CArray[t.CChar, 80], 16]
history: t.CArray[t.CArray[char, 80], 16]
history_count: int
history_idx: int
scroll_offset: int
@@ -961,17 +959,11 @@ class Text(Widget):
self.scroll_offset = 0
self.max_lines = TEXT_MAX_LINES
self.yscrollbar = None
i: int = 0
while i < TEXT_MAX_LINES:
j: int = 0
while j <= 79:
for i in range(TEXT_MAX_LINES):
for j in range(79 + 1):
self.lines[i][j] = 0
j += 1
i += 1
i = 0
while i < 80:
for i in range(80):
self.input_buf[i] = 0
i += 1
_register_widget(master, t.CType(self, Widget, t.CPtr))
def draw(self, fb: UINT32PTR, fw: int, fh: int):
@@ -982,16 +974,16 @@ class Text(Widget):
for i in range(visible):
line_idx: int = self.scroll_offset + i
if line_idx < self.line_count:
_draw_text(fb, fw, fh, self.x + 4, self.y + i * CHAR_H, c.Addr(self.lines[line_idx][0]), self.text_color)
_draw_text(fb, fw, fh, self.x + 4, self.y + i * CHAR_H, &self.lines[line_idx][0], self.text_color)
prompt_y: int = self.y + self.h - CHAR_H - 4
_draw_text(fb, fw, fh, self.x + 4, prompt_y, "> ", self.prompt_color)
if self.input_len > 0:
_draw_text(fb, fw, fh, self.x + 4 + 2 * CHAR_W, prompt_y, c.Addr(self.input_buf[0]), uint32(0xFFFFFF))
_draw_text(fb, fw, fh, self.x + 4 + 2 * CHAR_W, prompt_y, &self.input_buf[0], uint32(0xFFFFFF))
cx_pos: int = self.x + 4 + (2 + self.cursor_pos) * CHAR_W
if cx_pos < self.x + self.w - 4:
_fill_rect(fb, fw, fh, cx_pos, prompt_y, CHAR_W // 2, CHAR_H, self.cursor_color)
def handle_event(self, evt: window.InputEvent | t.CPtr) -> int:
def handle_event(self, evt: window.InputEvent*) -> int:
etype: uint32 = evt.type
ex: int = evt.x
ey: int = evt.y
@@ -999,7 +991,7 @@ class Text(Widget):
if self.contains(ex, ey):
if not self.focused:
self.focused = 1
tk: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk: Tk* = t.CType(self.master, Tk, t.CPtr)
tk.focused_widget = t.CType(self, Widget, t.CPtr)
prompt_y: int = self.y + self.h - CHAR_H - 4
if ey >= prompt_y and ey < prompt_y + CHAR_H:
@@ -1012,7 +1004,7 @@ class Text(Widget):
else:
if self.focused:
self.focused = 0
tk2: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
tk2: Tk* = t.CType(self.master, Tk, t.CPtr)
tk2.focused_widget = None
return 1
elif etype == window.EVENT_TYPE_KEY:
@@ -1114,7 +1106,7 @@ class Text(Widget):
while i > self.cursor_pos:
self.input_buf[i] = self.input_buf[i - 1]
i -= 1
self.input_buf[self.cursor_pos] = t.CChar(ch)
self.input_buf[self.cursor_pos] = char(ch)
self.input_len += 1
self.cursor_pos += 1
self.input_buf[self.input_len] = 0
@@ -1131,23 +1123,15 @@ class Text(Widget):
j += 1
self.lines[last][2 + j] = 0
if self.history_count < 16:
k: int = 0
while k < 80:
for k in range(80):
self.history[self.history_count][k] = self.input_buf[k]
k += 1
self.history_count += 1
else:
i: int = 0
while i < 15:
k2: int = 0
while k2 < 80:
for i in range(15):
for k2 in range(80):
self.history[i][k2] = self.history[i + 1][k2]
k2 += 1
i += 1
k3: int = 0
while k3 < 80:
for k3 in range(80):
self.history[15][k3] = self.input_buf[k3]
k3 += 1
self.history_idx = 0
cmd: t.CPtr = self.on_command
@@ -1174,7 +1158,7 @@ pop r12""",
start: int = 0
pos: int = 0
while True:
ch: t.CChar = c.Deref(text + pos)
ch: char = *(text + pos)
if ch == 0:
if pos > start:
self._insert_substring(text, start, pos)
@@ -1184,11 +1168,11 @@ pop r12""",
start = pos + 1
pos += 1
def insert_ptr(self, text: t.CConst | t.CChar | t.CPtr):
def insert_ptr(self, text: const str):
start: int = 0
pos: int = 0
while True:
ch: t.CChar = c.Deref(text + pos)
ch: char = *(text + pos)
if ch == 0:
if pos > start:
self._insert_substring(text, start, pos)
@@ -1198,15 +1182,11 @@ pop r12""",
start = pos + 1
pos += 1
def _insert_substring(self, text: t.CConst | t.CChar | t.CPtr, start: int, end: int):
def _insert_substring(self, text: const str, start: int, end: int):
if self.line_count >= self.max_lines:
i: int = 0
while i < self.max_lines - 1:
j: int = 0
while j <= 79:
for i in range(self.max_lines - 1):
for j in range(79 + 1):
self.lines[i][j] = self.lines[i + 1][j]
j += 1
i += 1
self.line_count -= 1
if self.scroll_offset > 0:
self.scroll_offset -= 1
@@ -1214,7 +1194,7 @@ pop r12""",
j: int = 0
k: int = start
while k < end and j < 79:
ch: t.CChar = c.Deref(text + k)
ch: char = *(text + k)
if ch == 9:
tab_stop: int = 8 - (j % 8)
while tab_stop > 0 and j < 79:
@@ -1241,8 +1221,8 @@ pop r12""",
self.scroll_offset = 0
self._update_scrollbar()
def get(self) -> t.CConst | t.CChar | t.CPtr:
return c.Addr(self.input_buf[0])
def get(self) -> const str:
return &self.input_buf[0]
def config(self, text_color: uint32 = None, bg_color: uint32 = None, prompt_color: uint32 = None, cursor_color: uint32 = None, border_color: uint32 = None):
if text_color is not None:
@@ -1268,7 +1248,7 @@ pop r12""",
if self.scroll_offset > max_off:
self.scroll_offset = max_off
if self.yscrollbar is not None:
sb: Scrollbar | t.CPtr = t.CType(self.yscrollbar, Scrollbar, t.CPtr)
sb: Scrollbar* = t.CType(self.yscrollbar, Scrollbar, t.CPtr)
if self.line_count <= vis:
sb.set(0, 1000)
else:
@@ -1284,12 +1264,12 @@ class Tk:
bh: int
style: int
bg_color: uint32
widgets: t.CArray[Widget | t.CPtr, MAX_WIDGETS]
widgets: t.CArray[Widget*, MAX_WIDGETS]
widget_count: int
focused_widget: Widget | t.CPtr
focused_widget: Widget*
_win_x: int
_win_y: int
_title: t.CArray[t.CChar, 32]
_title: t.CArray[char, 32]
resizable_w: int
resizable_h: int
_grid_rows: int
@@ -1309,8 +1289,7 @@ class Tk:
self._grid_rows = 0
self._grid_cols = 0
if _g_layout_init == 0:
i: int = 0
while i < MAX_WIDGETS:
for i in range(MAX_WIDGETS):
_g_wl_type[i] = 0
_g_wl_side[i] = 0
_g_wl_fill[i] = 0
@@ -1322,12 +1301,9 @@ class Tk:
_g_wl_rowspan[i] = 0
_g_wl_colspan[i] = 1
_g_wl_sticky[i] = 0
i += 1
_g_layout_init = 1
j: int = 0
while j < 32:
for j in range(32):
self._title[j] = 0
j += 1
def pack(self, idx: int, side: int, fill: int, expand: int, padx: int, pady: int):
_g_wl_type[idx] = 2
@@ -1348,13 +1324,13 @@ class Tk:
def title(self, text: str):
i: int = 0
while i < 31:
ch: t.CChar = text[i]
ch: char = text[i]
if ch == 0: break
self._title[i] = ch
i += 1
self._title[i] = 0
if self.win_id >= 0:
window.set_title(self.win_id, c.Addr(self._title[0]))
window.set_title(self.win_id, &self._title[0])
def set_style(self, s: int):
self.style = s
@@ -1371,14 +1347,14 @@ class Tk:
self.bw = w
self.bh = h - TITLE_H - 2
if self.win_id < 0:
self.win_id = window.create_window(x, y, w, h, c.Addr(self._title[0]), self.style)
self.win_id = window.create_window(x, y, w, h, &self._title[0], self.style)
self.buf = window.get_winbuf(self.win_id)
window.set_resizable(self.win_id, self.resizable_w, self.resizable_h)
else:
window.set_geometry(self.win_id, x, y, w, h)
self.buf = window.get_winbuf(self.win_id)
def setup(self, x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int):
def setup(self, x: int, y: int, w: int, h: int, title: const str, style: int):
self._win_x = x
self._win_y = y
self.win_id = window.create_window(x, y, w, h, title, style)
@@ -1398,12 +1374,10 @@ class Tk:
if not self.buf: return
if self.bw <= 0 or self.bh <= 0: return
_fill_rect(self.buf, self.bw, self.bh, 0, 0, self.bw, self.bh, self.bg_color)
i: int = 0
while i < self.widget_count:
w: Widget | t.CPtr = self.widgets[i]
for i in range(self.widget_count):
w: Widget* = self.widgets[i]
if w.visible:
w.draw(self.buf, self.bw, self.bh)
i += 1
window.flush(self.win_id)
def _do_layout(self):
@@ -1413,9 +1387,8 @@ class Tk:
cav_y: int = 0
cav_w: int = self.bw
cav_h: int = self.bh
i: int = 0
while i < self.widget_count:
w: Widget | t.CPtr = self.widgets[i]
for i in range(self.widget_count):
w: Widget* = self.widgets[i]
lt: int = _g_wl_type[i]
if lt == 2:
side: int = _g_wl_side[i]
@@ -1476,10 +1449,8 @@ class Tk:
c: int = _g_wl_col[i] + _g_wl_colspan[i]
if r > self._grid_rows: self._grid_rows = r
if c > self._grid_cols: self._grid_cols = c
i += 1
i = 0
while i < self.widget_count:
w: Widget | t.CPtr = self.widgets[i]
for i in range(self.widget_count):
w: Widget* = self.widgets[i]
if _g_wl_type[i] == 3:
if self._grid_rows <= 0: self._grid_rows = 1
if self._grid_cols <= 0: self._grid_cols = 1
@@ -1502,7 +1473,6 @@ class Tk:
w.w = ww
if (sticky & 2) != 0:
w.h = wh
i += 1
def update(self):
self.redraw()
@@ -1515,7 +1485,7 @@ class Tk:
self.redraw()
evt: window.InputEvent
while window.is_active(self.win_id):
result: int = window.poll_event(c.Addr(evt))
result: int = window.poll_event(&evt)
if result != 0:
if evt.win_id == self.win_id:
need_redraw: int = 0
@@ -1530,27 +1500,25 @@ class Tk:
need_redraw = 1
elif etype == window.EVENT_TYPE_KEY or etype == window.EVENT_TYPE_KEY_RELEASE:
if self.focused_widget is not None:
handled: int = self.focused_widget.handle_event(c.Addr(evt))
handled: int = self.focused_widget.handle_event(&evt)
if handled: need_redraw = 1
else:
if etype == window.EVENT_TYPE_HOVER:
i: int = self.widget_count - 1
while i >= 0:
w: Widget | t.CPtr = self.widgets[i]
w: Widget* = self.widgets[i]
if w.visible:
handled2: int = w.handle_event(c.Addr(evt))
handled2: int = w.handle_event(&evt)
if handled2:
need_redraw = 1
break
i -= 1
else:
i: int = 0
while i < self.widget_count:
w: Widget | t.CPtr = self.widgets[i]
for i in range(self.widget_count):
w: Widget* = self.widgets[i]
if w.visible:
handled2: int = w.handle_event(c.Addr(evt))
handled2: int = w.handle_event(&evt)
if handled2: need_redraw = 1
i += 1
if need_redraw:
self.redraw()
else:
-357
View File
@@ -1,357 +0,0 @@
# 01 - 语言概述与编译流程
## 语言定位
`Viper` 是一种 **系统级编程语言**,其语法基于 `Python`,但编译目标为 `LLVM IR`,最终生成原生机器码。`Viper` 不是 `Python` 的超集或子集,也不是"`C` 的语法糖"——它是一门拥有独立类型系统、独立编译模型、独立模块体系的语言。`Viper` 选择 `Python` 语法作为表达形式,是因为 `Python` 是人类公认的可读性最高的语言。
当前编译器 `TransPyC`(用 Python 实现)使用 Python 标准库 `ast` 解析源文件,将精力集中在语义翻译而非词法/语法分析上。但项目已在 [includes/ast](../includes/ast) 中实现**完全自研的 Python 解析器**(词法器 + 语法器 + AST 构造,约 4176 LOC,`AstTest` 综合测试通过),覆盖 CPython 几乎全部语法。这是向 `TransPyV`(用 Viper 重写编译器自身)完全自举的关键准备——自举后编译器将脱离 Python 运行时,解析、类型检查、IR 生成都由原生机器码完成。详见 [13-bootstrapping.md](13-bootstrapping.md)。
而实际上,下文中所有提到的 `C` 语言都是为了便于使用 `C` 的底层开发者理解。由于历史原因,在旧版本中我们使用 `C` 来作为中间语言,如同旧版本的 `C++` 一样,但现在 `target="c"` 的路径已经完全删除,`C` 路径永久不再受维护。
### 核心设计决策
1. **Python 语法,LLVM 语义**:源文件是完全合法的 `Python` 语法,但通过 `t` 模块的类型注解系统赋予完全不同的语义 —— `t.CInt` 不是 `Python` 的 `int`,而是 `LLVM` 的 `i32`
2. **类型注解即编译指令**:Viper 的类型注解不是可选的提示,而是编译器生成 `LLVM IR` 的决定性依据。`x: t.CInt` 生成 `i32`,`x: t.CInt | t.CPtr` 生成 `i32*`,但无注解时会自动推导,详见下文。
3. **两阶段编译**:先从源文件提取声明接口(`.pyi` + `.stub.ll`),再使用声明接口翻译源文件为含代码的 `.ll`。这是 `Viper` 区别于简单"`Python` 转 `C`"工具的关键架构
4. **`SHA1` 命名空间**:每个源文件按内容 `SHA1` 哈希命名,非导出函数和结构体自动加上 `SHA1` 前缀,从根本上消除跨模块的符号冲突
5. **万物皆数据**:为便于底层开发,实际上所有的变量和类型一般并不适用于鸭子类型,但在语义层面我们会尽可能贴近鸭子类型。
### 与 `Python` 的关系
| 特性 | `Python` | `Viper` |
|------|--------|-------|
| 类型系统 | 动态类型 | 静态类型(通过 `t` 模块注解,编译时确定) |
| 内存管理 | `GC` 自动回收 | 手动管理,无 `GC`,无运行时 |
| 运行时 | 解释执行 + 字节码 | 编译为原生机器码(通过 `LLVM`) |
| 对象模型 | 万物皆对象 | `@t.Object` 启用 OOP,`@t.CVTable` 为多态(vtable),`@t.NoVTable` 为非多态继承(C++ 风格,零运行时开销),普通 `class` 仅为结构体布局 |
| 标准库 | `Python` 标准库 | `Viper` 标准库(`includes/`)+ `ViperOS SDK` |
| 空值 | `None` | `None`(编译为 `NULL`/零值) |
| 模块系统 | 运行时 `import` | 编译时解析,插入 `.stub.ll`,`SHA1` 命名空间隔离 |
### 与 C 的关系
Viper 编译后的代码在底层等价于 `C` 编译后的机器码(都经过 LLVM),但 Viper 在语言层面提供了 C 所没有的能力:
- **SHA1 命名空间**:自动消除符号冲突,无需手动管理 `static`/命名前缀
- **类型组合语法**:`t.CConst | t.CInt | t.CPtr` 比 `const int*` 更具组合性
- **声明式内联汇编**:`c.Asm(f"mov {c.AsmOut(x, t.ASM_DESCR.OUTPUT_REG)}, rdi")` 比裸 `__asm__` 更安全,也更具可读性。
- **结构化预处理**:`c.CIfdef`/`c.CEndif()` 替代 `#ifdef`/`#endif`。
- **面向对象**:`@t.Object` + `@t.CVTable` 提供 `vtable` 支持的多态 `OOP`;`@t.NoVTable` 提供 C++ 风格的非多态继承(零 vtable 开销);PEP 695 泛型 + 递归泛型继承实现强类型自引用结构
- **存根驱动的模块系统**:`.pyi` 存根文件实现跨模块类型解析,无需头文件
- **更多内容**:额外更多的不依赖操作系统的函数和语法
## 两阶段编译流程
Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。
```
源文件 (.py) ──────────────────────────────────────────────────────
│ │
│ ┌─────────────── 阶段一:声明提取 ───────────────┐ │
│ │ │ │
│ │ 1. 计算源文件 SHA1 │ │
│ │ 2. 生成 <SHA1>.pyi(签名存根) │ │
│ │ 3. 构建结构体注册表 │ │
│ │ 4. 生成 <SHA1>.stub.ll(LLVM IR 声明) │ │
│ │ │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────── 阶段二:代码翻译 ───────────────┐ │
│ │ │ │
│ │ 1. 加载所有 .pyi 和 .stub.ll │ │
│ │ 2. 构建共享符号表 │ │
│ │ 3. 收集内联函数符号 │ │
│ │ 4. 翻译源文件 → <SHA1>.ll(含代码) │ │
│ │ 5. llc 编译 → <SHA1>.o(目标文件) │ │
│ │ 6. ld.lld 链接 → 可执行文件 │ │
│ │ │ │
│ └────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
```
### 阶段一:声明提取(Phase1Generator)
阶段一的目标是从每个源文件提取**声明接口**,使其他模块在阶段二翻译时能够正确解析跨模块引用。
#### 步骤 1:可达文件发现与拓扑排序
从入口文件(`main.py` 或 `project.json` 指定)出发,通过 `import` 语句递归遍历,找出所有可达的 `.py` 源文件。然后对文件进行拓扑排序,确保被依赖的模块先被处理。
```
main.py → import serial → import drivers.serial.uart.serial → ...
```
#### 步骤 2:生成 `.pyi` 签名存根
对每个源文件,计算其内容的 SHA1 哈希(16位),然后调用 `PythonToStubConverter` 生成签名存根文件 `<SHA1>.pyi`。
**SHA1 计算方式**:
```python
sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16]
```
**存根文件的内容规则**:
| 源文件元素 | 存根文件中的表示 |
|-----------|----------------|
| `t.CDefine` 常量 | 保留原样(含赋值):`MAX_SIZE: t.CDefine = 1024` |
| `t.CDefine` 函数(返回 `t.CDefine` 的函数) | 保留完整函数体(宏展开需要) |
| 普通函数 | 仅保留签名,添加 `| c.State`:`def foo(x: t.CInt) -> t.CVoid | c.State: pass` |
| 类定义 | 保留成员类型注解和方法签名 |
| 全局变量 | 添加 `t.CExtern`:`x: t.CExtern | t.CInt` |
| `c.CIfdef`/`c.CEndif()` 等预处理指令 | 保留原样 |
| `import` 语句 | 保留原样 |
**关键设计**:`t.CDefine` 常量和 `t.CDefine` 函数在存根中**保留完整定义**(包括赋值和函数体),因为它们是编译时常量/宏,其他模块引用时需要完整展开。普通函数只保留签名并标记 `c.State`(仅声明),因为函数体在阶段二生成。
#### 步骤 3:构建结构体注册表
扫描所有已生成的 `.pyi` 文件,提取:
- **结构体名称集合**:所有非枚举、非异常的 `class` 定义
- **枚举名称集合**:继承 `t.CEnum` 的类
- **异常名称集合**:继承 `Exception` 的类
- **结构体→SHA1 映射**:记录每个结构体定义在哪个模块中
这个注册表用于阶段一的声明生成和阶段二的类型解析,确保跨模块的结构体引用使用正确的 SHA1 命名空间。
#### 步骤 4:生成 `.stub.ll` LLVM IR 声明
对每个 `.pyi` 文件,由 `DeclarationGenerator` 生成对应的 LLVM IR 声明文件 `<SHA1>.stub.ll`。
**声明生成规则**:
| 元素 | 生成的 LLVM IR |
|------|---------------|
| 普通函数 | `declare void @"<SHA1>.foo"(i32)` — 非 CExport 函数加 SHA1 前缀 |
| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 |
| 结构体 | `%"<SHA1>.ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 |
| 全局变量 | `@varname = external global i32` |
| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) |
| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) |
| 枚举 | 为每个枚举成员生成 `@__config_EnumName_member = external global i32` |
**增量编译**:如果 `<SHA1>.pyi` 或 `<SHA1>.stub.ll` 已存在,则跳过生成(缓存命中)。只有源文件内容变化导致 SHA1 变化时才重新生成。
### 阶段二:代码翻译(Phase2Translator)
阶段二使用阶段一生成的声明接口,将源文件翻译为包含完整代码的 LLVM IR。
#### 步骤 1:加载声明接口
加载 `temp/` 目录中所有的 `.pyi` 和 `.stub.ll` 文件,构建:
- `sig_files`:SHA1 → `.pyi` 文件路径映射
- `stub_files`:SHA1 → `.stub.ll` 文件路径映射
- `sha1_map`:SHA1 → 源文件相对路径映射
#### 步骤 2:构建共享符号表
一次性构建所有文件共享的符号表数据,避免每个文件重复加载。将所有 `.pyi` 存根和 `.stub.ll` 声明中的类型信息注册到统一的 `SymbolTable` 中。
#### 步骤 3:收集内联函数符号
扫描 `includes/` 目录中被引用的模块,收集标记为 `t.CInline` 的函数。内联函数的完整 AST body 被保存,在翻译调用点时直接展开。值得注意的是,和 C 语言不同,`t.CInline` 不是优化建议,而是强制性的。
#### 步骤 4:翻译源文件
对每个源文件,使用 `TransPyC` 翻译器将 Python AST 翻译为 LLVM IR:
1. 将对应模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部
2. 所有被引用模块的 `.stub.ll` 声明也被嵌入
3. 翻译 AST 节点为 LLVM IR 指令
4. 输出 `<SHA1>.ll` 文件
#### 步骤 5:编译与链接
- `llc`:将每个 `.ll` 编译为 `.o` 目标文件
- `ld.lld`:将所有 `.o` 链接为最终可执行文件
## SHA1 命名空间机制
SHA1 命名空间是 Viper 解决跨模块符号冲突的核心机制。
### 问题
在 C 语言中,多个模块可能定义同名函数或结构体,导致链接时符号冲突。C 的解决方案是 `static`(限制可见性)和命名前缀(手动避免冲突)。
### Viper 的解决方案
Viper 使用源文件内容的 SHA1 哈希作为命名空间前缀:
```
源文件 A.py(SHA1 = a1b2c3d4e5f6g7h8)中定义:
class Point: x: t.CInt; y: t.CInt
def draw(p: Point) -> t.CVoid: ...
源文件 B.py(SHA1 = i9j0k1l2m3n4o5p6)中也定义:
class Point: x: t.CFloat; y: t.CFloat # 不同的结构体!
def draw(p: Point) -> t.CVoid: ...
编译后:
A.py 的结构体 → %"a1b2c3d4e5f6g7h8.Point" = type { i32, i32 }
A.py 的函数 → declare void @"a1b2c3d4e5f6g7h8.draw"(%"a1b2c3d4e5f6g7h8.Point"*)
B.py 的结构体 → %"i9j0k1l2m3n4o5p6.Point" = type { float, float }
B.py 的函数 → declare void @"i9j0k1l2m3n4o5p6.draw"(%"i9j0k1l2m3n4o5p6.Point"*)
```
**没有符号冲突**——即使两个模块定义了同名类型和函数,它们的 LLVM IR 符号也是不同的。即便有两个内容完全相同的文件也不会冲突,他们会被识别为同一个文件,然后进行单次编译。
### SHA1 前缀的豁免:`t.CExport`
标记为 `t.CExport` 的函数**不加 SHA1 前缀**,保持原始函数名。这是模块向外部暴露 API/ABI 的机制:
```python
# main.py — 入口函数,必须全局可见
def main() -> t.CInt | t.CExport:
return 0
# 编译后:define i32 @main() — 无 SHA1 前缀
```
```python
# serial.py — 驱动接口,对外暴露
def init() -> t.CVoid | t.CExport:
serial_puts("init\n")
# 编译后:define void @init() — 无 SHA1 前缀,其他模块可直接调用
```
### SHA1 与增量编译
SHA1 同时服务于增量编译:
- 源文件内容不变 → SHA1 不变 → `.pyi` 和 `.stub.ll` 缓存命中,跳过阶段一
- 源文件内容变化 → SHA1 变化 → 重新生成声明接口
- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,供阶段二加载
理论上,如果一个未经变动的模块的依赖路径上存在变动的模块,暂时的方法是将其简单做 SHA1 替换,暨将旧 SHA1 替换为新 SHA1,但不适用于签名改变的情况,不过签名改变这个未经变动的模块必然也需要改变,但是由于宏展开的存在,不能完全保证不会发生错误情况。且依赖路径的 SHA1 替换成功性未经完整测试,可能出现未定义行为。
## `t.CDefine` 深度解析
`t.CDefine` 是 Viper 中最特殊的类型——它不是数据类型,而是**编译时元指令**,控制编译器的代码生成行为。
### `t.CDefine` 常量
```python
MAX_SIZE: t.CDefine = 1024
PAGE_SIZE: t.CDefine = 4096
FA_READ: t.CDefine = 0x01
CPU_FEATURE_FPU: t.CDefine = (1 << 0)
```
**编译行为**:
1. **阶段一**:存根生成器保留 `t.CDefine` 常量的完整定义(包括赋值值),因为其他模块可能引用此常量
2. **阶段一**:`.stub.ll` 声明生成器**跳过** `t.CDefine` 常量,不生成 `external global` 声明
3. **阶段二**:翻译器遇到 `t.CDefine` 常量的引用时,直接内联其值,不生成任何加载指令
这意味着 `t.CDefine` 常量在 LLVM IR 层面**不存在**——它们在编译时被完全展开,等价于 C 的 `#define` 宏。
### `t.CDefine` 函数
当函数的返回类型注解包含 `t.CDefine` 时,该函数被编译器视为**宏函数**:
```python
def MAKE_FLAG(bit) -> t.CDefine:
return (1 << bit)
def GET_PAGE_ORDER(size) -> t.CDefine:
return size // PAGE_SIZE
```
**编译行为**:
1. **阶段一**:存根生成器保留 `t.CDefine` 函数的**完整函数体**(不像普通函数那样只保留签名)
2. **阶段二**:翻译器遇到 `t.CDefine` 函数的调用时,将调用内联展开为函数体的计算结果
`t.CDefine` 函数在 LLVM IR 中**不生成函数定义**——它们是纯粹的编译时宏。
### `t.CDefine` 与类型组合
`t.CDefine` 可以与具体类型组合使用,为常量指定底层类型:
```python
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
```
这表示常量在类型检查时被视为 `t.CUInt16T`(`uint16_t`),但在代码生成时仍然内联展开。
## `t.CExport` 深度解析
`t.CExport` 控制函数的符号可见性,是 SHA1 命名空间的豁免机制。
### 语义
| 修饰 | LLVM IR 函数名 | 链接可见性 | 用途 |
|------|---------------|-----------|------|
| 无修饰 | `@<SHA1>.funcname` | 模块内部 | 模块私有函数 |
| `t.CExport` | `@funcname` | 全局可见 | 对外暴露的 API |
| `t.CExtern` | `@funcname`(仅声明) | 外部定义 | 引用外部函数 |
### 使用场景
```python
# 入口函数 — 必须全局可见,链接器需要找到它
def _start() -> t.CInt | t.CExport:
return kernel_main()
# 驱动接口 — 其他模块/应用需要调用
def init() -> t.CVoid | t.CExport:
uart_init()
# 内部辅助函数 — 不需要全局可见,自动加 SHA1 前缀
def _helper() -> t.CInt:
return 42
```
### `t.CExport` 在存根中的表现
在 `.pyi` 存根文件中,`t.CExport` 函数与普通函数一样只保留签名(添加 `c.State`,表示单纯声明),但 `t.CExport` 标记被保留在返回类型注解中。阶段一的 `DeclarationGenerator` 检查 `t.CExport` 标记来决定是否添加 SHA1 前缀。
## `t.CInline` 深度解析
`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。
### 语义
```python
def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline:
return a + b
```
**编译行为**:
1. **阶段二预收集**:`_collect_inline_symbols` 扫描 `includes/` 目录中被引用的模块,收集所有 `t.CInline` 函数的 AST body
2. **翻译时展开**:遇到内联函数调用时,将函数体的 AST 直接嵌入调用点,替换参数为实际值
3. **不生成独立函数**:内联函数不生成 LLVM IR 函数定义(除非也被非内联调用)
### `t.CInline` 与 `t.CDefine` 函数的区别
| 特性 | `t.CInline` | `t.CDefine` 函数 |
|------|------------|-----------------|
| 展开时机 | 阶段二翻译时 | 阶段二翻译时 |
| 类型检查 | 完整的参数和返回类型检查 | 返回类型为宏,类型检查较弱 |
| 存根表示 | 签名 + `c.State` | 完整函数体 |
| LLVM IR | 可能生成函数定义(如果有非内联调用) | 不生成函数定义 |
| 适用场景 | 性能关键的短函数 | 编译时常量和宏计算 |
## 目标平台
默认目标三元组:`x86_64-none-elf`
数据布局:`e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128`
## Hello World 示例
```python
import t, c
def main() -> t.CInt | t.CExport:
print("Hello, ViperOS!\n")
return 0
```
编译流程:
1. **阶段一**:计算 `main.py` 的 SHA1,生成 `.pyi` 存根(`def main() -> t.CInt | t.CExport | c.State: pass`),生成 `.stub.ll` 声明(`declare i32 @main()`,因为是 CExport 不加前缀)
2. **阶段二**:翻译 `main.py` 为 `<SHA1>.ll`,嵌入 `print` 对应的 `puts`/`printf` 声明,生成 `define i32 @main()` 函数体
3. **编译**:`llc` 将 `.ll` 编译为 `.o`
4. **链接**:`ld.lld` 链接为可执行文件
-649
View File
@@ -1,649 +0,0 @@
# 02 - 类型系统
Viper 的类型系统通过 `t` 模块提供,所有类型注解继承 `t.CType` 。大都以 `t.C{TypeName:PascalCase}`为类型,类型注解是 Viper 的核心机制,决定了变量的内存布局、大小和对齐方式。
## 基本类型
### 整数类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CChar` | `char` | 8 | 是 |
| `t.CShort` | `short` | 16 | 是 |
| `t.CInt` | `int` | 32 | 是 |
| `t.CLong` | `long` | 64 | 是 |
| `t.CUnsignedChar` | `unsigned char` | 8 | 否 |
| `t.CUnsignedShort` | `unsigned short` | 16 | 否 |
| `t.CUnsigned` / `t.CUnsignedInt` | `unsigned int` | 32 | 否 |
| `t.CUnsignedLong` | `unsigned long` | 64 | 否 |
| `t.CSignedChar` | `signed char` | 8 | 是 |
值得注意的是,t.CUnsigned 一般不单独使用,而是配合其它有符号类型,替换表示无符号,比如 `t.CUnsigned | t.CInt`,由于为了便于使用一些常用类型,则将其组合为常用的 `t.CUnsignedInt` 等。
### 固定宽度整数类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CInt8T` | `int8_t` | 8 | 是 |
| `t.CInt16T` | `int16_t` | 16 | 是 |
| `t.CInt32T` | `int32_t` | 32 | 是 |
| `t.CInt64T` | `int64_t` | 64 | 是 |
| `t.CUInt8T` | `uint8_t` | 8 | 否 |
| `t.CUInt16T` | `uint16_t` | 16 | 否 |
| `t.CUInt32T` | `uint32_t` | 32 | 否 |
| `t.CUInt64T` | `uint64_t` | 64 | 否 |
### 最小宽度整数类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CIntLeast8T` | `int_least8_t` | ≥8 | 是 |
| `t.CIntLeast16T` | `int_least16_t` | ≥16 | 是 |
| `t.CIntLeast32T` | `int_least32_t` | ≥32 | 是 |
| `t.CIntLeast64T` | `int_least64_t` | ≥64 | 是 |
| `t.CUIntLeast8T` | `uint_least8_t` | ≥8 | 否 |
| `t.CUIntLeast16T` | `uint_least16_t` | ≥16 | 否 |
| `t.CUIntLeast32T` | `uint_least32_t` | ≥32 | 否 |
| `t.CUIntLeast64T` | `uint_least64_t` | ≥64 | 否 |
### 最快最小宽度整数类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CIntFast8T` | `int_fast8_t` | ≥8 | 是 |
| `t.CIntFast16T` | `int_fast16_t` | ≥16 | 是 |
| `t.CIntFast32T` | `int_fast32_t` | ≥32 | 是 |
| `t.CIntFast64T` | `int_fast64_t` | ≥64 | 是 |
| `t.CUIntFast8T` | `uint_fast8_t` | ≥8 | 否 |
| `t.CUIntFast16T` | `uint_fast16_t` | ≥16 | 否 |
| `t.CUIntFast32T` | `uint_fast32_t` | ≥32 | 否 |
| `t.CUIntFast64T` | `uint_fast64_t` | ≥64 | 否 |
### 最大宽度整数类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CIntMaxT` | `intmax_t` | ≥64 | 是 |
| `t.CUIntMaxT` | `uintmax_t` | ≥64 | 否 |
### stdint 短名别名
通过 `import stdint` 引入,这些短名是上述类型的 `t.CTypedef` 别名,便于在系统编程场景中快速使用。允许直接使用 `from stdint import *` 来直接使用。
#### 基本类型短名
| 短名 | 等价展开 | 说明 |
|------|---------|------|
| `stdint.INT` | `t.CInt` | - |
| `stdint.UINT` | `t.CUnsignedInt` | - |
| `stdint.BOOL` | `t.CInt` | 1 为真,0 为假 |
| `stdint.SHORT` | `t.CShort` | - |
| `stdint.USHORT` | `t.CUnsignedShort` | - |
| `stdint.LONG` | `t.CLong` | - |
| `stdint.ULONG` | `t.CUnsignedLong` | - |
| `stdint.LONGLONG` | `t.CLong \| t.CLong` | - |
| `stdint.ULONGLONG` | `t.CUnsignedLong \| t.CLong` | - |
| `stdint.FLOAT` | `t.CFloat` | - |
| `stdint.DOUBLE` | `t.CDouble` | - |
#### 固定宽度短名
| 短名 | 等价展开 |
|------|---------|
| `stdint.INT8` | `t.CInt8T` |
| `stdint.INT16` | `t.CInt16T` |
| `stdint.INT32` | `t.CInt32T` |
| `stdint.INT64` | `t.CInt64T` |
| `stdint.UINT8` | `t.CUInt8T` |
| `stdint.UINT16` | `t.CUInt16T` |
| `stdint.UINT32` | `t.CUInt32T` |
| `stdint.UINT64` | `t.CUInt64T` |
#### 字节与字短名
| 短名 | 等价展开 | 说明 |
|------|---------|------|
| `stdint.BYTE` | `t.CUnsignedChar` | 8 位无符号 |
| `stdint.WORD` | `t.CUInt16T` | 16 位无符号 |
| `stdint.DWORD` | `t.CUInt32T` | 32 位无符号 |
| `stdint.QWORD` | `t.CUInt64T` | 64 位无符号 |
#### 字符类型短名
| 短名 | 等价展开 | 说明 |
|------|---------|------|
| `stdint.TCHAR` | `t.CChar` | - |
| `stdint.CHARLIST` | `str \| t.CPtr` / `list[str, None]` | - |
| `stdint.WCHAR` | `stdint.WORD` | UTF-16 代码单元 |
| `stdint.CHAR8` | `t.CChar8T` | - |
| `stdint.CHAR16` | `t.CChar16T` | - |
| `stdint.CHAR32` | `t.CChar32T` | - |
#### 指针短名
| 短名 | 等价展开 |
|------|---------|
| `stdint.INTPTR` | `t.CInt \| t.CPtr` |
| `stdint.UINTPTR` | `t.CUnsignedInt \| t.CPtr` |
| `stdint.BYTEPTR` | `stdint.BYTE \| t.CPtr` |
| `stdint.SHORTPTR` | `t.CShort \| t.CPtr` |
| `stdint.USHORTPTR` | `t.CUnsignedShort \| t.CPtr` |
| `stdint.WCHARPTR` | `stdint.WORD \| t.CPtr` |
| `stdint.VOIDPTR` | `t.CVoid \| t.CPtr` |
| `stdint.INT8PTR` | `t.CInt8T \| t.CPtr` |
| `stdint.INT16PTR` | `t.CInt16T \| t.CPtr` |
| `stdint.INT32PTR` | `t.CInt32T \| t.CPtr` |
| `stdint.INT64PTR` | `t.CInt64T \| t.CPtr` |
| `stdint.UINT8PTR` | `t.CUInt8T \| t.CPtr` |
| `stdint.UINT16PTR` | `t.CUInt16T \| t.CPtr` |
| `stdint.UINT32PTR` | `t.CUInt32T \| t.CPtr` |
| `stdint.UINT64PTR` | `t.CUInt64T \| t.CPtr` |
| `stdint.CHAR8PTR` | `t.CChar8T \| t.CPtr` |
| `stdint.CHAR16PTR` | `t.CChar16T \| t.CPtr` |
| `stdint.CHAR32PTR` | `t.CChar32T \| t.CPtr` |
#### 平台特定短名
| 短名 | 等价展开 | 说明 |
|------|---------|------|
| `stdint.FSIZE_t` | `stdint.DWORD` | 文件大小 |
| `stdint.LBA_t` | `stdint.DWORD` | 逻辑块地址 |
### 平台相关类型
| Viper 类型 | C 等价 | 大小(位) | 有符号 |
|------------|--------|-----------|--------|
| `t.CSizeT` | `size_t` | 64 | 否 |
| `t.CIntPtrT` | `intptr_t` | 64 | 是 |
| `t.CUIntPtrT` | `uintptr_t` | 64 | 否 |
| `t.CPtrDiffT` | `ptrdiff_t` | 64 | 是 |
### stdint 短名别名
Viper 在 `stdint` 模块中提供了更简短的类型别名,通过 `t.CTypedef` 映射到对应的完整类型。使用时需 `import stdint`。
#### 固定宽度整数短名
| 短名 | 等价 Viper 类型 | C 等价 |
|------|----------------|--------|
| `INT8` | `t.CInt8T` | `int8_t` |
| `INT16` | `t.CInt16T` | `int16_t` |
| `INT32` | `t.CInt32T` | `int32_t` |
| `INT64` | `t.CInt64T` | `int64_t` |
| `UINT8` | `t.CUInt8T` | `uint8_t` |
| `UINT16` | `t.CUInt16T` | `uint16_t` |
| `UINT32` | `t.CUInt32T` | `uint32_t` |
| `UINT64` | `t.CUInt64T` | `uint64_t` |
#### 固定宽度指针短名
| 短名 | 等价 Viper 类型 | C 等价 |
|------|----------------|--------|
| `INT8PTR` | `t.CInt8T \| t.CPtr` | `int8_t*` |
| `INT16PTR` | `t.CInt16T \| t.CPtr` | `int16_t*` |
| `INT32PTR` | `t.CInt32T \| t.CPtr` | `int32_t*` |
| `INT64PTR` | `t.CInt64T \| t.CPtr` | `int64_t*` |
| `UINT8PTR` | `t.CUInt8T \| t.CPtr` | `uint8_t*` |
| `UINT16PTR` | `t.CUInt16T \| t.CPtr` | `uint16_t*` |
| `UINT32PTR` | `t.CUInt32T \| t.CPtr` | `uint32_t*` |
| `UINT64PTR` | `t.CUInt64T \| t.CPtr` | `uint64_t*` |
#### 字符类型短名
| 短名 | 等价 Viper 类型 | C 等价 |
|------|----------------|--------|
| `CHAR8` | `t.CChar8T` | `char8_t` |
| `CHAR16` | `t.CChar16T` | `char16_t` |
| `CHAR32` | `t.CChar32T` | `char32_t` |
| `CHAR8PTR` | `t.CChar8T \| t.CPtr` | `char8_t*` |
| `CHAR16PTR` | `t.CChar16T \| t.CPtr` | `char16_t*` |
| `CHAR32PTR` | `t.CChar32T \| t.CPtr` | `char32_t*` |
#### 基本类型短名
| 短名 | 等价 Viper 类型 | C 等价 |
|------|----------------|--------|
| `INT` | `t.CInt` | `int` |
| `UINT` | `t.CUnsignedInt` | `unsigned int` |
| `BOOL` | `t.CInt` | `int`(0/1) |
| `SHORT` | `t.CShort` | `short` |
| `USHORT` | `t.CUnsignedShort` | `unsigned short` |
| `LONG` | `t.CLong` | `long` |
| `ULONG` | `t.CUnsignedLong` | `unsigned long` |
| `LONGLONG` | `t.CLong \| t.CLong` | `long long` |
| `ULONGLONG` | `t.CUnsignedLong \| t.CLong` | `unsigned long long` |
| `FLOAT` | `t.CFloat` | `float` |
| `DOUBLE` | `t.CDouble` | `double` |
#### 平台 / Windows 风格短名
| 短名 | 等价 Viper 类型 | C 等价 |
|------|----------------|--------|
| `BYTE` | `t.CUnsignedChar` | `unsigned char`(8位) |
| `BYTEPTR` | `BYTE \| t.CPtr` | `unsigned char*` |
| `WORD` | `t.CUInt16T` | `uint16_t`(16位) |
| `DWORD` | `t.CUInt32T` | `uint32_t`(32位) |
| `QWORD` | `t.CUInt64T` | `uint64_t`(64位) |
| `INTPTR` | `t.CInt \| t.CPtr` | `int*` |
| `UINTPTR` | `t.CUnsignedInt \| t.CPtr` | `unsigned int*` |
| `SHORTPTR` | `t.CShort \| t.CPtr` | `short*` |
| `USHORTPTR` | `t.CUnsignedShort \| t.CPtr` | `unsigned short*` |
| `VOIDPTR` | `t.CVoid \| t.CPtr` | `void*` |
| `TCHAR` | `t.CChar` | `char` |
| `WCHAR` | `WORD` | `uint16_t`(UTF-16) |
| `WCHARPTR` | `WORD \| t.CPtr` | `uint16_t*`(UTF-16) |
| `CHARLIST` | `str \| t.CPtr` | `char*` |
| `FSIZE_t` | `DWORD` | `uint32_t` |
| `LBA_t` | `DWORD` | `uint32_t` |
### 浮点类型
| Viper 类型 | C 等价 | 大小(位) |
|------------|--------|-----------|
| `t.CFloat` | `float` | 32 |
| `t.CDouble` | `double` | 64 |
### 其他基本类型
| Viper 类型 | C 等价 | 说明 |
|------------|--------|------|
| `t.CVoid` | `void` | 空类型 |
| `t.CBool` | `bool` | 布尔类型(8位) |
| `t.CWCharT` | `wchar_t` | 宽字符(32位) |
| `t.CChar8T` | `char8_t` | UTF-8 字符(8位,无符号) |
| `t.CChar16T` | `char16_t` | UTF-16 字符(16位,无符号) |
| `t.CChar32T` | `char32_t` | UTF-32 字符(32位,无符号) |
### Python 便捷映射类型
| Python 类型| Viper 类型 | Viper 值 |
|--------|--------|------|
|`int`|`t.CInt`|-|
|`float`|`t.CFloat`|-|
|`str`|`t.CChar \| t.CPtr`|-|
|`bool`|`t.CBool`|-|
|`True`|`t.CBool`|`1`|
|`False`|`t.CBool`|`0`|
|`None`|`NULL`|`t.CIntPtr(0)`|
对于 t.py 和 c.py 的引用,必须使用 import,不能使用 from ... import ...,也不能使用 as,因为这两者都是直接以字符串识别的。
## 类型组合
Viper 使用 Python 的 `|` 来组合类型修饰符(TypeUnion),其仅在左值注解中有效,其它位置均为位或语义(至少重载前是这样的),这是 Viper 最重要的语法特性之一。
### 指针类型
使用 `t.CPtr` 表示指针,通过 `|` 与基本类型组合:
```python
x: t.CInt | t.CPtr # int* — 指向 int 的指针
p: t.CVoid | t.CPtr # void* — 通用指针
s: t.CChar | t.CPtr # char* — 字符串指针
pp: t.CInt | t.CPtr | t.CPtr # int** — 指向指针的指针
```
等价 C 代码:
```c
int* x;
void* p;
char* s;
int** pp;
```
同时,指针也可以用 `Ptr[T]` 的方法表示,但在 Viper 中不太推荐,虽然说这样做一直是类似工程的常见用法,但是如果此处 `T` 是一个多态,同时我们想要复用 Python 的高亮插件,插件无法识别 `Ptr[T]` 的属性取值,但是对于 `T | Ptr` 可以。
```python
x: t.CPtr[t.CInt]
p: t.CPtr[t.CVoid]
s: t.CPtr[t.CChar]
pp: t.CPtr[t.CPtr[t.CInt]]
pp2: t.CInt | t.CPtr[t.CPtr] # 同时也可以这么表示
```
等价 C 代码:
```c
int* x;
void* p;
char* s:
int** pp;
int** pp2;
```
### 类型限定符组合
```python
x: t.CConst | t.CInt # const int
p: t.CConst | t.CChar | t.CPtr # const char*
```
### 存储类组合
```python
x: t.CStatic | t.CInt # static int
f: t.CExtern | t.CInt # extern int(声明其存在于外部)
```
### 函数返回类型组合
```python
def foo() -> t.CInt | t.CExport: # 导出函数,返回 int
return 0
def bar() -> t.CVoid | t.CExtern: # 外部函数声明
pass
```
### `t.State` 声明性标记
`t.State` 是**声明性标记类型**,表示"仅声明不定义"(语义等价于 `t.CExport | t.CExtern`)。主要用于 FFI 外部函数声明:函数体为 `pass`,编译器只生成函数原型(declare),不生成定义(define),由链接器在外部库中解析符号。
```python
def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG,
dwShareMode: ULONG,
lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr,
dwCreationDisposition: ULONG,
dwFlagsAndAttributes: ULONG,
hTemplateFile: HANDLE) -> HANDLE | t.State:
pass
```
等价 C 声明:
```c
HANDLE CreateFileA(LPCSTR, ULONG, ULONG, SECURITY_ATTRIBUTES*, ULONG, ULONG, HANDLE);
```
`t.State` 是 Viper FFI 机制的核心,无需任何特殊语法,仅靠返回类型注解即可声明外部函数。详见 [08-c-operations.md 的 FFI 章节](08-c-operations.md#ffi-外部函数声明) 和 [includes/w32](../includes/w32) 的 Win32 绑定。
## 数组类型
使用 Python 的 `list[ElementType, Size]` 语法表示固定大小数组(通常的,这用于栈上和 BSS 段上):
```python
buf: list[t.CChar, 64] # char buf[64]
ids: list[t.CInt, 10] # int ids[10]
matrix: list[t.CFloat, 16] # float matrix[16]
entries: list[idt_entry, 256] # struct idt_entry entries[256]
s: list[t.CChar, None] # 自推长度 char s[];
```
等价 C 代码:
```c
char buf[64];
int ids[10];
float matrix[16];
struct idt_entry entries[256];
```
### 数组指针和函数指针
```python
lp: list[t.CInt, 12] | t.CPtr
vp: t.Callable[[t.CInt, t.CInt], t.CInt] = x # 其中 t.Callable = typing.Callable,可以直接使用。
```
## 结构体类型
使用 `class` 定义结构体,成员通过类型注解声明:
```python
class point:
x: t.CInt
y: t.CInt
```
等价 C 代码:
```c
struct point {
int x;
int y;
};
```
### 带指针成员的结构体
```python
class node:
value: t.CInt
next: node | t.CPtr # struct node* next
```
### 字节序标记
> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。
使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序:
```python
class network_packet:
length: t.CUInt16T | t.BigEndian # 大端序存储
type: t.CUInt8T # 默认小端序
```
## 联合体类型
继承 `t.CUnion` 定义联合体:
```python
class value(t.CUnion):
ival: t.CInt
fval: t.CFloat
pval: t.CVoid | t.CPtr
```
等价 C 代码:
```c
union value {
int ival;
float fval;
void* pval;
};
```
## 枚举类型
继承 `t.CEnum` 定义枚举:
```python
class color(t.CEnum):
RED: t.CEnum = 0
GREEN: t.CEnum = 1
BLUE: t.CEnum = 2
```
等价 C 代码:
```c
enum color {
RED = 0,
GREEN = 1,
BLUE = 2
};
```
枚举成员可直接使用名称:
```python
c: t.CInt = color.RED
```
### REnum(标签联合体)
`t.CEnum` 是普通枚举(整数常量集合),`t.REnum` 是**标签联合体**(tagged union / Rust enum 风格)。每个变体可携带不同的 payload,通过 `match` 模式匹配分派。适用于少变体、无通用字段、match 分派的场景(如类型系统、IR 表示)。
```python
class LLVMType(t.REnum):
class Int:
Bits: t.CInt
class Void:
pass
match ty:
case LLVMType.Int:
snprintf(buf, size, "i%d", ty.Bits)
case LLVMType.Void:
string.strcpy(buf, "void")
```
REnum 的详细用法、与 CEnum/胖节点 AST 的对比见 [05-classes.md 的 REnum 章节](05-classes.md#renum标签联合体)。
## Typedef
使用 `t.CTypedef` 创建类型别名:
```python
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)();
```
或通过注解赋值:
```python
MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct;
```
更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 t.CTypedef 的,还是后面的注解的,而且容易触发未定义行为。
## 泛型类型(PEP 695 语法)
Viper 支持 PEP 695 泛型语法 `class Name[T]:`,定义类型参数化的类。类型参数 `T` 在类体内可作为占位类型使用,实例化时用 `Name[ConcreteType]` 特化。
```python
@t.NoVTable
class GSList[T]:
Head: T | t.CPtr
Tail: T | t.CPtr
Count: t.CSizeT
lst: GSList[GNode] | t.CPtr = GSList[GNode]()
```
泛型类还支持**递归泛型继承**(如 `class GNode(GSListNode[GNode])`),实现强类型自引用结构,无需 `void*` + 转型。这是 C/C++/Rust 均无法如此简洁表达的能力。
泛型类的完整用法、递归继承、实例化示例见 [05-classes.md 的泛型类章节](05-classes.md#泛型类pep-695-语法)。
## 强制类型转换
在 Viper 中的强制类型转换有些不同,强制类型转换有两种方案,都是基于 `t.CType` 的用法,符合 Python 本意。
对于原先就继承自 `t.CType` 的类型来说,可以直接使用 call 的方法进行类型转换,比如
```python
x: t.CChar | t.CPtr = "Hello"
t.CVoid(x, t.CPtr)
```
其中用法为 `t.CType(x, ...)`,此处...可以是其它的 `t.CType` 或将要提到的 `Typedef`,将其视为组合类型对 `x` 进行强制转换。
额外补充一句,对于比较,四则运算,可以不使用强制类型转换,而是依靠隐式类型转换,但如果是严谨数学计算,推荐还是强制类型转换避免判断出错。
此外,若将一个不同类型的右值赋值到左值,则会隐式将右值转换为左值的类型。
如果你不喜欢 `t.CVoid(x, t.CPtr)` 的方法,认为这将 `void` 和 `ptr` 分开,不便于理解,那么还有一个方法,即将二者打包为一个 Typedef,即:
```python
VOIDPTR: t.CTypedef = t.CVoid | t.CPtr
```
则如果你想,你可以直接通过 call 的方式进行强转,比如:
```python
y: VOIDPTR = VOIDPTR(x)
```
## 宏定义常量
使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——标记为 `t.CDefine` 的常量在 LLVM IR 中不生成任何全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。
```python
MAX_SIZE: t.CDefine = 1024
PAGE_SIZE: t.CDefine = 4096
FA_READ: t.CDefine = 0x01
```
语义上等价于 C 的 `#define`:
```c
#define MAX_SIZE 1024
#define PAGE_SIZE 4096
#define FA_READ 0x01
```
宏定义支持表达式:
```python
CPU_FEATURE_FPU: t.CDefine = (1 << 0)
CPU_FEATURE_APIC: t.CDefine = (1 << 6)
```
宏定义也可与类型组合使用:
```python
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
```
## 位域
使用 `t.Bit(n)` 定义位域成员:
```python
class flags:
a: t.CUInt32T | t.Bit[1] # 此处,如果存入 2,二进制是 10,会被截断为 0
b: t.CUInt32T | t.Bit[3]
c: t.CUInt32T | t.Bit[4]
```
## LLVM IR 类型简写
Viper 提供了 LLVM IR 级别的类型简写:
```python
i1 # 1位整数
i8 # 8位有符号整数
i16 # 16位有符号整数
i32 # 32位有符号整数
i64 # 64位有符号整数
u1 # 1位无符号整数
u8 # 8位无符号整数
u16 # 16位无符号整数
u32 # 32位无符号整数
u64 # 64位无符号整数
```
仍然通过 `t.x` 的方式调用,比如 `t.i1` 等。
## `__attribute__` 属性
通过 `t.attr` 命名空间访问 GCC `__attribute__` 属性:
```python
t.attr.packed() # __attribute__((packed))
t.attr.aligned(16) # __attribute__((aligned(16)))
t.attr.section(".text.startup") # __attribute__((section(".text.startup")))
t.attr.always_inline() # __attribute__((always_inline))
t.attr.noinline() # __attribute__((noinline))
t.attr.noreturn() # __attribute__((noreturn))
t.attr.weak() # __attribute__((weak))
t.attr.unused() # __attribute__((unused))
t.attr.constructor() # __attribute__((constructor))
t.attr.destructor() # __attribute__((destructor))
t.attr.deprecated("use X") # __attribute__((deprecated("use X")))
```
### LLVM 函数属性
通过 `t.attr.llvm` 命名空间指定 LLVM 函数属性:
```python
t.attr.llvm.nobuiltin
t.attr.llvm.nounwind
t.attr.llvm.noredzone
t.attr.llvm.willreturn
t.attr.llvm.mustprogress
t.attr.llvm.optnone
t.attr.llvm.noinline
t.attr.llvm.alwaysinline
t.attr.llvm.readnone
t.attr.llvm.readonly
t.attr.llvm.writeonly
t.attr.llvm.inaccessiblememonly
t.attr.llvm.inaccessiblemem_or_argmemonly
```
在函数返回类型注解中使用:
```python
def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind:
return 0
```
-177
View File
@@ -1,177 +0,0 @@
# 03 - 变量声明与赋值
Viper 的变量声明使用 Python 的类型注解语法,通过 `t` 模块指定 C 级别的类型信息。
## 带注解的变量声明
使用 `变量名: 类型` 语法声明变量:
```python
x: t.CInt = 0 # int x = 0;
y: t.CUInt32T = 42 # uint32_t y = 42;
name: list[t.CChar, 64] # char name[64];
ptr: t.CVoid | t.CPtr # void* ptr;
msg: t.CConst | str = "Hello" # const char* msg = "Hello";
```
### 无初始值的声明
未赋值的变量声明会生成零初始化的变量,此处是未定义行为,即在不同环境位置可能会覆盖0,也可能不会,最好预先复制或用 memset 清除:
```python
count: t.CInt # int count = 0;
buffer: list[t.CChar, 256] # char buffer[256] = {0};
```
### 延迟赋值
变量可以先声明后赋值:
```python
x: t.CInt
x = 10
```
### 指针变量
```python
p: t.CInt | t.CPtr # int* p;
fb: t.CVoid | t.CPtr # void* fb;
str_ptr: t.CConst | t.CChar | t.CPtr # const char* str_ptr;
```
### 指针变量的特殊初始化
使用 `t.CVoid(0, t.CPtr)` 初始化指针为 NULL:
```python
p: t.CVoid | t.CPtr = t.CVoid(0, t.CPtr) # void* p = NULL;
```
或使用 `None`:
```python
p: t.CVoid | t.CPtr = None # void* p = NULL;
```
## 普通赋值
```python
x: t.CInt = 0
x = 42 # x = 42;
```
## 增强赋值
支持所有 Python 增强赋值运算符:
```python
x: t.CInt = 0
x += 1 # x += 1;
x -= 1 # x -= 1;
x *= 2 # x *= 2;
x //= 3 # x /= 3; (整数除法)
x %= 5 # x %= 5;
x <<= 1 # x <<= 1;
x >>= 1 # x >>= 1;
x |= 0xFF # x |= 0xFF;
x &= 0x0F # x &= 0x0F;
x ^= 0xAA # x ^= 0xAA;
```
## 全局变量
模块顶层声明的变量即为全局变量:
```python
kbd_tid: t.CInt = -1 # 全局 int kbd_tid = -1;
BootInfo: bootinfo | t.CPtr # 全局 struct bootinfo* BootInfo;
```
### 静态全局变量
```python
x: t.CStatic | t.CInt = 0 # static int x = 0;
```
### 外部声明
```python
x: t.CExtern | t.CInt # extern int x;
```
## 常量定义
使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——常量在 LLVM IR 中不生成全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。
```python
MAX_SIZE: t.CDefine = 1024
PAGE_SIZE: t.CDefine = 4096
FA_READ: t.CDefine = 0x01
FA_WRITE: t.CDefine = 0x02
```
## 字符串常量
Viper 中的字符串字面量编译为 C 的字符串常量(`const char*`):
```python
msg: t.CConst | str = "Hello, World!"
serial.puts(msg)
```
也可以直接传递字符串字面量:
```python
serial.puts("Hello, World!")
```
## 类型转换
使用类型构造函数进行显式类型转换:
```python
x: t.CInt = 42
y: t.CUInt32T = t.CUInt32T(x) # (uint32_t)x
f: t.CFloat = float(x) # (float)x
i: t.CInt = int(f) # (int)f
```
### 指针类型转换
```python
ptr: t.CVoid | t.CPtr = some_ptr
int_val: t.CUInt64T = t.CUInt64T(ptr) # (uint64_t)ptr — 指针转整数
```
## 结构体实例化
> 此处不理解参见 ([05-classes.md 中 结构体实例化与初始化](05-classes.md#结构体实例化与初始化))
直接使用类名作为构造函数:
```python
info: fat32_types.fat32_fileinfo
dp: fat32_types.fat32_dirobj
```
带初始化的实例化:
```python
obj: MyClass = MyClass(arg1, arg2)
```
使用 `c.Addr` 获取实例指针:
```python
obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2))
```
## delete 语句
`del` 语句可用于调用对象的 `__del__` 或 `__delete__` 方法:
```python
del obj # 调用 obj.__del__() 或 obj.__delete__()
del arr[idx] # 调用 arr.__delitem__(idx)
```
-254
View File
@@ -1,254 +0,0 @@
# 04 - 函数定义与调用
Viper 的函数定义使用 Python 的 `def` 语法,通过类型注解指定参数类型和返回类型。
## 基本函数定义
```python
def add(a: t.CInt, b: t.CInt) -> t.CInt:
return a + b
```
等价 C 代码:
```c
int add(int a, int b) {
return a + b;
}
```
## 无返回值函数
```python
def print_msg(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid:
serial.puts(msg)
```
等价 C 代码:
```c
void print_msg(const char* msg) {
serial_puts(msg);
}
```
## 函数修饰符
通过返回类型的 `|` 组合添加函数修饰符:
### 导出函数
` t.CExport` 控制函数的符号可见性——标记为 `t.CExport` 的函数不加 SHA1 前缀,全局可见。详见 [01-overview.md 中 t.CExport 深度解析](01-overview.md#tcexport-深度解析)。
```python
def _start() -> t.CInt | t.CExport:
return 0
```
### 外部函数声明
使用 `c.State` 表示仅声明不定义:
```python
def isr0() -> t.CExtern | t.CVoid | c.State: pass
def isr1() -> t.CExtern | t.CVoid | c.State: pass
```
等价 C 代码:
```c
extern void isr0();
extern void isr1();
```
### 内联函数
`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。详见 [01-overview.md 中 t.CInline 深度解析](01-overview.md#tcinline-深度解析)。
```python
def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline:
return a + b
```
### 宏函数
当函数返回类型注解包含 `t.CDefine` 时,该函数被视为宏函数,不生成 LLVM IR 函数定义,在调用处内联展开。详见 [01-overview.md 中 t.CDefine 函数](01-overview.md#tcdefine-函数)。
```python
def MAKE_FLAG(bit) -> t.CDefine:
return (1 << bit)
```
### 静态函数
```python
def helper() -> t.CVoid | t.CStatic:
pass
```
## 函数属性装饰器
使用 `@c.Attribute` 添加 GCC `__attribute__` 属性:
```python
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt:
return 0
```
等价 C 代码:
```c
__attribute__((section(".text.startup"), aligned(16)))
int _start() {
return 0;
}
```
### 常用属性组合
```python
@c.Attribute(t.attr.always_inline())
def hot_path() -> t.CInt:
return 0
@c.Attribute(t.attr.noreturn())
def panic(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid:
serial.puts(msg)
while True: pass
@c.Attribute(t.attr.packed)
```
## LLVM 函数属性
在返回类型注解中通过 `t.attr.llvm` 指定 LLVM 属性:
```python
def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind:
return 0
```
## 多返回值(CReturn)
使用 `@c.CReturn` 装饰器实现多返回值,通过指针参数实现:
```python
@c.CReturn(t.CInt, t.CInt)
def divmod(a: t.CInt, b: t.CInt) -> t.CVoid:
q: t.CInt = a // b
r: t.CInt = a % b
return q, r
```
规则:
1. `CReturn` 中的类型数量决定返回值个数
2. 自动为每个返回类型添加指针参数(`t.CInt` → `t.CInt | t.CPtr`)
3. 参数名自动生成为 `__ReturnValue0__`、`__ReturnValue1__` 等
4. 调用处自动传参 `&xxx`
5. 必须使用左右值赋值,返回值不能直接传入函数。
## 指针参数
```python
def read_data(buf: t.CChar | t.CPtr, size: t.CSizeT) -> t.CInt:
pass
```
等价 C 代码:
```c
int read_data(char* buf, size_t size);
```
### 输出参数模式
使用 `c.Addr` 传递变量地址作为输出参数:
```python
res: t.CInt = fat32.opendir("/", c.Addr(dp))
```
等价 C 代码:
```c
int res = fat32_opendir("/", &dp);
```
后续会使用隐式左值获取来减少 `c.Addr` 的直接使用。
## 函数指针类型
使用 `t.Callable` 定义函数指针类型:
```python
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt]
```
等价 C 代码:
```c
typedef int (*irq_handler_t)();
```
带参数的函数指针:
```python
callback_t: t.Callable[[t.CInt, t.CInt], t.CVoid]
```
## 默认参数
Viper 支持函数默认参数值:
```python
def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | str = "Window") -> t.CInt:
pass
```
## return 语句
```python
return 0 # return 0;
return # return; (void 函数)
return a, b # 多返回值(需配合 @c.CReturn)
```
## 全局变量声明
函数外的变量声明为全局变量,函数内通过 `global` 关键字访问:
```python
BootInfo: bootinfo | t.CPtr
def init() -> t.CVoid:
global BootInfo
BootInfo = saved_rdi
```
支持 func-in-func 嵌套函数。
## Call Func 函数调用
函数调用最好通过顺序调用来实现
```python
def add(x: int, y: int, z: int):
return (x + y) * z
def main() -> int | t.CExport:
print(add(1, 2, 3)) # (1 + 2) * 3 = 9
```
这也是 C 中的标准实现方法,但实际上,你也可以乱序传参。
```python
# 仍然用刚才的 add 举例
def main() -> int | t.CExport:
print(add(z=3, x=1, y=2)) # (1 + 2) * 3 = 9
```
乱序传参或带参传参对于结构体的初始化同样有效。同时,你也能够给函数指定默认值。
```python
def add(x: int, y: int, z: int = 1):
return (x + y) * z
def main() -> int | t.CExport:
print(add(1, 2)) # (1 + 2) * 1 = 3
```
在结构体中也可以指定默认值。
-258
View File
@@ -1,258 +0,0 @@
# 05 - 类与数据布局
Viper 中的 `class` 有两种用途:定义**数据布局**(结构体/联合体/枚举,本章内容),以及定义**面向对象的对象类型**(见 [06-oop.md](06-oop.md))。
## 结构体定义
普通 `class` 定义编译为 LLVM 结构体类型:
```python
class point:
x: t.CInt
y: t.CInt
```
在 C 中:
```c
struct point {
int x;
int y;
};
```
在 LLVM IR 中:
```llvm
%"<SHA1>.point" = type { i32, i32 }
```
### 带属性的结构体
```python
@c.Attribute(t.attr.packed)
class idt_entry:
base_low: t.CUInt16T
selector: t.CUInt16T
ist_attr: t.CUInt8T
type_attr: t.CUInt8T
base_middle: t.CUInt16T
base_high: t.CUInt32T
reserved1: t.CUInt32T
```
### 结构体数组
```python
idt: list[idt_entry, 256] = []
```
### 结构体指针成员
```python
class node:
value: t.CInt
next: node | t.CPtr # 指向自身的指针(有向图链表)
```
### 结构体实例化与初始化
```python
entry: idt_entry = idt_entry()
```
或带构造函数:
```python
mousepoint = Point(x=1, y=2)
```
乱序传参或带参传参对于结构体的初始化同样有效:
```python
entry: idt_entry = idt_entry(selector=0x08, base_low=0x0000)
```
也可以给结构体成员指定默认值:
```python
class config:
width: t.CInt = 640
height: t.CInt = 480
depth: t.CInt = 32
```
使用 `c.Addr` 获取实例指针:
```python
obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2))
```
### 字节序标记
> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。
使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序:
```python
class network_packet:
length: t.CUInt16T | t.BigEndian # 大端序存储
type: t.CUInt8T # 默认小端序
```
## 联合体
继承 `t.CUnion` 定义联合体:
```python
class value(t.CUnion):
ival: t.CInt
fval: t.CFloat
pval: t.CVoid | t.CPtr
```
等价 C 代码:
```c
union value {
int ival;
float fval;
void* pval;
};
```
## 枚举
继承 `t.CEnum` 定义枚举:
```python
class color(t.CEnum):
RED: t.CEnum = 0
GREEN: t.CEnum = 1
BLUE: t.CEnum = 2
```
等价 C 代码:
```c
enum color {
RED = 0,
GREEN = 1,
BLUE = 2
};
```
枚举成员可直接使用名称:
```python
c: t.CInt = color.RED
```
## REnum(标签联合体)
`t.CEnum` 是普通枚举(整数常量集合),`t.REnum` 是**标签联合体**(tagged union / Rust enum 风格)。每个变体可携带不同的 payload,通过 `match` 模式匹配分派。
### 适用场景
| 类型 | 变体数 | 通用字段 | 访问模式 | 适用 |
|------|--------|---------|---------|------|
| `t.CEnum` | 任意 | 无 | 整数比较 | 状态码、opcode、token 类型 |
| `t.REnum` | 少(~10) | 无 | match 分派 | 类型系统、AST 少变体场景 |
| 胖节点(如 AST) | 多(70+) | 有 | vtype + 直接属性 | AST 节点(见 [includes/ast](../includes/ast)) |
### 定义
```python
class LLVMType(t.REnum):
class Int: # 变体 Int,携带 payload
Bits: t.CInt
class Ptr: # 变体 Ptr,携带 payload
Pointee: LLVMType | t.CPtr # 自引用用指针
class Void: # 变体 Void,无 payload
pass
```
布局为 `{ i32 __tag, <max_variant_payload> }`,所有变体共享最大变体的 payload 空间。
### match 分派
```python
match ty:
case LLVMType.Int: # 位置绑定 payload:ty.Bits 可用
snprintf(buf, size, "i%d", ty.IntBits)
case LLVMType.Ptr: # ty.PtrPointee 可用
TypePrint(buf, size, ty.PtrPointee)
case LLVMType.Void:
string.strcpy(buf, "void")
```
详见 [includes/llvmlite/__types.py](../includes/llvmlite/__types.py) 的 `LLVMType` 实现。
## Typedef
使用 `t.CTypedef` 创建类型别名:
```python
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)();
```
或通过注解赋值:
```python
MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct;
```
更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 `t.CTypedef` 的,还是后面的注解的,而且容易触发未定义行为。
## 泛型类(PEP 695 语法)
TransPyC 支持 PEP 695 泛型语法 `class Name[T]:`,定义类型参数化的类。
### 基本泛型类
```python
@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 append(self, node: T): ...
```
### 递归泛型继承
泛型类可递归引用自身作为类型参数,实现强类型自引用结构(无需转型):
```python
@t.NoVTable
class GNode(GSListNode[GNode]): # 递归泛型继承
value: t.CInt
# 此时 GNode.Next: GNode|CPtr —— 强类型,零转型
```
这是 C(`void*` + cast)、C++(模板继承但无 `@t.NoVTable` 精细控制)、Rust(无继承,需 trait bound)均无法如此简洁表达的能力。
### 实例化
```python
lst: GSList[GNode] | t.CPtr = GSList[GNode]()
node: GNode | t.CPtr = GNode()
lst.append(node) # 类型安全:append 只接受 GNode
```
详见 [includes/linkedlist.py](../includes/linkedlist.py) 和 [includes/vector.py](../includes/vector.py)。
## 位域
使用 `t.Bit(n)` 定义位域成员:
```python
class flags:
a: t.CUInt32T | t.Bit[1]
b: t.CUInt32T | t.Bit[3]
c: t.CUInt32T | t.Bit[4]
```
注意:如果存入超出位域宽度的值,会被截断。例如 `a` 为 1 位,存入 2(二进制 `10`)会被截断为 0。
-692
View File
@@ -1,692 +0,0 @@
# 06 - 面向对象与运算符重载
Viper 中的 `class` 有两种语义:**数据布局**(结构体/联合体/枚举,见 [05-classes.md](05-classes.md))和**面向对象**。面向对象特性通过 `@t.Object` 装饰器启用,多态通过 `@t.CVTable` 装饰器启用,非多态继承(C++ 风格,无 vtable 开销)通过 `@t.NoVTable` 装饰器启用。
## `@t.Object` 面向对象
使用 `@t.Object` 装饰器启用面向对象特性,类将拥有成员方法、运算符重载、属性装饰器等 OOP 支持。编译器也会自动识别:如果结构体内有函数定义,会自动使用 `@t.Object` 行为,但在实际工程中更推荐明确标记,避免未定义行为。
### 基本定义
```python
@t.Object
class ViperKernel:
BootInfo: bootinfo | t.CPtr
VGA: vga._VGAScreenDriver | t.CPtr
VGA_drv: vga._VGAScreenDriver
def __init__(self):
self.BootInfo = BootInfo
serial.init()
serial.puts("ViperOS VKernel Test\n")
```
避免在 `__init__` 中使用 `return`,虽然不会报错,但是你永远无法获得 `return` 的结果,如果需要提前结束代码流,`return` 也不失为一种办法。
### 成员方法
```python
@t.Object
class Sheet:
id: t.CInt
x: t.CInt
y: t.CInt
w: t.CInt
h: t.CInt
def __init__(self, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
self.x = x
self.y = y
self.w = w
self.h = h
def MoveTo(self, nx: t.CInt, ny: t.CInt):
self.x = nx
self.y = ny
def Resize(self, nw: t.CInt, nh: t.CInt):
self.w = nw
self.h = nh
```
### 方法调用
```python
sheet: Sheet = Sheet(0, 0, 640, 480)
sheet.MoveTo(100, 100)
sheet.Resize(800, 600)
```
### 属性装饰器
支持 Python 的 `@property` 和 `@xxx.setter` 装饰器:
> `@xxx.setter` 和自定义装饰器正在试验阶段,尽可能不要使用
```python
@t.Object
class MyObj:
_value: t.CInt
@property
def value(self) -> t.CInt:
return self._value
@value.setter
def value(self, v: t.CInt):
self._value = v
```
### 静态方法
```python
@staticmethod
def _yield():
pass
```
### 对象指针与解引用
`@t.Object` 的实例通常通过指针操作:
```python
obj_ptr: MyClass | t.CPtr = c.Addr(MyClass())
obj: MyClass = c.Deref(obj_ptr)
```
### 成员访问
通过 `self` 访问成员变量和方法:
```python
def method(self) -> t.CVoid:
self.x = 10
y: t.CInt = self.y
self.DoSomething()
```
### 内嵌对象
`@t.Object` 可以包含其他对象实例(非指针):
```python
@t.Object
class Sheet:
_surf_obj: gfx.Surface
_renderer_obj: gfx.Renderer
surf: gfx.Surface | t.CPtr
renderer: gfx.Renderer | t.CPtr
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: t.CInt, h: t.CInt):
self._surf_obj = gfx.Surface(fb, zb, w, h)
self.surf = c.Addr(self._surf_obj)
self._renderer_obj = gfx.Renderer(self.surf)
self.renderer = c.Addr(self._renderer_obj)
```
### `__before_init__` 方法
所有类(不限 `@t.Object`/`@t.CVTable`)自动生成 `__before_init__` 方法,在 `__init__` 之前**自动填充成员默认值**,并对 `@t.CVTable` 类初始化 vtable:
```llvm
define void @"<SHA1>.ClassName.__before_init__"(%"<SHA1>.ClassName"* %self) {
entry:
; 对 @t.CVTable 类:存储 vtable 指针到 slot 0
; 遍历所有成员:若有默认值则 store 默认值,否则 store 零值
ret void
}
```
**职责**:
- 填充类定义中声明的成员默认值(如 `x: t.CInt = 0` 中的 `0`)
- 对无默认值的成员填充类型零值
- 对 `@t.CVTable` 类额外初始化 vtable 指针
**调用时机**(由编译器在构造时自动插入):
1. `alloca` 栈分配后调用一次
2. 若存在 `__new__` 方法且返回堆指针,对堆指针再调用一次(alloca 的默认值已随栈帧丢弃,必须重新填充)
3. `__init__` 调用前
**就地构造**:用户也可手动调用 `__before_init__` 实现就地构造(placement new 语义),典型用法见 `mpool.alloc_buf`:
```python
buf: Buf | t.CPtr = pool.alloc(Buf.__sizeof__())
buf.__before_init__() # 填充默认值
buf.__init__(args) # 用户初始化逻辑
```
跨模块导入类时,导入侧也会声明 `__before_init__`,保证跨模块构造行为一致。
## `@t.NoVTable` 非多态继承
`@t.NoVTable` 启用 C++ 风格的非多态继承(对应 `struct A : B {}` 无 virtual)。与 `@t.CVTable` 的区别:
| 特性 | `@t.NoVTable` | `@t.CVTable` |
|------|---------------|--------------|
| vtable 指针 | ❌ 无 | ✅ 自动插入 slot 0 |
| 虚派发 | ❌ 无 | ✅ 支持 |
| 方法继承 | ✅ 生成包装函数转发 | ✅ 通过 vtable |
| 字段展平 | ✅ 父类字段前置嵌入 | ✅ 父类字段前置嵌入(vtable 之后) |
| 运行时开销 | 零 | 每次虚调用一次间接跳转 |
### 基本定义
```python
@t.NoVTable
class LinkedNode:
next: "LinkedNode" | t.CPtr
prev: "LinkedNode" | t.CPtr
def append(self, node: "LinkedNode" | t.CPtr): ...
@t.NoVTable
class GNode(LinkedNode): # 非多态继承
value: t.CInt
```
子类 `GNode` 的结构体布局为 `{next, prev, value}`(父类字段前置,无 vtable 指针)。
### 方法继承机制
子类调用父类方法时,编译器通过 `_generate_inherited_method_wrappers` 自动生成包装函数:将 `self` bitcast 为父类指针后尾调用父类方法。例如 `gnode.append(child)` 会生成:
```llvm
define void @"<SHA1>.GNode.append"(%"<SHA1>.GNode"* %self, ...) {
entry:
%base = bitcast %"<SHA1>.GNode"* %self to %"<SHA1>.LinkedNode"*
call void @"<SHA1>.LinkedNode.append"(%"<SHA1>.LinkedNode"* %base, ...)
ret void
}
```
### 跨模块继承
跨模块父类(如 `linkedlist.LinkedNode`)的 `@t.NoVTable` 标记会在导入时被检测并记录,子类继承时同样跳过 vtable 插入。
### 向下转型
父类指针→子类指针需显式转型(生成 bitcast IR):
```python
root: Node = Node() # Node 继承 LinkedNode
child: LinkedNode | t.CPtr = root.child
# child 是 LinkedNode*,需要转回 Node*:
node: Node | t.CPtr = (Node | t.CPtr)(child)
```
隐式转型仅向上(子→父)。
## `@t.CVTable` 虚函数表与多态
> 尽可能避免使用 `self[0]` 来获取结构体成员,其不稳定,也不要手动操作虚表。
使用 `@t.CVTable` 装饰器可以启用虚函数表支持。启用后,结构体第一个成员自动插入 `i8*` 类型的 vtable 指针。`@t.CVTable` 的操作必须配合 `@t.Object`,但有时编译器会自动识别是否存在结构体内函数,自动使用 `@t.Object`。
### 基本定义
```python
@t.Object
@t.CVTable
class Base:
def __init__(self):
pass
def method(self) -> t.CInt:
return 0
```
在 LLVM IR 中,`@t.CVTable` 类的结构体类型自动插入 vtable 指针:
```llvm
%"<SHA1>.Base" = type { i8*, i32 }
```
同时,编译器会生成全局 vtable 变量:
```llvm
@"<SHA1>.Base_Vtable" = internal global [1 x i8*] zeroinitializer
```
### 继承与多态
虚表可以帮你使用继承语法实现多态:
```python
@t.Object
@t.CVTable
class Base:
def __init__(self):
pass
def method(self) -> t.CInt:
return 0
@t.Object
@t.CVTable
class M1(Base):
def method(self) -> t.CInt:
return 1
```
当 M1 被初始化时,VTable 会自动修改,这点和 C++ 相同,尽可能避免直接操作 VTable。
继承时,子类会自动继承父类的成员变量和方法。子类重写父类方法时,vtable 中对应位置的函数指针被子类方法替换,实现多态。
### VTable 运行时修改
如果需要临时构造一个额外的 `Base` 结构体,还可以使用:
```python
@t.Object
@t.CVTable
class Base:
def __init__(self):
pass
def method(self) -> t.CInt:
return 0
def __method1(self) -> t.CInt:
return 1
def main() -> t.CInt | t.CExport:
b: Base = Base()
b.method = __method1
```
启用 `VTable` 的表中,允许直接修改内部函数为函数指针,在底层,此操作将修改 `VTable` 来达成目的。编译器会检测当前 vtable 是否与类 vtable 相同,如果相同则创建 vtable 的副本(memcpy),避免修改影响所有实例。
### 虚方法调度机制
虚方法调用的核心流程:
1. 从对象指针 GEP 获取第 0 个 slot(vtable 指针)
2. 加载 vtable 指针
3. bitcast 为 `[N x i8*]*` 类型
4. GEP 获取方法索引处的函数指针
5. 加载函数指针
6. bitcast 为正确的函数指针类型
7. 间接调用
## 继承
### 结构体成员继承
当子类继承父类(父类在 `Gen.class_members` 中存在)时:
- 父类的成员变量被继承到子类(排在子类成员之前)
- 父类的默认值也被继承
- 父类的方法被继承(重命名为 `子类名.方法名`)
```python
@t.Object
class Animal:
name: list[t.CChar, 32]
age: t.CInt
def __init__(self, age: t.CInt):
self.age = age
def Speak(self) -> t.CVoid:
serial.puts("...\n")
@t.Object
class Dog(Animal):
breed: t.CInt
def Speak(self) -> t.CVoid:
serial.puts("Woof!\n")
```
### 异常类继承
Viper 支持异常类的继承,用于 `try/except` 的异常匹配:
```python
class MyError(Exception):
pass
class SpecificError(MyError):
pass
```
详见 [09-exceptions.md](09-exceptions.md)。
## 运算符重载
`@t.Object` 类支持运算符重载。编译器在遇到运算符时,首先检查左操作数是否为结构体类型,如果是则尝试调用对应的 dunder 方法。
### 算术运算符重载
| 运算符 | Dunder 方法 | 示例 |
|--------|------------|------|
| `+` | `__add__` | `a + b` → `a.__add__(b)` |
| `-` | `__sub__` | `a - b` → `a.__sub__(b)` |
| `*` | `__mul__` | `a * b` → `a.__mul__(b)` |
| `/` | `__truediv__` | `a / b` → `a.__truediv__(b)` |
| `//` | `__floordiv__` | `a // b` → `a.__floordiv__(b)` |
| `%` | `__mod__` | `a % b` → `a.__mod__(b)` |
| `**` | `__pow__` | `a ** b` → `a.__pow__(b)` |
示例:
```python
@t.Object
class Vec2:
x: t.CFloat
y: t.CFloat
def __init__(self, x: t.CFloat, y: t.CFloat):
self.x = x
self.y = y
def __add__(self, other: Vec2) -> Vec2:
result: Vec2 = Vec2(0.0, 0.0)
result.x = self.x + other.x
result.y = self.y + other.y
return result
def __mul__(self, scalar: t.CFloat) -> Vec2:
result: Vec2 = Vec2(0.0, 0.0)
result.x = self.x * scalar
result.y = self.y * scalar
return result
```
### 增量赋值运算符重载
| 增量运算符 | 优先 Dunder | 回退 Dunder |
|-----------|------------|------------|
| `+=` | `__iadd__` | `__add__` |
| `-=` | `__isub__` | `__sub__` |
| `*=` | `__imul__` | `__mul__` |
| `/=` | `__itruediv__` | `__truediv__` |
| `//=` | `__ifloordiv__` | `__floordiv__` |
| `%=` | `__imod__` | `__mod__` |
| `**=` | `__ipow__` | `__pow__` |
如果未定义增量版本(如 `__iadd__`),编译器自动回退到普通版本(如 `__add__`)。
### 比较运算符重载
> **实验性**:以下比较运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。定义它们不会报错,但比较运算不会自动调用。
| 运算符 | Dunder 方法 | 状态 |
|--------|------------|------|
| `==` | `__eq__` | 仅类型推断识别 |
| `!=` | `__ne__` | 仅类型推断识别 |
| `<` | `__lt__` | 仅类型推断识别 |
| `<=` | `__le__` | 仅类型推断识别 |
| `>` | `__gt__` | 仅类型推断识别 |
| `>=` | `__ge__` | 仅类型推断识别 |
### 反向运算符重载
> **实验性**:以下反向运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。
| Dunder 方法 | 预期语义 | 状态 |
|------------|---------|------|
| `__radd__` | 右操作数加法 | 仅类型推断识别 |
| `__rsub__` | 右操作数减法 | 仅类型推断识别 |
| `__rmul__` | 右操作数乘法 | 仅类型推断识别 |
| `__rtruediv__` | 右操作数真除法 | 仅类型推断识别 |
| `__rfloordiv__` | 右操作数整除 | 仅类型推断识别 |
| `__rmod__` | 右操作数取模 | 仅类型推断识别 |
| `__rpow__` | 右操作数幂运算 | 仅类型推断识别 |
### 一元运算符重载
> **实验性**:以下一元运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。
| 运算符 | Dunder 方法 | 状态 |
|--------|------------|------|
| `-a` | `__neg__` | 仅类型推断识别 |
| `+a` | `__pos__` | 仅类型推断识别 |
## 可调用对象 `__call__`
```python
@t.Object
class Counter:
value: t.CInt
def __init__(self):
self.value = 0
def __call__(self) -> t.CInt:
self.value += 1
return self.value
c: Counter = Counter()
x: t.CInt = c() # x = 1
y: t.CInt = c() # y = 2
```
## 下标访问重载
### `__getitem__` — 读取
```python
def __getitem__(self, key: t.CInt) -> t.CInt:
return self.data[key]
```
### `__setitem__` — 赋值
```python
def __setitem__(self, key: t.CInt, value: t.CInt):
self.data[key] = value
```
### `__delitem__` — 删除
```python
def __delitem__(self, key: t.CInt):
pass
```
## 布尔转换 `__bool__`
```python
@t.Object
class Buffer:
size: t.CInt
data: list[t.CChar, 1024]
def __bool__(self) -> t.CBool:
return self.size > 0
buf: Buffer = Buffer()
if buf:
serial.puts("buffer is not empty\n")
```
## 长度 `__len__`
```python
@t.Object
class Buffer:
size: t.CInt
def __len__(self) -> t.CInt:
return self.size
buf: Buffer = Buffer()
n: t.CInt = len(buf)
```
## 字符串转换 `__str__`
```python
@t.Object
class Point:
x: t.CInt
y: t.CInt
def __str__(self) -> t.CConst | t.CChar | t.CPtr:
return "Point"
p: Point = Point(1, 2)
print(p) # 调用 p.__str__()
```
## 绝对值 `__abs__`
```python
@t.Object
class SignedValue:
val: t.CInt
def __abs__(self) -> t.CInt:
if self.val < 0:
return -self.val
return self.val
sv: SignedValue = SignedValue()
sv.val = -42
a: t.CInt = abs(sv) # a = 42
```
## 迭代器协议
Viper 的迭代器协议与 Python 相同,但 `__next__` 的实现方式通过 `StopIteration` 异常来结束。
### `__iter__` 和 `__next__`
```python
@t.Object
class IntRange:
start: t.CInt
end: t.CInt
current: t.CInt
def __init__(self, start: t.CInt, end: t.CInt):
self.start = start
self.end = end
self.current = start
def __iter__(self):
return self
def __next__(self, stop_flag) -> t.CInt:
if self.current >= self.end:
raise StopIteration
val: t.CInt = self.current
self.current += 1
return val
```
### for 循环使用
```python
r: IntRange = IntRange(0, 10)
for i in r:
print(i)
```
编译器生成的等价逻辑:
```c
IntRange r = IntRange_init(0, 10);
IntRange iter = IntRange___iter__(&r);
while (1) {
i1 stop_flag = 0;
int i = IntRange___next__(&iter, &stop_flag);
if (stop_flag == 1) break;
print_int(i);
}
```
## 上下文管理器
`with` 语句要求对象实现 `__enter__` 和 `__exit__` 方法:
```python
@t.Object
class File:
fd: t.CInt
path: t.CConst | t.CChar | t.CPtr
def __init__(self, path: t.CConst | t.CChar | t.CPtr, flags: t.CInt):
self.path = path
self.fd = -1
def __enter__(self):
self.fd = fat32.open(self.path, self.flags)
return self
def __exit__(self):
fat32.close(self.fd)
def read(self) -> t.CInt:
return fat32.read(self.fd)
```
使用方式:
```python
with File("/test.txt", FA_READ) as f:
data: t.CInt = f.read()
```
编译器会自动保证 `__exit__` 在 `with` 块结束时被调用。
## 析构 `__del__` / `__delete__`
```python
del obj # 调用 obj.__del__() 或 obj.__delete__()
del arr[idx] # 调用 arr.__delitem__(idx)
```
## Dunder 方法完整参考
### 已实现自动调度的 Dunder 方法
| Dunder 方法 | 触发语法 | 说明 |
|------------|---------|------|
| `__init__` | `ClassName(args)` | 构造函数 |
| `__before_init__` | 自动生成 | vtable 初始化,在 `__init__` 之前执行 |
| `__add__` | `a + b` | 加法 |
| `__sub__` | `a - b` | 减法 |
| `__mul__` | `a * b` | 乘法 |
| `__truediv__` | `a / b` | 真除法 |
| `__floordiv__` | `a // b` | 整除 |
| `__mod__` | `a % b` | 取模 |
| `__pow__` | `a ** b` | 幂运算 |
| `__iadd__` | `a += b` | 增量加法(回退到 `__add__`) |
| `__isub__` | `a -= b` | 增量减法(回退到 `__sub__`) |
| `__imul__` | `a *= b` | 增量乘法(回退到 `__mul__`) |
| `__itruediv__` | `a /= b` | 增量真除法(回退到 `__truediv__`) |
| `__ifloordiv__` | `a //= b` | 增量整除(回退到 `__floordiv__`) |
| `__imod__` | `a %= b` | 增量取模(回退到 `__mod__`) |
| `__ipow__` | `a **= b` | 增量幂运算(回退到 `__pow__`) |
| `__call__` | `obj(args)` | 可调用对象 |
| `__getitem__` | `obj[key]` | 下标读取 |
| `__setitem__` | `obj[key] = value` | 下标赋值 |
| `__delitem__` | `del obj[key]` | 下标删除 |
| `__bool__` | `if obj:` | 布尔转换 |
| `__len__` | `len(obj)` | 长度 |
| `__str__` | `str(obj)` / `print(obj)` | 字符串转换 |
| `__abs__` | `abs(obj)` | 绝对值 |
| `__iter__` | `for x in obj:` | 获取迭代器 |
| `__next__` | `for x in obj:` | 获取下一个值(标志位方式) |
| `__enter__` | `with obj as x:` | 上下文管理器进入 |
| `__exit__` | `with obj as x:` | 上下文管理器退出 |
| `__del__` | `del obj` | 析构 |
| `__delete__` | `del obj` | 删除描述符 |
### 声明支持但未实现自动调度的 Dunder 方法
| Dunder 方法 | 预期触发语法 | 当前状态 |
|------------|------------|---------|
| `__eq__` | `a == b` | 仅类型推断识别,比较运算不自动调度 |
| `__ne__` | `a != b` | 同上 |
| `__lt__` | `a < b` | 同上 |
| `__le__` | `a <= b` | 同上 |
| `__gt__` | `a > b` | 同上 |
| `__ge__` | `a >= b` | 同上 |
| `__neg__` | `-a` | 仅类型推断识别,一元负号不自动调度 |
| `__pos__` | `+a` | 同上 |
| `__radd__` | 右操作数加法 | 仅类型推断识别 |
| `__rsub__` | 右操作数减法 | 同上 |
| `__rmul__` | 右操作数乘法 | 同上 |
| `__rtruediv__` | 右操作数真除法 | 同上 |
| `__rfloordiv__` | 右操作数整除 | 同上 |
| `__rmod__` | 右操作数取模 | 同上 |
| `__rpow__` | 右操作数幂运算 | 同上 |
-256
View File
@@ -1,256 +0,0 @@
# 07 - 控制流
Viper 支持 Python 风格的控制流语句,编译为 LLVM IR 的基本块和分支指令。
## 条件语句
### if / elif / else
```python
if x > 0:
y = 1
elif x == 0:
y = 0
else:
y = -1
```
等价 C 代码:
```c
if (x > 0) {
y = 1;
} else if (x == 0) {
y = 0;
} else {
y = -1;
}
```
### 条件表达式
```python
is_dir: t.CInt = 1 if (info.attr & AM_DIR) else 0
```
等价 C 代码:
```c
int is_dir = (info.attr & AM_DIR) ? 1 : 0;
```
### None 检查
```python
if BootInfo != None:
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
else:
paging.init(0, 0)
```
等价 C 代码:
```c
if (BootInfo != NULL) {
paging_init(BootInfo->MemmapAddr, BootInfo->MemmapSize);
} else {
paging_init(0, 0);
}
```
## 循环语句
### while 循环
```python
i: t.CInt = 0
while i < 10:
buf[i] = 0
i += 1
```
等价 C 代码:
```c
int i = 0;
while (i < 10) {
buf[i] = 0;
i += 1;
}
```
### while-else
```python
while i < count:
if found:
break
else:
serial.puts("not found\n")
```
`else` 块在循环正常结束(非 `break` 退出)时执行。
### 无限循环
```python
while True:
sched.Scheduler._yield()
```
等价 C 代码:
```c
while (1) {
scheduler_yield();
}
```
### for 循环(range)(关于 for 循环的更多用法,参见 [06-oop.md 中 迭代器协议](06-oop.md#迭代器协议))
```python
for i in range(10):
buf[i] = 0
for i in range(5, 10):
buf[i] = 0
for i in range(0, 100, 2):
buf[i] = 0
```
等价 C 代码:
```c
for (int i = 0; i < 10; i++) {
buf[i] = 0;
}
for (int i = 5; i < 10; i++) {
buf[i] = 0;
}
for (int i = 0; i < 100; i += 2) {
buf[i] = 0;
}
```
### for 循环(迭代器)
如果类实现了 `__iter__` 和 `__next__` 方法,可以使用 `for ... in` 迭代:
```python
container: Iter = Iter()
for item in container:
process(item)
```
### for-else
```python
for i in range(count):
if items[i] == target:
break
else:
serial.puts("not found\n")
```
### break 和 continue
```python
while True:
if done:
break
if skip:
continue
process()
```
## match 语句
Viper 支持 Python 3.10+ 的 `match` 语句,编译为 C 的 `switch` 语句:
```python
match self.ctype:
case UI_LABEL:
self.RenderLabel(sh)
case UI_BUTTON:
self.RenderButton(sh)
case UI_PANEL:
self.RenderPanel(sh)
case _:
pass
```
等价 C 代码:
```c
switch (self->ctype) {
case UI_LABEL:
self_RenderLabel(self, sh);
break;
case UI_BUTTON:
self_RenderButton(self, sh);
break;
case UI_PANEL:
self_RenderPanel(self, sh);
break;
default:
break;
}
```
### match 值匹配
```python
match code:
case 0:
serial.puts("OK\n")
case 1:
serial.puts("Error\n")
case _:
serial.puts("Unknown\n")
```
### match 或模式
```python
match value:
case 1 | 2 | 3:
serial.puts("small\n")
case _:
serial.puts("other\n")
```
### fallthrough(无 break)
默认每个 `case` 自动添加 `break`。如需 fallthrough,使用 `c.NoBreak`:
```python
match value:
case 1:
do_one()
c.NoBreak
case 2:
do_two()
```
如果需要提前 break,需要使用 `c.Break()`,因为在 `Python` 中,`match` 分支不支持直接使用 `break`。
## assert 语句
> 避免使用此语句,此语句未经充分测试,在多数情况下,编译器不知道如何展示结果。
```python
assert ptr != None, "null pointer"
```
编译为条件检查和错误报告。
## with 语句
`with` 语句用于资源管理,要求对象实现 `__enter__` 和 `__exit__` 方法:
```python
with File("/test.txt", FA_READ) as f:
data: t.CInt = f.read()
```
等价 C 代码:
```c
File* f = File_enter(File_new("/test.txt", FA_READ));
int data = File_read(f);
File_exit(f);
```
-304
View File
@@ -1,304 +0,0 @@
# 08 - C 语言操作
Viper 通过 `c` 模块提供对 C 语言底层特性的访问,包括指针操作、内联汇编、预处理指令等。
## 指针操作
### 取地址 `c.Addr`
```python
x: t.CInt = 42
p: t.CInt | t.CPtr = c.Addr(x) # int* p = &x;
```
对结构体成员取地址:
```python
res: t.CInt = fat32.opendir("/", c.Addr(dp)) # res = fat32_opendir("/", &dp);
```
对数组取地址:
```python
viperlib.snprintf(c.Addr(buf), 64, "hello %d", 42) # snprintf(&buf, 64, "hello %d", 42);
```
### 解引用 `c.Deref`
```python
ptr: Sheet | t.CPtr = c.Addr(sheet_obj)
obj: Sheet = c.Deref(ptr) # struct Sheet obj = *ptr;
```
### 内存拷贝 `c.Load`
```python
c.Load(ptr, value) # *ptr = *value;
```
### 解引用赋值 `c.DerefAs`
```python
c.DerefAs(ptr, value) # *ptr = value;
```
### 赋值 `c.Set`
```python
c.Set(target, value) # target = value;
```
## 内联汇编 `c.Asm`
Viper 提供了声明式的内联汇编语法,编译为 GCC 风格的 `__asm__ __volatile__` 语句。
### 基本用法
```python
c.Asm("nop") # __asm__ __volatile__("nop");
```
### 带操作数的汇编
使用 f-string 和 `c.AsmInp` / `c.AsmOut` 标记操作数:
```python
saved_rdi: t.CUnsignedLong
c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI])
```
等价 C 代码:
```c
__asm__ __volatile__(
"mov %0, rdi"
: "=r"(saved_rdi)
:
: "memory", "rdi"
);
```
### 输入操作数 `c.AsmInp`
```python
msg: t.CConst | t.CChar | t.CPtr = "Hello"
c.Asm(f"mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
```
### 完整示例
```python
c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
```
### ASM_DESCR 约束字符
#### 操作数修饰符
| 常量 | 值 | 说明 |
|------|----|------|
| `MODIFIER_OUTPUT` | `=` | 输出操作数 |
| `MODIFIER_READWRITE` | `+` | 读写操作数 |
| `MODIFIER_INPUT` | `` | 输入操作数(默认) |
| `MODIFIER_GLOBAL` | `&` | 全局操作数 |
#### 寄存器约束
| 常量 | 值 | 说明 |
|------|----|------|
| `REG_ANY` | `r` | 任何通用寄存器 |
| `REG_EAX` / `REG_RAX` | `a` | EAX/RAX |
| `REG_EBX` / `REG_RBX` | `b` | EBX/RBX |
| `REG_ECX` / `REG_RCX` | `c` | ECX/RCX |
| `REG_EDX` / `REG_RDX` | `d` | EDX/RDX |
| `REG_ESI` / `REG_RSI` | `S` | ESI/RSI |
| `REG_EDI` / `REG_RDI` | `D` | EDI/RDI |
| `REG_XMM` | `x` | XMM 寄存器 |
#### 内存与立即数
| 常量 | 值 | 说明 |
|------|----|------|
| `MEMORY` | `m` | 内存操作数 |
| `IMMEDIATE` | `i` | 立即数 |
| `ANY` | `g` | 通用寄存器/内存/立即数 |
#### 预定义组合约束
| 常量 | 值 | 说明 |
|------|----|------|
| `OUTPUT_REG` | `=r` | 输出,通用寄存器 |
| `OUTPUT_MEM` | `=m` | 输出,内存 |
| `OUTPUT_EAX` | `=a` | 输出,EAX/RAX |
| `INPUT_REG` | `r` | 输入,通用寄存器 |
| `INPUT_MEM` | `m` | 输入,内存 |
| `INPUT_IMM` | `i` | 输入,立即数 |
#### 破坏描述符
| 常量 | 说明 |
|------|------|
| `CLOBBER_EAX` / `CLOBBER_RAX` | 破坏 EAX/RAX |
| `CLOBBER_EBX` / `CLOBBER_RBX` | 破坏 EBX/RBX |
| `CLOBBER_ECX` / `CLOBBER_RCX` | 破坏 ECX/RCX |
| `CLOBBER_EDX` / `CLOBBER_RDX` | 破坏 EDX/RDX |
| `CLOBBER_ESI` / `CLOBBER_RSI` | 破坏 ESI/RSI |
| `CLOBBER_EDI` / `CLOBBER_RDI` | 破坏 EDI/RDI |
| `CLOBBER_CC` | 破坏条件码(标志寄存器) |
| `CLOBBER_MEMORY` | 破坏内存 |
| `CLOBBER_R8` ~ `CLOBBER_R15` | 破坏 R8~R15 |
## 预处理指令
Viper 通过 `c` 模块的函数调用实现 C 预处理指令。
### #define
```python
c.CDefine("MAX_SIZE", 1024) # #define MAX_SIZE 1024
```
上述方法容易引起未定义行为,至少是不便于理解,更常用的方式是使用类型注解:
```python
MAX_SIZE: t.CDefine = 1024 # #define MAX_SIZE 1024
```
### 条件编译
```python
c.CIfndef(HEADER_H) # #ifndef HEADER_H
c.CDefine(HEADER_H) # #define HEADER_H
c.CEndif() # #endif
```
```python
c.CIfdef(DEBUG) # #ifdef DEBUG
c.CEndif() # #endif
```
```python
c.CIf(VERSION > 2) # #if VERSION > 2
c.CElif(VERSION > 1) # #elif VERSION > 1
c.CElse() # #else
c.CEndif() # #endif
```
### #undef
```python
c.Undef(MACRO_NAME) # #undef MACRO_NAME
```
### #error
```python
c.CError("Platform not supported") # #error "Platform not supported"
```
### #pragma
> 此关键字已不再支持
```python
c.CPragma("GCC diagnostic push") # #pragma GCC diagnostic push
```
### ## 连接符
> 此方法可能已经不再支持
```python
c.TokenPast("PREFIX_", "NAME") # PREFIX_ ## NAME
```
由于编译器设计,以及不需要像 `C` 一样做大量字符替换,对于上述所有的条件宏都远比 `C` 差,实际工程中不推荐使用条件宏,后期将完善宏的设计,引入模板等。
## FFI 外部函数声明
Viper 的 FFI(Foreign Function Interface)**无需任何特殊语法**——仅靠返回类型注解中的 `t.State` 标记即可声明外部函数。`t.State` 是声明性标记类型,表示"仅声明不定义"(语义等价于 `t.CExport | t.CExtern`),编译器只生成 `declare` 原型,不生成 `define` 函数体,由链接器在外部库中解析符号。
### 基本声明
函数体为 `pass`,返回类型用 `RetType | t.State`:
```python
def isr0() -> t.CVoid | t.State: pass # extern void isr0(); — 来自汇编或外部
def getchar() -> t.CInt | t.State: pass # extern int getchar(); — 来自 libc
```
编译为 LLVM IR:
```llvm
declare void @"isr0"() ; 不加 SHA1 前缀(t.State 含 CExport 语义)
declare i32 @"getchar"()
```
### Win32 API 绑定示例
[includes/w32](../includes/w32) 中的 Win32 绑定全部通过 `t.State` 声明,零特殊语法:
```python
def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG,
dwShareMode: ULONG,
lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr,
dwCreationDisposition: ULONG,
dwFlagsAndAttributes: ULONG,
hTemplateFile: HANDLE) -> HANDLE | t.State:
pass
```
等价 C 声明:
```c
HANDLE CreateFileA(LPCSTR, ULONG, ULONG, SECURITY_ATTRIBUTES*,
ULONG, ULONG, HANDLE);
```
链接时通过 `project.json` 指定外部库(如 `kernel32.lib`、`user32.lib`),链接器解析这些符号。
### `t.State` 与 `t.CExtern` 的区别
| 修饰 | SHA1 前缀 | 生成内容 | 用途 |
|------|----------|---------|------|
| 无修饰 | ✅ 加前缀 | `declare` + `define` | 模块私有函数 |
| `t.CExtern` | ❌ 不加 | `declare`(引用外部) | 引用外部 C 函数 |
| `t.CExport` | ❌ 不加 | `declare` + `define` | 对外暴露 API |
| `t.State` | ❌ 不加 | 仅 `declare` | FFI 外部函数声明(= `CExport \| CExtern`) |
### 声明外部全局变量
外部全局变量通过 `t.CExtern` 注解声明:
```python
errno: t.CExtern | t.CInt # extern int errno;
```
详见 [02-type-system.md 的 t.State 章节](02-type-system.md#tstate-声明性标记) 和 [includes/w32](../includes/w32) 的 Win32 绑定实现。
## LLVM IR 内联
### c.LLVMIR
直接嵌入 LLVM IR 指令来实现高效且跨平台的汇编操作:
```python
c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
```
### c.LInp / c.LOut
标记 LLVM IR 的输入/输出操作数:
```python
c.LInp(expr) # 输入操作数
c.LOut(expr) # 输出操作数
```
## 运算符重载
`@t.Object` 类支持运算符重载,详见 [06-oop.md 中 运算符重载](06-oop.md#运算符重载)。
-186
View File
@@ -1,186 +0,0 @@
# 09 - 异常处理
Viper 支持 Python 风格的 `try/except/finally` 异常处理,编译为基于 jmp_buf 和错误码的 C 级别异常处理机制。
## 异常处理机制
Viper 的异常处理不使用 C++ 风格的零开销异常,而是通过函数参数传递错误码和错误消息实现。编译器自动为可能抛出异常的函数添加 `__eh_msg_out__` 和 `__eh_code_out__` 参数。
## try / except
```python
try:
result = risky_operation()
except ValueError:
serial.puts("ValueError occurred\n")
except OSError:
serial.puts("OSError occurred\n")
except Exception:
serial.puts("Unknown error\n")
```
### 内置异常类型
Viper 预定义了以下异常类型及其错误码:
| 异常类型 | 错误码 |
|---------|--------|
| `ValueError` | 1 |
| `TypeError` | 2 |
| `RuntimeError` | 3 |
| `ZeroDivisionError` | 4 |
| `IndexError` | 5 |
| `KeyError` | 6 |
| `IOError` | 7 |
| `OSError` | 8 |
| `AssertionError` | 9 |
| `Exception` | 99 |
### 自定义异常
```python
class DiskFullError(Exception):
pass
class ReadOnlyError(DiskFullError):
pass
```
自定义异常会自动分配递增的错误码(从 100 开始),并支持继承匹配。
### 多异常捕获
```python
try:
result = operation()
except (ValueError, TypeError):
serial.puts("Value or Type error\n")
```
### 获取异常信息
```python
try:
result = operation()
except Exception as e:
serial.puts("Error occurred\n")
```
## try / finally
```python
try:
result = operation()
finally:
cleanup()
```
`finally` 块无论是否发生异常都会执行。
## try / except / finally
```python
try:
result = operation()
except ValueError:
handle_value_error()
finally:
cleanup()
```
## raise 语句
### 抛出异常
```python
raise ValueError("invalid value")
```
### 抛出自定义异常
```python
raise MyCustomError("something went wrong")
```
### 重新抛出异常
```python
raise
```
### StopIteration
`StopIteration` 有特殊处理,用于迭代器协议:
```python
raise StopIteration
```
## 异常处理的编译实现
### 函数签名变换
可能抛出异常的函数会自动添加错误输出参数:
```python
def risky_operation() -> t.CInt:
if error:
raise ValueError("bad value")
return 0
```
编译后等价于:
```c
int risky_operation(char** __eh_msg_out__, int* __eh_code_out__) {
if (error) {
*__eh_code_out__ = 1; // ValueError code
*__eh_msg_out__ = "bad value";
return 0;
}
return 0;
}
```
### 调用点变换
```python
try:
result = risky_operation()
except ValueError:
handle_error()
```
编译后等价于:
```c
char* __eh_msg = NULL;
int __eh_code = 0;
int result = risky_operation(&__eh_msg, &__eh_code);
if (__eh_msg != NULL) {
if (__eh_code == 1) { // ValueError
handle_error();
}
}
```
## 异常继承匹配
异常匹配支持继承体系。捕获父类异常时,子类异常也会被匹配:
```python
class FileSystemError(Exception):
pass
class FileNotFoundError(FileSystemError):
pass
class PermissionError(FileSystemError):
pass
try:
operation()
except FileSystemError:
# 也会捕获 FileNotFoundError 和 PermissionError
handle_fs_error()
```
-258
View File
@@ -1,258 +0,0 @@
# 10 - 模块与导入系统
Viper 的模块系统基于 Python 的 `import` 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。
## 导入语法
### 标准导入
```python
import t, c # Viper 内置类型和操作模块
import asm # 汇编辅助模块
import string # 字符串操作模块
```
### 模块导入
```python
import bootinfo
import intr
import platform.pch as pch
import drivers.serial.uart.serial as serial
```
### from 导入
```python
from stdint import * # 导入所有 stdint 类型别名
from drivers.video.vesafb.vga import _VGAScreenDriver
```
### 相对导入
```python
from . import submodule
from .. import parent_module
```
## 特殊模块
### `t` 模块
类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入:
```python
import t
```
### `c` 模块
C 语言操作模块,提供指针操作、内联汇编、预处理指令等:
```python
import c
```
### `asm` 模块
汇编辅助模块,提供常用汇编指令的封装:
```python
import asm
asm.sti() # __asm__ __volatile__("sti");
asm.hlt() # __asm__ __volatile__("hlt");
asm.cli() # __asm__ __volatile__("cli");
asm.nop() # __asm__ __volatile__("nop");
asm.BSSClean() # 清零 BSS 段
```
### `string` 模块
字符串/内存操作模块,对应 C 标准库的 `string.h`:
> string 部分使用 x86_64 专有汇编进行加速,因此某些函数在其它架构可能需要手动重新编写。
```python
import string
string.memset(c.Addr(buf), 0, 64) # memset(&buf, 0, 64);
string.memcpy(dst, src, size) # memcpy(dst, src, size);
string.memmove(dst, src, size) # memmove(dst, src, size);
string.memcmp(a, b, size) # memcmp(a, b, size);
string.strcmp(a, b) # strcmp(a, b);
string.strcpy(dst, src) # strcpy(dst, src);
```
### `stdint` 模块
提供 C `stdint.h` 中的类型别名:
```python
from stdint import *
# 提供以下类型别名:
# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR
# INT8PTR, INT16PTR, INT32PTR, INT64PTR
# 等等
```
### `viperlib` 模块
ViperOS 标准库,提供常用 C 库函数:
```python
import viperlib
viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42);
```
### `vpsdk` 模块
> vpsdk 模块 专供于基于 Viper 开发的示例操作系统 ViperOS,不可用于其它平台,且需要特殊配置。
ViperOS 应用 SDK,提供系统调用和窗口管理:
```python
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.dynlib as dynlib
import vpsdk.syscall as syscall
```
### `ast` 模块(自研解析器)
[includes/ast](../includes/ast) 是**完全自研的 Python 解析器**(词法器 + 语法器 + AST 构造,约 4176 LOC),覆盖 CPython 几乎全部语法。这是向 `TransPyV` 完全自举的关键组件——自举后编译器不再依赖 Python 运行时解析源文件。
```python
from ast import parse, parse_expression
root: AST | t.CPtr = parse(src, pool) # 解析整个源文件
expr: AST | t.CPtr = parse_expression(src, pool) # 解析单个表达式
```
AST 采用**胖节点**设计:70+ 变体共用一个 struct,用 `vtype`(`ASTVType` 枚举)区分类型,通用字段直接属性访问。详见 [13-bootstrapping.md](13-bootstrapping.md) 和 [Test/AstTest](../Test/AstTest)。
### `llvmlite` 模块(自研 IR 生成库)
[includes/llvmlite](../includes/llvmlite) 是**完全自研的 LLVM IR 文本生成库**(约 1500 LOC),封装类型/值/模块/函数/基本块/构造器的创建与打印。同样是自举的关键组件。
```python
from llvmlite import LLVMTypeCore, LLVMModuleCore
type_core: LLVMTypeCore = LLVMTypeCore(pool)
i32: LLVMType | t.CPtr = type_core.Int32()
ptr_ty: LLVMType | t.CPtr = type_core.Ptr(i32)
mod_core: LLVMModuleCore = LLVMModuleCore(pool)
mod: Module | t.CPtr = mod_core.NewModule("main")
func: Function | t.CPtr = mod_core.CreateFunction(mod, "main", ret_ty)
```
类型系统用 `t.REnum`(`LLVMType`,少变体适合 match),指令 opcode 用 `t.CEnum`(`IROp`),对象分配用普通类 + `mpool`。详见 [includes/llvmlite/README.md](../includes/llvmlite/README.md) 的选型论证。
### `linkedlist` 模块(NoVTable + PEP 695 泛型示范)
[includes/linkedlist](../includes/linkedlist.py) 提供链表实现,是 `@t.NoVTable` 非多态继承和 PEP 695 递归泛型继承的典范用例:
```python
from linkedlist import LinkedNode, GSList
@t.NoVTable
class Node(LinkedNode): # 非多态继承,零 vtable 开销
value: t.CInt
lst: GSList[Node] | t.CPtr = GSList[Node]()
node: Node | t.CPtr = Node()
node.value = 42
lst.append(node) # 类型安全:append 只接受 Node
```
包含 `LinkedNode`/`SListNode`(双向/单向节点)和 `GSList[T]`(泛型链表,支持递归泛型继承 `class GNode(GSListNode[GNode])`)。详见 [05-classes.md 的泛型类章节](05-classes.md#泛型类pep-695-语法) 和 [06-oop.md 的 NoVTable 章节](06-oop.md#tnovtable-非多态继承)。
### `w32` 模块(Win32 FFI 绑定)
[includes/w32](../includes/w32) 提供 Win32 API 绑定,全部通过 `t.State` 的 FFI 机制声明(零特殊语法):
```python
from w32.win32file import CreateFileA, ReadFile, WriteFile
from w32.win32console import WriteConsole
from w32.win32memory import HeapAlloc, HeapFree
from w32.win32process import CreateProcess
from w32.win32sync import CreateMutex, WaitForSingleObject
handle: HANDLE = CreateFileA("test.txt", GENERIC_READ, FILE_SHARE_READ,
None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None)
```
子模块:`win32base`(基础类型/常量)、`win32file`(文件 IO)、`win32console`(控制台)、`win32memory`(内存)、`win32process`(进程/线程)、`win32sync`(同步对象)、`fileio`(高层文件操作封装)。详见 [08-c-operations.md 的 FFI 章节](08-c-operations.md#ffi-外部函数声明)。
## 模块解析流程
### 编译时模块加载
Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合:
1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件
2. **阶段一**:对每个源文件生成 `<SHA1>.pyi` 签名存根和 `<SHA1>.stub.ll` LLVM IR 声明
3. **阶段二**:加载所有 `.pyi` 和 `.stub.ll`,构建共享符号表
4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用
5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部
### 类型存根文件(.pyi)
`.pyi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。存根文件的内容规则:
| 元素 | 存根表示 |
|------|---------|
| `t.CDefine` 常量 | 保留完整定义(含赋值) |
| `t.CDefine` 函数 | 保留完整函数体 |
| 普通函数 | 仅签名 + `t.State` |
| 全局变量 | 添加 `t.CExtern` |
| 类定义 | 保留成员类型注解和方法签名 |
存根文件还自动添加宏守卫(`c.CIfndef`/`c.CEndif()`),防止重复包含。
### SHA1 命名空间与导入
每个模块的函数和结构体在 LLVM IR 中自动加上 SHA1 前缀,消除跨模块符号冲突。只有标记为 `t.CExport` 的函数保持原始名称。详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。
### 符号表
所有模块的类型信息统一存储在 `SymbolTable` 中,包含:
- 结构体/联合体/枚举定义
- 函数签名
- 全局变量
- typedef 别名
- `t.CDefine` 常量
### 跨模块类型引用
```python
# 在 fat32_types.py 中定义
class fat32_fileinfo:
fname: list[t.CChar, 13]
attr: t.CUInt8T
file_size: t.CUInt32T
# 在其他模块中引用
import fat32_types
info: fat32_types.fat32_fileinfo
```
跨模块引用的结构体在 LLVM IR 中使用 SHA1 前缀的类型名:
```llvm
%"<SHA1_of_fat32_types>.fat32_fileinfo" = type { [13 x i8], i8, i32 }
```
## 项目 includes 配置
在 `project.json` 中配置模块搜索路径:
```json
{
"includes": ["../.."],
"source_dir": "./Kernel"
}
```
编译器会在 `includes` 指定的目录中搜索导入的模块。
-204
View File
@@ -1,204 +0,0 @@
# 11 - 内置函数与运算符
Viper 支持 Python 内置函数和运算符,编译为对应的 C/LLVM 操作。
## 内置函数
### print
```python
print("Hello, World!") # 调用 puts 或 printf
print(x, y) # 多参数输出
```
### len
```python
n: t.CInt = len(array) # 获取数组长度(编译时常量)
```
### sizeof
```python
s: t.CSizeT = sizeof(t.CInt) # sizeof(int)
s: t.CSizeT = obj.__sizeof__() # sizeof(obj)
```
### abs
```python
a: t.CInt = abs(x) # abs(x)
```
### int / float / bool
```python
i: t.CInt = int(3.14) # (int)3.14
f: t.CFloat = float(42) # (float)42
b: t.CBool = bool(x) # x != 0
```
### min / max
```python
m: t.CInt = min(a, b) # a < b ? a : b
m: t.CInt = max(a, b) # a > b ? a : b
```
### chr / ord
```python
c: t.CChar = chr(65) # 'A' (整数转字符)
n: t.CInt = ord('A') # 65 (字符转整数)
```
### range
用于 `for` 循环:
```python
for i in range(10): pass # for (int i = 0; i < 10; i++)
for i in range(5, 10): pass # for (int i = 5; i < 10; i++)
for i in range(0, 10, 2): pass # for (int i = 0; i < 10; i += 2)
```
## 运算符
### 算术运算符
| Viper | C 等价 | 说明 |
|-------|--------|------|
| `a + b` | `a + b` | 加法 |
| `a - b` | `a - b` | 减法 |
| `a * b` | `a * b` | 乘法 |
| `a / b` | `a / b` | 浮点除法 |
| `a // b` | `a / b` | 整数除法 |
| `a % b` | `a % b` | 取模 |
| `a ** b` | `pow(a, b)` | 幂运算 |
| `-a` | `-a` | 取负 |
| `+a` | `+a` | 正号 |
### 位运算符
| Viper | C 等价 | 说明 |
|-------|--------|------|
| `a & b` | `a & b` | 按位与 |
| `a \| b` | `a \| b` | 按位或 |
| `a ^ b` | `a ^ b` | 按位异或 |
| `~a` | `~a` | 按位取反 |
| `a << n` | `a << n` | 左移 |
| `a >> n` | `a >> n` | 右移 |
> **注意**:`|` 运算符在类型注解中表示类型组合,在表达式中表示按位或。编译器根据上下文区分。
### 比较运算符
| Viper | C 等价 | 说明 |
|-------|--------|------|
| `a == b` | `a == b` | 等于 |
| `a != b` | `a != b` | 不等于 |
| `a < b` | `a < b` | 小于 |
| `a > b` | `a > b` | 大于 |
| `a <= b` | `a <= b` | 小于等于 |
| `a >= b` | `a >= b` | 大于等于 |
### 逻辑运算符
| Viper | C 等价 | 说明 |
|-------|--------|------|
| `a and b` | `a && b` | 逻辑与 |
| `a or b` | `a \|\| b` | 逻辑或 |
| `not a` | `!a` | 逻辑非 |
### 增强赋值运算符
| Viper | C 等价 |
|-------|--------|
| `a += b` | `a += b` |
| `a -= b` | `a -= b` |
| `a *= b` | `a *= b` |
| `a //= b` | `a /= b` |
| `a %= b` | `a %= b` |
| `a <<= b` | `a <<= b` |
| `a >>= b` | `a >>= b` |
| `a &= b` | `a &= b` |
| `a \|= b` | `a \|= b` |
| `a ^= b` | `a ^= b` |
## 类型自动转换
Viper 在算术运算中自动进行类型提升:
1. **整数宽度提升**:较窄的整数类型自动扩展为较宽的类型
- 有符号类型使用符号扩展(`sext`)
- 无符号类型使用零扩展(`zext`)
2. **整数到浮点**:整数与浮点数运算时,整数自动转换为浮点
3. **浮点精度提升**:`float` 与 `double` 运算时,`float` 提升为 `double`
## 指针算术
指针与整数的加法支持自动计算偏移:
```python
buf: t.CUInt32T | t.CPtr
buf[i] = value # buf[i] = value; (自动计算偏移)
```
## 数组下标
```python
buf: list[t.CChar, 64]
buf[0] = 'H' # buf[0] = 'H';
buf[i] = value # buf[i] = value;
info.fname[0] # info.fname[0] (结构体数组成员访问)
```
## 成员访问
```python
obj.x # obj.x (直接成员)
obj.method() # obj.method() (方法调用)
ptr.x # ptr->x (指针自动解引用)
```
## 字符串字面量
字符串字面量编译为 C 字符串常量(`const char*`),其为只读:
```python
serial.puts("Hello") # 传递 const char*
```
### 字符串索引
```python
msg: t.CConst | str = "Hello"
serial.puts(c.Addr(msg[4])) # 访问 msg[4] 的地址,输出 'o'
```
## C 标准库函数
Viper 内置支持以下 C 标准库函数的直接调用:
| 函数 | 签名 |
|------|------|
| `strlen(s)` | `size_t strlen(const char* s)` |
| `memset(s, c, n)` | `void* memset(void* s, int c, size_t n)` |
| `memcpy(d, s, n)` | `void* memcpy(void* d, const void* s, size_t n)` |
| `memmove(d, s, n)` | `void* memmove(void* d, const void* s, size_t n)` |
| `memcmp(a, b, n)` | `int memcmp(const void* a, const void* b, size_t n)` |
| `strcmp(a, b)` | `int strcmp(const char* a, const char* b)` |
| `strncmp(a, b, n)` | `int strncmp(const char* a, const char* b, size_t n)` |
| `strcpy(d, s)` | `char* strcpy(char* d, const char* s)` |
| `strncpy(d, s, n)` | `char* strncpy(char* d, const char* s, size_t n)` |
| `strcat(d, s)` | `char* strcat(char* d, const char* s)` |
| `puts(s)` | `int puts(const char* s)` |
| `atoi(s)` | `int atoi(const char* s)` |
| `atol(s)` | `long atol(const char* s)` |
| `abs(x)` | `int abs(int x)` |
| `labs(x)` | `long labs(long x)` |
部分模式比如裸机没有 libc,则不能使用这些函数,即使环境满足,Viper 标准库也可能和 C 标准库冲突。
-252
View File
@@ -1,252 +0,0 @@
# 12 - 项目配置与构建
Viper 项目使用 `project.json` 配置文件管理编译和链接参数。
## project.json 结构
```json
{
"name": "Kernel",
"version": "1.0.0",
"source_dir": "./Kernel",
"temp_dir": "./temp",
"output_dir": "./output",
"compiler": {
"cmd": "llc",
"flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"]
},
"linker": {
"cmd": "ld.lld.exe",
"flags": [
"-m", "elf_x86_64",
"-T", "linker.ld",
"--oformat", "elf64-x86-64",
"--strip-all"
],
"output": "kernel.bin"
},
"includes": ["../../includes"],
"target": {
"triple": "x86_64-none-elf",
"datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
},
"options": {
"slice_level": 3,
"target": "llvm",
"strict_mode": true
}
}
```
## 配置项说明
### 基本信息字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `name` | string | 项目名称 |
| `version` | string | 项目版本 |
| `source_dir` | string | 源代码目录(相对于 project.json 所在目录) |
| `temp_dir` | string | 临时文件目录(存放 .pyi 存根等) |
| `output_dir` | string | 输出文件目录 |
### 编译器配置
| 字段 | 类型 | 说明 |
|------|------|------|
| `compiler.cmd` | string | 编译器命令(通常为 `llc`) |
| `compiler.flags` | string[] | 编译器标志 |
常用 `llc` 标志:
- `-filetype=obj`:输出目标文件
- `-mtriple=x86_64-none-elf`:目标三元组
- `-relocation-model=static`:静态重定位
- `-O2`:优化级别
### 链接器配置
| 字段 | 类型 | 说明 |
|------|------|------|
| `linker.cmd` | string | 链接器命令(通常为 `ld.lld.exe`) |
| `linker.flags` | string[] | 链接器标志 |
| `linker.output` | string | 输出文件名 |
常用 `ld.lld` 标志:
- `-m elf_x86_64`:ELF x86_64 格式
- `-T linker.ld`:链接脚本
- `--oformat elf64-x86-64`:输出 ELF 格式
- `--oformat binary`:输出原始二进制(用于内核)
- `--strip-all`:去除所有符号信息
### 目标平台配置
| 字段 | 类型 | 说明 |
|------|------|------|
| `target.triple` | string | LLVM 目标三元组 |
| `target.datalayout` | string | LLVM 数据布局字符串 |
默认值:
- triple: `x86_64-none-elf`
- datalayout: `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128`
### 包含路径
| 字段 | 类型 | 说明 |
|------|------|------|
| `includes` | string[] | 模块搜索路径列表 |
### 编译选项
| 字段 | 类型 | 说明 |
|------|------|------|
| `options.slice_level` | int | 切片优化级别(0-3) |
| `options.target` | string | 编译目标(目前仅支持 `llvm`) |
| `options.strict_mode` | bool | 严格模式 |
## 切片优化级别
| 级别 | 名称 | 说明 |
|------|------|------|
| `0` | `no_optimize` | 无优化 |
| `1` | `conservative` | 保守优化 |
| `2` | `moderate` | 适度优化 |
| `3` | `aggressive` | 激进优化(默认) |
| `s` | `size` | 体积优化 |
## 项目结构示例
### 内核项目
```
VKernel/
├── project.json # 项目配置
├── linker.ld # 链接脚本
├── Kernel/ # 源代码目录
│ ├── main.py # 内核入口
│ ├── bootinfo.py
│ ├── intr/
│ │ ├── gdt.py
│ │ ├── idt.py
│ │ └── syscall.py
│ ├── drivers/
│ │ ├── serial/
│ │ ├── video/
│ │ ├── storage/
│ │ └── ...
│ └── ...
├── temp/ # 临时文件(自动生成)
│ ├── <SHA1>.pyi # 签名存根(阶段一生成)
│ ├── <SHA1>.stub.ll # LLVM IR 声明(阶段一生成)
│ └── _sha1_map.txt # SHA1→源文件路径映射
└── output/ # 输出文件(自动生成)
├── kernel.bin # 内核二进制
├── *.deps.json # 依赖信息
└── linker.ld # 生成的链接脚本
```
### 应用项目
```
HelloWorld/
├── project.json # 项目配置
├── linker.ld # 链接脚本
├── main.py # 应用入口
├── temp/ # 临时文件
└── output/ # 输出文件
└── helloworld.elf # ELF 可执行文件
```
### 库项目
```
SerialLogger/
├── project.json # 项目配置
├── linker.ld # 链接脚本
├── serial_logger.py # 库源码
├── temp/ # 临时文件
└── output/ # 输出文件
```
## 链接脚本
ViperOS 使用自定义链接脚本控制内存布局:
```ld
ENTRY(_start)
SECTIONS
{
. = 0x100000; /* 加载地址 */
.text : {
*(.text.startup)
*(.text*)
}
.rodata : {
*(.rodata*)
}
.data : {
*(.data*)
}
.bss : {
*(.bss*)
*(COMMON)
}
}
```
## 编译命令
TransPyC 编译器的基本用法(注:适用于单个文件,而不适用于工程):
```bash
python TransPyC.py -f InputFile -o OutputFile [options]
```
### 命令行参数
| 参数 | 说明 |
|------|------|
| `-f` | 输入文件路径 |
| `-o` | 输出文件路径 |
| `-wh` | 头文件列表 |
| `-debug` | 调试输出文件 |
| `-cc` | 编译命令 |
| `-cflags` | 编译标志 |
| `-run` | 编译后运行 |
| `-args` | 运行参数 |
| `-h` | 辅助文件(C 或 Python) |
工程编译使用:
```bash
python Projectrans.py xxx.json
```
即可
## 增量编译
TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合:
### 阶段一增量
- 每个源文件按内容计算 SHA1 哈希(16位)
- 如果 `<SHA1>.pyi` 和 `<SHA1>.stub.ll` 已存在,则跳过生成(缓存命中)
- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口
- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `<sha1>:<relative_path>`
### 阶段二增量
- 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射
- 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件
- 共享符号表一次性构建,避免每个文件重复加载
### SHA1 命名空间与增量编译的协同
SHA1 同时服务于命名空间隔离和增量编译:
- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突
- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成
详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。
-252
View File
@@ -1,252 +0,0 @@
# TransPyC 自举可行性分析
> **状态**:进行中
> **创建时间**:2026-06-26
> **最后更新**:2026-06-30
> **结论**:完全自举可行,核心障碍已被攻克,剩余工作明确
---
## 1. 背景
自举(bootstrapping)指用 TransPyC 语言重写 TransPyC 编译器自身,然后用现有编译器编译,得到新的原生编译器。本文档分析自举的可行性、进展与剩余工作。
**当前目标**:完全自举。TransPyC 的定位是独立的系统级语言,不是"Python → 原生 的工具"。自举是语言成熟度的证明,也是脱离 Python 运行时性能限制的必经之路。
---
## 2. LOC 统计
### 2.1 编译器主体(lib 目录)
| 子目录 | 文件数 | LOC | 说明 |
|--------|--------|-----|------|
| `lib/core` | 64 | 28,610 | 编译器核心 |
| ├─ `core/Handles` | 30 | 18,885 | AST 节点处理器(最大模块) |
| ├─ `core/LLVMCG` | 8 | 2,782 | LLVM 代码生成 |
| └─ `core/Translator` | 6 | 1,751 | 翻译器框架 |
| `lib/Projectrans` | 6 | 4,371 | 项目级翻译(Phase1/Phase2) |
| `lib/StubGen` | 4 | 1,187 | Stub 生成器 |
| `lib/Shell` | 4 | 630 | CLI 入口 |
| `lib/includes` | 2 | 1,609 | t.py(968) + c.py(641) 类型定义 |
| `lib/utils` | 1 | 40 | 辅助 |
| `lib/constants` | 1 | 36 | 配置 |
| **lib 总计** | **80** | **36,483** | |
### 2.2 Top 15 文件
| 文件 | LOC |
|------|-----|
| `lib/core/Handles/HandlesExprCall.py` | 3,153 |
| `lib/Projectrans/Phase2Translator.py` | 2,693 |
| `lib/core/Handles/HandlesImports.py` | 1,994 |
| `lib/core/Handles/HandlesFunctions.py` | 1,612 |
| `lib/core/Handles/HandlesAssign.py` | 1,544 |
| `lib/core/Handles/HandlesExprAttr.py` | 1,168 |
| `lib/core/Handles/HandlesClassDef.py` | 1,039 |
| `lib/core/Handles/HandlesFor.py` | 997 |
| `lib/core/Handles/HandlesTypeMerge.py` | 991 |
| `lib/includes/t.py` | 968 |
| `lib/StubGen/Converter.py` | 893 |
| `lib/core/Handles/HandlesExprBuiltin.py` | 868 |
| `lib/Projectrans/DeclarationGenerator.py` | 845 |
| `lib/core/Handles/HandlesBase.py` | 756 |
| `lib/core/stub_generator.py` | 699 |
### 2.3 运行时库(includes 目录)
| 模块 | LOC | 说明 |
|------|-----|------|
| `includes/numpy/__init__.py` | 1,016 | ndarray n 维数组 |
| `includes/zlib/` | ~1,900 | 完整 deflate/inflate/huffman/checksum |
| `includes/ast/` | 4,176 | **自研 Python 解析器(自举组件)** |
| `includes/llvmlite/` | ~1,500 | **自研 LLVM IR 生成库(自举组件)** |
| `includes/linkedlist.py` | ~400 | 泛型链表(@t.NoVTable + PEP 695) |
| `includes/vipermath.py` | 450 | 数学库 |
| ...(30+ 文件) | ... | mpool/mbuddy/string/stdio/json/w32 等 |
| **includes 总计** | **~12,000** | |
### 2.4 全项目总计
```
全项目 .py 总计:~48,000 LOC
```
**自举相关核心数字:**
- 编译器主体(lib 不含 t.py/c.py):~34,874 LOC
- 自举基础组件(includes/ast + includes/llvmlite):~5,700 LOC ✅ 已完成
- 运行时库(includes 其余):~9,500 LOC
---
## 3. 自举进展(已完成的核心组件)
### 3.1 ✅ includes/ast —— Python 解析器自举
**状态**:完成,AstTest 通过(解析 CPython 几乎全部语法)
| 文件 | LOC | 功能 |
|------|-----|------|
| `__tokens.py` | ~600 | TokenType/Keyword/TokOp 枚举 + 查找表 |
| `__nodes.py` | ~1,400 | AST 胖节点 + ASTVType/ASTCtx/OpKind CEnum |
| `__lexer.py` | ~800 | 词法分析器 |
| `__parser.py` | 4,176(含表格) | 递归下降语法分析器 |
**覆盖语法**:装饰器、async/await、match(含复杂模式 `[x,*rest]`/`{'type':t,**rest}`/`Point(x,y)`/`0|1|2`)、try/except/finally/raise from、with、lambda、列表/集合/字典/生成器推导式、f-string(含 `!r`/`!s` 转换和 `:>{width}` 格式说明)、链式比较、walrus、yield from、global/nonlocal、切片、嵌套三元。
**设计要点**:
- 胖节点设计(所有节点共用一个 `AST` struct,用 `vtype` 区分)—— 避免 REnum 在 70+ 变体下的内存膨胀
- 从 `mpool.MPool` 分配,零 Python 运行时依赖
- API 与 Python `ast` 模块对齐:`parse(src, pool) -> AST`
### 3.2 ✅ includes/llvmlite —— LLVM IR 生成库自举
**状态**:完成,LLvmLiteTest 18/18 通过,TransPyV 自举实验跑通
| 文件 | 功能 |
|------|------|
| `__types.py` | `LLVMType` REnum + 类型构造/打印 |
| `__values.py` | Value/Constant/SSA 值表示 |
| `__function.py` | Function + BasicBlock + 参数管理 |
| `__module.py` | Module 容器 + 目标三元组 + 输出 .ll |
| `__builder.py` | IRBuilder(指令发射 + SSA 命名) |
**设计要点**:
- `LLVMType` 用 `t.REnum`(tagged union)—— 少变体、无通用字段、match 分派的理想场景
- 指令 opcode 用 `t.CEnum`(IROp)—— 类型安全且零开销
- IR 文本生成用 `viperlib.snprintf` 格式化,避免手写逐字符拼接
- 对象分配用普通类 + `mpool`,不持有全局 `mbuddy`
**验证**:[TransPyV/App/main.py](../TransPyV/App/main.py) 10 个测试覆盖类型打印、值打印、build_add、if-else、模块打印、lli 实际执行。TransPyV 程序运行时自己生成合法 IR,被 `lli` 成功执行。
### 3.3 ✅ 基础设施库
以下 includes/ 库为自举后的编译器提供数据结构和系统调用基础:
| 库 | 自举中的作用 |
|----|-------------|
| `linkedlist.py` | AST 节点树、符号表链、IR 指令链的容器(`@t.NoVTable` + PEP 695 递归泛型继承) |
| `mpool.py` / `mbuddy.py` | 编译器内存管理(替代 Python GC) |
| `string.py` / `viperlib.py` | 字符串处理 + snprintf(替代 Python 字符串方法) |
| `w32/` | FFI 声明,自举后编译器调用 llc/clang/linker 的基础 |
| `json/` | 符号表序列化(替代 pickle) |
---
## 4. 障碍分析(修正版)
原版本文档列出的"三大致命依赖"已被逐一攻克或降级:
### 4.1 ~~llvmlite 依赖(原:致命)~~ → ✅ 已解决
**原问题**:编译器通过 `llvmlite.ir` 生成 IR,TransPyC 无法调用 Python 库。
**解决**:`includes/llvmlite/` 用 TransPyC 自身实现了 LLVM IR 文本生成库,API 与 Python `llvmlite.ir` 对齐。采用"字符串拼 IR"路径(路径 A),不绑定 LLVM C API。18/18 测试通过,TransPyV 自举实验验证可生成可执行 IR。
### 4.2 ~~ast 模块依赖(原:致命)~~ → ✅ 已解决
**原问题**:编译器用 Python `ast` 模块解析源码,自举需自己写 Python 解析器(预计 5,000-10,000 LOC)。
**解决**:`includes/ast/` 4,176 LOC 实现完整 Python 解析器,AstTest 解析 CPython 凥乎全部语法通过。预言已兑现,且实际规模(4,176 LOC)低于预估下限(5,000 LOC)。
### 4.3 ~~动态反射 4241 处(原:致命)~~ → ⚠️ 降级为可控
**原问题**:`getattr`/`setattr`/`hasattr`/`isinstance`/`issubclass` 共 4,241 处,静态语言无法直接表达。
**修正分析**:4241 这个数字按 Python 语法 grep 统计,未区分"语义上需要反射"和"用反射偷懒"。实际分类:
| 用法 | 数量估计 | 是否真反射 | TransPyC 解法 |
|------|----------|-----------|--------------|
| `isinstance(node, ast.Xxx)` AST 节点分派 | ~2000 | ❌ 否 | 胖节点 `node.vtype == ASTVType.Xxx` 整数比较 |
| `isinstance(x, ir.IntType)` IR 类型分派 | ~500 | ❌ 否 | REnum `match x: case LLVMType.Int:` tag 比较 |
| `getattr(t, name, None)` 字符串→类型查表 | ~35 | ❌ 否 | 注册表 `t_type_registry: dict[str, t.CInt]` |
| `CTypeInfo.__getattr__` 门面路由 | ~100 | ✅ 是 | 重构为 REnum + match 显式分派 |
| `copy.deepcopy` / `pickle` | ~10 | ✅ 是 | 已解决(`__getstate__/__setstate__`) |
| `hasattr` 防御性检查 | ~1500 | ⚠️ 多数可消除 | 显式字段声明 + None 检查 |
**真实反射障碍约 200-500 处**,集中体现在 `CTypeInfo` 门面模式(FIELD_ROUTES 动态路由到 `_ts`/`_sm`)。重构方案:用 REnum + match 替换 `__getattr__` 路由,已在 `includes/llvmlite/__types.py` 验证此范式可行。
### 4.4 Python 标准库依赖(原:严重)→ ⚠️ 部分已解决
| Python 库 | 用途 | TransPyC 现状 |
|-----------|------|--------------|
| `ast` | 源码解析 | ✅ `includes/ast/` |
| `llvmlite.ir` | LLVM IR 生成 | ✅ `includes/llvmlite/` |
| `json` | 序列化 | ✅ `includes/json/` |
| `os`/`sys` | 文件/路径 | ⚠️ `includes/os/` + `w32/`(Windows) |
| `subprocess` | 调用 llc/clang | ❌ 待实现(w32 CreateProcess 可基础) |
| `pickle` | 符号表序列化 | ❌ 待实现(json 替代) |
| `concurrent.futures` | 并行编译 | ❌ 待实现(w32 线程可基础) |
| `re` | 正则表达式 | ❌ 待实现 |
| `traceback` | 异常栈 | ❌ 待实现 |
---
## 5. 自举路径
### 5.1 路径 A:完全自举(当前目标,可行)
**已完成**:
1. ✅ `includes/ast/` Python 解析器(4,176 LOC)
2. ✅ `includes/llvmlite/` LLVM IR 生成库(~1,500 LOC)
3. ✅ 基础设施库(linkedlist/mpool/mbuddy/string/json/w32)
**剩余工作**:
1. **CTypeInfo 门面重构**(~200-500 处真反射 → REnum + match)
2. **lib/core 重写**(~20K LOC TransPyC,含 Handles/LLVMCG/Translator)
3. **lib/Projectrans 重写**(~5K LOC,Phase1/Phase2/DeclarationGenerator)
4. **lib/StubGen 重写**(~2K LOC)
5. **Python 标准库缺口补齐**(os/subprocess/re/pickle,~5K LOC)
**预计新增代码量**:30-35K LOC TransPyC。与已完成的 includes/ast(4,176 LOC)+ includes/llvmlite(~1,500 LOC)+ 其他基础库为同一量级——已经证明过两次能做这件事。
### 5.2 关键技术验证点(已完成)
以下能力已在 includes/ 库中验证,证明 TransPyC 能承载编译器复杂度:
- **复杂泛型容器**:`linkedlist.py` 的递归泛型继承 `class GNode(GSListNode[GNode])`(C/C++/Rust 均无法如此简洁表达)
- **复杂算法**:`zlib/` 的完整 deflate/inflate/huffman(~1,900 LOC 生产级压缩)
- **n 维数组**:`numpy/__init__.py` 的 ndarray + 运算符重载 + `__new__` 堆分配
- **平台 FFI**:`w32/` 的 Win32 API 绑定(file/memory/process/sync/console)
- **LLVM IR 生成**:`llvmlite/` 的 REnum 类型系统 + IRBuilder + ModulePrint
---
## 6. 自举的意义
1. **性能**:当前 Python 编译器翻译 6 个文件 0.6s,全量编译 36K LOC 编译器自身时 Python 解释器开销显著。自举后编译器是原生码,编译速度数量级提升。
2. **部署**:当前分发需 Python 运行时 + llvmlite + ast 依赖。自举后只需一个可执行文件 + llc/clang——系统级语言编译器该有的形态。
3. **语言成熟度证明**:能写自己的编译器是系统级语言的"成人礼"。C、C++、Rust、Go、Zig 全都走过这条路。
4. **dogfooding 闭环**:自举后每次改编译器都用编译器自己编译自己,持续暴露 bug 和性能瓶颈,形成正反馈。`includes/ast` 和 `includes/llvmlite` 的开发过程已经产出了大量深层 bug 修复(REnum 变体名冲突、跨模块继承字段展平、NoVTable OOP 方法继承等)。
---
## 7. 结论
| 维度 | 评估 |
|------|------|
| 理论可行性 | ✅ 可行(图灵完备) |
| 实践可行性 | ✅ 完全自举可行(核心障碍已攻克) |
| 当前进展 | ⚠️ 前端(ast)+ 后端(llvmlite)+ 基础库已就位,剩中间层(lib/core)重构 |
| 剩余工作量 | ~30-35K LOC TransPyC 重写 + CTypeInfo 门面重构 |
| 推荐策略 | 路径 A:完全自举,按 lib/core → lib/Projectrans → lib/StubGen 顺序推进 |
**核心判断**:原版本文档的"三大致命依赖"结论已全部失效——llvmlite 和 ast 已被 includes/ 下的自研库替代,4241 处反射中 90% 是工程偷懒而非语义需要。完全自举从"几乎不可能"变为"明确可行",剩余工作是体量问题而非技术障碍。
---
## 8. 附录:原版本文档的修正说明
本文档(2026-06-30 版)修正了 2026-06-26 原版的以下错误判断:
| 原版断言 | 修正 |
|---------|------|
| "完全自举几乎不可能" | 完全自举可行,核心障碍已攻克 |
| "llvmlite 依赖致命" | 已被 `includes/llvmlite/` 解决(18/18 测试) |
| "ast 模块依赖致命" | 已被 `includes/ast/` 解决(4,176 LOC,AstTest 通过) |
| "4241 处动态反射致命" | 90% 是工程偷懒(isinstance 节点分派/IR 类型分派),真实反射约 200-500 处 |
| "推荐路径 C:不自举" | 推荐路径 A:完全自举 |
| "预计自举后 60K-80K LOC" | 修正为 30-35K LOC(基础组件已 5,700 LOC 完成) |
-3523
View File
File diff suppressed because it is too large. Load diff
+35 -35
View File
@@ -2,41 +2,41 @@ import t, c
from . import syscall as syscall
from stdint import *
STYLE_CLASSIC: t.CDefine = 0
STYLE_WIN10: t.CDefine = 1
STYLE_WIN11: t.CDefine = 2
STYLE_WIN7: t.CDefine = 3
STYLE_WINXP: t.CDefine = 4
define STYLE_CLASSIC = 0
define STYLE_WIN10 = 1
define STYLE_WIN11 = 2
define STYLE_WIN7 = 3
define STYLE_WINXP = 4
EVENT_TYPE_NONE: t.CDefine = 0
EVENT_TYPE_CLICK: t.CDefine = 1
EVENT_TYPE_HOVER: t.CDefine = 2
EVENT_TYPE_RELEASE: t.CDefine = 3
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
EVENT_TYPE_KEY: t.CDefine = 5
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
EVENT_TYPE_PING: t.CDefine = 7
EVENT_TYPE_RESIZE: t.CDefine = 8
define EVENT_TYPE_NONE = 0
define EVENT_TYPE_CLICK = 1
define EVENT_TYPE_HOVER = 2
define EVENT_TYPE_RELEASE = 3
define EVENT_TYPE_HOVER_LEAVE = 4
define EVENT_TYPE_KEY = 5
define EVENT_TYPE_KEY_RELEASE = 6
define EVENT_TYPE_PING = 7
define EVENT_TYPE_RESIZE = 8
KEY_STATE_PRESS: t.CDefine = 1
KEY_STATE_RELEASE: t.CDefine = 2
KEY_STATE_REPEAT: t.CDefine = 3
define KEY_STATE_PRESS = 1
define KEY_STATE_RELEASE = 2
define KEY_STATE_REPEAT = 3
CURSOR_DEFAULT: t.CDefine = 0
CURSOR_IBEAM: t.CDefine = 1
CURSOR_RESIZE_EW: t.CDefine = 2
CURSOR_RESIZE_NS: t.CDefine = 3
CURSOR_RESIZE_NWSE: t.CDefine = 4
define CURSOR_DEFAULT = 0
define CURSOR_IBEAM = 1
define CURSOR_RESIZE_EW = 2
define CURSOR_RESIZE_NS = 3
define CURSOR_RESIZE_NWSE = 4
VK_LEFT: t.CDefine = -1
VK_RIGHT: t.CDefine = -2
VK_UP: t.CDefine = -3
VK_DOWN: t.CDefine = -4
VK_HOME: t.CDefine = -5
VK_END: t.CDefine = -6
VK_DELETE: t.CDefine = -7
VK_PRIOR: t.CDefine = -8
VK_NEXT: t.CDefine = -9
define VK_LEFT = -1
define VK_RIGHT = -2
define VK_UP = -3
define VK_DOWN = -4
define VK_HOME = -5
define VK_END = -6
define VK_DELETE = -7
define VK_PRIOR = -8
define VK_NEXT = -9
@c.Attribute(t.attr.packed)
@t.Object
@@ -50,10 +50,10 @@ class InputEvent:
_pad1: uint8
_pad2: uint8
def create_window(x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int) -> int:
def create_window(x: int, y: int, w: int, h: int, title: const str, style: int) -> int:
return int(syscall._syscall6(uint64(syscall.CREATE_WINDOW), uint64(x), uint64(y), uint64(w), uint64(h), uint64(title), uint64(style)))
def draw_text(win_id: int, x: int, y: int, text: t.CConst | t.CChar | t.CPtr, color: uint32) -> int:
def draw_text(win_id: int, x: int, y: int, text: const str, color: uint32) -> int:
return int(syscall._syscall5(uint64(syscall.DRAW_TEXT), uint64(win_id), uint64(x), uint64(y), uint64(text), uint64(color)))
def get_winbuf(win_id: int) -> UINT32PTR:
@@ -68,7 +68,7 @@ def flush(win_id: int):
def mainloop(win_id: int):
syscall._syscall1(uint64(syscall.WAIT_WINDOW), uint64(win_id))
def poll_event(evt: InputEvent | t.CPtr) -> int:
def poll_event(evt: InputEvent*) -> int:
return int(syscall._syscall1(uint64(syscall.POLL_EVENT), uint64(evt)))
def is_active(win_id: int) -> int:
@@ -77,7 +77,7 @@ def is_active(win_id: int) -> int:
def set_cursor_type(win_id: int, cursor_t: int):
syscall._syscall2(uint64(syscall.SET_CURSOR), uint64(win_id), uint64(cursor_t))
def set_title(win_id: int, title: t.CConst | str) -> int:
def set_title(win_id: int, title: const str) -> int:
return int(syscall._syscall2(uint64(syscall.SET_TITLE), uint64(win_id), uint64(title)))
def set_geometry(win_id: int, x: int, y: int, w: int, h: int) -> int: