diff --git a/Apps/Gargantua/main.vp b/Apps/Gargantua/main.vp index 777a996..5e0caef 100644 --- a/Apps/Gargantua/main.vp +++ b/Apps/Gargantua/main.vp @@ -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) diff --git a/Apps/HelloWorld/main.vp b/Apps/HelloWorld/main.vp index 5dc02f1..c0b929e 100644 --- a/Apps/HelloWorld/main.vp +++ b/Apps/HelloWorld/main.vp @@ -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) diff --git a/Apps/Scene3D/gfx.vp b/Apps/Scene3D/gfx.vp index a19c719..0c33a9c 100644 --- a/Apps/Scene3D/gfx.vp +++ b/Apps/Scene3D/gfx.vp @@ -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): diff --git a/Apps/Scene3D/main.vp b/Apps/Scene3D/main.vp index 531a772..4162f8b 100644 --- a/Apps/Scene3D/main.vp +++ b/Apps/Scene3D/main.vp @@ -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) diff --git a/Apps/Terminal/main.vp b/Apps/Terminal/main.vp index 637cd4c..102b6f1 100644 --- a/Apps/Terminal/main.vp +++ b/Apps/Terminal/main.vp @@ -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) diff --git a/Libs/SerialLogger/serial_logger.vp b/Libs/SerialLogger/serial_logger.vp index 5416102..f19496f 100644 --- a/Libs/SerialLogger/serial_logger.vp +++ b/Libs/SerialLogger/serial_logger.vp @@ -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")) diff --git a/Libs/VPUI64/vpui64.vp b/Libs/VPUI64/vpui64.vp index f43e3fc..5e73579 100644 --- a/Libs/VPUI64/vpui64.vp +++ b/Libs/VPUI64/vpui64.vp @@ -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) diff --git a/VKernel/Kernel/bootinfo.vp b/VKernel/Kernel/bootinfo.vp index d048ac9..7938fec 100644 --- a/VKernel/Kernel/bootinfo.vp +++ b/VKernel/Kernel/bootinfo.vp @@ -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 diff --git a/VKernel/Kernel/drivers/devfs/devfs.vp b/VKernel/Kernel/drivers/devfs/devfs.vp index 2d961c5..62787fa 100644 --- a/VKernel/Kernel/drivers/devfs/devfs.vp +++ b/VKernel/Kernel/drivers/devfs/devfs.vp @@ -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) diff --git a/VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.vp b/VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.vp index 8c5976f..89488f4 100644 --- a/VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.vp +++ b/VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.vp @@ -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] = ' ' diff --git a/VKernel/Kernel/drivers/fs/fat32/fat32_part.vp b/VKernel/Kernel/drivers/fs/fat32/fat32_part.vp index e4090b4..d58a7fd 100644 --- a/VKernel/Kernel/drivers/fs/fat32/fat32_part.vp +++ b/VKernel/Kernel/drivers/fs/fat32/fat32_part.vp @@ -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 diff --git a/VKernel/Kernel/drivers/fs/fat32/fat32_types.vp b/VKernel/Kernel/drivers/fs/fat32/fat32_types.vp index b9bcb3c..b1c552d 100644 --- a/VKernel/Kernel/drivers/fs/fat32/fat32_types.vp +++ b/VKernel/Kernel/drivers/fs/fat32/fat32_types.vp @@ -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: diff --git a/VKernel/Kernel/drivers/input/keyboard/keyboard.vp b/VKernel/Kernel/drivers/input/keyboard/keyboard.vp index 77501c2..80f9674 100644 --- a/VKernel/Kernel/drivers/input/keyboard/keyboard.vp +++ b/VKernel/Kernel/drivers/input/keyboard/keyboard.vp @@ -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 diff --git a/VKernel/Kernel/drivers/input/mouse/mouse.vp b/VKernel/Kernel/drivers/input/mouse/mouse.vp index 38bce65..f7a7456 100644 --- a/VKernel/Kernel/drivers/input/mouse/mouse.vp +++ b/VKernel/Kernel/drivers/input/mouse/mouse.vp @@ -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: diff --git a/VKernel/Kernel/drivers/serial/uart/su8250.vp b/VKernel/Kernel/drivers/serial/uart/su8250.vp index 75f846b..39895c9 100644 --- a/VKernel/Kernel/drivers/serial/uart/su8250.vp +++ b/VKernel/Kernel/drivers/serial/uart/su8250.vp @@ -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,避免递归调用 diff --git a/VKernel/Kernel/drivers/usb/hid/usb_kbd.vp b/VKernel/Kernel/drivers/usb/hid/usb_kbd.vp index 4235775..af8a12c 100644 --- a/VKernel/Kernel/drivers/usb/hid/usb_kbd.vp +++ b/VKernel/Kernel/drivers/usb/hid/usb_kbd.vp @@ -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 diff --git a/VKernel/Kernel/drivers/video/vesafb/gfx.vp b/VKernel/Kernel/drivers/video/vesafb/gfx.vp index 0082ed1..424ccb0 100644 --- a/VKernel/Kernel/drivers/video/vesafb/gfx.vp +++ b/VKernel/Kernel/drivers/video/vesafb/gfx.vp @@ -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) diff --git a/VKernel/Kernel/execrunner/elf.vp b/VKernel/Kernel/execrunner/elf.vp index abb8b51..a9054a1 100644 --- a/VKernel/Kernel/execrunner/elf.vp +++ b/VKernel/Kernel/execrunner/elf.vp @@ -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 diff --git a/VKernel/Kernel/main.vp b/VKernel/Kernel/main.vp index d0079f8..03bffc9 100644 --- a/VKernel/Kernel/main.vp +++ b/VKernel/Kernel/main.vp @@ -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() diff --git a/VKernel/Kernel/paging/paging.vp b/VKernel/Kernel/paging/paging.vp index 914cf74..3225c94 100644 --- a/VKernel/Kernel/paging/paging.vp +++ b/VKernel/Kernel/paging/paging.vp @@ -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 位 diff --git a/VKernel/Kernel/sched/sched.vp b/VKernel/Kernel/sched/sched.vp index fbbdcb9..f04d422 100644 --- a/VKernel/Kernel/sched/sched.vp +++ b/VKernel/Kernel/sched/sched.vp @@ -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: diff --git a/VKernel/Kernel/services/desktop.vp b/VKernel/Kernel/services/desktop.vp index 8567abd..6cd87a9 100644 --- a/VKernel/Kernel/services/desktop.vp +++ b/VKernel/Kernel/services/desktop.vp @@ -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) diff --git a/vpsdk/dynlib.vp b/vpsdk/dynlib.vp index eef32f1..2cb6a04 100644 --- a/vpsdk/dynlib.vp +++ b/vpsdk/dynlib.vp @@ -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))) diff --git a/vpsdk/fs.vp b/vpsdk/fs.vp index 9d55634..057b632 100644 --- a/vpsdk/fs.vp +++ b/vpsdk/fs.vp @@ -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 diff --git a/vpsdk/process.vp b/vpsdk/process.vp index 32acefd..1e6876c 100644 --- a/vpsdk/process.vp +++ b/vpsdk/process.vp @@ -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: diff --git a/vpsdk/stdio.vp b/vpsdk/stdio.vp index db159f5..d223ff9 100644 --- a/vpsdk/stdio.vp +++ b/vpsdk/stdio.vp @@ -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); diff --git a/vpsdk/stdlib.vp b/vpsdk/stdlib.vp index d088b26..85842ae 100644 --- a/vpsdk/stdlib.vp +++ b/vpsdk/stdlib.vp @@ -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 diff --git a/vpsdk/syscall.vp b/vpsdk/syscall.vp index 85db03f..1a49894 100644 --- a/vpsdk/syscall.vp +++ b/vpsdk/syscall.vp @@ -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, diff --git a/vpsdk/vpui.vp b/vpsdk/vpui.vp index 7d93d56..a0c286c 100644 --- a/vpsdk/vpui.vp +++ b/vpsdk/vpui.vp @@ -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: diff --git a/vpsdk/wiki/01-overview.md b/vpsdk/wiki/01-overview.md deleted file mode 100644 index efec04b..0000000 --- a/vpsdk/wiki/01-overview.md +++ /dev/null @@ -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. 生成 .pyi(签名存根) │ │ - │ │ 3. 构建结构体注册表 │ │ - │ │ 4. 生成 .stub.ll(LLVM IR 声明) │ │ - │ │ │ │ - │ └────────────────────────────────────────────────┘ │ - │ │ - │ ┌─────────────── 阶段二:代码翻译 ───────────────┐ │ - │ │ │ │ - │ │ 1. 加载所有 .pyi 和 .stub.ll │ │ - │ │ 2. 构建共享符号表 │ │ - │ │ 3. 收集内联函数符号 │ │ - │ │ 4. 翻译源文件 → .ll(含代码) │ │ - │ │ 5. llc 编译 → .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` 生成签名存根文件 `.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 声明文件 `.stub.ll`。 - -**声明生成规则**: - -| 元素 | 生成的 LLVM IR | -|------|---------------| -| 普通函数 | `declare void @".foo"(i32)` — 非 CExport 函数加 SHA1 前缀 | -| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 | -| 结构体 | `%".ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 | -| 全局变量 | `@varname = external global i32` | -| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) | -| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) | -| 枚举 | 为每个枚举成员生成 `@__config_EnumName_member = external global i32` | - -**增量编译**:如果 `.pyi` 或 `.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. 输出 `.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 函数名 | 链接可见性 | 用途 | -|------|---------------|-----------|------| -| 无修饰 | `@.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` 为 `.ll`,嵌入 `print` 对应的 `puts`/`printf` 声明,生成 `define i32 @main()` 函数体 -3. **编译**:`llc` 将 `.ll` 编译为 `.o` -4. **链接**:`ld.lld` 链接为可执行文件 diff --git a/vpsdk/wiki/02-type-system.md b/vpsdk/wiki/02-type-system.md deleted file mode 100644 index b3adad5..0000000 --- a/vpsdk/wiki/02-type-system.md +++ /dev/null @@ -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 -``` diff --git a/vpsdk/wiki/03-variables.md b/vpsdk/wiki/03-variables.md deleted file mode 100644 index 684e8d1..0000000 --- a/vpsdk/wiki/03-variables.md +++ /dev/null @@ -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) -``` diff --git a/vpsdk/wiki/04-functions.md b/vpsdk/wiki/04-functions.md deleted file mode 100644 index 48da6aa..0000000 --- a/vpsdk/wiki/04-functions.md +++ /dev/null @@ -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 -``` - -在结构体中也可以指定默认值。 diff --git a/vpsdk/wiki/05-classes.md b/vpsdk/wiki/05-classes.md deleted file mode 100644 index 7c003ba..0000000 --- a/vpsdk/wiki/05-classes.md +++ /dev/null @@ -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 -%".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, }`,所有变体共享最大变体的 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。 diff --git a/vpsdk/wiki/06-oop.md b/vpsdk/wiki/06-oop.md deleted file mode 100644 index cdb349f..0000000 --- a/vpsdk/wiki/06-oop.md +++ /dev/null @@ -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 @".ClassName.__before_init__"(%".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 @".GNode.append"(%".GNode"* %self, ...) { -entry: - %base = bitcast %".GNode"* %self to %".LinkedNode"* - call void @".LinkedNode.append"(%".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 -%".Base" = type { i8*, i32 } -``` - -同时,编译器会生成全局 vtable 变量: - -```llvm -@".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__` | 右操作数幂运算 | 同上 | diff --git a/vpsdk/wiki/07-control-flow.md b/vpsdk/wiki/07-control-flow.md deleted file mode 100644 index 6115aee..0000000 --- a/vpsdk/wiki/07-control-flow.md +++ /dev/null @@ -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); -``` diff --git a/vpsdk/wiki/08-c-operations.md b/vpsdk/wiki/08-c-operations.md deleted file mode 100644 index 253a74c..0000000 --- a/vpsdk/wiki/08-c-operations.md +++ /dev/null @@ -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#运算符重载)。 diff --git a/vpsdk/wiki/09-exceptions.md b/vpsdk/wiki/09-exceptions.md deleted file mode 100644 index 7f93516..0000000 --- a/vpsdk/wiki/09-exceptions.md +++ /dev/null @@ -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() -``` diff --git a/vpsdk/wiki/10-imports.md b/vpsdk/wiki/10-imports.md deleted file mode 100644 index 0324803..0000000 --- a/vpsdk/wiki/10-imports.md +++ /dev/null @@ -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. **阶段一**:对每个源文件生成 `.pyi` 签名存根和 `.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 -%".fat32_fileinfo" = type { [13 x i8], i8, i32 } -``` - -## 项目 includes 配置 - -在 `project.json` 中配置模块搜索路径: - -```json -{ - "includes": ["../.."], - "source_dir": "./Kernel" -} -``` - -编译器会在 `includes` 指定的目录中搜索导入的模块。 diff --git a/vpsdk/wiki/11-builtins.md b/vpsdk/wiki/11-builtins.md deleted file mode 100644 index 877b367..0000000 --- a/vpsdk/wiki/11-builtins.md +++ /dev/null @@ -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 标准库冲突。 diff --git a/vpsdk/wiki/12-project.md b/vpsdk/wiki/12-project.md deleted file mode 100644 index f289240..0000000 --- a/vpsdk/wiki/12-project.md +++ /dev/null @@ -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/ # 临时文件(自动生成) -│ ├── .pyi # 签名存根(阶段一生成) -│ ├── .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位) -- 如果 `.pyi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) -- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 -- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `:` - -### 阶段二增量 - -- 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射 -- 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件 -- 共享符号表一次性构建,避免每个文件重复加载 - -### SHA1 命名空间与增量编译的协同 - -SHA1 同时服务于命名空间隔离和增量编译: -- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 -- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 - -详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 diff --git a/vpsdk/wiki/13-bootstrapping.md b/vpsdk/wiki/13-bootstrapping.md deleted file mode 100644 index acddd9d..0000000 --- a/vpsdk/wiki/13-bootstrapping.md +++ /dev/null @@ -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 完成) | diff --git a/vpsdk/wiki/all.md b/vpsdk/wiki/all.md deleted file mode 100644 index c0c2f70..0000000 --- a/vpsdk/wiki/all.md +++ /dev/null @@ -1,3523 +0,0 @@ -# 01 - 语言概述与编译流程 - -## 语言定位 - -`Viper` 是一种 **系统级编程语言**,其语法基于 `Python`,但编译目标为 `LLVM IR`,最终生成原生机器码。`Viper` 不是 `Python` 的超集或子集,也不是"`C` 的语法糖"——它是一门拥有独立类型系统、独立编译模型、独立模块体系的语言。`Viper` 选择 `Python` 语法作为表达形式,是因为 `Python` 的 `AST` 可被标准库直接解析,从而将编译器的精力集中在语义翻译而非词法/语法分析上。同时也是因为 `Python` 是人类公认的可读性最高的语言。 - -而实际上,下文中所有提到的 `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` 类有对象语义,`@t.CVTable` 为多态,普通 `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` -- **存根驱动的模块系统**:`.pyi` 存根文件实现跨模块类型解析,无需头文件 -- **更多内容**:额外更多的不依赖操作系统的函数和语法 - -## 两阶段编译流程 - -Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。 - -``` -源文件 (.py) ────────────────────────────────────────────────────── - │ │ - │ ┌─────────────── 阶段一:声明提取 ───────────────┐ │ - │ │ │ │ - │ │ 1. 计算源文件 SHA1 │ │ - │ │ 2. 生成 .pyi(签名存根) │ │ - │ │ 3. 构建结构体注册表 │ │ - │ │ 4. 生成 .stub.ll(LLVM IR 声明) │ │ - │ │ │ │ - │ └────────────────────────────────────────────────┘ │ - │ │ - │ ┌─────────────── 阶段二:代码翻译 ───────────────┐ │ - │ │ │ │ - │ │ 1. 加载所有 .pyi 和 .stub.ll │ │ - │ │ 2. 构建共享符号表 │ │ - │ │ 3. 收集内联函数符号 │ │ - │ │ 4. 翻译源文件 → .ll(含代码) │ │ - │ │ 5. llc 编译 → .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` 生成签名存根文件 `.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 声明文件 `.stub.ll`。 - -**声明生成规则**: - -| 元素 | 生成的 LLVM IR | -|------|---------------| -| 普通函数 | `declare void @".foo"(i32)` — 非 CExport 函数加 SHA1 前缀 | -| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 | -| 结构体 | `%".ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 | -| 全局变量 | `@varname = external global i32` | -| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) | -| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) | -| 枚举 | 为每个枚举成员生成 `@__config_EnumName_member = external global i32` | - -**增量编译**:如果 `.pyi` 或 `.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. 输出 `.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 函数名 | 链接可见性 | 用途 | -|------|---------------|-----------|------| -| 无修饰 | `@.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` 为 `.ll`,嵌入 `print` 对应的 `puts`/`printf` 声明,生成 `define i32 @main()` 函数体 -3. **编译**:`llc` 将 `.ll` 编译为 `.o` -4. **链接**:`ld.lld` 链接为可执行文件 - - -# 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.CUnginedInt` 等。 - -### 固定宽度整数类型 - -| 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 -``` - -## 数组类型 - -使用 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 -``` - -## 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 的,还是后面的注解的,而且容易触发未定义行为。 - -## 强制类型转换 -在 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 -``` - - -# 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) -``` - - -# 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 -``` - -在结构体中也可以指定默认值。 - - -# 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 -%".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 -``` - -## 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` 的,还是后面的注解的,而且容易触发未定义行为。 - -## 位域 - -使用 `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。 - - -# 06 - 面向对象与运算符重载 - -Viper 中的 `class` 有两种语义:**数据布局**(结构体/联合体/枚举,见 [05-classes.md](05-classes.md))和**面向对象**。面向对象特性通过 `@t.Object` 装饰器启用,多态通过 `@t.CVTable` 装饰器启用。 - -## `@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__` 之前初始化 vtable: - -```llvm -declare void @".ClassName.__before_init__"(%".ClassName"*) -``` - -值得注意的是,`__before_init__` 并不帮忙初始化内存,而只是初始化虚表等准备工作,实际上,我们更希望用户能自己管理内存。实验性阶段内容中,我们通过内存池机制来帮助用户管理碎片化内容,包括部分小的结构体,但较大内容最好还是由用户手动处理。 - -## `@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 -%".Base" = type { i8*, i32 } -``` - -同时,编译器会生成全局 vtable 变量: - -```llvm -@".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__` | 右操作数幂运算 | 同上 | - - -# 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); -``` - - -# 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` 差,实际工程中不推荐使用条件宏,后期将完善宏的设计,引入模板等。 - -## 仅声明 `c.State` - -`c.State` 用于声明但不定义函数或变量: - -```python -def isr0() -> t.CExtern | t.CVoid | c.State: pass # extern void isr0(); -``` - -## 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#运算符重载)。 - - -# 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() -``` - - -# 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 -``` - -## 模块解析流程 - -### 编译时模块加载 - -Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合: - -1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件 -2. **阶段一**:对每个源文件生成 `.pyi` 签名存根和 `.stub.ll` LLVM IR 声明 -3. **阶段二**:加载所有 `.pyi` 和 `.stub.ll`,构建共享符号表 -4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用 -5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部 - -### 类型存根文件(.pyi) - -`.pyi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。存根文件的内容规则: - -| 元素 | 存根表示 | -|------|---------| -| `t.CDefine` 常量 | 保留完整定义(含赋值) | -| `t.CDefine` 函数 | 保留完整函数体 | -| 普通函数 | 仅签名 + `c.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 -%".fat32_fileinfo" = type { [13 x i8], i8, i32 } -``` - -## 项目 includes 配置 - -在 `project.json` 中配置模块搜索路径: - -```json -{ - "includes": ["../.."], - "source_dir": "./Kernel" -} -``` - -编译器会在 `includes` 指定的目录中搜索导入的模块。 - - -# 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 标准库冲突。 - - -# 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/ # 临时文件(自动生成) -│ ├── .pyi # 签名存根(阶段一生成) -│ ├── .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位) -- 如果 `.pyi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) -- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 -- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `:` - -### 阶段二增量 - -- 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射 -- 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件 -- 共享符号表一次性构建,避免每个文件重复加载 - -### SHA1 命名空间与增量编译的协同 - -SHA1 同时服务于命名空间隔离和增量编译: -- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 -- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 - -详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 - - diff --git a/vpsdk/window.vp b/vpsdk/window.vp index ad99953..f788e94 100644 --- a/vpsdk/window.vp +++ b/vpsdk/window.vp @@ -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: