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

61
stage0/include/color.h Normal file
View File

@@ -0,0 +1,61 @@
/**
* @file color.h
* @brief ANSI终端颜色控制码定义
*
* 提供跨平台的终端文本颜色和样式控制支持
*/
#ifndef __SCC_TERMINAL_COLOR_H__
#define __SCC_TERMINAL_COLOR_H__
/* clang-format off */
/// @name 前景色控制码
/// @{
#define ANSI_FG_BLACK "\33[30m" ///< 黑色前景
#define ANSI_FG_RED "\33[31m" ///< 红色前景
#define ANSI_FG_GREEN "\33[32m" ///< 绿色前景
#define ANSI_FG_YELLOW "\33[33m" ///< 黄色前景
#define ANSI_FG_BLUE "\33[34m" ///< 蓝色前景
#define ANSI_FG_MAGENTA "\33[35m" ///< 品红色前景
#define ANSI_FG_CYAN "\33[36m" ///< 青色前景
#define ANSI_FG_WHITE "\33[37m" ///< 白色前景
/// @}
/// @name 背景色控制码
/// @{
#define ANSI_BG_BLACK "\33[40m" ///< 黑色背景
#define ANSI_BG_RED "\33[41m" ///< 红色背景
#define ANSI_BG_GREEN "\33[42m" ///< 绿色背景
#define ANSI_BG_YELLOW "\33[43m" ///< 黄色背景
#define ANSI_BG_BLUE "\33[44m" ///< 蓝色背景
#define ANSI_BG_MAGENTA "\33[45m" ///< 品红色背景原始代码此处应为45m
#define ANSI_BG_CYAN "\33[46m" ///< 青色背景
#define ANSI_BG_WHITE "\33[47m" ///< 白色背景
/// @}
/// @name 文字样式控制码
/// @{
#define ANSI_UNDERLINED "\33[4m" ///< 下划线样式
#define ANSI_BOLD "\33[1m" ///< 粗体样式
#define ANSI_NONE "\33[0m" ///< 重置所有样式
/// @}
/* clang-format on */
/**
* @def ANSI_FMT
* @brief 安全文本格式化宏
* @param str 目标字符串
* @param fmt ANSI格式序列可组合多个样式
*
* @note 当定义ANSI_FMT_DISABLE时自动禁用颜色输出
* @code
* printf(ANSI_FMT("Warning!", ANSI_FG_YELLOW ANSI_BOLD));
* @endcode
*/
#ifndef ANSI_FMT_DISABLE
#define ANSI_FMT(str, fmt) fmt str ANSI_NONE ///< 启用样式包裹
#else
#define ANSI_FMT(str, fmt) str ///< 禁用样式输出
#endif
#endif /* __SCC_TERMINAL_COLOR_H__ */

View File

@@ -9,7 +9,8 @@
#ifndef nullptr #ifndef nullptr
#define nullptr NULL #define nullptr NULL
#endif #endif
typedef size_t usize; typedef uintptr_t usize;
typedef intptr_t isize;
#define MAP_TYPEOF __typeof__ #define MAP_TYPEOF __typeof__
@@ -26,150 +27,147 @@ typedef size_t usize;
#define MAP_CMP_INT(a, b) ((a) != (b)) #define MAP_CMP_INT(a, b) ((a) != (b))
static inline usize map_hash_str(const char *s) { static inline usize map_hash_str(const char *s) {
usize h = 5381; usize h = 5381;
while (*s) while (*s)
h = ((h << 5) + h) + (unsigned char)*s++; h = ((h << 5) + h) + (unsigned char)*s++;
return h; return h;
} }
#define MAP_HASH_STR map_hash_str #define MAP_HASH_STR map_hash_str
#define MAP_CMP_STR strcmp #define MAP_CMP_STR strcmp
/* ---------- 数据结构宏 ---------- */ /* ---------- 数据结构宏 ---------- */
#define MAP_SLOT(key_t, val_t) \ #define MAP_SLOT(key_t, val_t) \
struct { \ struct { \
key_t key; \ key_t key; \
val_t val; \ val_t val; \
char state; \ char state; \
} }
#define MAP(key_t, val_t) \ #define MAP(key_t, val_t) \
struct { \ struct { \
usize size; \ usize size; \
usize cap; \ usize cap; \
MAP_SLOT(key_t, val_t) * data; \ MAP_SLOT(key_t, val_t) * data; \
usize (*hash)(key_t); \ usize (*hash)(key_t); \
int (*cmp)(key_t, key_t); \ int (*cmp)(key_t, key_t); \
} }
/* ---------- 操作宏 ---------- */ /* ---------- 操作宏 ---------- */
/** 初始化,必须提供哈希和比较函数 */ /** 初始化,必须提供哈希和比较函数 */
#define map_init(map, hash_fn, cmp_fn) \ #define map_init(map, hash_fn, cmp_fn) \
do { \ do { \
(map).size = 0; \ (map).size = 0; \
(map).cap = 0; \ (map).cap = 0; \
(map).data = nullptr; \ (map).data = nullptr; \
(map).hash = (hash_fn); \ (map).hash = (hash_fn); \
(map).cmp = (cmp_fn); \ (map).cmp = (cmp_fn); \
} while (0) } while (0)
/** 释放内部数组 */ /** 释放内部数组 */
#define map_free(map) \ #define map_free(map) \
do { \ do { \
free((map).data); \ free((map).data); \
(map).data = nullptr; \ (map).data = nullptr; \
(map).size = (map).cap = 0; \ (map).size = (map).cap = 0; \
} while (0) } while (0)
/** 遍历所有有效元素 */ /** 遍历所有有效元素 */
#define map_for(map, idx) \ #define map_for(map, idx) \
for (usize(idx) = 0; (idx) < (map).cap; ++(idx)) \ for (usize(idx) = 0; (idx) < (map).cap; ++(idx)) \
if ((map).data[(idx)].state == __MAP_SLOT_OCCUPIED) if ((map).data[(idx)].state == __MAP_SLOT_OCCUPIED)
/** /**
* 插入(若键已存在则更新值) * 插入(若键已存在则更新值)
* 注意:扩容使用 realloc失败会 abort可自行修改错误处理 * 注意:扩容使用 realloc失败会 abort可自行修改错误处理
*/ */
#define map_put(map, _key, _val) \ #define map_put(map, _key, _val) \
do { \ do { \
/* 扩容 */ \ /* 扩容 */ \
if ((map).cap == 0 || \ if ((map).cap == 0 || (map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \
(map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \ usize new_cap = (map).cap == 0 ? 8 : (map).cap * 2; \
usize new_cap = (map).cap == 0 ? 8 : (map).cap * 2; \ MAP_SLOT(MAP_TYPEOF((map).data->key), MAP_TYPEOF((map).data->val)) *new_data = \
MAP_SLOT(MAP_TYPEOF((map).data->key), \ calloc(new_cap, sizeof(*new_data)); \
MAP_TYPEOF((map).data->val)) *new_data = \ if (!new_data) \
calloc(new_cap, sizeof(*new_data)); \ abort(); \
if (!new_data) \ /* 重新插入旧元素 */ \
abort(); \ for (usize _i = 0; _i < (map).cap; ++_i) { \
/* 重新插入旧元素 */ \ if ((map).data[_i].state == __MAP_SLOT_OCCUPIED) { \
for (usize _i = 0; _i < (map).cap; ++_i) { \ usize _h = (map).hash((map).data[_i].key) & (new_cap - 1); \
if ((map).data[_i].state == __MAP_SLOT_OCCUPIED) { \ while (new_data[_h].state == __MAP_SLOT_OCCUPIED) \
usize _h = (map).hash((map).data[_i].key) & (new_cap - 1); \ _h = (_h + 1) & (new_cap - 1); \
while (new_data[_h].state == __MAP_SLOT_OCCUPIED) \ new_data[_h].key = (map).data[_i].key; \
_h = (_h + 1) & (new_cap - 1); \ new_data[_h].val = (map).data[_i].val; \
new_data[_h].key = (map).data[_i].key; \ new_data[_h].state = __MAP_SLOT_OCCUPIED; \
new_data[_h].val = (map).data[_i].val; \ } \
new_data[_h].state = __MAP_SLOT_OCCUPIED; \ } \
} \ free((map).data); \
} \ (map).data = (void *)new_data; \
free((map).data); \ (map).cap = new_cap; \
(map).data = (void *)new_data; \ } \
(map).cap = new_cap; \ /* 查找或插入 */ \
} \ usize _mask = (map).cap - 1; \
/* 查找或插入 */ \ usize _idx = (map).hash(_key) & _mask; \
usize _mask = (map).cap - 1; \ usize _first_del = (usize) - 1; \
usize _idx = (map).hash(_key) & _mask; \ while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
usize _first_del = (usize) - 1; \ if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ (map).cmp((map).data[_idx].key, _key) == 0) { \
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ (map).data[_idx].val = _val; \
(map).cmp((map).data[_idx].key, _key) == 0) { \ break; \
(map).data[_idx].val = _val; \ } \
break; \ if ((map).data[_idx].state == __MAP_SLOT_DELETED && _first_del == (usize) - 1) \
} \ _first_del = _idx; \
if ((map).data[_idx].state == __MAP_SLOT_DELETED && \ _idx = (_idx + 1) & _mask; \
_first_del == (usize) - 1) \ } \
_first_del = _idx; \ if ((map).data[_idx].state == __MAP_SLOT_EMPTY) { \
_idx = (_idx + 1) & _mask; \ usize _target = (_first_del != (usize) - 1) ? _first_del : _idx; \
} \ (map).data[_target].key = _key; \
if ((map).data[_idx].state == __MAP_SLOT_EMPTY) { \ (map).data[_target].val = _val; \
usize _target = (_first_del != (usize) - 1) ? _first_del : _idx; \ (map).data[_target].state = __MAP_SLOT_OCCUPIED; \
(map).data[_target].key = _key; \ ++(map).size; \
(map).data[_target].val = _val; \ } \
(map).data[_target].state = __MAP_SLOT_OCCUPIED; \ } while (0)
++(map).size; \
} \
} while (0)
/** /**
* 查询:若找到,*out_val 被赋值为对应值并返回 1否则返回 0 * 查询:若找到,*out_val 被赋值为对应值并返回 1否则返回 0
*/ */
#define map_get(map, _key, out_val) \ #define map_get(map, _key, out_val) \
(({ \ (({ \
int _found = 0; \ int _found = 0; \
if ((map).cap > 0) { \ if ((map).cap > 0) { \
usize _mask = (map).cap - 1; \ usize _mask = (map).cap - 1; \
usize _idx = (map).hash(_key) & _mask; \ usize _idx = (map).hash(_key) & _mask; \
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
(map).cmp((map).data[_idx].key, _key) == 0) { \ (map).cmp((map).data[_idx].key, _key) == 0) { \
*out_val = (map).data[_idx].val; \ *out_val = (map).data[_idx].val; \
_found = 1; \ _found = 1; \
break; \ break; \
} \ } \
_idx = (_idx + 1) & _mask; \ _idx = (_idx + 1) & _mask; \
} \ } \
} \ } \
_found; \ _found; \
})) }))
/** /**
* 删除指定键 * 删除指定键
*/ */
#define map_del(map, _key) \ #define map_del(map, _key) \
do { \ do { \
if ((map).cap == 0) \ if ((map).cap == 0) \
break; \ break; \
usize _mask = (map).cap - 1; \ usize _mask = (map).cap - 1; \
usize _idx = (map).hash(_key) & _mask; \ usize _idx = (map).hash(_key) & _mask; \
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
(map).cmp((map).data[_idx].key, _key) == 0) { \ (map).cmp((map).data[_idx].key, _key) == 0) { \
(map).data[_idx].state = __MAP_SLOT_DELETED; \ (map).data[_idx].state = __MAP_SLOT_DELETED; \
--(map).size; \ --(map).size; \
break; \ break; \
} \ } \
_idx = (_idx + 1) & _mask; \ _idx = (_idx + 1) & _mask; \
} \ } \
} while (0) } while (0)
#endif /* __CORE_MAP_H__ */ #endif /* __CORE_MAP_H__ */

View File

@@ -18,6 +18,7 @@
#define __vec_free free #define __vec_free free
#define __vec_memcpy memcpy #define __vec_memcpy memcpy
#else #else
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -32,11 +33,11 @@ typedef size_t usize;
#ifndef LOG_FATAL #ifndef LOG_FATAL
#include <stdio.h> #include <stdio.h>
#define LOG_FATAL(...) \ #define LOG_FATAL(...) \
do { \ do { \
printf(__VA_ARGS__); \ printf(__VA_ARGS__); \
abort(); \ abort(); \
} while (0) } while (0)
#endif #endif
#ifndef Assert #ifndef Assert
@@ -61,12 +62,12 @@ typedef size_t usize;
* struct people { VEC(char) name; int age; VEC(struct people) children; * struct people { VEC(char) name; int age; VEC(struct people) children;
* }; * };
*/ */
#define VEC(type) \ #define VEC(type) \
struct { \ struct { \
usize size; \ usize size; \
usize cap; \ usize cap; \
type *data; \ type *data; \
} }
/** @defgroup vec_operations 动态数组操作宏 */ /** @defgroup vec_operations 动态数组操作宏 */
@@ -77,20 +78,20 @@ typedef size_t usize;
* *
* @note 此宏不会分配内存,仅做零初始化 * @note 此宏不会分配内存,仅做零初始化
*/ */
#define vec_init(vec) \ #define vec_init(vec) \
do { \ do { \
(vec).size = 0, (vec).cap = 0, (vec).data = 0; \ (vec).size = 0, (vec).cap = 0, (vec).data = 0; \
} while (0) } while (0)
#define vec_realloc(vec, new_cap) \ #define vec_realloc(vec, new_cap) \
do { \ do { \
void *data = __vec_realloc((vec).data, new_cap * sizeof(*(vec).data)); \ void *data = __vec_realloc((vec).data, new_cap * sizeof(*(vec).data)); \
if (!data) { \ if (!data) { \
LOG_FATAL("vector_push: realloc failed\n"); \ LOG_FATAL("vector_push: realloc failed\n"); \
} \ } \
(vec).cap = new_cap; \ (vec).cap = new_cap; \
(vec).data = data; \ (vec).data = data; \
} while (0) } while (0)
#define vec_size(vec) ((vec).size) #define vec_size(vec) ((vec).size)
#define vec_cap(vec) ((vec).cap) #define vec_cap(vec) ((vec).cap)
@@ -105,15 +106,15 @@ typedef size_t usize;
* @note 当容量不足时自动扩容为2倍初始容量为4 * @note 当容量不足时自动扩容为2倍初始容量为4
* @warning 内存分配失败时会触发LOG_FATAL * @warning 内存分配失败时会触发LOG_FATAL
*/ */
#define vec_push(vec, value) \ #define vec_push(vec, value) \
do { \ do { \
if ((vec).size >= (vec).cap) { \ if ((vec).size >= (vec).cap) { \
usize cap = (vec).cap ? (vec).cap * 2 : 4; \ usize cap = (vec).cap ? (vec).cap * 2 : 4; \
vec_realloc(vec, cap); \ vec_realloc(vec, cap); \
} \ } \
Assert((vec).data != nullptr); \ Assert((vec).data != nullptr); \
(vec).data[(vec).size++] = value; \ (vec).data[(vec).size++] = value; \
} while (0) } while (0)
/** /**
* @def vec_pop(vec) * @def vec_pop(vec)
@@ -149,43 +150,43 @@ typedef size_t usize;
* *
* @note 释放后需重新初始化才能再次使用 * @note 释放后需重新初始化才能再次使用
*/ */
#define vec_free(vec) \ #define vec_free(vec) \
do { \ do { \
if ((vec).data == nullptr) \ if ((vec).data == nullptr) \
break; \ break; \
__vec_free((vec).data); \ __vec_free((vec).data); \
(vec).data = nullptr; \ (vec).data = nullptr; \
(vec).size = (vec).cap = 0; \ (vec).size = (vec).cap = 0; \
} while (0) } while (0)
#define vec_unsafe_get_data(vec) ((vec).data) #define vec_unsafe_get_data(vec) ((vec).data)
#define vec_unsafe_from_buffer(vec, buffer, buffer_size) \ #define vec_unsafe_from_buffer(vec, buffer, buffer_size) \
do { \ do { \
(vec).size = buffer_size; \ (vec).size = buffer_size; \
(vec).cap = (vec).size; \ (vec).cap = (vec).size; \
(vec).data = buffer; \ (vec).data = buffer; \
} while (0) } while (0)
#define vec_unsafe_from_static_array(vec, array) \ #define vec_unsafe_from_static_array(vec, array) \
do { \ do { \
(vec).size = sizeof(array) / sizeof((array)[0]); \ (vec).size = sizeof(array) / sizeof((array)[0]); \
(vec).cap = (vec).size; \ (vec).cap = (vec).size; \
(vec).data = array; \ (vec).data = array; \
} while (0) } while (0)
/** /**
* @def vec_sized_realloc(vec, elem_size, new_cap) * @def vec_sized_realloc(vec, elem_size, new_cap)
* @brief 内部宏:按 elem_size 重新分配内存 * @brief 内部宏:按 elem_size 重新分配内存
*/ */
#define vec_sized_realloc(vec, elem_size, new_cap) \ #define vec_sized_realloc(vec, elem_size, new_cap) \
do { \ do { \
void *new_data = __vec_realloc((vec).data, (new_cap) * (elem_size)); \ void *new_data = __vec_realloc((vec).data, (new_cap) * (elem_size)); \
if (!new_data) \ if (!new_data) \
LOG_FATAL("vec_sized_realloc: failed\n"); \ LOG_FATAL("vec_sized_realloc: failed\n"); \
(vec).data = new_data; \ (vec).data = new_data; \
(vec).cap = new_cap; \ (vec).cap = new_cap; \
} while (0) } while (0)
/** /**
* @def vec_sized_push(vec, elem_size, src_ptr) * @def vec_sized_push(vec, elem_size, src_ptr)
@@ -198,24 +199,23 @@ typedef size_t usize;
* @note 使用前需确保 vec.data 类型与 src_ptr 无关,内部会按字节拷贝。 * @note 使用前需确保 vec.data 类型与 src_ptr 无关,内部会按字节拷贝。
* 推荐声明时为 `VEC(char)` 或 `VEC(unsigned char)`。 * 推荐声明时为 `VEC(char)` 或 `VEC(unsigned char)`。
*/ */
#define vec_sized_push(vec, elem_size, src_ptr, copy_size) \ #define vec_sized_push(vec, elem_size, src_ptr, copy_size) \
do { \ do { \
if ((vec).size >= (vec).cap) { \ if ((vec).size >= (vec).cap) { \
usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \ usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \
vec_sized_realloc(vec, elem_size, new_cap); \ vec_sized_realloc(vec, elem_size, new_cap); \
} \ } \
char *slot = (char *)(vec).data + (vec).size * (elem_size); \ char *slot = (char *)(vec).data + (vec).size * (elem_size); \
__vec_memcpy(slot, (src_ptr), (copy_size)); \ __vec_memcpy(slot, (src_ptr), (copy_size)); \
(vec).size++; \ (vec).size++; \
} while (0) } while (0)
/** /**
* @def vec_sized_at_ptr(vec, elem_size, idx) * @def vec_sized_at_ptr(vec, elem_size, idx)
* @brief 获取第 idx 个元素的指针void* * @brief 获取第 idx 个元素的指针void*
* @return 指向元素的指针,需转换为具体类型使用 * @return 指向元素的指针,需转换为具体类型使用
*/ */
#define vec_sized_at_ptr(vec, elem_size, idx) \ #define vec_sized_at_ptr(vec, elem_size, idx) ((void *)((char *)(vec).data + (idx) * (elem_size)))
((void *)((char *)(vec).data + (idx) * (elem_size)))
/** /**
* @def vec_sized_foreach(vec, elem_size, elem_ptr_var, block) * @def vec_sized_foreach(vec, elem_size, elem_ptr_var, block)
@@ -223,24 +223,24 @@ typedef size_t usize;
* @param elem_ptr_var 循环内的变量名void* 类型) * @param elem_ptr_var 循环内的变量名void* 类型)
* @param block 循环体语句块 * @param block 循环体语句块
*/ */
#define vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \ #define vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \
do { \ do { \
for (usize __i = 0; __i < (vec).size; ++__i) { \ for (usize __i = 0; __i < (vec).size; ++__i) { \
void *elem_ptr_var = vec_sized_at_ptr(vec, elem_size, __i); \ void *elem_ptr_var = vec_sized_at_ptr(vec, elem_size, __i); \
block; \ block; \
} \ } \
} while (0) } while (0)
/** /**
* @def vec_sized_pop(vec, elem_size) * @def vec_sized_pop(vec, elem_size)
* @brief 弹出最后一个元素(仅减小 size不返回数据 * @brief 弹出最后一个元素(仅减小 size不返回数据
*/ */
#define vec_sized_pop(vec, elem_size) \ #define vec_sized_pop(vec, elem_size) \
do { \ do { \
if ((vec).size == 0) \ if ((vec).size == 0) \
LOG_FATAL("vec_sized_pop: empty\n"); \ LOG_FATAL("vec_sized_pop: empty\n"); \
(vec).size--; \ (vec).size--; \
} while (0) } while (0)
/** /**
* @def vec_sized_clear(vec) * @def vec_sized_clear(vec)

88
stage0/include/log.c Normal file
View File

@@ -0,0 +1,88 @@
#include "log.h"
static inline int log_snprintf(char *s, size_t n, const char *format, ...) {
int ret;
va_list args;
va_start(args, format);
ret = log_vsnprintf(s, n, format, args);
va_end(args);
return ret;
}
int log_default_handler(logger_t *module, log_level_t level, const char *file, int line,
const char *func, const char *fmt, ...) {
const char *level_str;
int offset = 0;
va_list args;
va_start(args, fmt);
/* clang-format off */
switch (level) {
case LOG_LEVEL_DEBUG: level_str = "DEBUG"; break;
case LOG_LEVEL_INFO: level_str = "INFO "; break;
case LOG_LEVEL_WARN: level_str = "WARN "; break;
case LOG_LEVEL_ERROR: level_str = "ERROR"; break;
case LOG_LEVEL_FATAL: level_str = "FATAL"; break;
case LOG_LEVEL_TRACE: level_str = "TRACE"; break;
default: level_str = "NOTSET"; break;
}
/// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出
#ifndef __LOG_NO_COLOR__
const char *color_code;
switch (level) {
case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break;
case LOG_LEVEL_INFO: color_code = ANSI_FG_GREEN; break;
case LOG_LEVEL_TRACE: color_code = ANSI_FG_BLUE; break;
case LOG_LEVEL_WARN: color_code = ANSI_FG_YELLOW; break;
case LOG_LEVEL_ERROR: color_code = ANSI_FG_RED; break;
case LOG_LEVEL_FATAL: color_code = ANSI_FG_RED ANSI_UNDERLINED; break;
default: color_code = ANSI_NONE;
}
/* clang-format on */
offset = log_snprintf(module->buf, sizeof(module->buf),
ANSI_BOLD "%s[%s] %s - %s:%d in %s()" ANSI_NONE " ", color_code,
level_str, module->name, file, line, func);
#else
offset = log_snprintf(module->buf, sizeof(module->buf), "[%s] %s - %s:%d in %s() ", level_str,
module->name, file, line, func);
#endif
/* 然后写入用户消息(如果有) */
if (fmt && fmt[0]) {
log_vsnprintf(module->buf + offset, sizeof(module->buf) - offset, fmt, args);
}
va_end(args);
log_puts(module->buf);
// for clangd warning
// clang-analyzer-deadcode.DeadStores
(void)color_code;
(void)level_str;
if (level & LOG_LEVEL_FATAL) {
log_abort();
}
return 0;
}
logger_t __default_logger_root = {
.name = "root",
.level = LOG_LEVEL_ALL,
.handler = log_default_handler,
};
void init_logger(logger_t *logger, const char *name) {
logger->name = name;
logger->handler = log_default_handler;
log_set_level(logger, LOG_LEVEL_ALL);
}
void log_set_level(logger_t *logger, int level) {
if (logger)
logger->level = level;
else
__default_logger_root.level = level;
}
void log_set_handler(logger_t *logger, log_handler handler) {
if (logger)
logger->handler = handler;
else
__default_logger_root.handler = handler;
}

193
stage0/include/log.h Normal file
View File

@@ -0,0 +1,193 @@
/**
* @file log.h
* @brief 日志系统核心模块(支持多级日志、断言和异常处理)
*/
#ifndef __SCC_LOG_IMPL_H__
#define __SCC_LOG_IMPL_H__
#include "color.h"
#include <stdarg.h>
#ifdef __SCC_LOG_IMPL_USE_STD_IMPL__
#include <stdio.h>
#include <stdlib.h>
#define log_vsnprintf vsnprintf
#define log_puts puts
#define log_abort abort
#endif
#ifdef __GNUC__ // GCC, Clang
#define __scc_log_unreachable() (__builtin_unreachable())
#elif defined _MSC_VER // MSVC
#define __scc_log_unreachable() (__assume(false))
#elif defined __SCC_BUILTIN_UNREACHEABLE__ // The SCC Compiler (my compiler)
#define __scc_log_unreachable() (__scc_builtin_unreachable())
#else
#define __scc_log_unreachable() ((void)0)
#endif
#ifndef log_vsnprintf
#define log_vsnprintf(...)
#warning "log_vsnprintf not defined"
#endif
#ifndef log_puts
#define log_puts(...)
#warning "log_puts not defined"
#endif
#ifndef log_abort
#define log_abort(...)
#warning "log_abort not defined"
#endif
/**
* @brief 日志级别枚举
*
* 定义日志系统的输出级别和组合标志位
*/
typedef enum log_level {
LOG_LEVEL_NOTSET = 0, ///< 未设置级别(继承默认配置)
LOG_LEVEL_DEBUG = 1 << 0, ///< 调试信息(开发阶段详细信息)
LOG_LEVEL_INFO = 1 << 1, ///< 常规信息(系统运行状态)
LOG_LEVEL_WARN = 1 << 2, ///< 警告信息(潜在问题提示)
LOG_LEVEL_ERROR = 1 << 3, ///< 错误信息(可恢复的错误)
LOG_LEVEL_FATAL = 1 << 4, ///< 致命错误(导致程序终止的严重错误)
LOG_LEVEL_TRACE = 1 << 5, ///< 追踪(性能追踪或者栈帧追踪)
LOG_LEVEL_ALL = 0xFF, ///< 全级别标志(组合所有日志级别)
} log_level_t;
#ifndef LOGGER_MAX_BUF_SIZE
#define LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸
#endif
typedef struct logger logger_t;
typedef int (*log_handler)(logger_t *module, log_level_t level, const char *file, int line,
const char *func, const char *fmt, ...);
/**
* @brief 日志器实例结构体
*
* 每个日志器实例维护独立的配置和缓冲区
*/
struct logger {
const char *name; ///< 日志器名称(用于模块区分)
log_level_t level; ///< 当前设置的日志级别
union {
log_handler handler;
void *user_handler;
}; ///< 日志处理回调函数
void *user_data; ///< 用户自定义数据
char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区
};
int log_default_handler(logger_t *module, log_level_t level, const char *file, int line,
const char *func, const char *fmt, ...);
extern logger_t __default_logger_root;
#ifndef LOG_DEFAULT_HANDLER
#define LOG_DEFAULT_HANDLER &__default_logger_root
#endif
/**
* @brief 初始化日志实例 其余参数设置为默认值
* @param[in] logger 日志器实例指针
* @param[in] name 日志器名称nullptr表示获取默认日志器名称
*/
void init_logger(logger_t *logger, const char *name);
/**
* @brief 设置日志级别
* @param[in] logger 目标日志器实例
* @param[in] level 要设置的日志级别(可组合多个级别)
*/
void log_set_level(logger_t *logger, int level);
/**
* @brief 设置自定义日志处理器
* @param[in] logger 目标日志器实例
* @param[in] handler 自定义处理函数nullptr恢复默认处理
*/
void log_set_handler(logger_t *logger, log_handler handler);
#ifndef LOG_MAX_MAROC_BUF_SIZE
#define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE ///< 宏展开缓冲区尺寸
#endif
#define SCC_LOG_HANDLE_ARGS(_module_, _level_, ...) \
(_module_), (_level_), __FILE__, __LINE__, __func__, ##__VA_ARGS__
#define SCC_LOG_IMPL(_module_, _level_, _fmt_, ...) \
do { \
/* TODO check _module_ is nullptr */ \
if ((_module_)->handler && ((_module_)->level & (_level_))) \
(_module_)->handler(SCC_LOG_HANDLE_ARGS(_module_, _level_, _fmt_, ##__VA_ARGS__)); \
} while (0)
/* clang-format off */
/// @name 模块日志宏
/// @{
#define MLOG_NOTSET(module, ...)SCC_LOG_IMPL(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
#define MLOG_DEBUG(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别
#define MLOG_INFO(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
#define MLOG_WARN(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
#define MLOG_ERROR(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
#define MLOG_FATAL(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
#define MLOG_TRACE(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
/// @}
/// @name 快捷日志宏
/// @{
#define LOG_NOTSET(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
#define LOG_DEBUG(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别
#define LOG_INFO(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
#define LOG_WARN(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
#define LOG_ERROR(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
#define LOG_FATAL(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
#define LOG_TRACE(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
/// @}
/* clang-format on */
/**
* @def _Assert
* @brief 断言检查内部宏
* @param cond 检查条件表达式
* @param ... 错误信息参数(格式字符串+参数)
*/
#define _Assert(cond, ...) \
((void)((cond) || (__default_logger_root.handler(SCC_LOG_HANDLE_ARGS( \
&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__)), \
log_abort(), __scc_log_unreachable(), 0)))
/// @name 断言工具宏
/// @{
#define __INNERSCC_LOG_IMPL_STR(str) #str
#define _SCC_LOG_IMPL_STR(str) __INNERSCC_LOG_IMPL_STR(str)
#define AssertFmt(cond, format, ...) \
_Assert(cond, "Assertion Failure: " format, ##__VA_ARGS__) ///< 带格式的断言检查
#define PanicFmt(format, ...) _Assert(0, "Panic: " format, ##__VA_ARGS__) ///< 立即触发致命错误
#define Assert(cond) AssertFmt(cond, "cond is `" _SCC_LOG_IMPL_STR(cond) "`") ///< 基础断言检查
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
#define TODO() PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
#define UNREACHABLE() PanicFmt("UNREACHABLE") ///< 触发致命错误(代码不可达)
#define FIXME(str) PanicFmt("FIXME " _SCC_LOG_IMPL_STR(str)) ///< 提醒开发者修改代码(触发致命错误)
/// @}
/**
* @brief 静态断言(编译时)
*
* 利用数组大小不能为负的特性
* 或使用 _Static_assert (C11)
*/
#if __STDC_VERSION__ >= 201112L
#define StaticAssert _Static_assert
#else
#define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
#endif
#ifdef __SCC_LOG_IMPL_IMPORT_SRC__
#include "log.c"
#endif
#endif /* __SCC_LOG_IMPL_H__ */

10
stage0/include/utils.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#define __SCC_LOG_IMPL_USE_STD_IMPL__
#include "log.h"
#include "core_map.h"
#include "core_vec.h"
#endif /* __UTILS_H__ */

View File

@@ -370,49 +370,6 @@ int spl_prog_add_data(spl_prog_t *prog, void *ptr, usize size) {
return vec_size(prog->gdata); return vec_size(prog->gdata);
} }
spl_val_t spl_prog_emit(spl_prog_t *prog, uint16_t opcode, uint16_t type, spl_val_t imm) {
spl_ins_t ins = {opcode, type, imm};
spl_val_t addr = vec_size(prog->insns);
vec_push(prog->insns, ins);
return addr;
}
int spl_prog_add_func_simple(spl_prog_t *prog, const char *name, spl_val_t nargs) {
spl_func_t func = {0};
if (!prog || !name)
return -1;
func.name = strdup(name);
func.idx_of_strtab = 0;
func.nargs = nargs;
func.ninsns = 0;
func.address = vec_size(prog->insns);
vec_push(prog->funcs, func);
return (int)vec_size(prog->funcs) - 1;
}
int spl_prog_update_func(spl_prog_t *prog, int func_idx, const char *name, spl_val_t nargs) {
if (!prog || func_idx < 0 || func_idx >= (int)vec_size(prog->funcs))
return spl_prog_add_func_simple(prog, name, nargs);
spl_func_t *func = &vec_at(prog->funcs, func_idx);
func->address = vec_size(prog->insns);
func->nargs = nargs;
return func_idx;
}
void spl_prog_end_func(spl_prog_t *prog, int func_idx) {
if (!prog || func_idx < 0 || func_idx >= (int)vec_size(prog->funcs))
return;
spl_func_t *func = &vec_at(prog->funcs, func_idx);
func->ninsns = vec_size(prog->insns) - func->address;
}
int spl_prog_add_str(spl_prog_t *prog, const char *str) {
if (!prog || !str)
return -1;
vec_push(prog->strtab, strdup(str));
return (int)vec_size(prog->strtab) - 1;
}
spl_func_t *spl_prog_get_func(spl_prog_t *prog, const char *name) { spl_func_t *spl_prog_get_func(spl_prog_t *prog, const char *name) {
if (!prog || !name) if (!prog || !name)
return NULL; return NULL;
@@ -445,10 +402,14 @@ const char *opcode_name[] = {
const char *spl_opcode_name(spl_opcode_t opcode) { return opcode_name[opcode]; } const char *spl_opcode_name(spl_opcode_t opcode) { return opcode_name[opcode]; }
const char *spl_type_tag_name(spl_type_t type) { const char *spl_type_tag_name(spl_type_t type) {
switch (type) { switch (type) {
case SPL_VOID: return "void"; case SPL_VOID:
case SPL_BOOL: return "bool"; return "void";
case SPL_I8: return "i8"; case SPL_BOOL:
case SPL_U8: return "u8"; return "bool";
case SPL_I8:
return "i8";
case SPL_U8:
return "u8";
case SPL_I16: case SPL_I16:
return "i16"; return "i16";
case SPL_U16: case SPL_U16:

View File

@@ -208,13 +208,6 @@ int spl_prog_add_native(spl_prog_t *prog, spl_native_t *native);
spl_func_t *spl_prog_get_func(spl_prog_t *prog, const char *name); spl_func_t *spl_prog_get_func(spl_prog_t *prog, const char *name);
spl_native_t *spl_prog_get_native(spl_prog_t *prog, const char *name); spl_native_t *spl_prog_get_native(spl_prog_t *prog, const char *name);
/* High-level program construction helpers */
spl_val_t spl_prog_emit(spl_prog_t *prog, uint16_t opcode, uint16_t type, spl_val_t imm);
int spl_prog_add_func_simple(spl_prog_t *prog, const char *name, spl_val_t nargs);
int spl_prog_update_func(spl_prog_t *prog, int func_idx, const char *name, spl_val_t nargs);
void spl_prog_end_func(spl_prog_t *prog, int func_idx);
int spl_prog_add_str(spl_prog_t *prog, const char *str);
/* Opcode name lookup for debugging/dumping */ /* Opcode name lookup for debugging/dumping */
const char *spl_opcode_name(spl_opcode_t opcode); const char *spl_opcode_name(spl_opcode_t opcode);
const char *spl_type_tag_name(spl_type_t type); const char *spl_type_tag_name(spl_type_t type);

View File

@@ -5,7 +5,7 @@
*/ */
#include "include/acutest.h" #include "include/acutest.h"
#include "spl_ir.h" #include "spl_mcode.h"
#include "spl_vm.h" #include "spl_vm.h"
#include <stdio.h> #include <stdio.h>
@@ -13,7 +13,7 @@
#include <string.h> #include <string.h>
/* ================================================================ /* ================================================================
* Binary-writing helpers (mirrors spl_ir.c internal format) * Binary-writing helpers (mirrors spl_mcode.c internal format)
* ================================================================ */ * ================================================================ */
/* Write spl_val_t (8 LE bytes), advance pointer */ /* Write spl_val_t (8 LE bytes), advance pointer */

1
stage1/spl_ast.c Normal file
View File

@@ -0,0 +1 @@
#include "spl_ast.h"

305
stage1/spl_ast.h Normal file
View File

@@ -0,0 +1,305 @@
#ifndef __SPL_AST_H__
#define __SPL_AST_H__
#include "../stage0/include/utils.h"
#include "spl_lexer.h"
#include "spl_tok.h"
#include <math.h>
typedef enum {
SPL_AST_CONTAINER_MEMBER,
SPL_AST_FN_DECL,
SPL_AST_TYPE_DECL,
SPL_AST_VAR_DECL,
SPL_AST_CONST_DECL,
SPL_AST_MEMBER_DECL,
SPL_AST__COMPTIME_STMT, /*不实现*/
SPL_AST__DIRECTIVE_BLOCK, /*不实现*/
SPL_AST_BLOCK,
SPL_AST_BLOCK_ITEM,
SPL_AST_EXPR,
SPL_AST_TYPE_EXPR,
SPL_AST_ATTR_LIST,
} spl_ast_node_kind_t;
typedef struct {
const char *fname;
int line;
int col;
} spl_ast_loc_t;
struct spl_ast_node;
typedef struct spl_ast_node spl_ast_node_t;
typedef usize spl_ast_node_ref_t;
typedef VEC(spl_ast_node_ref_t) spl_ast_node_ref_vec_t;
struct spl_ast_node {
spl_ast_node_kind_t kind;
spl_ast_loc_t loc;
union {
spl_ast_node_ref_vec_t container_member;
spl_ast_node_ref_vec_t attr_list;
struct {
spl_ast_node_ref_t attr_list;
const char *name;
spl_ast_node_ref_t param_list;
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_t block;
} fn_decl;
spl_ast_node_ref_vec_t param_list;
struct {
spl_ast_node_ref_t attr_list;
const char *name;
spl_ast_node_ref_t type_expr;
} param_decl;
struct {
spl_ast_node_ref_t attr_list;
const char *name;
enum {
SPL_AST_TYPE_STRUCT,
SPL_AST_TYPE_UNION,
SPL_AST_TYPE_ENUM,
SPL_AST_TYPE_TYPE_EXPR,
};
union {
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_t aggregate_list;
};
} type_decl;
struct {
spl_ast_node_ref_t attr_list;
const char *name;
spl_ast_node_ref_t type_expr;
} member_decl;
struct {
spl_ast_node_ref_t attr_list;
const char *name;
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_t expr;
} var_decl;
struct {
spl_ast_node_ref_t attr_list;
spl_ast_node_ref_t type_expr;
const char *name;
spl_ast_node_ref_t expr;
} const_decl;
spl_ast_node_ref_vec_t block;
struct {
enum {
SPL_AST_IF_STATEMENT,
SPL_AST_IFVAR_STATEMENT,
SPL_AST_WHILE_STATEMENT,
SPL_AST_LOOP_STATEMENT,
SPL_AST_FOR_STATEMENT,
SPL_AST_MATCH_STATEMENT,
SPL_AST_RET_STATEMENT,
SPL_AST_BREAK_STATEMENT,
SPL_AST_CONTINUE_STATEMENT,
SPL_AST_DEFER_STATEMENT,
SPL_AST_VARDECL,
SPL_AST_TYPEDECL,
SPL_AST_EXPR_STATEMENT,
SPL_PACED_EXPR,
} kind;
union {
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_t if_block;
spl_ast_node_ref_t else_block;
} if_statement;
struct {
spl_ast_node_ref_t packed_expr;
spl_ast_node_ref_t if_block;
spl_ast_node_ref_t else_block;
} ifvar_statement;
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_t while_block;
} while_statement;
struct {
spl_ast_node_ref_t loop_block;
} loop_statement;
struct {
spl_ast_node_ref_vec_t expr_vec;
VEC(char *) ident_vec;
spl_ast_node_ref_t block;
} for_statement;
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_vec_t paced_exprs;
spl_ast_node_ref_vec_t statements;
} match_statement;
struct {
spl_ast_node_ref_t expr;
} ret_statement;
struct {
} break_statement;
struct {
} continue_statement;
struct {
spl_ast_node_ref_t block_or_statement;
} defer_statement;
spl_ast_node_ref_t var_decl;
spl_ast_node_ref_t type_decl;
spl_ast_node_ref_t expr_statement;
struct {
const char *ident;
const char *bind_ident;
spl_ast_node_ref_t expr;
} packed_expr;
};
} block_item;
struct {
enum {
SPL_AST_ASSIGN_EXPR,
SPL_AST_BOOLOR_EXPR,
SPL_AST_BOOLAND_EXPR,
SPL_AST_BITOR_EXPR,
SPL_AST_BITXOR_EXPR,
SPL_AST_BITAND_EXPR,
SPL_AST_CMPEQ_EXPR,
SPL_AST_CMP_EXPR,
SPL_AST_RANGE_EXPR,
SPL_AST_SHIFT_EXPR,
SPL_AST_ADD_EXPR,
SPL_AST_MUL_EXPR,
SPL_AST_PREFIX_EXPR,
SPL_AST_POSTFIX_EXPR, /*left ref node*/
SPL_AST_PRIMARY_EXPR, /*left ref node*/
} op;
struct {
spl_ast_node_ref_t left;
spl_ast_node_ref_t right;
} op_expr;
} expr;
struct {
enum {
SPL_AST_CALL_EXPR,
SPL_AST_IDENT_EXPR,
SPL_AST_DEREF_EXPR,
SPL_AST_INDEX_EXPR,
SPL_AST_SLICE_EXPR,
SPL_AST_AS_EXPR,
} kind;
union {
spl_ast_node_ref_vec_t call_expr;
const char *indet_expr;
spl_ast_node_ref_t index_expr;
struct {
spl_ast_node_ref_t begin;
spl_ast_node_ref_t end;
} slice_expr;
spl_ast_node_ref_t type_expr;
};
} postfix_expr;
struct {
enum {
SPL_AST_INTEGER,
SPL_AST_FLOAT,
SPL_AST_CHAR_LIT,
SPL_AST_STRING_LIT,
SPL_AST_TRUE,
SPL_AST_FALSE,
SPL_AST_NULL,
SPL_AST_IDENT,
SPL_AST_ARGGREGATE_INIT,
SPL_AST_EXPR_EXPR,
SPL_AST_ARRAY_LIT,
SPL_AST_BUILTIN_EXPR,
SPL_AST_BLOCK_EXPR,
};
union {
isize integer_expr;
double float_expr;
char char_lit_expr;
const char *string_lit_expr;
const char *ident;
/*aggregate_init_item*/
spl_ast_node_ref_vec_t aggregate_init_expr;
spl_ast_node_ref_t expr;
struct {
isize integer;
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_vec_t expr_list;
} array_lit_expr;
struct {
const char *ident;
spl_ast_node_ref_vec_t expr_list;
} builtin_expr;
spl_ast_node_ref_t block_expr;
};
} primary_expr;
struct {
const char *ident;
spl_ast_node_ref_t expr;
} aggregate_init_item;
struct {
/* ASTERISK = 1, [] = 2, else = 0*/
int pointer;
/* if array_size != 0 then pointer == 2 */
int array_size;
enum {
SPL_AST_BASE_TYPE_FN,
SPL_AST_BASE_TYPE_PATH,
} kind;
const char *spl_base_type;
union {
spl_ast_node_ref_vec_t type_path;
struct {
spl_ast_node_ref_t param_list;
spl_ast_node_ref_t type_expr;
} fn_type;
};
} type_expr;
struct {
enum {
SPL_AST_TYPE_VOID,
SPL_AST_TYPE_BOOL,
SPL_AST_TYPE_I8,
SPL_AST_TYPE_U8,
SPL_AST_TYPE_I16,
SPL_AST_TYPE_U16,
SPL_AST_TYPE_I32,
SPL_AST_TYPE_U32,
SPL_AST_TYPE_I64,
SPL_AST_TYPE_U64,
SPL_AST_TYPE_ISIZE,
SPL_AST_TYPE_USIZE,
SPL_AST_TYPE__F32, /*不实现*/
SPL_AST_TYPE__F64, /*不实现*/
SPL_AST_TYPE_PTR,
SPL_AST_TYPE_ANY,
SPL_AST_TYPE_IDENT,
} kind;
const char *ident;
} type_atom;
};
};
typedef VEC(spl_ast_node_t) spl_ast_node_vec_t;
typedef struct {
int parsed;
spl_tok_vec_t input;
spl_ast_node_vec_t buckets;
spl_ast_node_ref_t root;
} spl_ast_t;
void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec /*move*/);
void spl_ast_drop(spl_ast_t *ast);
void spl_ast_prase(spl_ast_t *ast);
void spl_ast_valid(spl_ast_t *ast);
void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node);
#endif /* __SPL_AST_H__ */

View File

@@ -1,264 +0,0 @@
/* spl_comp.c — SPL compiler main logic and codegen helpers */
#include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
/* ---- Compiler context init/drop ---- */
void spl_comp_init(spl_comp_t *ctx) {
memset(ctx, 0, sizeof(*ctx));
vec_init(ctx->toks);
vec_init(ctx->scopes);
vec_init(ctx->funcs);
map_init(ctx->const_values, MAP_HASH_STR, MAP_CMP_STR);
spl_prog_init(&ctx->prog);
ctx->error_msg[0] = '\0';
ctx->parse_context[0] = '\0';
spl_emit_init(&ctx->emit, &ctx->prog);
spl_type_ctx_init(&ctx->tctx);
ctx->current_ret_type_idx = -1;
}
void spl_comp_drop(spl_comp_t *ctx) {
if (!ctx)
return;
spl_tok_vec_drop(&ctx->toks);
vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); }
vec_free(ctx->scopes);
vec_for(ctx->funcs, i) {
free(ctx->funcs.data[i].name);
free(ctx->funcs.data[i].param_type_indices);
free(ctx->funcs.data[i].param_names);
}
vec_free(ctx->funcs);
map_free(ctx->const_values);
spl_prog_drop(&ctx->prog);
free(ctx->break_patches);
spl_emit_drop(&ctx->emit);
spl_type_ctx_drop(&ctx->tctx);
}
void spl_comp_reset(spl_comp_t *ctx) {
spl_tok_vec_drop(&ctx->toks);
vec_init(ctx->toks);
vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); }
vec_free(ctx->scopes);
vec_init(ctx->scopes);
ctx->scope_depth = 0;
ctx->tok_idx = 0;
ctx->has_error = 0;
ctx->error_msg[0] = '\0';
ctx->current_func_idx = -1;
ctx->current_ret_type_idx = -1;
fa_init(&ctx->emit.frame);
ctx->in_loop = 0;
ctx->break_patch_count = 0;
ctx->break_patch_cap = 0;
ctx->continue_target = 0;
ctx->defer_count = 0;
ctx->next_gdata_idx = 0;
ctx->addr_of_mode = 0;
free(ctx->break_patches);
ctx->break_patches = NULL;
vec_free(ctx->emit.fixups);
vec_init(ctx->emit.fixups);
}
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
if (ctx->has_error)
return;
char body[COMP_ERROR_MAX - 64];
va_list args;
va_start(args, fmt);
vsnprintf(body, sizeof(body), fmt, args);
va_end(args);
if (ctx->error_line > 0)
snprintf(ctx->error_msg, COMP_ERROR_MAX - 1, "line %zu:%zu: %s", ctx->error_line,
ctx->error_col, body);
else
snprintf(ctx->error_msg, COMP_ERROR_MAX - 1, "%s", body);
ctx->has_error = 1;
}
void spl_comp_err_tok(spl_comp_t *ctx, spl_tok_t *tok, const char *fmt, ...) {
if (ctx->has_error)
return;
char body[COMP_ERROR_MAX - 64];
va_list args;
va_start(args, fmt);
vsnprintf(body, sizeof(body), fmt, args);
va_end(args);
if (tok) {
snprintf(ctx->error_msg, COMP_ERROR_MAX - 1, "line %zu:%zu: %s", tok->line, tok->col, body);
} else {
snprintf(ctx->error_msg, COMP_ERROR_MAX - 1, "%s", body);
}
ctx->has_error = 1;
}
/* ---- Scope management ---- */
void spl_push_scope(spl_comp_t *ctx) {
spl_scope_t scope;
vec_init(scope.vars);
scope.depth = ++ctx->scope_depth;
vec_push(ctx->scopes, scope);
}
void spl_pop_scope(spl_comp_t *ctx) {
if (vec_size(ctx->scopes) > 0) {
spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1);
vec_for(scope->vars, i) { free(vec_at(scope->vars, i).name); }
vec_free(scope->vars);
ctx->scope_depth--;
ctx->scopes.size--;
} else {
ctx->scope_depth--;
}
}
/* ---- Variable management ---- */
int spl_declare_var(spl_comp_t *ctx, const char *name, int type_idx, int is_const) {
spl_var_info_t var;
memset(&var, 0, sizeof(var));
var.name = strdup(name);
var.type_idx = type_idx;
var.is_const = is_const;
var.depth = ctx->scope_depth;
var.offset = fa_alloc(&ctx->emit.frame, spl_type_size(&ctx->tctx, type_idx));
if (vec_size(ctx->scopes) > 0) {
spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1);
vec_push(scope->vars, var);
}
return var.offset;
}
spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name) {
for (int i = (int)vec_size(ctx->scopes) - 1; i >= 0; i--) {
spl_scope_t *scope = &vec_at(ctx->scopes, i);
for (int j = (int)vec_size(scope->vars) - 1; j >= 0; j--) {
if (strcmp(vec_at(scope->vars, j).name, name) == 0)
return &vec_at(scope->vars, j);
}
}
return NULL;
}
int spl_get_var_offset(spl_comp_t *ctx, const char *name) {
spl_var_info_t *v = spl_lookup_var(ctx, name);
return v ? v->offset : -1;
}
/* ---- Function management ---- */
int spl_declare_func(spl_comp_t *ctx, const char *name, int ret_type_idx, int nparams,
int is_extern, int is_pub) {
vec_for(ctx->funcs, i) {
spl_func_info_t *existing = &vec_at(ctx->funcs, i);
if (strcmp(existing->name, name) == 0) {
existing->ret_type_idx = ret_type_idx;
existing->nparams = nparams;
existing->is_extern = is_extern;
existing->is_pub = is_pub;
existing->func_idx =
spl_prog_update_func(&ctx->prog, existing->func_idx, name, nparams);
return (int)i;
}
}
spl_func_info_t fi;
memset(&fi, 0, sizeof(fi));
fi.name = strdup(name);
fi.ret_type_idx = ret_type_idx;
fi.nparams = nparams;
fi.is_extern = is_extern;
fi.is_pub = is_pub;
if (is_extern)
fi.func_idx = -1;
else
fi.func_idx = spl_prog_add_func_simple(&ctx->prog, name, nparams);
vec_push(ctx->funcs, fi);
return (int)vec_size(ctx->funcs) - 1;
}
int spl_lookup_func(spl_comp_t *ctx, const char *name) {
{
int current = ctx->tctx.current_type_idx;
while (current >= 0) {
spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, current);
if (items) {
vec_for(*items, j) {
spl_type_item_t *it = &vec_at(*items, j);
if (it->item_kind == ITEM_METHOD && it->name && strcmp(it->name, name) == 0)
return it->method.func_idx;
}
}
current = vec_at(ctx->tctx.types, current).parent_type_idx;
}
}
vec_for(ctx->funcs, j) {
if (strcmp(vec_at(ctx->funcs, j).name, name) == 0)
return (int)j;
}
return -1;
}
int spl_ensure_native(spl_comp_t *ctx, const char *name) {
vec_for(ctx->prog.natives, ni) {
if (strcmp(vec_at(ctx->prog.natives, ni).name, name) == 0)
return (int)ni;
}
spl_native_t nat;
nat.name = strdup(name);
nat.idx_of_strtab = 0;
nat.impl_fn = NULL;
vec_push(ctx->prog.natives, nat);
return (int)vec_size(ctx->prog.natives) - 1;
}
/* ---- String/data management ---- */
int spl_add_string(spl_comp_t *ctx, const char *str) {
return spl_add_global_data(ctx, (void *)str, strlen(str) + 1);
}
int spl_add_global_data(spl_comp_t *ctx, void *data, usize size) {
return spl_prog_add_data(&ctx->prog, data, size);
}
/* ---- Register runtime natives ---- */
void spl_comp_register(spl_prog_t *prog) { (void)prog; }
/* ---- Main compilation ---- */
int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) {
ctx->toks = spl_lex(source, fname);
ctx->tok_idx = 0;
ctx->fname = fname;
ctx->source = source;
while (ctx->tok_idx < vec_size(ctx->toks) &&
vec_at(ctx->toks, ctx->tok_idx).type == TOK_ENDLINE)
ctx->tok_idx++;
spl_parse_prog(ctx);
if (ctx->has_error)
return -1;
emit_patch_call_fixups(&ctx->emit, &ctx->prog);
return 0;
}

View File

@@ -1,206 +0,0 @@
/* spl_comp.h — SPL compiler: type system, parser, codegen */
#ifndef __SPL_COMP_H__
#define __SPL_COMP_H__
#include "../stage0/spl_ir.h"
#include "spl_lexer.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "spl_emit.h"
#include "spl_type.h"
/* Forward declarations */
typedef struct spl_comp spl_comp_t;
/* ============================================================
* Scope / symbol table
* ============================================================ */
typedef struct spl_var_info {
char *name;
int type_idx;
int offset;
int is_const;
int depth;
} spl_var_info_t;
typedef VEC(spl_var_info_t) spl_var_vec_t;
typedef struct spl_scope {
spl_var_vec_t vars;
int depth;
} spl_scope_t;
typedef VEC(spl_scope_t) spl_scope_vec_t;
typedef struct spl_func_info {
char *name;
int ret_type_idx;
int *param_type_indices;
char **param_names;
int nparams;
int func_idx;
int is_extern;
int is_pub;
} spl_func_info_t;
typedef VEC(spl_func_info_t) spl_func_info_vec_t;
/* ============================================================
* Compiler context
* ============================================================ */
#define COMP_ERROR_MAX 256
#define DEFER_MAX 64
typedef struct {
usize body_start;
usize jmp_exit;
int depth;
int count_at_decl;
} spl_defer_entry_t;
typedef struct spl_comp {
/* Lexer output */
spl_tok_vec_t toks;
usize tok_idx;
const char *fname;
const char *source;
/* Program output */
spl_prog_t prog;
/* IR emission + frame allocator */
spl_emit_t emit;
/* Error state */
char error_msg[COMP_ERROR_MAX];
int has_error;
usize error_line;
usize error_col;
/* Scopes */
spl_scope_vec_t scopes;
int scope_depth;
/* Function table */
spl_func_info_vec_t funcs;
/* Type context — first-class type arena + namespace */
spl_type_ctx_t tctx;
/* Current function context */
int current_func_idx;
int current_ret_type_idx;
char parse_context[COMP_ERROR_MAX]; /* current parsing context for error messages */
/* Loop context for break/continue */
int in_loop;
usize *break_patches;
usize break_patch_count;
usize break_patch_cap;
usize continue_target;
/* Defer stack */
spl_defer_entry_t defer_stack[DEFER_MAX];
int defer_count;
/* Global data index for string literals */
int next_gdata_idx;
/* Const values */
MAP(const char *, spl_val_t) const_values;
int addr_of_mode;
} spl_comp_t;
/* Initialize/destroy compiler context */
void spl_comp_init(spl_comp_t *ctx);
void spl_comp_drop(spl_comp_t *ctx);
/* Main compilation entry: source → .sir */
int spl_compile(spl_comp_t *ctx, const char *source, const char *fname);
/* Reset for a new compilation */
void spl_comp_reset(spl_comp_t *ctx);
/* Error reporting */
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...);
void spl_comp_err_tok(spl_comp_t *ctx, spl_tok_t *tok, const char *fmt, ...);
/* ============================================================
* Parser functions (spl_parser.c)
* ============================================================ */
void spl_parse_prog(spl_comp_t *ctx);
void parse_type_decl(spl_comp_t *ctx);
/* ============================================================
* Expression functions (spl_expr.c)
* ============================================================ */
enum {
PREC_MIN = 0,
PREC_ASSIGN = 1,
PREC_LOGOR = 2,
PREC_LOGAND = 3,
PREC_OR = 4,
PREC_XOR = 5,
PREC_AND = 6,
PREC_CMPEQ = 7,
PREC_CMP = 8,
PREC_SHIFT = 9,
PREC_ADD = 10,
PREC_MUL = 11,
PREC_PREFIX = 12,
PREC_POSTFIX = 13
};
typedef struct {
int type_idx;
int is_lvalue;
} spl_expr_result_t;
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec);
spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, int type_idx);
/* Match arm pattern comparison */
int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int val_offset, int by_value);
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset);
/* ============================================================
* Statement functions (spl_stmt.c)
* ============================================================ */
void spl_parse_stmt(spl_comp_t *ctx);
void spl_parse_block(spl_comp_t *ctx);
spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx);
/* ============================================================
* Remaining helpers in spl_comp.c
* ============================================================ */
/* Variable management */
int spl_declare_var(spl_comp_t *ctx, const char *name, int type_idx, int is_const);
spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name);
int spl_get_var_offset(spl_comp_t *ctx, const char *name);
/* Function management */
int spl_declare_func(spl_comp_t *ctx, const char *name, int ret_type_idx, int nparams,
int is_extern, int is_pub);
int spl_lookup_func(spl_comp_t *ctx, const char *name);
int spl_ensure_native(spl_comp_t *ctx, const char *name);
/* String/data management */
int spl_add_string(spl_comp_t *ctx, const char *str);
int spl_add_global_data(spl_comp_t *ctx, void *data, usize size);
/* Scope management */
void spl_push_scope(spl_comp_t *ctx);
void spl_pop_scope(spl_comp_t *ctx);
/* Register runtime natives (stub) */
void spl_comp_register(spl_prog_t *prog);
#endif /* __SPL_COMP_H__ */

View File

@@ -1,282 +0,0 @@
/* spl_emit.c — IR emission: frame allocator + Layer 1/2 ops */
#include "spl_emit.h"
#include "spl_comp.h"
#include "spl_type.h"
#include <string.h>
/* ============================================================
* Lifecycle
* ============================================================ */
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog) {
memset(e, 0, sizeof(*e));
e->prog = prog;
vec_init(e->fixups);
}
void spl_emit_drop(spl_emit_t *e) {
if (!e)
return;
vec_free(e->fixups);
}
/* ============================================================
* Frame allocator — non-inline
* ============================================================ */
int fa_alloc_type(spl_frame_alloc_t *fa, spl_type_ctx_t *tctx, int type_idx) {
return fa_alloc(fa, spl_type_size(tctx, type_idx));
}
spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t imm) {
return spl_prog_emit(e->prog, opcode, type, imm);
}
/* ============================================================
* Layer 1 — single-instruction semantic wrappers
* ============================================================ */
void emit_drop(spl_emit_t *e) { emit_raw(e, SPL_DROP, SPL_VOID, 0); }
void emit_dup(spl_emit_t *e) { emit_raw(e, SPL_DUP, SPL_VOID, 0); }
void emit_swap(spl_emit_t *e) { emit_raw(e, SPL_SWAP, SPL_VOID, 0); }
void emit_rot(spl_emit_t *e) { emit_raw(e, SPL_ROT, SPL_VOID, 0); }
void emit_pick(spl_emit_t *e, int n) { emit_raw(e, SPL_PICK, SPL_VOID, n); }
void emit_push_i32(spl_emit_t *e, int v) { emit_raw(e, SPL_PUSH, SPL_I32, (spl_val_t)v); }
void emit_push_usize(spl_emit_t *e, usize v) { emit_raw(e, SPL_PUSH, SPL_USIZE, (spl_val_t)v); }
void emit_push_u64(spl_emit_t *e, uint64_t v) { emit_raw(e, SPL_PUSH, SPL_U64, (spl_val_t)v); }
void emit_push_f64(spl_emit_t *e, uint64_t v) { emit_raw(e, SPL_PUSH, SPL_F64, (spl_val_t)v); }
void emit_push_ptr(spl_emit_t *e, spl_val_t v) { emit_raw(e, SPL_PUSH, SPL_PTR, v); }
void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v) { emit_raw(e, SPL_PUSH, bt, v); }
void emit_load_ptr(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_PTR, 0); }
void emit_load_usize(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_USIZE, 0); }
void emit_load_type(spl_emit_t *e, uint16_t bt) { emit_raw(e, SPL_LOAD, bt, 0); }
void emit_store_i32(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_I32, 0); }
void emit_store_ptr(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_PTR, 0); }
void emit_store_usize(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_USIZE, 0); }
void emit_store_type(spl_emit_t *e, uint16_t bt) { emit_raw(e, SPL_STORE, bt, 0); }
void emit_add_usize(spl_emit_t *e) { emit_raw(e, SPL_ADD, SPL_USIZE, 0); }
void emit_add_u64(spl_emit_t *e) { emit_raw(e, SPL_ADD, SPL_U64, 0); }
void emit_mul_u64(spl_emit_t *e) { emit_raw(e, SPL_MUL, SPL_U64, 0); }
void emit_sub_usize(spl_emit_t *e) { emit_raw(e, SPL_SUB, SPL_USIZE, 0); }
void emit_ult_usize(spl_emit_t *e) { emit_raw(e, SPL_ULT, SPL_USIZE, 0); }
void emit_jmp(spl_emit_t *e, spl_val_t offset) { emit_raw(e, SPL_JMP, SPL_VOID, offset); }
spl_val_t emit_jmp_here(spl_emit_t *e) { return emit_raw(e, SPL_JMP, SPL_VOID, 0); }
spl_val_t emit_bz_here(spl_emit_t *e) { return emit_raw(e, SPL_BZ, SPL_VOID, 0); }
spl_val_t emit_bnz_here(spl_emit_t *e) { return emit_raw(e, SPL_BNZ, SPL_VOID, 0); }
void emit_patch(spl_emit_t *e, spl_val_t addr, spl_val_t target) {
if (addr < vec_size(e->prog->insns))
vec_at(e->prog->insns, addr).imm = target;
}
void emit_patch_here(spl_emit_t *e, spl_val_t addr) {
spl_val_t here = vec_size(e->prog->insns);
emit_patch(e, addr, here - addr - 1);
}
void emit_laddr(spl_emit_t *e, int offset) { emit_raw(e, SPL_LADDR, SPL_PTR, offset); }
void emit_gaddr(spl_emit_t *e, int idx) { emit_raw(e, SPL_GADDR, SPL_PTR, idx); }
void emit_call(spl_emit_t *e, int nargs) { emit_raw(e, SPL_CALL, SPL_VOID, nargs); }
void emit_ncall(spl_emit_t *e, int nargs) { emit_raw(e, SPL_NCALL, SPL_VOID, nargs); }
void emit_alloc(spl_emit_t *e, int slots) { emit_raw(e, SPL_ALLOC, SPL_VOID, slots); }
void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt) { emit_raw(e, op, bt, 0); }
void emit_dbg_void(spl_emit_t *e) { emit_raw(e, SPL_DBG, SPL_VOID, 0); }
void emit_dbg_usize(spl_emit_t *e) { emit_raw(e, SPL_DBG, SPL_USIZE, 0); }
/* ============================================================
* Layer 2 — semantic-level helpers
* ============================================================ */
void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots) {
for (usize i = 0; i < nslots; i++) {
if (i < nslots - 1)
emit_dup(e);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_load_ptr(e);
emit_laddr(e, dest_offset + (int)(i * sizeof(spl_val_t)));
emit_swap(e);
emit_store_ptr(e);
}
}
void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth) {
for (usize i = 0; i < nslots; i++) {
emit_dup(e);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_load_ptr(e);
emit_pick(e, 2 + depth);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_swap(e);
emit_store_ptr(e);
}
emit_drop(e);
emit_drop(e);
}
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, usize byte_offset,
int data_type_idx, int var_offset) {
emit_laddr(e, ptr_slot_offset);
emit_load_ptr(e);
emit_ptr_add(e, byte_offset);
if (data_type_idx >= 0 && !spl_type_is_scalar(tctx, data_type_idx) &&
spl_type_size(tctx, data_type_idx) > sizeof(spl_val_t)) {
emit_frame_copy(e, var_offset, spl_type_slot_count(tctx, data_type_idx));
} else {
uint16_t bt = spl_type_emit_type(tctx, data_type_idx);
emit_load_type(e, bt);
emit_laddr(e, var_offset);
emit_swap(e);
emit_store_type(e, bt);
}
}
void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type) {
emit_laddr(e, offset);
emit_swap(e);
emit_store_type(e, type);
}
void emit_ptr_add(spl_emit_t *e, usize byte_off) {
if (byte_off > 0) {
emit_push_usize(e, byte_off);
emit_add_usize(e);
}
}
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx) {
spl_val_t fixup_addr = emit_raw(e, SPL_PUSH, SPL_PTR, 0);
emit_call(e, nargs);
spl_fixup_entry_t fe = {fixup_addr, func_idx};
vec_push(e->fixups, fe);
return fixup_addr;
}
void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx) {
if (spl_type_needs_multi_slot(tctx, ret_type_idx)) {
emit_laddr(e, (int)sizeof(spl_val_t));
emit_raw(e, SPL_RET, SPL_PTR, 0);
} else {
uint16_t rt = spl_type_emit_type(tctx, ret_type_idx);
emit_raw(e, SPL_RET, rt, 0);
}
}
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog) {
for (usize i = 0; i < vec_size(e->fixups); i++) {
spl_fixup_entry_t *fe = &vec_at(e->fixups, i);
if (fe->func_idx >= 0 && fe->func_idx < (int)vec_size(prog->funcs)) {
spl_val_t addr = vec_at(prog->funcs, fe->func_idx).address;
vec_at(prog->insns, fe->insn_idx).imm = addr;
} else {
fprintf(stderr, "WARN: fixup func_idx=%d out of bounds [0,%zu), insn_idx=%zu\n",
fe->func_idx, vec_size(prog->funcs), fe->insn_idx);
}
}
}
void spl_emit_ret(spl_comp_t *ctx, int ret_type_idx) {
if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) {
emit_laddr(&ctx->emit, (int)sizeof(spl_val_t));
emit_swap(&ctx->emit);
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, ret_type_idx), 0);
}
emit_return(&ctx->emit, &ctx->tctx, ret_type_idx);
}
void spl_emit_store_init(spl_comp_t *ctx, int var_offset, int var_type_idx) {
if (var_type_idx >= 0 && (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT ||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM)) {
usize sz = spl_type_size(&ctx->tctx, var_type_idx);
if (sz <= sizeof(spl_val_t)) {
emit_store_to_laddr(&ctx->emit, var_offset,
spl_type_emit_type(&ctx->tctx, var_type_idx));
} else {
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
emit_frame_copy(&ctx->emit, var_offset, nslots);
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ARRAY) {
int elem_idx = spl_type_elem_type(&ctx->tctx, var_type_idx);
spl_type_t bt = spl_type_emit_type(&ctx->tctx, elem_idx);
usize stride = spl_type_elem_stride(&ctx->tctx, elem_idx);
int arr_len = (int)spl_type_array_len(&ctx->tctx, var_type_idx);
for (int i = arr_len - 1; i >= 0; i--) {
emit_laddr(&ctx->emit, var_offset + (int)(i * stride));
emit_swap(&ctx->emit);
if (elem_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_idx)) {
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, elem_idx), 0);
} else {
emit_store_type(&ctx->emit, bt);
}
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE) {
emit_store_to_laddr(&ctx->emit, var_offset + (int)sizeof(spl_val_t), SPL_USIZE);
emit_store_to_laddr(&ctx->emit, var_offset, SPL_PTR);
} else {
spl_type_t bt = spl_type_emit_type(&ctx->tctx, var_type_idx);
emit_store_to_laddr(&ctx->emit, var_offset, bt);
}
}
void spl_emit_defer(spl_comp_t *ctx) {
if (ctx->defer_count >= DEFER_MAX)
return;
spl_val_t jmp_skip = emit_jmp_here(&ctx->emit);
spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count];
e->body_start = jmp_skip + 1;
e->jmp_exit = 0;
e->depth = ctx->scope_depth;
e->count_at_decl = ctx->defer_count;
ctx->defer_count++;
}
void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth) {
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t skip_addr = e->body_start - 1;
spl_val_t skip_target = e->jmp_exit + 1;
emit_patch(&ctx->emit, skip_addr, skip_target - skip_addr - 1);
}
for (int i = ctx->defer_count - 1; i >= 0; i--) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t here = vec_size(ctx->prog.insns);
spl_val_t jmp_offset = (spl_val_t)((isize)e->body_start - (isize)here - 1);
emit_jmp(&ctx->emit, jmp_offset);
if (e->jmp_exit > 0)
emit_patch(&ctx->emit, e->jmp_exit, here + 1 - e->jmp_exit - 1);
}
int new_count = 0;
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
ctx->defer_stack[new_count++] = ctx->defer_stack[i];
}
ctx->defer_count = new_count;
}

View File

@@ -1,155 +0,0 @@
#ifndef __SPL_EMIT_H__
#define __SPL_EMIT_H__
#include "../stage0/spl_ir.h"
#include "spl_type.h"
#include <stdint.h>
/* ============================================================
* Frame allocator
* ============================================================ */
typedef struct {
int current_bytes;
int peak_bytes;
} spl_frame_alloc_t;
static inline void fa_init(spl_frame_alloc_t *fa) {
fa->current_bytes = 0;
fa->peak_bytes = 0;
}
static inline int fa_alloc(spl_frame_alloc_t *fa, usize byte_size) {
usize aligned = (byte_size + sizeof(spl_val_t) - 1) & ~(sizeof(spl_val_t) - 1);
if (aligned < sizeof(spl_val_t))
aligned = sizeof(spl_val_t);
int offset = fa->current_bytes;
fa->current_bytes += (int)aligned;
if (fa->current_bytes > fa->peak_bytes)
fa->peak_bytes = fa->current_bytes;
return offset;
}
int fa_alloc_type(spl_frame_alloc_t *fa, spl_type_ctx_t *tctx, int type_idx);
static inline void fa_reset_to(spl_frame_alloc_t *fa, int mark) { fa->current_bytes = mark; }
static inline int fa_alloc_slots(spl_frame_alloc_t *fa, usize nslots) {
return fa_alloc(fa, nslots * sizeof(spl_val_t));
}
static inline int fa_alloc_temp(spl_frame_alloc_t *fa, usize nslots) {
return fa_alloc_slots(fa, nslots);
}
static inline void fa_free(spl_frame_alloc_t *fa, int mark) { fa->current_bytes = mark; }
/* ============================================================
* Emit context
* ============================================================ */
typedef struct {
spl_val_t insn_idx;
int func_idx;
} spl_fixup_entry_t;
typedef struct {
spl_prog_t *prog;
spl_frame_alloc_t frame;
VEC(spl_fixup_entry_t) fixups;
} spl_emit_t;
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog);
void spl_emit_drop(spl_emit_t *e);
/* ============================================================
* Layer 1 — single-instruction semantic wrappers
* ============================================================ */
/* Stack ops */
void emit_drop(spl_emit_t *e);
void emit_dup(spl_emit_t *e);
void emit_swap(spl_emit_t *e);
void emit_rot(spl_emit_t *e);
void emit_pick(spl_emit_t *e, int n);
/* Push */
void emit_push_i32(spl_emit_t *e, int v);
void emit_push_usize(spl_emit_t *e, usize v);
void emit_push_u64(spl_emit_t *e, uint64_t v);
void emit_push_f64(spl_emit_t *e, uint64_t v);
void emit_push_ptr(spl_emit_t *e, spl_val_t v);
void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v);
/* Load */
void emit_load_ptr(spl_emit_t *e);
void emit_load_usize(spl_emit_t *e);
void emit_load_type(spl_emit_t *e, uint16_t bt);
/* Store */
void emit_store_i32(spl_emit_t *e);
void emit_store_ptr(spl_emit_t *e);
void emit_store_usize(spl_emit_t *e);
void emit_store_type(spl_emit_t *e, uint16_t bt);
/* Arithmetic */
void emit_add_usize(spl_emit_t *e);
void emit_add_u64(spl_emit_t *e);
void emit_mul_u64(spl_emit_t *e);
void emit_sub_usize(spl_emit_t *e);
/* Compare */
void emit_ult_usize(spl_emit_t *e);
/* Branch */
void emit_jmp(spl_emit_t *e, spl_val_t offset);
spl_val_t emit_jmp_here(spl_emit_t *e);
spl_val_t emit_bz_here(spl_emit_t *e);
spl_val_t emit_bnz_here(spl_emit_t *e);
void emit_patch(spl_emit_t *e, spl_val_t addr, spl_val_t target);
void emit_patch_here(spl_emit_t *e, spl_val_t addr);
/* Address */
void emit_laddr(spl_emit_t *e, int offset);
void emit_gaddr(spl_emit_t *e, int idx);
/* Call */
void emit_call(spl_emit_t *e, int nargs);
void emit_ncall(spl_emit_t *e, int nargs);
/* Misc */
void emit_alloc(spl_emit_t *e, int slots);
void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt);
void emit_dbg_void(spl_emit_t *e);
void emit_dbg_usize(spl_emit_t *e);
/* Low-level emit (raw opcode + type + imm) */
spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t imm);
/* ============================================================
* Layer 2 — semantic-level helpers
* ============================================================ */
void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots);
void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth);
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, usize byte_offset,
int data_type_idx, int var_offset);
void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type);
void emit_ptr_add(spl_emit_t *e, usize byte_off);
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx);
void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx);
/* Patch all fixups */
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog);
/* ============================================================
* Layer 3 — compiler-level helpers (need spl_comp_t for tctx)
* ============================================================ */
struct spl_comp;
void spl_emit_ret(struct spl_comp *ctx, int ret_type_idx);
void spl_emit_store_init(struct spl_comp *ctx, int var_offset, int var_type_idx);
void spl_emit_defer(struct spl_comp *ctx);
void spl_emit_defer_epilogue(struct spl_comp *ctx, int depth);
#endif /* __SPL_EMIT_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,142 +0,0 @@
/* spl_lex_util.c — Lexer utility functions */
#include "spl_lex_util.h"
#include <stdio.h>
#include <string.h>
spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF)
ctx->tok_idx++;
return t;
}
int expect(spl_comp_t *ctx, spl_tok_type_t type) {
spl_tok_t *tok = peek(ctx);
if (tok->type == type) {
advance(ctx);
return 1;
}
/* Extract token text for display (up to 40 chars) */
char val_buf[64];
usize display_len = tok->len < 40 ? tok->len : 40;
memcpy(val_buf, tok->lexeme, display_len);
val_buf[display_len] = '\0';
/* Replace newlines with \n for display */
for (usize i = 0; i < display_len; i++) {
if (val_buf[i] == '\n')
val_buf[i] = ' ';
}
if (ctx->parse_context[0]) {
spl_comp_err_tok(ctx, tok, "%s: expected %s, got %s '%s'", ctx->parse_context,
spl_tok_type_name(type), spl_tok_type_name(tok->type), val_buf);
} else {
spl_comp_err_tok(ctx, tok, "expected %s, got %s '%s'", spl_tok_type_name(type),
spl_tok_type_name(tok->type), val_buf);
}
return 0;
}
int match(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
return 0;
}
void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
}
int spl_parse_int_literal(spl_comp_t *ctx, int *val) {
int negate = 0;
if (peek(ctx)->type == TOK_SUB) {
negate = 1;
advance(ctx);
}
if (peek(ctx)->type != TOK_INT_LITERAL) {
if (negate)
ctx->tok_idx--; /* un-consume the SUB token */
return 0;
}
spl_tok_t *tok = advance(ctx);
long long v = strtoll(tok->lexeme, NULL, 0);
*val = negate ? -(int)v : (int)v;
return 1;
}
const char *spl_tok_type_name(spl_tok_type_t type) {
switch (type) {
#define X(name, enum_name, dummy) \
case enum_name: \
return #name;
KEYWORD_TABLE
TOKEN_TABLE
#undef X
default:
return "???";
}
}
void spl_tok_dump(spl_tok_t *tok) {
if (!tok)
return;
/* Extract token text for display (up to 40 chars) */
char buf[64];
usize display_len = tok->len < 40 ? tok->len : 40;
memcpy(buf, tok->lexeme, display_len);
buf[display_len] = '\0';
/* Replace newlines with \n for display */
for (usize i = 0; i < display_len; i++) {
if (buf[i] == '\n')
buf[i] = ' ';
}
printf("%s:%zu:%zu %-20s '%s'", tok->fname ? tok->fname : "", tok->line, tok->col,
spl_tok_type_name(tok->type), buf);
if (tok->type == TOK_INT_LITERAL) {
printf(" [int]");
} else if (tok->type == TOK_STRING_LITERAL) {
printf(" [string]");
} else if (tok->type == TOK_CHAR_LITERAL) {
printf(" [char]");
} else if (tok->type == TOK_FLOAT_LITERAL) {
printf(" [float]");
}
printf("\n");
}
void spl_tok_vec_dump(spl_tok_vec_t *toks) {
if (!toks)
return;
printf("=== TOKEN DUMP (%zu tokens) ===\n", vec_size(*toks));
vec_for(*toks, i) {
spl_tok_t *tok = &vec_at(*toks, i);
printf("%4zu: ", i);
spl_tok_dump(tok);
}
}
void spl_tok_vec_drop(spl_tok_vec_t *toks) {
if (toks) {
vec_free(*toks);
}
}
usize spl_tok_copy_name(spl_tok_t *tok, char *buf, usize buf_size) {
if (!tok || !buf || buf_size == 0)
return 0;
usize nlen = tok->len < buf_size - 1 ? tok->len : buf_size - 1;
memcpy(buf, tok->lexeme, nlen);
buf[nlen] = '\0';
return nlen;
}

View File

@@ -1,29 +0,0 @@
/* spl_lex_util.h — Shared token helper utilities */
#ifndef __SPL_LEX_UTIL_H__
#define __SPL_LEX_UTIL_H__
#include "spl_comp.h"
/* Token stream access */
spl_tok_t *peek(spl_comp_t *ctx);
spl_tok_t *advance(spl_comp_t *ctx);
/* Token matching helpers */
int expect(spl_comp_t *ctx, spl_tok_type_t type);
int match(spl_comp_t *ctx, spl_tok_type_t type);
void skip_nl(spl_comp_t *ctx);
/* Token introspection */
const char *spl_tok_type_name(spl_tok_type_t type);
void spl_tok_dump(spl_tok_t *tok);
void spl_tok_vec_dump(spl_tok_vec_t *toks);
void spl_tok_vec_drop(spl_tok_vec_t *toks);
usize spl_tok_copy_name(spl_tok_t *tok, char *buf, usize buf_size);
const char *spl_tok_loc_str(spl_comp_t *ctx);
/* Parse an integer literal value, handling optional '-' prefix for negatives.
* Returns 1 on success (value in *val), 0 if current token isn't an integer.
* On success, advances past all consumed tokens. On failure, does not advance. */
int spl_parse_int_literal(spl_comp_t *ctx, int *val);
#endif /* __SPL_LEX_UTIL_H__ */

View File

@@ -2,130 +2,7 @@
#ifndef __SPL_LEXER_H__ #ifndef __SPL_LEXER_H__
#define __SPL_LEXER_H__ #define __SPL_LEXER_H__
#include "../stage0/spl_ir.h" #include "spl_tok.h"
/* clang-format off */
#define KEYWORD_TABLE \
X(as , KW_AS , SPL_V0) \
X(asm , KW_ASM , SPL_V0) \
X(bool , KW_BOOL , SPL_V0) \
X(break , KW_BREAK , SPL_V0) \
X(catch , KW_CATCH , SPL_V0) \
X(comptime , KW_COMPTIME , SPL_V0) \
X(const , KW_CONST , SPL_V0) \
X(continue , KW_CONTINUE , SPL_V0) \
X(defer , KW_DEFER , SPL_V0) \
X(else , KW_ELSE , SPL_V0) \
X(enum , KW_ENUM , SPL_V0) \
X(extern , KW_EXTERN , SPL_V0) \
X(false , KW_FALSE , SPL_V0) \
X(fn , KW_FN , SPL_V0) \
X(for , KW_FOR , SPL_V0) \
X(if , KW_IF , SPL_V0) \
X(loop , KW_LOOP , SPL_V0) \
X(match , KW_MATCH , SPL_V0) \
X(null , KW_NULL , SPL_V0) \
X(pub , KW_PUB , SPL_V0) \
X(ret , KW_RET , SPL_V0) \
X(struct , KW_STRUCT , SPL_V0) \
X(test , KW_TEST , SPL_V0) \
X(true , KW_TRUE , SPL_V0) \
X(try , KW_TRY , SPL_V0) \
X(type , KW_TYPE , SPL_V0) \
X(union , KW_UNION , SPL_V0) \
X(var , KW_VAR , SPL_V0) \
X(void , KW_VOID , SPL_V0) \
X(while , KW_WHILE , SPL_V0) \
X(_ , KW_ANY , SPL_V0) \
// KEYWORD_TABLE
#define TOKEN_TABLE \
X(unknown , TOK_UNKNOWN , SPL_V0 ) \
X(EOF , TOK_EOF , SPL_V0 ) \
X(blank , TOK_BLANK , SPL_V0 ) \
X(endline , TOK_ENDLINE , SPL_V0 ) \
X("#" , TOK_SHARP , SPL_V0 ) \
X("@" , TOK_AT , SPL_V0 ) \
X("==" , TOK_EQ , SPL_V0 ) \
X("=" , TOK_ASSIGN , SPL_V0 ) \
X("+=" , TOK_ASSIGN_ADD , SPL_V0 ) \
X("+" , TOK_ADD , SPL_V0 ) \
X("-=" , TOK_ASSIGN_SUB , SPL_V0 ) \
X("->" , TOK_RIGHT_ARRAY , SPL_V0 ) \
X("<-" , TOK_LEFT_ARRAY , SPL_V0 ) \
X("-" , TOK_SUB , SPL_V0 ) \
X("*=" , TOK_ASSIGN_MUL , SPL_V0 ) \
X("*" , TOK_MUL , SPL_V0 ) \
X("/=" , TOK_ASSIGN_DIV , SPL_V0 ) \
X("/" , TOK_DIV , SPL_V0 ) \
X("//" , TOK_LINE_COMMENT , SPL_V0 ) \
X("/* */" , TOK_BLOCK_COMMENT , SPL_V0 ) \
X("%=" , TOK_ASSIGN_MOD , SPL_V0 ) \
X("%" , TOK_MOD , SPL_V0 ) \
X("&&" , TOK_AND_AND , SPL_V0 ) \
X("&=" , TOK_ASSIGN_AND , SPL_V0 ) \
X("&" , TOK_AND , SPL_V0 ) \
X("||" , TOK_OR_OR , SPL_V0 ) \
X("|=" , TOK_ASSIGN_OR , SPL_V0 ) \
X("|" , TOK_OR , SPL_V0 ) \
X("^=" , TOK_ASSIGN_XOR , SPL_V0 ) \
X("^" , TOK_XOR , SPL_V0 ) \
X("<<=" , TOK_ASSIGN_L_SH , SPL_V0 ) \
X("<<" , TOK_L_SH , SPL_V0 ) \
X("<=" , TOK_LE , SPL_V0 ) \
X("<" , TOK_LT , SPL_V0 ) \
X(">>=" , TOK_ASSIGN_R_SH , SPL_V0 ) \
X(">>" , TOK_R_SH , SPL_V0 ) \
X(">=" , TOK_GE , SPL_V0 ) \
X(">" , TOK_GT , SPL_V0 ) \
X("!" , TOK_NOT , SPL_V0 ) \
X("!=" , TOK_NEQ , SPL_V0 ) \
X("~" , TOK_BIT_NOT , SPL_V0 ) \
X("[" , TOK_L_BRACKET , SPL_V0 ) \
X("]" , TOK_R_BRACKET , SPL_V0 ) \
X("(" , TOK_L_PAREN , SPL_V0 ) \
X(")" , TOK_R_PAREN , SPL_V0 ) \
X("{" , TOK_L_BRACE , SPL_V0 ) \
X("}" , TOK_R_BRACE , SPL_V0 ) \
X(";" , TOK_SEMICOLON , SPL_V0 ) \
X("," , TOK_COMMA , SPL_V0 ) \
X(":" , TOK_COLON , SPL_V0 ) \
X(":=" , TOK_COLON_ASSIGN , SPL_V0 ) \
X("." , TOK_DOT , SPL_V0 ) \
X(".." , TOK_RANGE , SPL_V0 ) \
X("..." , TOK_ELLIPSIS , SPL_V0 ) \
X("?" , TOK_COND , SPL_V0 ) \
X(ident , TOK_IDENT , SPL_V0 ) \
X(int , TOK_INT_LITERAL , SPL_V0 ) \
X(float , TOK_FLOAT_LITERAL , SPL_V0 ) \
X(char , TOK_CHAR_LITERAL , SPL_V0 ) \
X(string , TOK_STRING_LITERAL , SPL_V0 ) \
// TOKEN_TABLE
/* clang-format on */
/* spl_tok_type_t — KEYWORD_TABLE + TOKEN_TABLE 展开 */
/* clang-format off */
typedef enum {
#define X(name, enum_name, dummy) enum_name,
KEYWORD_TABLE
#undef X
#define X(name, enum_name, dummy) enum_name,
TOKEN_TABLE
#undef X
} spl_tok_type_t;
/* clang-format on */
typedef struct {
spl_tok_type_t type;
const char *lexeme;
usize len; /* token length in bytes */
const char *fname;
usize offset;
usize line;
usize col;
} spl_tok_t;
typedef VEC(spl_tok_t) spl_tok_vec_t;
/* Lexer entry point */ /* Lexer entry point */
spl_tok_vec_t spl_lex(const char *source, const char *fname); spl_tok_vec_t spl_lex(const char *source, const char *fname);

View File

@@ -1,753 +0,0 @@
/* spl_parser.c — Top-level parser: function declarations, type declarations, etc. */
#include "spl_comp.h"
#include "spl_lex_util.h"
#include <string.h>
/* ============================================================
* Parse function definition
* ============================================================ */
enum { MAX_PARAMS = 64 };
static int parse_params_decl(spl_comp_t *ctx, char pnames[][256], int ptypes[]) {
int nparams = 0;
skip_nl(ctx);
if (peek(ctx)->type != TOK_R_PAREN) {
{
usize saved = ctx->tok_idx;
spl_tok_t *ptok = advance(ctx);
skip_nl(ctx);
if (ptok->type == KW_VOID && peek(ctx)->type == TOK_R_PAREN) {
expect(ctx, TOK_R_PAREN);
return 0;
}
ctx->tok_idx = saved;
}
while (1) {
if (peek(ctx)->type == TOK_ELLIPSIS) {
advance(ctx);
break;
}
spl_tok_t *pname = advance(ctx);
spl_tok_copy_name(pname, pnames[nparams], 256);
skip_nl(ctx);
if (peek(ctx)->type == TOK_COLON) {
advance(ctx);
skip_nl(ctx);
ptypes[nparams] = spl_type_parse(&ctx->tctx, ctx);
} else {
ptypes[nparams] = spl_type_basic(&ctx->tctx, SPL_I32);
}
nparams++;
skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
break;
}
}
expect(ctx, TOK_R_PAREN);
return nparams;
}
static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx, int nparams,
char pnames[][256], int ptypes[], int is_pub) {
snprintf(ctx->parse_context, sizeof(ctx->parse_context), "function '%s'", fn_name);
int fi = spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 0, is_pub);
{
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
f->param_type_indices = calloc(nparams, sizeof(int));
f->param_names = calloc(nparams, sizeof(char *));
for (int i = 0; i < nparams; i++) {
f->param_type_indices[i] = ptypes[i];
f->param_names[i] = strdup(pnames[i]);
}
}
ctx->current_func_idx = fi;
ctx->current_ret_type_idx = ret_type_idx;
fa_init(&ctx->emit.frame);
spl_push_scope(ctx);
for (int i = 0; i < nparams; i++) {
spl_declare_var(ctx, pnames[i], ptypes[i], 0);
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_BRACE) {
advance(ctx);
skip_nl(ctx);
spl_val_t alloc_addr = vec_size(ctx->prog.insns);
emit_alloc(&ctx->emit, 0);
while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
spl_parse_stmt(ctx);
skip_nl(ctx);
}
/* Error recovery: skip to matching } if has_error caused early exit */
if (ctx->has_error) {
int depth = 1;
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE)
depth++;
else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
} else if (tt == TOK_EOF)
break;
advance(ctx);
}
if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
else
return 0;
} else {
if (!expect(ctx, TOK_R_BRACE))
return 0;
}
int total_phys_slots = 0;
for (int i = 0; i < nparams; i++) {
usize psz = spl_type_size(&ctx->tctx, ptypes[i]);
total_phys_slots += (int)((psz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t));
}
if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) {
usize min_bytes = spl_type_slot_count(&ctx->tctx, ret_type_idx) * sizeof(spl_val_t);
if ((usize)ctx->emit.frame.peak_bytes < min_bytes)
ctx->emit.frame.peak_bytes = (int)min_bytes;
}
int alloc_slots = ctx->emit.frame.peak_bytes / (int)sizeof(spl_val_t) - total_phys_slots;
if (alloc_slots < 0 || alloc_slots > 65536) {
fprintf(
stderr,
"WARN: parse_fn_body: suspicious alloc_slots=%d (peak_bytes=%d, phys_slots=%d)\n",
alloc_slots, ctx->emit.frame.peak_bytes, total_phys_slots);
}
emit_patch(&ctx->emit, alloc_addr, alloc_slots);
}
spl_emit_defer_epilogue(ctx, ctx->scope_depth);
spl_pop_scope(ctx);
emit_return(&ctx->emit, &ctx->tctx, ctx->current_ret_type_idx);
{
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
spl_prog_end_func(&ctx->prog, f->func_idx);
}
ctx->current_func_idx = -1;
ctx->current_ret_type_idx = -1;
return fi;
}
static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
advance(ctx); /* fn */
skip_nl(ctx);
spl_tok_t *fname_tok = advance(ctx);
char fn_name[256];
spl_tok_copy_name(fname_tok, fn_name, sizeof(fn_name));
skip_nl(ctx);
if (!expect(ctx, TOK_L_PAREN))
return;
char pnames[MAX_PARAMS][256];
int ptypes[MAX_PARAMS];
int nparams = parse_params_decl(ctx, pnames, ptypes);
skip_nl(ctx);
int ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
ret_type_idx = spl_type_parse(&ctx->tctx, ctx);
if (ret_type_idx < 0)
ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
skip_nl(ctx);
}
int fi;
if (is_extern) {
fi = spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, is_pub);
spl_ensure_native(ctx, fn_name);
if (ctx->tctx.current_type_idx == 0)
spl_type_add_method(&ctx->tctx, 0, fn_name, fi);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
return;
}
if (peek(ctx)->type == TOK_SEMICOLON) {
advance(ctx);
return;
}
skip_nl(ctx);
fi = parse_fn_body(ctx, fn_name, ret_type_idx, nparams, pnames, ptypes, is_pub);
if (ctx->tctx.current_type_idx == 0)
spl_type_add_method(&ctx->tctx, 0, fn_name, fi);
}
/* ============================================================
* Parse method declaration inside a type body
* ============================================================ */
static void parse_method_decl(spl_comp_t *ctx, int container_type_idx) {
advance(ctx); /* fn */
skip_nl(ctx);
spl_tok_t *mname_tok = advance(ctx);
char mname[256];
spl_tok_copy_name(mname_tok, mname, sizeof(mname));
const char *cname = spl_type_name(&ctx->tctx, container_type_idx);
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", cname ? cname : "anon", mname);
skip_nl(ctx);
if (!expect(ctx, TOK_L_PAREN))
return;
char pnames[MAX_PARAMS][256];
int ptypes[MAX_PARAMS];
int nparams = parse_params_decl(ctx, pnames, ptypes);
skip_nl(ctx);
int ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
ret_type_idx = spl_type_parse(&ctx->tctx, ctx);
if (ret_type_idx < 0)
ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
skip_nl(ctx);
}
int fi = parse_fn_body(ctx, qualified, ret_type_idx, nparams, pnames, ptypes, 0);
spl_type_add_method(&ctx->tctx, container_type_idx, mname, fi);
}
/* ============================================================
* Parse type container body (shared for struct, union, enum)
* ============================================================ */
static void parse_type_body(spl_comp_t *ctx, int container_type_idx, int is_enum) {
if (peek(ctx)->type != TOK_L_BRACE)
return;
advance(ctx); /* { */
int saved_current = ctx->tctx.current_type_idx;
ctx->tctx.current_type_idx = container_type_idx;
/* === Pass 1: Parse all nested type declarations first === */
{
usize saved = ctx->tok_idx;
int depth = 1;
while (!ctx->has_error && depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE) {
depth++;
advance(ctx);
} else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
advance(ctx);
} else if (tt == KW_TYPE && depth == 1) {
parse_type_decl(ctx);
} else if (tt == TOK_EOF) {
break;
} else {
advance(ctx);
}
}
ctx->tok_idx = saved;
}
/* === Pre-register method names for forward references === */
{
const char *cname = spl_type_name(&ctx->tctx, container_type_idx);
if (cname) {
usize saved = ctx->tok_idx;
int depth = 1;
while (!ctx->has_error && depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE) {
depth++;
advance(ctx);
} else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
advance(ctx);
} else if (tt == KW_FN && depth == 1) {
advance(ctx); /* fn */
skip_nl(ctx);
spl_tok_t *name_tok = advance(ctx);
char mname[256];
spl_tok_copy_name(name_tok, mname, sizeof(mname));
/* Count parameters for forward reference */
int pcount = 0;
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx); /* ( */
skip_nl(ctx);
if (peek(ctx)->type != TOK_R_PAREN) {
pcount = 1;
for (;;) {
advance(ctx); /* skip param name or type token */
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
break;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx); /* , */
skip_nl(ctx);
pcount++;
}
}
}
advance(ctx); /* ) */
}
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", cname, mname);
int fi = spl_declare_func(ctx, qualified, -1, pcount, 0, 0);
spl_type_add_method(&ctx->tctx, container_type_idx, mname, fi);
} else if (tt == TOK_EOF) {
break;
} else {
advance(ctx);
}
}
ctx->tok_idx = saved;
}
}
/* === Pass 2: Parse fields/variants and methods === */
{
int depth = 1;
while (!ctx->has_error && depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
skip_nl(ctx);
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE) {
depth++;
advance(ctx);
} else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0) {
advance(ctx);
break;
}
advance(ctx);
} else if (tt == KW_TYPE && depth == 1) {
parse_type_decl(ctx);
} else if (tt == KW_VAR && depth == 1 && !is_enum) {
advance(ctx); /* var */
skip_nl(ctx);
spl_tok_t *ftok = advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == TOK_COLON) {
advance(ctx); /* : */
skip_nl(ctx);
int ftype = spl_type_parse(&ctx->tctx, ctx);
char fname[256];
spl_tok_copy_name(ftok, fname, sizeof(fname));
if (ftype >= 0)
spl_type_add_var(&ctx->tctx, container_type_idx, fname, ftype);
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
advance(ctx);
} else if (tt == TOK_IDENT && depth == 1) {
if (is_enum) {
spl_tok_t *vtok = advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == TOK_COLON) {
advance(ctx); /* : */
skip_nl(ctx);
int dtype = spl_type_parse(&ctx->tctx, ctx);
char vname[256];
spl_tok_copy_name(vtok, vname, sizeof(vname));
spl_type_add_variant(&ctx->tctx, container_type_idx, vname,
dtype >= 0 ? dtype : -1);
} else if (tt == TOK_EOF) {
break;
} else {
char vname[256];
spl_tok_copy_name(vtok, vname, sizeof(vname));
spl_type_add_variant(&ctx->tctx, container_type_idx, vname, -1);
}
} else {
spl_tok_t *ftok = advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == TOK_COLON) {
advance(ctx); /* : */
skip_nl(ctx);
int ftype = spl_type_parse(&ctx->tctx, ctx);
char fname[256];
spl_tok_copy_name(ftok, fname, sizeof(fname));
if (ftype >= 0)
spl_type_add_field(&ctx->tctx, container_type_idx, fname, ftype);
}
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
advance(ctx);
} else if (tt == KW_FN && depth == 1) {
spl_type_compute_layout(&ctx->tctx, container_type_idx);
parse_method_decl(ctx, container_type_idx);
} else {
advance(ctx);
}
}
}
ctx->tctx.current_type_idx = saved_current;
}
/* ============================================================
* Parse type declaration
* ============================================================ */
void parse_type_decl(spl_comp_t *ctx) {
advance(ctx); /* type */
spl_tok_t *name_tok = advance(ctx);
char tname[256];
spl_tok_copy_name(name_tok, tname, sizeof(tname));
snprintf(ctx->parse_context, sizeof(ctx->parse_context), "type '%s'", tname);
skip_nl(ctx);
if (!expect(ctx, TOK_ASSIGN))
return;
skip_nl(ctx);
int parent_type_idx = ctx->tctx.current_type_idx;
/* Check if already pre-registered in Pass 0 */
int existing = spl_type_resolve(&ctx->tctx, tname);
if (peek(ctx)->type == KW_STRUCT) {
advance(ctx);
int ti;
if (existing >= 0)
ti = existing;
else
ti = spl_type_struct(&ctx->tctx, tname);
if (parent_type_idx >= 0 && existing < 0)
spl_type_add_nested(&ctx->tctx, parent_type_idx, tname, ti);
skip_nl(ctx);
parse_type_body(ctx, ti, 0);
} else if (peek(ctx)->type == KW_UNION) {
advance(ctx);
int ti;
if (existing >= 0)
ti = existing;
else
ti = spl_type_union(&ctx->tctx, tname);
if (parent_type_idx >= 0 && existing < 0)
spl_type_add_nested(&ctx->tctx, parent_type_idx, tname, ti);
skip_nl(ctx);
parse_type_body(ctx, ti, 1);
} else if (peek(ctx)->type == KW_ENUM) {
advance(ctx);
int ti;
if (existing >= 0)
ti = existing;
else
ti = spl_type_enum(&ctx->tctx, tname);
if (parent_type_idx >= 0 && existing < 0)
spl_type_add_nested(&ctx->tctx, parent_type_idx, tname, ti);
skip_nl(ctx);
parse_type_body(ctx, ti, 1);
} else if (peek(ctx)->type == TOK_IDENT ||
(peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) {
int base = spl_type_parse(&ctx->tctx, ctx);
if (base >= 0) {
spl_type_alias(&ctx->tctx, tname, base);
}
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
}
/* ============================================================
* Pre-registration pass: register all names before filling bodies
* ============================================================ */
/* Skip a { ... } function body */
static void skip_fn_body(spl_comp_t *ctx) {
int depth = 1;
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE)
depth++;
else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
} else if (tt == TOK_EOF)
break;
advance(ctx);
}
if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
}
/* Pre-register a type name (and nested type names), skip the body */
static void pre_register_type_decl(spl_comp_t *ctx) {
advance(ctx); /* type */
spl_tok_t *name_tok = advance(ctx);
char tname[256];
spl_tok_copy_name(name_tok, tname, sizeof(tname));
skip_nl(ctx);
if (!expect(ctx, TOK_ASSIGN))
return;
skip_nl(ctx);
int parent_type_idx = ctx->tctx.current_type_idx;
int ti = -1;
if (peek(ctx)->type == KW_STRUCT) {
advance(ctx);
ti = spl_type_struct(&ctx->tctx, tname);
} else if (peek(ctx)->type == KW_ENUM) {
advance(ctx);
ti = spl_type_enum(&ctx->tctx, tname);
} else if (peek(ctx)->type == KW_UNION) {
advance(ctx);
ti = spl_type_union(&ctx->tctx, tname);
}
if (ti >= 0) {
if (parent_type_idx >= 0)
spl_type_add_nested(&ctx->tctx, parent_type_idx, tname, ti);
/* Register nested type names inside the body */
if (peek(ctx)->type == TOK_L_BRACE) {
int saved_current = ctx->tctx.current_type_idx;
ctx->tctx.current_type_idx = ti;
int depth = 1;
advance(ctx); /* { */
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE) {
depth++;
advance(ctx);
} else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
advance(ctx);
} else if (tt == KW_TYPE && depth == 1) {
pre_register_type_decl(ctx);
} else if (tt == TOK_EOF) {
break;
} else {
advance(ctx);
}
}
if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
ctx->tctx.current_type_idx = saved_current;
}
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
}
/* Pre-register a function name and signature, skip the body */
static void pre_register_fn_decl(spl_comp_t *ctx, int is_extern) {
advance(ctx);
skip_nl(ctx);
spl_tok_t *fname_tok = advance(ctx);
char fn_name[256];
spl_tok_copy_name(fname_tok, fn_name, sizeof(fn_name));
skip_nl(ctx);
if (!expect(ctx, TOK_L_PAREN))
return;
char pnames[MAX_PARAMS][256];
int ptypes[MAX_PARAMS];
int nparams = parse_params_decl(ctx, pnames, ptypes);
skip_nl(ctx);
int ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
ret_type_idx = spl_type_parse(&ctx->tctx, ctx);
if (ret_type_idx < 0)
ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
skip_nl(ctx);
}
if (is_extern) {
spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, 0);
spl_ensure_native(ctx, fn_name);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
return;
}
if (peek(ctx)->type == TOK_SEMICOLON) {
advance(ctx);
return;
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_BRACE) {
skip_fn_body(ctx);
}
skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
}
/* ============================================================
* Parse top-level program
* ============================================================ */
void spl_parse_prog(spl_comp_t *ctx) {
/* Pass 0: Pre-register all type names, function signatures, and variables */
{
usize saved = ctx->tok_idx;
while (!ctx->has_error && peek(ctx)->type != TOK_EOF) {
skip_nl(ctx);
if (peek(ctx)->type == TOK_EOF)
break;
switch (peek(ctx)->type) {
case KW_TYPE:
pre_register_type_decl(ctx);
break;
case KW_FN:
pre_register_fn_decl(ctx, 0);
break;
case KW_PUB: {
advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == KW_FN)
pre_register_fn_decl(ctx, 0);
else if (peek(ctx)->type == KW_TYPE)
pre_register_type_decl(ctx);
break;
}
case TOK_AT:
case TOK_SHARP: {
int tt = peek(ctx)->type;
advance(ctx);
skip_nl(ctx);
if (tt == TOK_AT) {
if (peek(ctx)->type == KW_EXTERN) {
advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx);
skip_nl(ctx);
advance(ctx);
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
advance(ctx);
}
}
} else {
if (peek(ctx)->type == TOK_L_BRACKET) {
advance(ctx);
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
}
}
skip_nl(ctx);
if (peek(ctx)->type == KW_FN)
pre_register_fn_decl(ctx, 1);
break;
}
default:
/* Skip unrecognized tokens (stmts, etc.) */
advance(ctx);
break;
}
}
ctx->tok_idx = saved;
}
/* Pass 1: Fill all bodies */
while (!ctx->has_error && peek(ctx)->type != TOK_EOF) {
skip_nl(ctx);
if (peek(ctx)->type == TOK_EOF)
break;
switch (peek(ctx)->type) {
case KW_FN:
parse_fn_decl(ctx, 0, 0);
break;
case KW_TYPE:
parse_type_decl(ctx);
break;
case KW_PUB: {
advance(ctx); /* skip pub */
skip_nl(ctx);
if (peek(ctx)->type == KW_FN)
parse_fn_decl(ctx, 0, 1);
else if (peek(ctx)->type == KW_TYPE)
parse_type_decl(ctx);
break;
}
case TOK_AT:
case TOK_SHARP: {
int tt = peek(ctx)->type;
advance(ctx); /* @ or # */
skip_nl(ctx);
if (tt == TOK_AT) {
if (peek(ctx)->type == KW_EXTERN) {
advance(ctx); /* extern */
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx); /* ( */
skip_nl(ctx);
advance(ctx); /* target name (e.g. "vm") */
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
advance(ctx);
}
}
} else {
if (peek(ctx)->type == TOK_L_BRACKET) {
advance(ctx);
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
}
}
skip_nl(ctx);
if (peek(ctx)->type == KW_FN)
parse_fn_decl(ctx, 1, 0);
break;
}
default: {
usize prev = ctx->tok_idx;
spl_parse_stmt(ctx);
if (ctx->tok_idx == prev)
advance(ctx);
break;
}
}
}
/* Recompute all type layouts now that forward references are resolved */
for (int i = 0; i < (int)vec_size(ctx->tctx.types); i++) {
spl_type_compute_layout(&ctx->tctx, i);
}
}

File diff suppressed because it is too large Load Diff

122
stage1/spl_tok.h Normal file
View File

@@ -0,0 +1,122 @@
/* spl_tok.h — Token type definitions (extracted from spl_lexer.h) */
#ifndef __SPL_TOK_H__
#define __SPL_TOK_H__
#include "../stage0/include/utils.h"
/* clang-format off */
#define KEYWORD_TABLE \
X(as , KW_AS , SPL_V0) \
X(bool , KW_BOOL , SPL_V0) \
X(break , KW_BREAK , SPL_V0) \
X(comptime , KW_COMPTIME , SPL_V0) \
X(const , KW_CONST , SPL_V0) \
X(continue , KW_CONTINUE , SPL_V0) \
X(defer , KW_DEFER , SPL_V0) \
X(else , KW_ELSE , SPL_V0) \
X(enum , KW_ENUM , SPL_V0) \
X(false , KW_FALSE , SPL_V0) \
X(fn , KW_FN , SPL_V0) \
X(for , KW_FOR , SPL_V0) \
X(if , KW_IF , SPL_V0) \
X(loop , KW_LOOP , SPL_V0) \
X(match , KW_MATCH , SPL_V0) \
X(null , KW_NULL , SPL_V0) \
X(ret , KW_RET , SPL_V0) \
X(struct , KW_STRUCT , SPL_V0) \
X(true , KW_TRUE , SPL_V0) \
X(type , KW_TYPE , SPL_V0) \
X(union , KW_UNION , SPL_V0) \
X(var , KW_VAR , SPL_V0) \
X(void , KW_VOID , SPL_V0) \
X(while , KW_WHILE , SPL_V0) \
X(_ , KW_ANY , SPL_V0) \
// KEYWORD_TABLE
#define TOKEN_TABLE \
X(unknown , TOK_UNKNOWN , SPL_V0 ) \
X(EOF , TOK_EOF , SPL_V0 ) \
X(blank , TOK_BLANK , SPL_V0 ) \
X(endline , TOK_ENDLINE , SPL_V0 ) \
X("#" , TOK_SHARP , SPL_V0 ) \
X("@" , TOK_AT , SPL_V0 ) \
X("==" , TOK_EQ , SPL_V0 ) \
X("=" , TOK_ASSIGN , SPL_V0 ) \
X("+=" , TOK_ASSIGN_ADD , SPL_V0 ) \
X("+" , TOK_ADD , SPL_V0 ) \
X("-=" , TOK_ASSIGN_SUB , SPL_V0 ) \
X("->" , TOK_RIGHT_ARRAY , SPL_V0 ) \
X("<-" , TOK_LEFT_ARRAY , SPL_V0 ) \
X("-" , TOK_SUB , SPL_V0 ) \
X("*=" , TOK_ASSIGN_MUL , SPL_V0 ) \
X("*" , TOK_MUL , SPL_V0 ) \
X("/=" , TOK_ASSIGN_DIV , SPL_V0 ) \
X("/" , TOK_DIV , SPL_V0 ) \
X("//" , TOK_LINE_COMMENT , SPL_V0 ) \
X("/* */" , TOK_BLOCK_COMMENT , SPL_V0 ) \
X("%=" , TOK_ASSIGN_MOD , SPL_V0 ) \
X("%" , TOK_MOD , SPL_V0 ) \
X("&&" , TOK_AND_AND , SPL_V0 ) \
X("&=" , TOK_ASSIGN_AND , SPL_V0 ) \
X("&" , TOK_AND , SPL_V0 ) \
X("||" , TOK_OR_OR , SPL_V0 ) \
X("|=" , TOK_ASSIGN_OR , SPL_V0 ) \
X("|" , TOK_OR , SPL_V0 ) \
X("^=" , TOK_ASSIGN_XOR , SPL_V0 ) \
X("^" , TOK_XOR , SPL_V0 ) \
X("<<=" , TOK_ASSIGN_L_SH , SPL_V0 ) \
X("<<" , TOK_L_SH , SPL_V0 ) \
X("<=" , TOK_LE , SPL_V0 ) \
X("<" , TOK_LT , SPL_V0 ) \
X(">>=" , TOK_ASSIGN_R_SH , SPL_V0 ) \
X(">>" , TOK_R_SH , SPL_V0 ) \
X(">=" , TOK_GE , SPL_V0 ) \
X(">" , TOK_GT , SPL_V0 ) \
X("!" , TOK_NOT , SPL_V0 ) \
X("!=" , TOK_NEQ , SPL_V0 ) \
X("~" , TOK_BIT_NOT , SPL_V0 ) \
X("[" , TOK_L_BRACKET , SPL_V0 ) \
X("]" , TOK_R_BRACKET , SPL_V0 ) \
X("(" , TOK_L_PAREN , SPL_V0 ) \
X(")" , TOK_R_PAREN , SPL_V0 ) \
X("{" , TOK_L_BRACE , SPL_V0 ) \
X("}" , TOK_R_BRACE , SPL_V0 ) \
X(";" , TOK_SEMICOLON , SPL_V0 ) \
X("," , TOK_COMMA , SPL_V0 ) \
X(":" , TOK_COLON , SPL_V0 ) \
X(":=" , TOK_COLON_ASSIGN , SPL_V0 ) \
X("." , TOK_DOT , SPL_V0 ) \
X(".." , TOK_RANGE , SPL_V0 ) \
X("..." , TOK_ELLIPSIS , SPL_V0 ) \
X("=>" , TOK_FAT_ARROW , SPL_V0 ) \
X("?" , TOK_COND , SPL_V0 ) \
X(ident , TOK_IDENT , SPL_V0 ) \
X(int , TOK_INT_LITERAL , SPL_V0 ) \
X(float , TOK_FLOAT_LITERAL , SPL_V0 ) \
X(char , TOK_CHAR_LITERAL , SPL_V0 ) \
X(string , TOK_STRING_LITERAL , SPL_V0 ) \
// TOKEN_TABLE
/* clang-format on */
typedef enum {
#define X(name, enum_name, dummy) enum_name,
KEYWORD_TABLE
#undef X
#define X(name, enum_name, dummy) enum_name,
TOKEN_TABLE
#undef X
} spl_tok_type_t;
typedef struct {
spl_tok_type_t type;
const char *lexeme;
usize len;
const char *fname;
usize offset;
usize line;
usize col;
} spl_tok_t;
typedef VEC(spl_tok_t) spl_tok_vec_t;
#endif /* __SPL_TOK_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,213 +0,0 @@
#ifndef __SPL_TYPE_H__
#define __SPL_TYPE_H__
#include "../stage0/spl_ir.h"
#include "spl_lexer.h"
/* ============================================================
* Type kinds
* ============================================================ */
typedef enum {
TYPE_VOID,
TYPE_BASIC,
TYPE_PTR,
TYPE_ARRAY,
TYPE_SLICE,
TYPE_STRUCT,
TYPE_UNION,
TYPE_ENUM,
TYPE_NAME,
TYPE_FN,
TYPE_COUNT,
} spl_type_kind_t;
#define ENUM_TAG_SIZE 4 /* discriminator tag byte size */
/* ============================================================
* Item kinds — unified member storage
* ============================================================ */
typedef enum {
ITEM_FIELD, /* aggregate_field : struct/union field */
ITEM_VARIANT, /* enum_field : enum variant */
ITEM_METHOD, /* method : type method */
ITEM_NESTED_TYPE, /* nested_type : child type decl */
ITEM_VAR, /* aggregate_field : type-level var */
} spl_type_item_kind_t;
/* ============================================================
* Type item — one member/variant/method/nested-type
* ============================================================ */
typedef struct {
const char *name;
spl_type_item_kind_t item_kind;
union {
struct {
int type_idx; /* field type */
usize offset; /* byte offset (for array: array_len) */
} aggregate_field;
struct {
int type_idx; /* data type, -1 if none */
isize value; /* discriminator value */
} enum_field;
struct {
int func_idx; /* index in spl_comp_t.funcs */
} method;
struct {
int type_idx; /* child type index */
} nested_type;
};
} spl_type_item_t;
typedef VEC(spl_type_item_t) spl_type_item_vec_t;
/* ============================================================
* Type info — one type definition
*
* PTR : items[0].aggregate_field.type_idx = elem
* ARRAY : items[0].aggregate_field.type_idx = elem,
* items[0].aggregate_field.offset = len
* SLICE : same as PTR
* STRUCT : items = ITEM_FIELD for each field
* UNION : items = ITEM_FIELD for each field
* ENUM : items = ITEM_VARIANT for each variant
* NAME : items[0].aggregate_field.type_idx = alias target
* ============================================================ */
typedef struct spl_type_info {
char *name;
spl_type_kind_t kind;
spl_type_t basic_type; /* for TYPE_BASIC */
spl_type_item_vec_t items;
usize byte_size; /* total byte size (cached) */
usize slot_count; /* stack slot count (cached) */
int resolved; /* layout computed */
int parent_type_idx; /* enclosing type, -1 for root */
} spl_type_info_t;
typedef VEC(spl_type_info_t) spl_type_info_vec_t;
/* ============================================================
* Type context — type arena + namespace
*
* types[0] = root (compilation unit type)
* Types form a tree via parent_type_idx on each type info.
* current_type_idx tracks the innermost type being parsed.
* ============================================================ */
typedef struct {
spl_type_info_vec_t types;
MAP(const char *, int) type_map; /* name → type_idx 加速查找 */
int root_type_idx; /* 编译单元自身 = 0 */
int current_type_idx; /* 当前作用域类型 */
int basic_cache[SPL_TYPE_COUNT]; /* memoized basic-type → type_idx */
} spl_type_ctx_t;
/* ============================================================
* Lifecycle
* ============================================================ */
void spl_type_ctx_init(spl_type_ctx_t *tctx);
void spl_type_ctx_drop(spl_type_ctx_t *tctx);
/* ============================================================
* Constructors — all return type_idx (index into tctx->types)
* ============================================================ */
int spl_type_basic(spl_type_ctx_t *tctx, spl_type_t bt);
int spl_type_ptr(spl_type_ctx_t *tctx, int elem_type_idx);
int spl_type_array(spl_type_ctx_t *tctx, int elem_type_idx, usize len);
int spl_type_slice(spl_type_ctx_t *tctx, int elem_type_idx);
int spl_type_struct(spl_type_ctx_t *tctx, const char *name);
int spl_type_union(spl_type_ctx_t *tctx, const char *name);
int spl_type_enum(spl_type_ctx_t *tctx, const char *name);
int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx);
int spl_type_fn(spl_type_ctx_t *tctx, int params_type_idx, int ret_type_idx);
/* ============================================================
* Item management — add members to aggregate types
* ============================================================ */
void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, int field_type_idx);
void spl_type_add_var(spl_type_ctx_t *tctx, int type_idx, const char *name, int var_type_idx);
void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, int data_type_idx);
void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx);
void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name,
int child_type_idx);
/* ============================================================
* Layout — compute byte_size / slot_count, set resolved
* ============================================================ */
void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx);
/* ============================================================
* Accessors — get info from type_idx
* ============================================================ */
spl_type_kind_t spl_type_kind(spl_type_ctx_t *tctx, int type_idx);
spl_type_t spl_type_basic_type(spl_type_ctx_t *tctx, int type_idx);
const char *spl_type_name(spl_type_ctx_t *tctx, int type_idx);
usize spl_type_size(spl_type_ctx_t *tctx, int type_idx);
usize spl_type_slot_count(spl_type_ctx_t *tctx, int type_idx);
usize spl_type_elem_stride(spl_type_ctx_t *tctx, int elem_type_idx);
/* Element type for PTR / ARRAY / SLICE / NAME (reads items[0]) */
int spl_type_elem_type(spl_type_ctx_t *tctx, int type_idx);
usize spl_type_array_len(spl_type_ctx_t *tctx, int type_idx);
/* Scalar: fits in one slot, supports ==/!= directly */
int spl_type_is_scalar(spl_type_ctx_t *tctx, int type_idx);
/* Integer type check */
int spl_type_is_integer(spl_type_t bt);
/* True for types that support inline literal {} syntax */
int spl_type_has_inline_literal(spl_type_ctx_t *tctx, int type_idx);
/* True for multi-slot type — alias for needs_multi_slot for semantic clarity */
int spl_type_is_aggregate(spl_type_ctx_t *tctx, int type_idx);
/* Multi-slot: aggregate type needing >1 stack slots */
int spl_type_needs_multi_slot(spl_type_ctx_t *tctx, int type_idx);
/* Follow alias chain to underlying type */
int spl_type_resolve_underlying(spl_type_ctx_t *tctx, int type_idx);
/* SPL_IR opcode type tag for LOAD/STORE */
spl_type_t spl_type_emit_type(spl_type_ctx_t *tctx, int type_idx);
/* Debug string */
const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx);
/* ============================================================
* Item iteration — filter by item_kind
* ============================================================ */
int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, spl_type_item_kind_t kind);
spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx, int item_index);
/* Returns pointer to first item of given kind, with *count set */
spl_type_item_t *spl_type_first_of_kind(spl_type_ctx_t *tctx, int type_idx,
spl_type_item_kind_t kind, int *count);
/* Get raw items vec for direct iteration (avoids double-lookup) */
spl_type_item_vec_t *spl_type_items(spl_type_ctx_t *tctx, int type_idx);
/* ============================================================
* Type resolution — name → type_idx
* ============================================================ */
/* Walk current → parent chain, then type_map */
int spl_type_resolve(spl_type_ctx_t *tctx, const char *name);
/* Resolve within a specific parent type's ITEM_NESTED_TYPE items */
int spl_type_resolve_in(spl_type_ctx_t *tctx, int parent_idx, const char *name);
/* ============================================================
* Forward declaration for spl_parse_type
* ============================================================ */
struct spl_comp;
int spl_type_parse(spl_type_ctx_t *tctx, struct spl_comp *ctx);
#endif /* __SPL_TYPE_H__ */

View File

@@ -1,13 +1,4 @@
/* splc0.c — Stage 1 SPL compiler (bootstrap) /* splc0.c — SPL compiler CLI */
* Usage:
* splc0 <input.spl> <output.sir> — compile
* splc0 --dump-tokens <input.spl> — dump tokens
* splc0 --help — help
*/
#include "../stage0/spl_ir.h"
#include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -33,75 +24,19 @@ static char *read_file(const char *path, long *out_len) {
return buf; return buf;
} }
static int cmd_dump_tokens(int argc, char **argv) {
if (argc < 1) {
fprintf(stderr, "Usage: splc0 --dump-tokens <file.spl>\n");
return 1;
}
long len;
char *src = read_file(argv[0], &len);
if (!src)
return 1;
spl_tok_vec_t toks = spl_lex(src, argv[0]);
spl_tok_vec_dump(&toks);
spl_tok_vec_drop(&toks);
free(src);
return 0;
}
static int cmd_compile(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: splc0 <input.spl> <output.sir>\n");
return 1;
}
const char *inpath = argv[0];
const char *outpath = argv[1];
long len;
char *src = read_file(inpath, &len);
if (!src)
return 1;
spl_comp_t ctx;
spl_comp_init(&ctx);
int ret = 0;
if (spl_compile(&ctx, src, inpath) != 0) {
fprintf(stderr, "compilation failed: %s\n", ctx.error_msg);
ret = 1;
goto cleanup;
}
if (spl_prog_store_to_file(outpath, &ctx.prog) != 0) {
fprintf(stderr, "failed to write '%s'\n", outpath);
ret = 1;
goto cleanup;
}
printf("compiled %s -> %s\n", inpath, outpath);
cleanup:
spl_comp_drop(&ctx);
free(src);
return ret;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: splc0 [--dump-tokens|--help] <input.spl> [output.sir]\n"); fprintf(stderr, "Usage: splc0 [--dump <flags>] <in> [out]\n");
return 1; return 1;
} }
if (strcmp(argv[1], "--dump") == 0)
if (strcmp(argv[1], "--dump-tokens") == 0) { // return cmd_dump(argc - 2, argv + 2);
return cmd_dump_tokens(argc - 2, argv + 2); return 0;
}
if (strcmp(argv[1], "--help") == 0) { if (strcmp(argv[1], "--help") == 0) {
printf("SPL Compiler (stage1 bootstrap)\n"); printf("splc0 <in> <out> compile\n");
printf(" splc0 <input.spl> <output.sir> - compile\n"); printf("splc0 --dump <f> <file> dump: tokens,cst,ast,ir,mcode,all\n");
printf(" splc0 --dump-tokens <file.spl> - dump token stream\n");
return 0; return 0;
} }
// return cmd_compile(argc - 1, argv + 1);
return cmd_compile(argc - 1, argv + 1); return 0;
} }

View File

@@ -1,9 +1,8 @@
/* spc_vm.c VM launcher for stage 1 */ /* spc_vm.c 鈥?VM launcher for stage 1 */
#include "../stage0/spl_ir.h" #include "../stage0/spl_mcode.h"
#include "../stage0/spl_syscall.h" #include "../stage0/spl_syscall.h"
#include "../stage0/spl_vm.h" #include "../stage0/spl_vm.h"
#include "spl_comp.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -11,28 +10,31 @@
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
int argi = 1; int argi = 1;
if (argi >= argc) { /* Parse flags: --entry <name>, --trace, -d */
fprintf(stderr, "Usage: spc_vm <file.sir> [entry] [--trace]\n");
return 1;
}
const char *path = argv[argi++];
/* Parse flags: --entry <name>, --trace */
const char *entry = "main"; const char *entry = "main";
int trace = 0; int trace = 0;
int debug_addr = 0;
for (int i = argi; i < argc; i += 1) { for (int i = argi; i < argc; i += 1) {
if (strcmp(argv[i], "--entry") == 0 && i + 1 < argc) { if (strcmp(argv[i], "--entry") == 0 && i + 1 < argc) {
entry = argv[++i]; entry = argv[++i];
} else if (strcmp(argv[i], "--trace") == 0) { } else if (strcmp(argv[i], "--trace") == 0) {
trace = 1; trace = 1;
} else if (strcmp(argv[i], "-d") == 0) {
debug_addr = 1;
} else if (argv[i][0] != '-') {
argi = i;
break;
} }
} }
/* Adjust argv so the SPL program sees path as argv[0] and if (argi >= argc) {
* remaining positional args as argv[1..], just like a native exe. */ fprintf(stderr, "Usage: spc_vm [-d] [--trace] <file.sir> [args...]\n");
int spl_argc = argc - (argi - 1); return 1;
}
const char *path = argv[argi++];
const char **spl_argv = argv + (argi - 1); const char **spl_argv = argv + (argi - 1);
int spl_argc = (int)(argc - (argi - 1));
spl_prog_t prog; spl_prog_t prog;
if (spl_prog_load_from_file(path, &prog) != 0) { if (spl_prog_load_from_file(path, &prog) != 0) {
@@ -41,7 +43,6 @@ int main(int argc, const char **argv) {
} }
spl_syscall_register(&prog); spl_syscall_register(&prog);
spl_comp_register(&prog);
spl_vm_t vm; spl_vm_t vm;
spl_vm_init(&vm); spl_vm_init(&vm);
@@ -56,6 +57,7 @@ int main(int argc, const char **argv) {
return 1; return 1;
} }
spl_vm_set_trace(&vm, trace); spl_vm_set_trace(&vm, trace);
if (debug_addr) spl_vm_set_debug(&vm, 1);
int ret = spl_vm_run_until(&vm, 0); int ret = spl_vm_run_until(&vm, 0);
spl_vm_drop(&vm); spl_vm_drop(&vm);

View File

@@ -24,8 +24,8 @@ type Expr = enum {
fn eval(self: *Expr) i32 { fn eval(self: *Expr) i32 {
match self { match self {
.Int(val) => ret val, .Int[val] => ret val,
.Add(left, right) => ret eval(left) + eval(right), .Add[.left = left, .right = right] => ret eval(left) + eval(right),
} }
ret 0; ret 0;
} }

View File

@@ -79,7 +79,7 @@ fn test_optional_match() i32 {
var o: Optional = Optional { .Some = 42 }; var o: Optional = Optional { .Some = 42 };
match o { match o {
.Some(val) => { .Some[val] => {
if val != 42 { ret 1; } if val != 42 { ret 1; }
}, },
.None => { .None => {
@@ -90,7 +90,7 @@ fn test_optional_match() i32 {
o = Optional { .None }; o = Optional { .None };
var is_none: i32 = 0; var is_none: i32 = 0;
match o { match o {
.Some(val) => {}, .Some[val] => {},
.None => { is_none = 1; } .None => { is_none = 1; }
} }
if is_none != 1 { ret 3; } if is_none != 1 { ret 3; }
@@ -98,7 +98,7 @@ fn test_optional_match() i32 {
/* 多次提取不同值 */ /* 多次提取不同值 */
o = Optional { .Some = 99 }; o = Optional { .Some = 99 };
match o { match o {
.Some(val) => { .Some[val] => {
if val != 99 { ret 4; } if val != 99 { ret 4; }
}, },
.None => { ret 5; } .None => { ret 5; }
@@ -115,10 +115,10 @@ fn test_shape_match() i32 {
/* Circle: 单数据 */ /* Circle: 单数据 */
var s: Shape = Shape { .Circle = 10 }; var s: Shape = Shape { .Circle = 10 };
match s { match s {
.Circle(r) => { .Circle[r] => {
if r != 10 { ret 1; } if r != 10 { ret 1; }
}, },
.Rect(w, h) => { .Rect[.x = w, .y = h] => {
ret 2; ret 2;
} }
} }
@@ -126,8 +126,8 @@ fn test_shape_match() i32 {
/* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */ /* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */
s = Shape { .Rect = Point { .x = 3, .y = 4 } }; s = Shape { .Rect = Point { .x = 3, .y = 4 } };
match s { match s {
.Circle(r) => { ret 3; }, .Circle[r] => { ret 3; },
.Rect(w, h) => { .Rect[.x = w, .y = h] => {
if w != 3 { ret 4; } if w != 3 { ret 4; }
if h != 4 { ret 5; } if h != 4 { ret 5; }
} }
@@ -143,16 +143,16 @@ fn test_shape_match() i32 {
fn test_action_result_match() i32 { fn test_action_result_match() i32 {
var r: ActionResult = ActionResult { .Success = 200 }; var r: ActionResult = ActionResult { .Success = 200 };
match r { match r {
.Success(code) => { .Success[code] => {
if code != 200 { ret 1; } if code != 200 { ret 1; }
}, },
.NotFound => { .NotFound => {
ret 2; ret 2;
}, },
.Timeout(ms) => { .Timeout[ms] => {
ret 3; ret 3;
}, },
.Error(msg) => { .Error[msg] => {
ret 4; ret 4;
} }
} }
@@ -160,21 +160,21 @@ fn test_action_result_match() i32 {
r = ActionResult { .NotFound }; r = ActionResult { .NotFound };
var found: i32 = 1; var found: i32 = 1;
match r { match r {
.Success(code) => { found = 0; }, .Success[code] => { found = 0; },
.NotFound => { }, .NotFound => { },
.Timeout(ms) => { found = 0; }, .Timeout[ms] => { found = 0; },
.Error(msg) => { found = 0; } .Error[msg] => { found = 0; }
} }
if found != 1 { ret 5; } if found != 1 { ret 5; }
r = ActionResult { .Timeout = 5000 }; r = ActionResult { .Timeout = 5000 };
match r { match r {
.Success(code) => { ret 6; }, .Success[code] => { ret 6; },
.NotFound => { ret 7; }, .NotFound => { ret 7; },
.Timeout(ms) => { .Timeout[ms] => {
if ms != 5000 { ret 8; } if ms != 5000 { ret 8; }
}, },
.Error(msg) => { ret 9; } .Error[msg] => { ret 9; }
} }
ret 0; ret 0;
@@ -252,7 +252,7 @@ fn test_match_in_loop() i32 {
} }
match o { match o {
.Some(val) => { .Some[val] => {
sum = sum + val; sum = sum + val;
}, },
.None => { } .None => { }

View File

@@ -253,13 +253,13 @@ fn test_enum_complex() i32 {
/* Verify active variant */ /* Verify active variant */
match s { match s {
.Active(val) => { .Active[val] => {
if val != 42 { ret 1; } if val != 42 { ret 1; }
}, },
.Inactive => { .Inactive => {
ret 2; ret 2;
}, },
.Pending(px, py) => { .Pending[.x = px, .y = py] => {
ret 3; ret 3;
} }
} }
@@ -268,18 +268,18 @@ fn test_enum_complex() i32 {
var s2: Status = Status { .Inactive }; var s2: Status = Status { .Inactive };
var is_inactive: i32 = 0; var is_inactive: i32 = 0;
match s2 { match s2 {
.Active(val) => {}, .Active[val] => {},
.Inactive => { is_inactive = 1; }, .Inactive => { is_inactive = 1; },
.Pending(px, py) => {} .Pending[.x = px, .y = py] => {}
} }
if is_inactive != 1 { ret 4; } if is_inactive != 1 { ret 4; }
/* Test Pending variant with struct data */ /* Test Pending variant with struct data */
var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } }; var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } };
match s3 { match s3 {
.Active(val) => { ret 5; }, .Active[val] => { ret 5; },
.Inactive => { ret 6; }, .Inactive => { ret 6; },
.Pending(px, py) => { .Pending[.x = px, .y = py] => {
if px != 7 { ret 7; } if px != 7 { ret 7; }
if py != 8 { ret 8; } if py != 8 { ret 8; }
} }