stage1 重构代码

This commit is contained in:
zzy
2026-08-01 21:15:47 +08:00
parent a77eade06f
commit b43042c88d
30 changed files with 1211 additions and 6502 deletions

335
SPL.md
View File

@@ -5,11 +5,10 @@
SPL是一个从零构建的自举编译器项目。引导链:
```
stage0/spl_vm.c — SIR 虚拟机C 语言实现
stage1/spc0.c — SPL→SIR 编译器C 语言实现,引导用
stage1/spc1.spl — SPL→SIR 编译器SPL 语言实现,自举第一版
stage0/spl_vm.c — SIR 虚拟机 (C 语言实现)
stage1/splc0.c — SPL→SIR 编译器 (C 语言实现,引导用)
stage1/splc1.spl — SPL→SIR 编译器 (SPL 语言实现,自举第一版)
...将来...
spc2.spl → spc3.spl → ... → 完全自举
```
# SPL 语法规范
@@ -26,14 +25,16 @@ Root <- skip ContainerMembers eof
ContainerMembers <- ContainerDeclaration*
ContainerDeclaration
<- FnDecl
/ TypeDecl
/ VarDecl
/ ConstDecl
/ ComptimeStmt
/ DirectiveBlock (* @init { } / #test { } *)
ContainerDeclaration <- AttrList? DeclarationBody
DeclarationBody (* LL(1): FIRST 集合互斥 *)
<- FnDecl (* fn ... *)
/ TypeDecl (* type X = ... *)
/ MemberDecl (* IDENTIFIER [: TypeExpr] *)
/ VarDecl (* var x: T *)
/ ConstDecl (* const x: T = xxx *)
/ ComptimeStmt (* comptime ... *)
/ Block (* @init { } / #test { } *)
# ================================================================
# @ / # 属性列表 (对称设计)
@@ -52,17 +53,15 @@ DirectiveHead
# ================================================================
DirectiveBlock
<- DirectiveHead Block (* @init { } / #test { } *)
(* 注意: @assert(x); @dbg(x); 是表达式语句, 走 ExprStatement → BuiltinExpr, 不经过这里 *)
<- DirectiveHead Block (* @init { } / #test { } *)
# ================================================================
# comptime — 编译期执行 / 断言 (仅容器层)
# ================================================================
ComptimeStmt
<- KEYWORD_comptime Block (* comptime { code } *)
/ KEYWORD_comptime Expr SEMICOLON (* comptime <expr>; *)
<- KEYWORD_comptime Block (* comptime { code } *)
/ KEYWORD_comptime Expr SEMICOLON (* comptime <expr>; *)
# ================================================================
@@ -70,7 +69,7 @@ ComptimeStmt
# ================================================================
FnDecl
<- AttrList? KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr?
<- KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr?
(SEMICOLON / Block)
ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
@@ -85,7 +84,7 @@ ParamDecl
# ================================================================
TypeDecl
<- AttrList? KEYWORD_type IDENTIFIER EQUAL TypeBody (* @packed type Vec = struct { ... } *)
<- KEYWORD_type IDENTIFIER EQUAL TypeBody (* @packed type Vec = struct { ... } *)
TypeBody
<- KEYWORD_struct LBRACE AggregateBody RBRACE
@@ -96,22 +95,14 @@ TypeBody
AggregateBody <- AggregateItem*
AggregateItem
<- MethodDecl (* fn ... *)
/ TypeDecl (* type X = ... *)
/ VarDecl (* var x: T *)
/ ComptimeStmt (* comptime ... *)
/ MemberDecl (* IDENTIFIER [: TypeExpr] *)
<- ContainerDeclaration
(* struct: 字段, 必须 IDENTIFIER : TypeExpr (语义层检查)
union: 联合体字段, 同上
enum: 变体, IDENTIFIER : TypeExpr 或 纯 IDENTIFIER (朴素变体) *)
MemberDecl
<- AttrList? IDENTIFIER (COLON TypeExpr)? (COMMA / SEMICOLON)?
MethodDecl
<- AttrList? KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr? Block
<- IDENTIFIER (COLON TypeExpr)? (COMMA / SEMICOLON)?
# ================================================================
# 变量 / 常量
@@ -119,12 +110,12 @@ MethodDecl
# ================================================================
VarDecl
<- AttrList? KEYWORD_var IDENTIFIER
<- KEYWORD_var IDENTIFIER
(COLON TypeExpr / COLON_ASSIGN Expr)?
(EQUAL Expr)? SEMICOLON (* @volatile var flag: i32; *)
(EQUAL Expr)? SEMICOLON (* @volatile var flag: i32; *)
ConstDecl
<- AttrList? KEYWORD_const IDENTIFIER
<- KEYWORD_const IDENTIFIER
(COLON TypeExpr / COLON_ASSIGN Expr)?
EQUAL Expr SEMICOLON
@@ -139,6 +130,7 @@ BlockItem <- Statement
Statement (* LL(1): 14 分支互斥 *)
<- IfStatement
/ IfVarStatement
/ WhileStatement
/ LoopStatement
/ ForStatement
@@ -153,41 +145,42 @@ Statement (* LL(1): 14 分支互
ExprStatement <- Expr SEMICOLON
# ---- if ----
# if else
IfStatement
<- KEYWORD_if Expr BlockOrStmt (KEYWORD_else BlockOrStmt)?
<- KEYWORD_if Expr Block ElsePart?
BlockOrStmt <- Block / Statement
IfVarStatement
<- KEYWORD_if KEYWORD_var DOT IDENTIFIER (LBRACKET IDENTIFIER RBRACKET)? EQUAL Expr
Block ElsePart?
ElsePart
<- KEYWORD_else ( Block (* else { ... } *)
/ IfStatement (* else if ... *)
/ IfVarStatement (* else if var ... *)
)
# ---- while / loop / for ----
WhileStatement <- KEYWORD_while Expr BlockOrStmt
WhileStatement <- KEYWORD_while Expr Block
LoopStatement <- KEYWORD_loop BlockOrStmt
LoopStatement <- KEYWORD_loop Block
ForStatement
<- KEYWORD_for Expr (COMMA Expr)* KEYWORD_as IDENTIFIER (COMMA IDENTIFIER)* BlockOrStmt
<- KEYWORD_for Expr (COMMA Expr)* KEYWORD_as
IDENTIFIER (COMMA IDENTIFIER)* Block
# ---- match ----
MatchStatement <- KEYWORD_match Expr LBRACE MatchArm* RBRACE
MatchArm
<- MatchPat (COMMA MatchPat)* FAT_ARROW Statement
/ UNDERSCORE FAT_ARROW Statement
MatchPat (* LL(1): . / _ / Expr *)
<- DOT IDENTIFIER BindSpec?
/ Expr
BindSpec
<- LBRACKET IDENTIFIER RBRACKET
/ LBRACKET DOT IDENTIFIER EQUAL IDENTIFIER
(COMMA DOT IDENTIFIER EQUAL IDENTIFIER)* RBRACKET
<- MatchPat FAT_R_ARROW Statement
/ UNDERSCORE FAT_R_ARROW Statement
MatchPat (* LL(1): . / _ / Expr *)
<- DOT IDENTIFIER (LBRACKET IDENTIFIER RBRACKET)? (* 仅允许 .Item 或 .Item[bind] *)
/ Expr (* 字面量或变量常量 *)
# ---- 跳转 ----
@@ -198,7 +191,7 @@ ContinueStatement <- KEYWORD_continue SEMICOLON
# ---- defer ----
DeferStatement <- KEYWORD_defer BlockOrStmt
DeferStatement <- KEYWORD_defer (Block / Statement)
# ================================================================
@@ -215,16 +208,11 @@ BitXorExpr <- BitAndExpr (CARET BitAndExpr)*
BitAndExpr <- CmpEqExpr (AMPERSAND CmpEqExpr)*
CmpEqExpr <- CmpExpr ((EQ_EQ / BANG_EQUAL) CmpExpr)*
CmpExpr <- RangeExpr ((L_ARROW / L_ARROW_EQ / R_ARROW / R_ARROW_EQ) RangeExpr)*
# 新增 RangeExpr: 支持 a..b 和 a..
RangeExpr <- ShiftExpr (DOT2 ShiftExpr?)?
ShiftExpr <- AddExpr ((L_ARROW2 / R_ARROW2) AddExpr)*
AddExpr <- MulExpr ((PLUS / MINUS) MulExpr)*
MulExpr <- PrefixExpr ((ASTERISK / SLASH / PERCENT) PrefixExpr)*
PrefixExpr <- PrefixOp* PostfixExpr
PrefixOp <- MINUS / BANG / TILDE / AMPERSAND / ASTERISK
@@ -232,12 +220,12 @@ PrefixOp <- MINUS / BANG / TILDE / AMPERSAND / ASTERISK
PostfixExpr
<- PrimaryExpr
( LPAREN ExprList RPAREN (* 函数调用 *)
/ DOT IDENTIFIER (* 字段/方法 *)
/ DOT ASTERISK (* 解引用 *)
/ LBRACKET Expr RBRACKET (* 索引 *)
/ LBRACKET Expr DOT2 Expr? RBRACKET (* 切片 *)
/ KEYWORD_as TypeExpr (* 类型转换 *)
( LPAREN ExprList RPAREN (* 函数调用 *)
/ DOT IDENTIFIER (* 字段/方法 *)
/ DOT ASTERISK (* 解引用 *)
/ LBRACKET Expr RBRACKET (* 索引 *)
/ LBRACKET Expr DOT2 Expr? RBRACKET (* 切片 *)
/ KEYWORD_as TypeExpr (* 类型转换 *)
)*
ExprList <- (Expr COMMA)* Expr?
@@ -255,7 +243,7 @@ PrimaryExpr
/ LPAREN Expr RPAREN
/ ArrayLiteral
/ BuiltinExpr
/ Block (* 块表达式 *)
/ Block (* 块表达式 *)
ArrayLiteral <- LBRACKET INTEGER RBRACKET TypeExpr LBRACE ExprList? RBRACE
@@ -275,9 +263,9 @@ TypeExpr <- PrefixTypeOp* TypeBase
TypeBase <- FnTypeExpr / TypePath
PrefixTypeOp (* LL(1): * / [ *)
PrefixTypeOp (* LL(1): * / [ *)
<- ASTERISK
/ LBRACKET (RBRACKET / INTEGER RBRACKET) (* [] 或 [N] *)
/ LBRACKET (RBRACKET / INTEGER RBRACKET) (* [] 或 [N] *)
FnTypeExpr <- KEYWORD_fn LPAREN TypeExprList? RPAREN TypeExpr
@@ -285,7 +273,7 @@ TypeExprList <- (TypeExpr COMMA)* TypeExpr?
TypePath <- TypeAtom (DOT TypeAtom)*
TypeAtom (* LL(1): 关键词 / IDENTIFIER / _ *)
TypeAtom (* LL(1): 关键词 / IDENTIFIER / _ *)
<- KEYWORD_void / KEYWORD_bool
/ KEYWORD_i8 / KEYWORD_u8 / KEYWORD_i16 / KEYWORD_u16
/ KEYWORD_i32 / KEYWORD_u32 / KEYWORD_i64 / KEYWORD_u64
@@ -366,7 +354,8 @@ COMMA <- ',' SEMICOLON <- ';'
COLON <- ':' DOT <- '.'
DOT2 <- '..' DOT3 <- '...'
AT <- '@' SHARP <- '#'
FAT_ARROW <- '=>'
FAT_R_ARROW <- '=>' FAT_D_ARROW <- '<=>'
R_ARROW <- '<-' L_ARROW <- '->' D_ARROW '<->'
EQUAL <- '='
COLON_ASSIGN <- ':='
@@ -428,18 +417,18 @@ eof <- !.
零静默原则: 任何可能出错或危险的构造至少产生一条警告,绝无静默通过。严格模式下所有警告视为错误。
无未定义行为: 所有行为必须完全定义,否则为编译错误或宽松模式下的警告。任何不安全操作均需显式标记。
无未定义行为: 所有行为必须完全定义,否则为编译错误 (或宽松模式下的警告)。任何不安全操作均需显式标记。
内置数据类型: 语言内置区间 a..b 和切片 []T它们是真实的结构体拥有明确的内部字段用于迭代和切片操作。
## 容器层文件 = 匿名 struct
## 容器层 (文件 = 匿名 struct)
文件视为匿名 struct顶层声明顺序处理。
声明 静态约束 动态语义
FnDecl 名称唯一,签名完整。 仅定义。
TypeDecl 同作用域名称唯一。 定义类型别名或聚合体,编译时解析。
VarDecl容器级 var: 必须初始化类型完整。const: 初始化必须编译期可求值。 const 编译时计算var 启动初始化一次。
VarDecl (容器级) var: 必须初始化类型完整。const: 初始化必须编译期可求值。 const 编译时计算var 启动初始化一次。
ConstDecl 必须编译期可求值。 编译期常量。
ComptimeStmt 内部代码全部在编译时执行。 编译时执行,可生成声明。
DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识别指令触发警告/错误。 同左。
@@ -450,7 +439,7 @@ DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识
@name(args) / #name(args): 内置调用,出现在表达式位置。
语义: 完全由语言版本或库注册决定。当前所有均视为未识别,产生警告宽松 或错误严格
语义: 完全由语言版本或库注册决定。当前所有均视为未识别,产生警告 (宽松) 或错误 (严格)
## 函数
text
@@ -459,9 +448,9 @@ AttrList? fn IDENTIFIER ( ParamDeclList ) TypeExpr? ( ; | Block )
返回类型: 省略即 void。仅有 ; 表示外部声明。
调用: 实参与形参数量、类型必须完全匹配无隐式可变参数
调用: 实参与形参数量、类型必须完全匹配 (无隐式可变参数)
执行: 新作用域 → 形参绑定实参 → 执行 Block → 遇 ret expr 返回类型匹配,或 void 函数自然结束返回。
执行: 新作用域 → 形参绑定实参 → 执行 Block → 遇 ret expr 返回 (类型匹配),或 void 函数自然结束返回。
## 类型声明与聚合体
### 别名
@@ -475,19 +464,19 @@ type T = TypeExpr — 完全同义。
访问: expr.field。若 expr 是 struct 值,直接取字段;若为指针,自动解引用一层再取字段。多级指针必须连续 .*。
### union
字段共享内存,直接读取视为不安全。当前版本只允许通过 match 解构读取,且必须穷举所有可能变体或通配 _
字段共享内存,直接读取视为不安全。当前版本只允许通过 match 解构读取,且必须穷举所有可能变体 (或通配 _)
### enum
变体: variant 或 variant : Type。
构造: EnumName.variant 或带 (payload)。
匹配: match 必须穷举或含 _,否则编译错误。
匹配: match 必须穷举 (或含 _),否则编译错误。
## 变量与常量
var x: T 或 var x := init: 可变量。
局部变量未初始化: 必须显式标注类型 var x: T;无 =。宽松模式警告,严格模式错误。绝不静默。
局部变量未初始化: 必须显式标注类型 var x: T; (无 =)。宽松模式警告,严格模式错误。绝不静默。
const x: T = expr 或 const x := expr: 不可变量,必须初始化,一次绑定。
@@ -496,7 +485,7 @@ const x: T = expr 或 const x := expr: 不可变量,必须初始化,一次
## 块与语句
块 { ... } 引入作用域,可为表达式: 尾表达式无分号则块值即其值,否则 void。
### 控制流强制大括号体
### 控制流 (强制大括号体)
if
if 条件 { ... } [else { ... }]
@@ -511,13 +500,13 @@ loop
loop { ... }: 无限循环break 退出。
for
语法PEG 已定义:
语法 (PEG 已定义):
ForRange 是逗号分隔的表达式列表。每个表达式在启动阶段只能是内置可迭代对象:
区间 a..b 或 a..无右端点: 内置类型 Range内部字段 begin 和 endend 可为 none 表示无界。迭代产生从 begin 开始递增的整数,直到 end不含。若为 a..,则产生无界序列。
区间 a..b 或 a.. (无右端点): 内置类型 Range内部字段 begin 和 end (end 可为 none 表示无界)。迭代产生从 begin 开始递增的整数,直到 end (不含)。若为 a..,则产生无界序列。
切片/数组 expr类型为 []T 或 [N]T: 内置切片类型,内部结构为 ptr: *T, len: usize。迭代依次产生每个元素类型为 T。
切片/数组 expr (类型为 []T 或 [N]T): 内置切片类型,内部结构为 ptr: *T, len: usize。迭代依次产生每个元素类型为 T。
语义:
@@ -527,7 +516,7 @@ as 后的变量列表长度必须等于 n否则编译错误。
每个 Ei 必须是上述内置可迭代对象,否则编译错误。
并行迭代: 每次迭代从每个 Ei 中各自取出一个值,按顺序绑定到对应变量只读,作用域在循环体内
并行迭代: 每次迭代从每个 Ei 中各自取出一个值,按顺序绑定到对应变量 (只读,作用域在循环体内)
循环继续直到任意一个序列耗尽。若序列长度不同,最短的耗尽时循环停止,忽略其余序列剩余元素。
@@ -535,13 +524,13 @@ as 后的变量列表长度必须等于 n否则编译错误。
长度协调:
区间 a..b 具有确定长度 b - a若 b >= a否则为 0
区间 a..b 具有确定长度 b - a (若 b >= a否则为 0)
切片 []T 的长度由其 len 字段确定。
区间 a.. 无界,其长度由循环中其他序列的最短长度决定。例如 for my_slice, 0.. as elem, idx 中0.. 将提供与 my_slice 等长的索引序列,因为循环在 my_slice 耗尽时终止。实际上 0.. 等价于 0..my_slice.len。
若循环中只有无界序列而没有有限序列,则循环无限进行此时需 loop 替代,但语言仍接受
若循环中只有无界序列而没有有限序列,则循环无限进行 (此时需 loop 替代,但语言仍接受)
示例:
// 单区间
@@ -550,7 +539,7 @@ for 0..5 as i { ... } // i: 0,1,2,3,4
// 单切片
for my_slice as elem { ... }
// 切片 + 索引用户显式提供从0开始的区间
// 切片 + 索引 (用户显式提供从0开始的区间)
for my_slice, 0.. as elem, idx { ... } // idx 与 elem 一一对应
// 两个等长切片
@@ -562,7 +551,7 @@ for my_slice, 0.. as elem // 双序列却只有一个变量
match
用于枚举或 union。
臂: .variant [bind] => { ... }bind 仅支持 [id]绑定整个载荷
臂: .variant [bind] => { ... }bind 仅支持 [id] (绑定整个载荷)
必须穷举或含 _否则编译错误。
@@ -623,7 +612,7 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量
## 类型表达式
基础类型: void, bool, 整数/浮点类型。
指针: *T, *_任意指针[N]T数组[]T切片
指针: *T, *_ (任意指针)[N]T (数组)[]T (切片)
函数类型: fn(T1, T2) RetType。
@@ -647,13 +636,13 @@ null → ?T。
区间类型 Range
语法 a..b 或 a..。
内部结构: { begin: i64, end: ?i64 }具体整数类型可能由上下文决定,默认为 i64
内部结构: { begin: i64, end: ?i64 } (具体整数类型可能由上下文决定,默认为 i64)
a..b: begin = a, end = b。
a..: begin = a, end = null。
用作迭代器时: 产生从 begin 到 end-1 的整数若 end 为 null 则无穷。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界等于 0..other.len,如果配对序列也是无界则无限循环。
用作迭代器时: 产生从 begin 到 end-1 的整数 (若 end 为 null 则无穷)。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界 (等于 0..other.len),如果配对序列也是无界则无限循环。
切片类型 []T
内部结构: { ptr: *T, len: usize }。
@@ -681,17 +670,17 @@ a..: begin = a, end = null。
所有内置类型的内部表示与分类
类型兼容性与隐式转换规则附警告/错误表格
类型兼容性与隐式转换规则 (附警告/错误表格)
表达式与语句的类型推导/检查规则伪代码
表达式与语句的类型推导/检查规则 (伪代码)
特殊类型的处理指针、区间、切片等
特殊类型的处理 (指针、区间、切片等)
原则: 所有可能不安全或信息丢失的隐式转换均产生警告;不允许静默转换。最终严格模式下警告将变为错误。
## 内置基础类型
### 整数类型
类型 大小(位) 表示 对齐
类型 大小 (位) 表示 对齐
i8, u8 8 二进制补码 / 无符号 1 字节
i16, u16 16 同上 2 字节
i32, u32 32 同上 4 字节
@@ -721,7 +710,7 @@ void: 大小为 0表示无值仅用于函数返回或指针。
### 数组类型
[N]T: 固定长度数组,长度为编译期常量 N元素类型 T。连续内存布局大小 = N * sizeof(T)。
数组可隐式转换为切片见隐式转换
数组可隐式转换为切片 (见隐式转换)
### 切片类型
[]T: 切片,内部结构 { ptr: *T, len: usize }。值类型同聚合类型行为。
@@ -735,7 +724,7 @@ a..b 或 a..: 类型为 Range内部结构 { begin: isize, end: ?isize }。
a..b: end 为 b。
a..: end 为 null无界
a..: end 为 null (无界)
Range 是值类型同聚合类型行为。
@@ -744,23 +733,23 @@ Range 是值类型同聚合类型行为。
### 函数类型
fn(参数类型列表) 返回类型
函数值本身的大小和表示未指定闭包待定,但函数名作为标识符使用时具有指针语义类似函数指针
函数值本身的大小和表示未指定 (闭包待定),但函数名作为标识符使用时具有指针语义 (类似函数指针)
### 可选类型(暂时不需要实现)
?T: 可为 null 的类型。内部表示同 T 但附加一个判别可能通过 null 指针表示,视 T 而定。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式具体实现定义
?T: 可为 null 的类型。内部表示同 T 但附加一个判别 (可能通过 null 指针表示,视 T 而定)。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式 (具体实现定义)
null 字面量只能出现在需要 ?T 的上下文中。
### 自定义聚合类型
struct: 字段连续排列可能有对齐填充,每个字段有自己的类型。赋值是逐字段拷贝。
struct: 字段连续排列 (可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。
union: 所有字段共享起始地址,大小等于最大字段加上对齐。直接字段读取被视为不安全,需通过 match 解构。
union: 所有字段共享起始地址,大小等于最大字段 (加上对齐)。直接字段读取被视为不安全,需通过 match 解构。
enum: 带标签的联合体,每个变体可有载荷。大小实现定义,但需容纳判别式及最大载荷。
## 类型分类
### 值类型复制语义
所有基本标量类型,或者说底层寄存器类型整数、浮点、bool
### 值类型 (复制语义)
所有基本标量类型,或者说底层寄存器类型 (整数、浮点、bool)
struct
@@ -775,7 +764,7 @@ struct
### 引用/指针类型
\*T、\*_
函数指针内部类似 \*const fn(...)
函数指针 (内部类似 \*const fn(...))
### 特殊类型
void: 无法实例化,仅用于返回或指针目标。
@@ -786,17 +775,17 @@ null: 不是独立类型,仅用于初始化或赋值给 ?T。
下表中,“允许”表示可自动转换,否则需要显式 as 转换。警告列表明编译器必须输出诊断信息,不可静默。
源类型 目标类型 允许? 警告? 备注
T任意 T 是 无 相同类型
T (任意) T 是 无 相同类型
*T *_ 是 警告: “丢失类型信息”
*_ *T 是 警告: “不安全的指针重解释”
[N]T []T 是 无 数组到切片强制转换
整数字面量 整数类型 U 是若值在 U 范围内 无 字面量自动拓宽
整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽
i32 i64 否 — 需显式 as i64防止意外
i64 i32 否 — 窄化必须显式
null ?T 是 无 空值初始化
?T T 否 — 需显式解包如 orelse但语言暂未定义将来扩展
?T T 否 — 需显式解包 (如 orelse但语言暂未定义将来扩展)
T ?T 是 无 提升为可选
浮点字面量 f32 是值可表示则
浮点字面量 f32 是 (值可表示则)
f64 f32 否 — 窄化需显式
bool 整数 否 —
整数 bool 否 —
@@ -805,7 +794,7 @@ bool 整数 否 —
隐式转换不会嵌套传递。例如 *T 到 *_ 是警告转换,但不因此进一步允许 *_ 到 **T 的隐式转换。
字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文如赋值给 i64 变量,或作为 Range 的边界Range 内部为 isize所以 0..5 中的 0 和 5 会拓宽为 isize
字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界Range 内部为 isize所以 0..5 中的 0 和 5 会拓宽为 isize)
所有其他未列出的类型转换均需显式 as。
@@ -821,7 +810,7 @@ true / false → bool
null → 必须从上下文推导出 ?T无法推导则报错。
字符串字面量 → []u8具体待定
字符串字面量 → []u8 (具体待定)
### 二元运算
算术 e1 + e2、-、*、/、%:
@@ -830,7 +819,7 @@ null → 必须从上下文推导出 ?T无法推导则报错。
t1 = type(e1), t2 = type(e2)
若 t1 == t2 且 t1 ∈ 数值类型:
返回 t1
否则若 t1 和 t2 为整数且其中一个是字面量类型为 i32 或可拓宽:
否则若 t1 和 t2 为整数且其中一个是字面量 (类型为 i32 或可拓宽):
返回 max(t1, t2) // 字面量拓宽
否则:
错误 "类型不匹配"
@@ -839,7 +828,7 @@ t1 = type(e1), t2 = type(e2)
```text
t1 = type(e1), t2 = type(e2)
若 t1 和 t2 兼容相同或允许隐式转换:
若 t1 和 t2 兼容 (相同或允许隐式转换):
返回 bool
否则:
错误
@@ -862,8 +851,8 @@ t1 = type(e1), t2 = type(e2)
~e: e 必须为整数,结果同类型。
&e: e 必须为可寻址左值变量、字段、*解引用等。若 e 类型为 T结果为 *T。
注意: 没有 * 前缀运算符解引用仅后缀 .*
&e: e 必须为可寻址左值 (变量、字段、*解引用等)。若 e 类型为 T结果为 *T。
注意: 没有 * 前缀运算符 (解引用仅后缀 .*)
### 后缀运算
e.\*: 要求 e 类型为 \*T结果为 T且作为左值。
@@ -878,19 +867,19 @@ e.field:
e[i]:
e 类型为 [N]T 或 []T 或 *T视为指向单个元素或数组起始i 为整数。结果为 T 左值。
e 类型为 [N]T 或 []T 或 *T (视为指向单个元素或数组起始)i 为整数。结果为 T 左值。
e[a..b]:
e 类型为 [N]T 或 []Ta 和 b 为整数可省略 b。结果为 []T。
e 类型为 [N]T 或 []Ta 和 b 为整数 (可省略 b)。结果为 []T。
e(args):
e 类型必须为函数类型 fn(T1, T2, ...) Ret。实参类型须与形参兼容允许隐式转换。结果为 Ret。
e 类型必须为函数类型 fn(T1, T2, ...) Ret。实参类型须与形参兼容 (允许隐式转换)。结果为 Ret。
e as Type:
要求源类型与目标类型间存在合法显式转换包括整数窄化、指针转换等。结果为 Type。
要求源类型与目标类型间存在合法显式转换 (包括整数窄化、指针转换等)。结果为 Type。
### 主要表达式
标识符: 查找作用域,返回其声明类型。
@@ -905,7 +894,7 @@ Type 必须是 struct 类型。检查字段数量是否齐全,每个 ei 类型
comptime e: e 必须在编译时可求值,类型同 e。
内置调用 @id(args) / #id(args): 未定义则警告/错误按模式,否则行为由对应内置定义决定。
内置调用 @id(args) / #id(args): 未定义则警告/错误 (按模式),否则行为由对应内置定义决定。
## 语句类型规则
### 变量声明
@@ -913,7 +902,7 @@ var x: T = e;: e 的类型必须兼容 T。x 获得类型 T可变。
var x := e;: 推导类型为 e 的类型x 可变。
var x: T;: 无初始化x 具有类型 T。警告宽松模式或错误严格模式。不可用于 const。
var x: T;: 无初始化x 具有类型 T。警告 (宽松模式)或错误 (严格模式)。不可用于 const。
const x: T = e;: 同上兼容性x 不可变。
@@ -923,15 +912,15 @@ const x := e;: 推导类型,不可变。
x = e;: x 必须是可变变量e 的类型兼容 x 的类型。
### 控制流
if cond { ... } else { ... }: cond 必须为 bool。若 if 用作表达式,两分支块的类型必须相同或均为 void
if cond { ... } else { ... }: cond 必须为 bool。若 if 用作表达式,两分支块的类型必须相同 (或均为 void)
while cond { ... }: cond 必须为 bool。
loop { ... }: 无类型限制。
for range_list as var_list { ... }见下节
for range_list as var_list { ... } (见下节)
match e { arms }: e 的类型为枚举或 union。每个模式臂的类型若 match 用作表达式必须一致。必须穷举。
match e { arms }: e 的类型为枚举或 union。每个模式臂的类型 (若 match 用作表达式)必须一致。必须穷举。
### for 循环详细类型规则
语法: for E1, E2, ... as v1, v2, ... { ... }
@@ -940,25 +929,25 @@ ForRange 提供表达式列表 [E1, E2, ...]。as 后标识符列表 [v1, v2, ..
如果动态类型动态长度,则警告具体行为待定,整个语法待定,下面将是暂时语法。
```
每个 Ei 的类型必须为内置可迭代类型当前启动阶段仅包括 Range 和 []T / [N]T。若 Ei 的类型不是这两者之一,编译错误。
每个 Ei 的类型必须为内置可迭代类型 (当前启动阶段仅包括 Range 和 []T / [N]T)。若 Ei 的类型不是这两者之一,编译错误。
对于 Ei:
若为 Range: 每次迭代产出的值类型为 isizeRange 的边界类型,这里默认为 isize
若为 Range: 每次迭代产出的值类型为 isize (Range 的边界类型,这里默认为 isize)
若为 []T 或 [N]T: 产出元素类型为 T。
相应地vi 被推导为只读变量,其类型为对应 Ei 产出的值类型。
所有序列的长度必须可静态协调见下文,否则编译错误或警告,宽松模式下允许无界
所有序列的长度必须可静态协调 (见下文),否则编译错误 (或警告,宽松模式下允许无界)
长度协调规则:
若所有序列均为有界Range 有 end 不为 null或切片长度已知,则循环次数为最短长度。
若所有序列均为有界 (Range 有 end 不为 null或切片长度已知),则循环次数为最短长度。
若存在无界 Range如 0..,则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx0.. 的长度由 slice.len 决定。
若存在无界 Range (如 0..),则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx0.. 的长度由 slice.len 决定。
若只有无界序列,则为无限循环合法,但通常应使用 loop
若只有无界序列,则为无限循环 (合法,但通常应使用 loop)
```
示例:
@@ -968,7 +957,7 @@ for my_slice, 0.. as elem, idx { ... }
// 0..: Range 无界 → idx: i64长度由 my_slice 决定
```
## 类型系统限制
无隐式类型提升除字面量整数拓宽和数组到切片外
无隐式类型提升 (除字面量整数拓宽和数组到切片外)
无默认初始化: var x: T; 不初始化,警告/错误。
@@ -992,9 +981,9 @@ ABI 剥离:跨函数调用和返回统一由 @abi.call / @abi.ret 封装,内
## 词法前缀与语义
前缀 语义 示例
@ 全局函数名、类型名、内置函数调用 @main, @Vec2, @arith.add
% 局部变量虚拟寄存器 %sum, %ptr
% 局部变量 (虚拟寄存器) %sum, %ptr
\# 基本块标签 \#entry, \#loop_body
! 编译/链接标记元数据 !export("C"), !section(".text")
! 编译/链接标记 (元数据) !export("C"), !section(".text")
词法成本极低:最多两字符即可区分所有实体,无需长关键字。
语义完全解耦:
@@ -1029,8 +1018,6 @@ Stmt ← VarDef ';'
VarDef ← LOCAL_IDENT '=' Expr // 严格 SSA 单次定义
CallStmt ← Expr // 忽略返回值
Branch ← 'br' LOCAL_IDENT ',' LABEL ',' LABEL
Return ← 'ret' (LOCAL_IDENT | CONSTANT)? ';'
Label ← LABEL ':'
Expr ← CallExpr | LOCAL_IDENT | CONSTANT
@@ -1058,13 +1045,13 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
## 内置函数库
## 验证规则约束
单一定值:每个 %name 在其函数内只被赋值一次%x = … 或作为参数,且使用前必须支配所有使用点。
单一定值:每个 %name 在其函数内只被赋值一次 (%x = … 或作为参数),且使用前必须支配所有使用点。
类型匹配:@arith.add(i32)(%a, %b) 要求 %a 和 %b 的类型都是 i32 绝对的类型匹配。
块终止:每个基本块以 br 或 ret 结束,目标 #label 必须在当前函数内存在。
函数存在性:所有调用的 @ 函数@arith.add必须来自库。
函数存在性:所有调用的 @ 函数 (@arith.add)必须来自库。
## 完整内置函数库 (@ 调用)
### 算术运算
@@ -1074,8 +1061,8 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
@arith.add(T)(%a:T, %b:T) -> T 加法
@arith.sub(T)(%a:T, %b:T) -> T 减法
@arith.mul(T)(%a:T, %b:T) -> T 乘法
@arith.div(T)(%a:T, %b:T) -> T 除法整数截断向零,浮点为 IEEE 除法
@arith.rem(T)(%a:T, %b:T) -> T 取余仅整数,符号跟随被除数
@arith.div(T)(%a:T, %b:T) -> T 除法 (整数截断向零,浮点为 IEEE 除法)
@arith.rem(T)(%a:T, %b:T) -> T 取余 (仅整数,符号跟随被除数)
@arith.neg(T)(%a:T) -> T 取负
@arith.abs(T)(%a:T) -> T 绝对值
### 位运算
@@ -1085,8 +1072,8 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
@arith.and(T)(%a:T, %b:T) -> T 按位与
@arith.or(T)(%a:T, %b:T) -> T 按位或
@arith.xor(T)(%a:T, %b:T) -> T 按位异或
@arith.shl(T)(%a:T, %b:T) -> T 左移,%b 为移位量类型同 T
@arith.shr(T)(%a:T, %b:T) -> T 右移算术或逻辑由 T 的有无符号决定
@arith.shl(T)(%a:T, %b:T) -> T 左移,%b 为移位量 (类型同 T)
@arith.shr(T)(%a:T, %b:T) -> T 右移 (算术或逻辑由 T 的有无符号决定)
@arith.not(T)(%a:T) -> T 按位取反
### 比较运算
操作数类型 T 必须一致,返回 bool。
@@ -1094,7 +1081,7 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
函数签名 说明
@cmp.eq(T)(%a:T, %b:T) -> bool 相等
@cmp.ne(T)(%a:T, %b:T) -> bool 不等
@cmp.lt(T)(%a:T, %b:T) -> bool 小于有符号/无符号根据 T
@cmp.lt(T)(%a:T, %b:T) -> bool 小于 (有符号/无符号根据 T)
@cmp.le(T)(%a:T, %b:T) -> bool 小于等于
@cmp.gt(T)(%a:T, %b:T) -> bool 大于
@cmp.ge(T)(%a:T, %b:T) -> bool 大于等于
@@ -1105,60 +1092,71 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
@cast.sext(SRC_T, DST_T)(%a:SRC_T) -> DST_T 有符号扩展整数
@cast.fext(SRC_T, DST_T)(%a:SRC_T) -> DST_T 浮点扩展
@cast.ftrunc(SRC_T, DST_T)(%a:SRC_T) -> DST_T 浮点截断
@cast.bitcast(SRC_T, DST_T)(%a:SRC_T) -> DST_T 位模式重解释类型大小必须相等
@cast.ptrtoint(P_T, INT_T)(%ptr:P_T) -> INT_T 指针到整数
@cast.inttoptr(INT_T, P_T)(%val:INT_T) -> P_T 整数到指针
@cast.bool_to_int(INT_T)(%cond:bool) -> INT_T 布尔转整数true->1, false->0
@cast.bitcast(SRC_T, DST_T)(%a:SRC_T) -> DST_T 位模式重解释 (类型大小必须相等)
@cast.ptr2int(P_T, INT_T)(%ptr:P_T) -> INT_T 指针到整数
@cast.int2ptr(INT_T, P_T)(%val:INT_T) -> P_T 整数到指针
@case.int2float(INT_T, F_T)(%val:INT_T) -> F_T 整数到浮点数
@case.float2int(F_T, INT_T)(%val:F_T) -> INT_T 浮点数到整数
@cast.bool2int(INT_T)(%cond:bool) -> INT_T 布尔转整数 (true->1, false->0)
### 内存操作
函数签名 说明
@mem.alloca(T)(%count:i32) -> ptr<T> 栈上分配 %count * sizeof(T) 字节,返回对齐的指针
@mem.alloca(T)(%count:usize) -> ptr<T> 栈上分配 %count * sizeof(T) 字节,返回对齐的指针
@mem.load(T)(%ptr:ptr<T>) -> T 从内存加载类型为 T 的值
@mem.store(T)(%ptr:ptr<T>, %val:T) 存储值到内存
@mem.offset(T)(%ptr:ptr<T>, %offset:i32) -> ptr<T> 指针算术,以 sizeof(T) 为单位偏移
@mem.copy(%dst:ptr<void>, %src:ptr<void>, %size:i32) 内存块复制
@mem.set(%dst:ptr<void>, %val:u8, %size:i32) 内存块填充
@mem.fence(%ordering:u32) 内存屏障见原子操作节
@mem.offset(T)(%ptr:ptr<T>, %offset:isize) -> ptr<T> 指针算术,以 sizeof(T) 为单位偏移
@mem.copy(%dst:ptr<void>, %src:ptr<void>, %size:usize) 内存块复制
@mem.set(%dst:ptr<void>, %val:u8, %size:usize) 内存块填充
@mem.fence(%ordering:isize) 内存屏障 (见原子操作节)
### 类型信息查询
所有查询在编译期求值,返回整数。
函数签名 说明
@type.sizeof(T)() -> i32 返回类型 T 的字节大小
@type.alignof(T)() -> i32 返回类型 T 的对齐要求
@type.offsetof(T)(%field_index:i32) -> i32 聚合类型 T 中第 field_index 个字段的字节偏移字段从0编号
@type.field_count(T)() -> i32 返回聚合类型的字段数量
@type.const(T)(LITERAL) -> T LITERAL是源语言层面的字面量表示
@type.bitsizeof(T)() -> usize 返回类型 T 的位大小
@type.sizeof(T)() -> usize 返回类型 T 的字节大小
@type.alignof(T)() -> usize 返回类型 T 的对齐要求
@type.offsetof(T)(%field_index:usize) -> usize 聚合类型 T 中第 field_index 个字段的字节偏移 (字段从0编号)
@type.field_count(T)() -> usize 返回聚合类型的字段数量
### 聚合类型操作
函数签名 说明
@agg.extract(T, FIELD_INDEX)(%val:T) -> FIELD_T 从 struct 中提取第 FIELD_INDEX 个字段(常量索引)
@agg.insert(T, FIELD_INDEX)(%agg:T, %field:FIELD_T) -> T 替换 struct 中指定字段,返回新 struct
@agg.extract_union(T, FIELD_IDENT)(%val:T) -> FIELD_T 从 union 中读取指定字段(需确保当前活跃)
@agg.insert_union(T, FIELD_IDENT)(%payload:FIELD_T) -> T 创建 union 值,将载荷写入指定字段
### ABI 调用接口
用于跨函数边界,封装调用约定。
@agg.construct(T)(%f1: T1, %f2: T2, ...) -> T 从各个字段值构造一个结构体/联合体值。T 为具体的聚合类型。
- 参数个数必须等于类型 T 的字段总数。
- 每个参数的类型必须与对应字段的类型精确匹配 (无隐式转换)。
- 适用于 struct 和 union。对于 union参数只能有一个 (因为只有一个活跃字段),该参数类型必须与某个字段类型兼容 (见联合体处理)。
函数签名 说明
@abi.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fnFT 为 fn<param_types...->ret_type>
@abi.ret(T)(%val?) 按目标平台调用约定从当前函数返回T 为返回值类型void 时不带参数
内部函数若未使用 !export 标记,可自由使用直接 ret 指令而不经过 @abi.ret此时编译器可完全自定义内部调用协议
@agg.extract(T, FIELD_INDEX)(%val:T) -> FIELD_T 从聚合值中提取指定索引的字段。FIELD_INDEX 为编译期常量。
- FIELD_INDEX 必须为非负整数常量,小于类型 T 的字段数。
- 对于 struct返回对应字段的值类型为字段声明类型。
- 对于 union由于所有字段共享存储允许用任意有效字段索引提取返回值类型为对应字段声明类型。这本身已包含“按不同类型解读同一块存储”的语义无需额外的 bitcast (但也可结合 @cast.bitcast 使用)
@agg.insert(T, FIELD_INDEX)(%agg:T, %field:FIELD_T) -> T 替换聚合值中指定字段,返回新值 (不可变更新)。T 必须为 struct。
- 仅适用于 struct 类型。union 是不可变更新无意义 (因为只有一个活跃字段,应使用 construct 重新创建)。
- FIELD_INDEX 为合法字段索引,%field 类型必须与该字段类型一致。
- 返回的 T 值其他字段保持不变。
### 原子操作(可选,现在不实现)
原子操作需要一个 ordering 参数,类型为 u32使用常量表示内存顺序可参照 C11 内存模型定义,例如 0=relaxed, 1=acquire, 2=release, 3=acq_rel, 4=seq_cst)。
原子操作需要一个 ordering 参数,类型为 u32使用常量表示内存顺序 (可参照 C11 内存模型定义,例如 0=relaxed, 1=acquire, 2=release, 3=acq_rel, 4=seq_cst)
函数签名 说明
@atomic.load(T)(%ptr:ptr<T>, %ordering:u32) -> T 原子加载
@atomic.store(T)(%ptr:ptr<T>, %val:T, %ordering:u32) 原子存储
@atomic.rmw_add(T)(%ptr:ptr<T>, %val:T, %ordering:u32) -> T 原子交换加返回旧值
@atomic.rmw_add(T)(%ptr:ptr<T>, %val:T, %ordering:u32) -> T 原子交换加 (返回旧值)
@atomic.rmw_sub(T)(%ptr:ptr<T>, %val:T, %ordering:u32) -> T 原子交换减
@atomic.rmw_and(T), or, xor, xchg 等类似
@atomic.cmpxchg(T)(%ptr:ptr<T>, %expected:T, %desired:T, %ordering_success:u32, %ordering_failure:u32) -> {old:T, ok:bool} 原子比较交换,返回旧值和成功标志通过 struct 返回
### 控制流扩展间接跳转、选择
@atomic.cmpxchg(T)(%ptr:ptr<T>, %expected:T, %desired:T, %ordering_success:u32, %ordering_failure:u32) -> {old:T, ok:bool} 原子比较交换,返回旧值和成功标志 (通过 struct 返回)
### 控制流扩展 (间接跳转、选择)
函数签名 说明
@control.select(T)(%cond:bool, %true_val:T, %false_val:T) -> T 选择操作无分支,类似三元运算符
@control.unreachable() -> void 标记不可达代码
@control.trap() -> void 触发运行时陷阱
@control.select(T)(%cond:bool, %true_val:T, %false_val:T) -> T 选择操作 (无分支,类似三元运算符)
@control.br(bool, label, label) -> ! 条件分支:根据第一个参数跳转到第二或第三个(标签或者地址)。终止函数 (调用后控制流不返回)。
@control.jmp(label) -> ! 无条件跳转(跳转到标签或者地址)。终止函数。
@control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fnFT 为 fn<param_types...->ret_type>
@control.ret(T)(%val?) 按目标平台调用约定从当前函数返回T 为返回值类型void 时不带参数
@control.unreachable() -> ! 标记不可达代码
@control.trap() -> ! 触发运行时陷阱
### 调试与内省
函数签名 说明
@dbg.breakpoint() 插入调试断点
@dbg.declare(%var:%) 声明局部变量的调试信息可被后端忽略
@dbg.declare(%var:%) 声明局部变量的调试信息 (可被后端忽略)
## 完整标记系统 (! 前缀)
标记附加在函数定义前,用逗号分隔。所有标记均不影响 IR 控制流语义,仅向后端传递元数据。
@@ -1172,4 +1170,3 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
!naked — 无函数序言/尾声 中断向量、系统调用包装
!noinline — 禁止内联 调试或特殊性能需求
!alwaysinline — 总是内联 简单的包装函数