diff --git a/SPL.md b/SPL.md index 9a64e05..ee0873c 100644 --- a/SPL.md +++ b/SPL.md @@ -5,11 +5,10 @@ SPL是一个从零构建的自举编译器项目。引导链: ``` -stage0/spl_vm.c — SIR 虚拟机(C 语言实现) -stage1/spc0.c — SPL→SIR 编译器(C 语言实现,引导用) -stage1/spc1.spl — SPL→SIR 编译器(SPL 语言实现,自举第一版) +stage0/spl_vm.c — SIR 虚拟机 (C 语言实现) +stage1/splc0.c — SPL→SIR 编译器 (C 语言实现,引导用) +stage1/splc1.spl — SPL→SIR 编译器 (SPL 语言实现,自举第一版) ...将来... -spc2.spl → spc3.spl → ... → 完全自举 ``` # SPL 语法规范 @@ -26,14 +25,16 @@ Root <- skip ContainerMembers eof ContainerMembers <- ContainerDeclaration* -ContainerDeclaration - <- FnDecl - / TypeDecl - / VarDecl - / ConstDecl - / ComptimeStmt - / DirectiveBlock (* @init { } / #test { } *) +ContainerDeclaration <- AttrList? DeclarationBody +DeclarationBody (* LL(1): FIRST 集合互斥 *) + <- FnDecl (* fn ... *) + / TypeDecl (* type X = ... *) + / MemberDecl (* IDENTIFIER [: TypeExpr] *) + / VarDecl (* var x: T *) + / ConstDecl (* const x: T = xxx *) + / ComptimeStmt (* comptime ... *) + / Block (* @init { } / #test { } *) # ================================================================ # @ / # 属性列表 (对称设计) @@ -52,17 +53,15 @@ DirectiveHead # ================================================================ DirectiveBlock - <- DirectiveHead Block (* @init { } / #test { } *) - (* 注意: @assert(x); @dbg(x); 是表达式语句, 走 ExprStatement → BuiltinExpr, 不经过这里 *) - + <- DirectiveHead Block (* @init { } / #test { } *) # ================================================================ # comptime — 编译期执行 / 断言 (仅容器层) # ================================================================ ComptimeStmt - <- KEYWORD_comptime Block (* comptime { code } *) - / KEYWORD_comptime Expr SEMICOLON (* comptime ; *) + <- KEYWORD_comptime Block (* comptime { code } *) + / KEYWORD_comptime Expr SEMICOLON (* comptime ; *) # ================================================================ @@ -70,7 +69,7 @@ ComptimeStmt # ================================================================ FnDecl - <- AttrList? KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr? + <- KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr? (SEMICOLON / Block) ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? @@ -85,7 +84,7 @@ ParamDecl # ================================================================ TypeDecl - <- AttrList? KEYWORD_type IDENTIFIER EQUAL TypeBody (* @packed type Vec = struct { ... } *) + <- KEYWORD_type IDENTIFIER EQUAL TypeBody (* @packed type Vec = struct { ... } *) TypeBody <- KEYWORD_struct LBRACE AggregateBody RBRACE @@ -96,22 +95,14 @@ TypeBody AggregateBody <- AggregateItem* AggregateItem - <- MethodDecl (* fn ... *) - / TypeDecl (* type X = ... *) - / VarDecl (* var x: T *) - / ComptimeStmt (* comptime ... *) - / MemberDecl (* IDENTIFIER [: TypeExpr] *) + <- ContainerDeclaration (* struct: 字段, 必须 IDENTIFIER : TypeExpr (语义层检查) union: 联合体字段, 同上 enum: 变体, IDENTIFIER : TypeExpr 或 纯 IDENTIFIER (朴素变体) *) MemberDecl - <- AttrList? IDENTIFIER (COLON TypeExpr)? (COMMA / SEMICOLON)? - -MethodDecl - <- AttrList? KEYWORD_fn IDENTIFIER LPAREN ParamDeclList RPAREN TypeExpr? Block - + <- IDENTIFIER (COLON TypeExpr)? (COMMA / SEMICOLON)? # ================================================================ # 变量 / 常量 @@ -119,12 +110,12 @@ MethodDecl # ================================================================ VarDecl - <- AttrList? KEYWORD_var IDENTIFIER + <- KEYWORD_var IDENTIFIER (COLON TypeExpr / COLON_ASSIGN Expr)? - (EQUAL Expr)? SEMICOLON (* @volatile var flag: i32; *) + (EQUAL Expr)? SEMICOLON (* @volatile var flag: i32; *) ConstDecl - <- AttrList? KEYWORD_const IDENTIFIER + <- KEYWORD_const IDENTIFIER (COLON TypeExpr / COLON_ASSIGN Expr)? EQUAL Expr SEMICOLON @@ -139,6 +130,7 @@ BlockItem <- Statement Statement (* LL(1): 14 分支互斥 *) <- IfStatement + / IfVarStatement / WhileStatement / LoopStatement / ForStatement @@ -153,41 +145,42 @@ Statement (* LL(1): 14 分支互 ExprStatement <- Expr SEMICOLON - -# ---- if ---- +# if else IfStatement - <- KEYWORD_if Expr BlockOrStmt (KEYWORD_else BlockOrStmt)? + <- KEYWORD_if Expr Block ElsePart? -BlockOrStmt <- Block / Statement +IfVarStatement + <- KEYWORD_if KEYWORD_var DOT IDENTIFIER (LBRACKET IDENTIFIER RBRACKET)? EQUAL Expr + Block ElsePart? +ElsePart + <- KEYWORD_else ( Block (* else { ... } *) + / IfStatement (* else if ... *) + / IfVarStatement (* else if var ... *) + ) # ---- while / loop / for ---- -WhileStatement <- KEYWORD_while Expr BlockOrStmt +WhileStatement <- KEYWORD_while Expr Block -LoopStatement <- KEYWORD_loop BlockOrStmt +LoopStatement <- KEYWORD_loop Block ForStatement - <- KEYWORD_for Expr (COMMA Expr)* KEYWORD_as IDENTIFIER (COMMA IDENTIFIER)* BlockOrStmt + <- KEYWORD_for Expr (COMMA Expr)* KEYWORD_as + IDENTIFIER (COMMA IDENTIFIER)* Block # ---- match ---- MatchStatement <- KEYWORD_match Expr LBRACE MatchArm* RBRACE MatchArm - <- MatchPat (COMMA MatchPat)* FAT_ARROW Statement - / UNDERSCORE FAT_ARROW Statement - -MatchPat (* LL(1): . / _ / Expr *) - <- DOT IDENTIFIER BindSpec? - / Expr - -BindSpec - <- LBRACKET IDENTIFIER RBRACKET - / LBRACKET DOT IDENTIFIER EQUAL IDENTIFIER - (COMMA DOT IDENTIFIER EQUAL IDENTIFIER)* RBRACKET + <- MatchPat FAT_R_ARROW Statement + / UNDERSCORE FAT_R_ARROW Statement +MatchPat (* LL(1): . / _ / Expr *) + <- DOT IDENTIFIER (LBRACKET IDENTIFIER RBRACKET)? (* 仅允许 .Item 或 .Item[bind] *) + / Expr (* 字面量或变量常量 *) # ---- 跳转 ---- @@ -198,7 +191,7 @@ ContinueStatement <- KEYWORD_continue SEMICOLON # ---- defer ---- -DeferStatement <- KEYWORD_defer BlockOrStmt +DeferStatement <- KEYWORD_defer (Block / Statement) # ================================================================ @@ -215,16 +208,11 @@ BitXorExpr <- BitAndExpr (CARET BitAndExpr)* BitAndExpr <- CmpEqExpr (AMPERSAND CmpEqExpr)* CmpEqExpr <- CmpExpr ((EQ_EQ / BANG_EQUAL) CmpExpr)* CmpExpr <- RangeExpr ((L_ARROW / L_ARROW_EQ / R_ARROW / R_ARROW_EQ) RangeExpr)* - -# 新增 RangeExpr: 支持 a..b 和 a.. RangeExpr <- ShiftExpr (DOT2 ShiftExpr?)? - ShiftExpr <- AddExpr ((L_ARROW2 / R_ARROW2) AddExpr)* AddExpr <- MulExpr ((PLUS / MINUS) MulExpr)* MulExpr <- PrefixExpr ((ASTERISK / SLASH / PERCENT) PrefixExpr)* - PrefixExpr <- PrefixOp* PostfixExpr - PrefixOp <- MINUS / BANG / TILDE / AMPERSAND / ASTERISK @@ -232,12 +220,12 @@ PrefixOp <- MINUS / BANG / TILDE / AMPERSAND / ASTERISK PostfixExpr <- PrimaryExpr - ( LPAREN ExprList RPAREN (* 函数调用 *) - / DOT IDENTIFIER (* 字段/方法 *) - / DOT ASTERISK (* 解引用 *) - / LBRACKET Expr RBRACKET (* 索引 *) - / LBRACKET Expr DOT2 Expr? RBRACKET (* 切片 *) - / KEYWORD_as TypeExpr (* 类型转换 *) + ( LPAREN ExprList RPAREN (* 函数调用 *) + / DOT IDENTIFIER (* 字段/方法 *) + / DOT ASTERISK (* 解引用 *) + / LBRACKET Expr RBRACKET (* 索引 *) + / LBRACKET Expr DOT2 Expr? RBRACKET (* 切片 *) + / KEYWORD_as TypeExpr (* 类型转换 *) )* ExprList <- (Expr COMMA)* Expr? @@ -255,7 +243,7 @@ PrimaryExpr / LPAREN Expr RPAREN / ArrayLiteral / BuiltinExpr - / Block (* 块表达式 *) + / Block (* 块表达式 *) ArrayLiteral <- LBRACKET INTEGER RBRACKET TypeExpr LBRACE ExprList? RBRACE @@ -275,9 +263,9 @@ TypeExpr <- PrefixTypeOp* TypeBase TypeBase <- FnTypeExpr / TypePath -PrefixTypeOp (* LL(1): * / [ *) +PrefixTypeOp (* LL(1): * / [ *) <- ASTERISK - / LBRACKET (RBRACKET / INTEGER RBRACKET) (* [] 或 [N] *) + / LBRACKET (RBRACKET / INTEGER RBRACKET) (* [] 或 [N] *) FnTypeExpr <- KEYWORD_fn LPAREN TypeExprList? RPAREN TypeExpr @@ -285,7 +273,7 @@ TypeExprList <- (TypeExpr COMMA)* TypeExpr? TypePath <- TypeAtom (DOT TypeAtom)* -TypeAtom (* LL(1): 关键词 / IDENTIFIER / _ *) +TypeAtom (* LL(1): 关键词 / IDENTIFIER / _ *) <- KEYWORD_void / KEYWORD_bool / KEYWORD_i8 / KEYWORD_u8 / KEYWORD_i16 / KEYWORD_u16 / KEYWORD_i32 / KEYWORD_u32 / KEYWORD_i64 / KEYWORD_u64 @@ -366,7 +354,8 @@ COMMA <- ',' SEMICOLON <- ';' COLON <- ':' DOT <- '.' DOT2 <- '..' DOT3 <- '...' AT <- '@' SHARP <- '#' -FAT_ARROW <- '=>' +FAT_R_ARROW <- '=>' FAT_D_ARROW <- '<=>' +R_ARROW <- '<-' L_ARROW <- '->' D_ARROW '<->' EQUAL <- '=' COLON_ASSIGN <- ':=' @@ -428,18 +417,18 @@ eof <- !. 零静默原则: 任何可能出错或危险的构造至少产生一条警告,绝无静默通过。严格模式下所有警告视为错误。 -无未定义行为: 所有行为必须完全定义,否则为编译错误(或宽松模式下的警告)。任何不安全操作均需显式标记。 +无未定义行为: 所有行为必须完全定义,否则为编译错误 (或宽松模式下的警告)。任何不安全操作均需显式标记。 内置数据类型: 语言内置区间 a..b 和切片 []T,它们是真实的结构体,拥有明确的内部字段,用于迭代和切片操作。 -## 容器层(文件 = 匿名 struct) +## 容器层 (文件 = 匿名 struct) 文件视为匿名 struct,顶层声明顺序处理。 声明 静态约束 动态语义 FnDecl 名称唯一,签名完整。 仅定义。 TypeDecl 同作用域名称唯一。 定义类型别名或聚合体,编译时解析。 -VarDecl(容器级) var: 必须初始化,类型完整。const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。 +VarDecl (容器级) var: 必须初始化,类型完整。const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。 ConstDecl 必须编译期可求值。 编译期常量。 ComptimeStmt 内部代码全部在编译时执行。 编译时执行,可生成声明。 DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识别指令触发警告/错误。 同左。 @@ -450,7 +439,7 @@ DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识 @name(args) / #name(args): 内置调用,出现在表达式位置。 -语义: 完全由语言版本或库注册决定。当前所有均视为未识别,产生警告(宽松) 或错误(严格)。 +语义: 完全由语言版本或库注册决定。当前所有均视为未识别,产生警告 (宽松) 或错误 (严格)。 ## 函数 text @@ -459,9 +448,9 @@ AttrList? fn IDENTIFIER ( ParamDeclList ) TypeExpr? ( ; | Block ) 返回类型: 省略即 void。仅有 ; 表示外部声明。 -调用: 实参与形参数量、类型必须完全匹配(无隐式可变参数)。 +调用: 实参与形参数量、类型必须完全匹配 (无隐式可变参数)。 -执行: 新作用域 → 形参绑定实参 → 执行 Block → 遇 ret expr 返回(类型匹配),或 void 函数自然结束返回。 +执行: 新作用域 → 形参绑定实参 → 执行 Block → 遇 ret expr 返回 (类型匹配),或 void 函数自然结束返回。 ## 类型声明与聚合体 ### 别名 @@ -475,19 +464,19 @@ type T = TypeExpr — 完全同义。 访问: expr.field。若 expr 是 struct 值,直接取字段;若为指针,自动解引用一层再取字段。多级指针必须连续 .*。 ### union -字段共享内存,直接读取视为不安全。当前版本只允许通过 match 解构读取,且必须穷举所有可能变体(或通配 _)。 +字段共享内存,直接读取视为不安全。当前版本只允许通过 match 解构读取,且必须穷举所有可能变体 (或通配 _)。 ### enum 变体: variant 或 variant : Type。 构造: EnumName.variant 或带 (payload)。 -匹配: match 必须穷举(或含 _),否则编译错误。 +匹配: match 必须穷举 (或含 _),否则编译错误。 ## 变量与常量 var x: T 或 var x := init: 可变量。 -局部变量未初始化: 必须显式标注类型 var x: T;(无 =)。宽松模式警告,严格模式错误。绝不静默。 +局部变量未初始化: 必须显式标注类型 var x: T; (无 =)。宽松模式警告,严格模式错误。绝不静默。 const x: T = expr 或 const x := expr: 不可变量,必须初始化,一次绑定。 @@ -496,7 +485,7 @@ const x: T = expr 或 const x := expr: 不可变量,必须初始化,一次 ## 块与语句 块 { ... } 引入作用域,可为表达式: 尾表达式无分号则块值即其值,否则 void。 -### 控制流(强制大括号体) +### 控制流 (强制大括号体) if if 条件 { ... } [else { ... }] @@ -511,13 +500,13 @@ loop loop { ... }: 无限循环,break 退出。 for -语法(PEG 已定义): +语法 (PEG 已定义): ForRange 是逗号分隔的表达式列表。每个表达式在启动阶段只能是内置可迭代对象: -区间 a..b 或 a..(无右端点): 内置类型 Range,内部字段 begin 和 end(end 可为 none 表示无界)。迭代产生从 begin 开始递增的整数,直到 end(不含)。若为 a..,则产生无界序列。 +区间 a..b 或 a.. (无右端点): 内置类型 Range,内部字段 begin 和 end (end 可为 none 表示无界)。迭代产生从 begin 开始递增的整数,直到 end (不含)。若为 a..,则产生无界序列。 -切片/数组 expr(类型为 []T 或 [N]T): 内置切片类型,内部结构为 ptr: *T, len: usize。迭代依次产生每个元素,类型为 T。 +切片/数组 expr (类型为 []T 或 [N]T): 内置切片类型,内部结构为 ptr: *T, len: usize。迭代依次产生每个元素,类型为 T。 语义: @@ -527,7 +516,7 @@ as 后的变量列表长度必须等于 n,否则编译错误。 每个 Ei 必须是上述内置可迭代对象,否则编译错误。 -并行迭代: 每次迭代从每个 Ei 中各自取出一个值,按顺序绑定到对应变量(只读,作用域在循环体内)。 +并行迭代: 每次迭代从每个 Ei 中各自取出一个值,按顺序绑定到对应变量 (只读,作用域在循环体内)。 循环继续直到任意一个序列耗尽。若序列长度不同,最短的耗尽时循环停止,忽略其余序列剩余元素。 @@ -535,13 +524,13 @@ as 后的变量列表长度必须等于 n,否则编译错误。 长度协调: -区间 a..b 具有确定长度 b - a(若 b >= a,否则为 0)。 +区间 a..b 具有确定长度 b - a (若 b >= a,否则为 0)。 切片 []T 的长度由其 len 字段确定。 区间 a.. 无界,其长度由循环中其他序列的最短长度决定。例如 for my_slice, 0.. as elem, idx 中,0.. 将提供与 my_slice 等长的索引序列,因为循环在 my_slice 耗尽时终止。实际上 0.. 等价于 0..my_slice.len。 -若循环中只有无界序列而没有有限序列,则循环无限进行(此时需 loop 替代,但语言仍接受)。 +若循环中只有无界序列而没有有限序列,则循环无限进行 (此时需 loop 替代,但语言仍接受)。 示例: // 单区间 @@ -550,7 +539,7 @@ for 0..5 as i { ... } // i: 0,1,2,3,4 // 单切片 for my_slice as elem { ... } -// 切片 + 索引(用户显式提供从0开始的区间) +// 切片 + 索引 (用户显式提供从0开始的区间) for my_slice, 0.. as elem, idx { ... } // idx 与 elem 一一对应 // 两个等长切片 @@ -562,7 +551,7 @@ for my_slice, 0.. as elem // 双序列却只有一个变量 match 用于枚举或 union。 -臂: .variant [bind] => { ... },bind 仅支持 [id](绑定整个载荷)。 +臂: .variant [bind] => { ... },bind 仅支持 [id] (绑定整个载荷)。 必须穷举或含 _,否则编译错误。 @@ -623,7 +612,7 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量 ## 类型表达式 基础类型: void, bool, 整数/浮点类型。 -指针: *T, *_(任意指针),[N]T(数组),[]T(切片)。 +指针: *T, *_ (任意指针),[N]T (数组),[]T (切片)。 函数类型: fn(T1, T2) RetType。 @@ -647,13 +636,13 @@ null → ?T。 区间类型 Range 语法 a..b 或 a..。 -内部结构: { begin: i64, end: ?i64 }(具体整数类型可能由上下文决定,默认为 i64)。 +内部结构: { begin: i64, end: ?i64 } (具体整数类型可能由上下文决定,默认为 i64)。 a..b: begin = a, end = b。 a..: begin = a, end = null。 -用作迭代器时: 产生从 begin 到 end-1 的整数(若 end 为 null 则无穷)。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界(等于 0..other.len),如果配对序列也是无界则无限循环。 +用作迭代器时: 产生从 begin 到 end-1 的整数 (若 end 为 null 则无穷)。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界 (等于 0..other.len),如果配对序列也是无界则无限循环。 切片类型 []T 内部结构: { ptr: *T, len: usize }。 @@ -681,17 +670,17 @@ a..: begin = a, end = null。 所有内置类型的内部表示与分类 -类型兼容性与隐式转换规则(附警告/错误表格) +类型兼容性与隐式转换规则 (附警告/错误表格) -表达式与语句的类型推导/检查规则(伪代码) +表达式与语句的类型推导/检查规则 (伪代码) -特殊类型的处理(指针、区间、切片等) +特殊类型的处理 (指针、区间、切片等) 原则: 所有可能不安全或信息丢失的隐式转换均产生警告;不允许静默转换。最终严格模式下警告将变为错误。 ## 内置基础类型 ### 整数类型 -类型 大小(位) 表示 对齐 +类型 大小 (位) 表示 对齐 i8, u8 8 二进制补码 / 无符号 1 字节 i16, u16 16 同上 2 字节 i32, u32 32 同上 4 字节 @@ -721,7 +710,7 @@ void: 大小为 0,表示无值,仅用于函数返回或指针。 ### 数组类型 [N]T: 固定长度数组,长度为编译期常量 N,元素类型 T。连续内存布局,大小 = N * sizeof(T)。 -数组可隐式转换为切片(见隐式转换)。 +数组可隐式转换为切片 (见隐式转换)。 ### 切片类型 []T: 切片,内部结构 { ptr: *T, len: usize }。值类型同聚合类型行为。 @@ -735,7 +724,7 @@ a..b 或 a..: 类型为 Range,内部结构 { begin: isize, end: ?isize }。 a..b: end 为 b。 -a..: end 为 null(无界)。 +a..: end 为 null (无界)。 Range 是值类型同聚合类型行为。 @@ -744,23 +733,23 @@ Range 是值类型同聚合类型行为。 ### 函数类型 fn(参数类型列表) 返回类型 -函数值本身的大小和表示未指定(闭包待定),但函数名作为标识符使用时具有指针语义(类似函数指针)。 +函数值本身的大小和表示未指定 (闭包待定),但函数名作为标识符使用时具有指针语义 (类似函数指针)。 ### 可选类型(暂时不需要实现) -?T: 可为 null 的类型。内部表示同 T 但附加一个判别(可能通过 null 指针表示,视 T 而定)。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式(具体实现定义)。 +?T: 可为 null 的类型。内部表示同 T 但附加一个判别 (可能通过 null 指针表示,视 T 而定)。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式 (具体实现定义)。 null 字面量只能出现在需要 ?T 的上下文中。 ### 自定义聚合类型 -struct: 字段连续排列(可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。 +struct: 字段连续排列 (可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。 -union: 所有字段共享起始地址,大小等于最大字段(加上对齐)。直接字段读取被视为不安全,需通过 match 解构。 +union: 所有字段共享起始地址,大小等于最大字段 (加上对齐)。直接字段读取被视为不安全,需通过 match 解构。 enum: 带标签的联合体,每个变体可有载荷。大小实现定义,但需容纳判别式及最大载荷。 ## 类型分类 -### 值类型(复制语义) -所有基本标量类型,或者说底层寄存器类型(整数、浮点、bool) +### 值类型 (复制语义) +所有基本标量类型,或者说底层寄存器类型 (整数、浮点、bool) struct @@ -775,7 +764,7 @@ struct ### 引用/指针类型 \*T、\*_ -函数指针(内部类似 \*const fn(...)) +函数指针 (内部类似 \*const fn(...)) ### 特殊类型 void: 无法实例化,仅用于返回或指针目标。 @@ -786,17 +775,17 @@ null: 不是独立类型,仅用于初始化或赋值给 ?T。 下表中,“允许”表示可自动转换,否则需要显式 as 转换。警告列表明编译器必须输出诊断信息,不可静默。 源类型 目标类型 允许? 警告? 备注 -T(任意) T 是 无 相同类型 +T (任意) T 是 无 相同类型 *T *_ 是 警告: “丢失类型信息” *_ *T 是 警告: “不安全的指针重解释” [N]T []T 是 无 数组到切片强制转换 -整数字面量 整数类型 U 是(若值在 U 范围内) 无 字面量自动拓宽 +整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽 i32 i64 否 — 需显式 as i64,防止意外 i64 i32 否 — 窄化必须显式 null ?T 是 无 空值初始化 -?T T 否 — 需显式解包(如 orelse,但语言暂未定义,将来扩展) +?T T 否 — 需显式解包 (如 orelse,但语言暂未定义,将来扩展) T ?T 是 无 提升为可选 -浮点字面量 f32 是(值可表示则) 无 +浮点字面量 f32 是 (值可表示则) 无 f64 f32 否 — 窄化需显式 bool 整数 否 — 整数 bool 否 — @@ -805,7 +794,7 @@ bool 整数 否 — 隐式转换不会嵌套传递。例如 *T 到 *_ 是警告转换,但不因此进一步允许 *_ 到 **T 的隐式转换。 -字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文(如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize)。 +字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize)。 所有其他未列出的类型转换均需显式 as。 @@ -821,7 +810,7 @@ true / false → bool null → 必须从上下文推导出 ?T,无法推导则报错。 -字符串字面量 → []u8(具体待定) +字符串字面量 → []u8 (具体待定) ### 二元运算 算术 e1 + e2、-、*、/、%: @@ -830,7 +819,7 @@ null → 必须从上下文推导出 ?T,无法推导则报错。 t1 = type(e1), t2 = type(e2) 若 t1 == t2 且 t1 ∈ 数值类型: 返回 t1 -否则若 t1 和 t2 为整数且其中一个是字面量(类型为 i32 或可拓宽): +否则若 t1 和 t2 为整数且其中一个是字面量 (类型为 i32 或可拓宽): 返回 max(t1, t2) // 字面量拓宽 否则: 错误 "类型不匹配" @@ -839,7 +828,7 @@ t1 = type(e1), t2 = type(e2) ```text t1 = type(e1), t2 = type(e2) -若 t1 和 t2 兼容(相同或允许隐式转换): +若 t1 和 t2 兼容 (相同或允许隐式转换): 返回 bool 否则: 错误 @@ -862,8 +851,8 @@ t1 = type(e1), t2 = type(e2) ~e: e 必须为整数,结果同类型。 -&e: e 必须为可寻址左值(变量、字段、*解引用等)。若 e 类型为 T,结果为 *T。 -注意: 没有 * 前缀运算符(解引用仅后缀 .*)。 +&e: e 必须为可寻址左值 (变量、字段、*解引用等)。若 e 类型为 T,结果为 *T。 +注意: 没有 * 前缀运算符 (解引用仅后缀 .*)。 ### 后缀运算 e.\*: 要求 e 类型为 \*T,结果为 T,且作为左值。 @@ -878,19 +867,19 @@ e.field: e[i]: -e 类型为 [N]T 或 []T 或 *T(视为指向单个元素或数组起始),i 为整数。结果为 T 左值。 +e 类型为 [N]T 或 []T 或 *T (视为指向单个元素或数组起始),i 为整数。结果为 T 左值。 e[a..b]: -e 类型为 [N]T 或 []T,a 和 b 为整数(可省略 b)。结果为 []T。 +e 类型为 [N]T 或 []T,a 和 b 为整数 (可省略 b)。结果为 []T。 e(args): -e 类型必须为函数类型 fn(T1, T2, ...) Ret。实参类型须与形参兼容(允许隐式转换)。结果为 Ret。 +e 类型必须为函数类型 fn(T1, T2, ...) Ret。实参类型须与形参兼容 (允许隐式转换)。结果为 Ret。 e as Type: -要求源类型与目标类型间存在合法显式转换(包括整数窄化、指针转换等)。结果为 Type。 +要求源类型与目标类型间存在合法显式转换 (包括整数窄化、指针转换等)。结果为 Type。 ### 主要表达式 标识符: 查找作用域,返回其声明类型。 @@ -905,7 +894,7 @@ Type 必须是 struct 类型。检查字段数量是否齐全,每个 ei 类型 comptime e: e 必须在编译时可求值,类型同 e。 -内置调用 @id(args) / #id(args): 未定义则警告/错误(按模式),否则行为由对应内置定义决定。 +内置调用 @id(args) / #id(args): 未定义则警告/错误 (按模式),否则行为由对应内置定义决定。 ## 语句类型规则 ### 变量声明 @@ -913,7 +902,7 @@ var x: T = e;: e 的类型必须兼容 T。x 获得类型 T,可变。 var x := e;: 推导类型为 e 的类型,x 可变。 -var x: T;: 无初始化,x 具有类型 T。警告(宽松模式)或错误(严格模式)。不可用于 const。 +var x: T;: 无初始化,x 具有类型 T。警告 (宽松模式)或错误 (严格模式)。不可用于 const。 const x: T = e;: 同上兼容性,x 不可变。 @@ -923,15 +912,15 @@ const x := e;: 推导类型,不可变。 x = e;: x 必须是可变变量,e 的类型兼容 x 的类型。 ### 控制流 -if cond { ... } else { ... }: cond 必须为 bool。若 if 用作表达式,两分支块的类型必须相同(或均为 void)。 +if cond { ... } else { ... }: cond 必须为 bool。若 if 用作表达式,两分支块的类型必须相同 (或均为 void)。 while cond { ... }: cond 必须为 bool。 loop { ... }: 无类型限制。 -for range_list as var_list { ... }(见下节)。 +for range_list as var_list { ... } (见下节)。 -match e { arms }: e 的类型为枚举或 union。每个模式臂的类型(若 match 用作表达式)必须一致。必须穷举。 +match e { arms }: e 的类型为枚举或 union。每个模式臂的类型 (若 match 用作表达式)必须一致。必须穷举。 ### for 循环详细类型规则 语法: for E1, E2, ... as v1, v2, ... { ... } @@ -940,25 +929,25 @@ ForRange 提供表达式列表 [E1, E2, ...]。as 后标识符列表 [v1, v2, .. 如果动态类型动态长度,则警告具体行为待定,整个语法待定,下面将是暂时语法。 ``` -每个 Ei 的类型必须为内置可迭代类型(当前启动阶段仅包括 Range 和 []T / [N]T)。若 Ei 的类型不是这两者之一,编译错误。 +每个 Ei 的类型必须为内置可迭代类型 (当前启动阶段仅包括 Range 和 []T / [N]T)。若 Ei 的类型不是这两者之一,编译错误。 对于 Ei: -若为 Range: 每次迭代产出的值类型为 isize(Range 的边界类型,这里默认为 isize)。 +若为 Range: 每次迭代产出的值类型为 isize (Range 的边界类型,这里默认为 isize)。 若为 []T 或 [N]T: 产出元素类型为 T。 相应地,vi 被推导为只读变量,其类型为对应 Ei 产出的值类型。 -所有序列的长度必须可静态协调(见下文),否则编译错误(或警告,宽松模式下允许无界)。 +所有序列的长度必须可静态协调 (见下文),否则编译错误 (或警告,宽松模式下允许无界)。 长度协调规则: -若所有序列均为有界(Range 有 end 不为 null,或切片长度已知),则循环次数为最短长度。 +若所有序列均为有界 (Range 有 end 不为 null,或切片长度已知),则循环次数为最短长度。 -若存在无界 Range(如 0..),则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx,0.. 的长度由 slice.len 决定。 +若存在无界 Range (如 0..),则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx,0.. 的长度由 slice.len 决定。 -若只有无界序列,则为无限循环(合法,但通常应使用 loop)。 +若只有无界序列,则为无限循环 (合法,但通常应使用 loop)。 ``` 示例: @@ -968,7 +957,7 @@ for my_slice, 0.. as elem, idx { ... } // 0..: Range 无界 → idx: i64,长度由 my_slice 决定 ``` ## 类型系统限制 -无隐式类型提升(除字面量整数拓宽和数组到切片外)。 +无隐式类型提升 (除字面量整数拓宽和数组到切片外)。 无默认初始化: var x: T; 不初始化,警告/错误。 @@ -992,9 +981,9 @@ ABI 剥离:跨函数调用和返回统一由 @abi.call / @abi.ret 封装,内 ## 词法前缀与语义 前缀 语义 示例 @ 全局函数名、类型名、内置函数调用 @main, @Vec2, @arith.add -% 局部变量(虚拟寄存器) %sum, %ptr +% 局部变量 (虚拟寄存器) %sum, %ptr \# 基本块标签 \#entry, \#loop_body -! 编译/链接标记(元数据) !export("C"), !section(".text") +! 编译/链接标记 (元数据) !export("C"), !section(".text") 词法成本极低:最多两字符即可区分所有实体,无需长关键字。 语义完全解耦: @@ -1029,8 +1018,6 @@ Stmt ← VarDef ';' VarDef ← LOCAL_IDENT '=' Expr // 严格 SSA 单次定义 CallStmt ← Expr // 忽略返回值 -Branch ← 'br' LOCAL_IDENT ',' LABEL ',' LABEL -Return ← 'ret' (LOCAL_IDENT | CONSTANT)? ';' Label ← LABEL ':' Expr ← CallExpr | LOCAL_IDENT | CONSTANT @@ -1058,13 +1045,13 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine ## 内置函数库 ## 验证规则约束 -单一定值:每个 %name 在其函数内只被赋值一次(%x = … 或作为参数),且使用前必须支配所有使用点。 +单一定值:每个 %name 在其函数内只被赋值一次 (%x = … 或作为参数),且使用前必须支配所有使用点。 类型匹配:@arith.add(i32)(%a, %b) 要求 %a 和 %b 的类型都是 i32 绝对的类型匹配。 块终止:每个基本块以 br 或 ret 结束,目标 #label 必须在当前函数内存在。 -函数存在性:所有调用的 @ 函数(如 @arith.add)必须来自库。 +函数存在性:所有调用的 @ 函数 (如 @arith.add)必须来自库。 ## 完整内置函数库 (@ 调用) ### 算术运算 @@ -1074,8 +1061,8 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine @arith.add(T)(%a:T, %b:T) -> T 加法 @arith.sub(T)(%a:T, %b:T) -> T 减法 @arith.mul(T)(%a:T, %b:T) -> T 乘法 -@arith.div(T)(%a:T, %b:T) -> T 除法(整数截断向零,浮点为 IEEE 除法) -@arith.rem(T)(%a:T, %b:T) -> T 取余(仅整数,符号跟随被除数) +@arith.div(T)(%a:T, %b:T) -> T 除法 (整数截断向零,浮点为 IEEE 除法) +@arith.rem(T)(%a:T, %b:T) -> T 取余 (仅整数,符号跟随被除数) @arith.neg(T)(%a:T) -> T 取负 @arith.abs(T)(%a:T) -> T 绝对值 ### 位运算 @@ -1085,8 +1072,8 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine @arith.and(T)(%a:T, %b:T) -> T 按位与 @arith.or(T)(%a:T, %b:T) -> T 按位或 @arith.xor(T)(%a:T, %b:T) -> T 按位异或 -@arith.shl(T)(%a:T, %b:T) -> T 左移,%b 为移位量(类型同 T) -@arith.shr(T)(%a:T, %b:T) -> T 右移(算术或逻辑由 T 的有无符号决定) +@arith.shl(T)(%a:T, %b:T) -> T 左移,%b 为移位量 (类型同 T) +@arith.shr(T)(%a:T, %b:T) -> T 右移 (算术或逻辑由 T 的有无符号决定) @arith.not(T)(%a:T) -> T 按位取反 ### 比较运算 操作数类型 T 必须一致,返回 bool。 @@ -1094,7 +1081,7 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine 函数签名 说明 @cmp.eq(T)(%a:T, %b:T) -> bool 相等 @cmp.ne(T)(%a:T, %b:T) -> bool 不等 -@cmp.lt(T)(%a:T, %b:T) -> bool 小于(有符号/无符号根据 T) +@cmp.lt(T)(%a:T, %b:T) -> bool 小于 (有符号/无符号根据 T) @cmp.le(T)(%a:T, %b:T) -> bool 小于等于 @cmp.gt(T)(%a:T, %b:T) -> bool 大于 @cmp.ge(T)(%a:T, %b:T) -> bool 大于等于 @@ -1105,60 +1092,71 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine @cast.sext(SRC_T, DST_T)(%a:SRC_T) -> DST_T 有符号扩展整数 @cast.fext(SRC_T, DST_T)(%a:SRC_T) -> DST_T 浮点扩展 @cast.ftrunc(SRC_T, DST_T)(%a:SRC_T) -> DST_T 浮点截断 -@cast.bitcast(SRC_T, DST_T)(%a:SRC_T) -> DST_T 位模式重解释(类型大小必须相等) -@cast.ptrtoint(P_T, INT_T)(%ptr:P_T) -> INT_T 指针到整数 -@cast.inttoptr(INT_T, P_T)(%val:INT_T) -> P_T 整数到指针 -@cast.bool_to_int(INT_T)(%cond:bool) -> INT_T 布尔转整数(true->1, false->0) +@cast.bitcast(SRC_T, DST_T)(%a:SRC_T) -> DST_T 位模式重解释 (类型大小必须相等) +@cast.ptr2int(P_T, INT_T)(%ptr:P_T) -> INT_T 指针到整数 +@cast.int2ptr(INT_T, P_T)(%val:INT_T) -> P_T 整数到指针 +@case.int2float(INT_T, F_T)(%val:INT_T) -> F_T 整数到浮点数 +@case.float2int(F_T, INT_T)(%val:F_T) -> INT_T 浮点数到整数 +@cast.bool2int(INT_T)(%cond:bool) -> INT_T 布尔转整数 (true->1, false->0) ### 内存操作 函数签名 说明 -@mem.alloca(T)(%count:i32) -> ptr 栈上分配 %count * sizeof(T) 字节,返回对齐的指针 +@mem.alloca(T)(%count:usize) -> ptr 栈上分配 %count * sizeof(T) 字节,返回对齐的指针 @mem.load(T)(%ptr:ptr) -> T 从内存加载类型为 T 的值 @mem.store(T)(%ptr:ptr, %val:T) 存储值到内存 -@mem.offset(T)(%ptr:ptr, %offset:i32) -> ptr 指针算术,以 sizeof(T) 为单位偏移 -@mem.copy(%dst:ptr, %src:ptr, %size:i32) 内存块复制 -@mem.set(%dst:ptr, %val:u8, %size:i32) 内存块填充 -@mem.fence(%ordering:u32) 内存屏障(见原子操作节) +@mem.offset(T)(%ptr:ptr, %offset:isize) -> ptr 指针算术,以 sizeof(T) 为单位偏移 +@mem.copy(%dst:ptr, %src:ptr, %size:usize) 内存块复制 +@mem.set(%dst:ptr, %val:u8, %size:usize) 内存块填充 +@mem.fence(%ordering:isize) 内存屏障 (见原子操作节) ### 类型信息查询 所有查询在编译期求值,返回整数。 函数签名 说明 -@type.sizeof(T)() -> i32 返回类型 T 的字节大小 -@type.alignof(T)() -> i32 返回类型 T 的对齐要求 -@type.offsetof(T)(%field_index:i32) -> i32 聚合类型 T 中第 field_index 个字段的字节偏移(字段从0编号) -@type.field_count(T)() -> i32 返回聚合类型的字段数量 +@type.const(T)(LITERAL) -> T LITERAL是源语言层面的字面量表示 +@type.bitsizeof(T)() -> usize 返回类型 T 的位大小 +@type.sizeof(T)() -> usize 返回类型 T 的字节大小 +@type.alignof(T)() -> usize 返回类型 T 的对齐要求 +@type.offsetof(T)(%field_index:usize) -> usize 聚合类型 T 中第 field_index 个字段的字节偏移 (字段从0编号) +@type.field_count(T)() -> usize 返回聚合类型的字段数量 ### 聚合类型操作 函数签名 说明 -@agg.extract(T, FIELD_INDEX)(%val:T) -> FIELD_T 从 struct 中提取第 FIELD_INDEX 个字段(常量索引) -@agg.insert(T, FIELD_INDEX)(%agg:T, %field:FIELD_T) -> T 替换 struct 中指定字段,返回新 struct -@agg.extract_union(T, FIELD_IDENT)(%val:T) -> FIELD_T 从 union 中读取指定字段(需确保当前活跃) -@agg.insert_union(T, FIELD_IDENT)(%payload:FIELD_T) -> T 创建 union 值,将载荷写入指定字段 -### ABI 调用接口 -用于跨函数边界,封装调用约定。 +@agg.construct(T)(%f1: T1, %f2: T2, ...) -> T 从各个字段值构造一个结构体/联合体值。T 为具体的聚合类型。 +- 参数个数必须等于类型 T 的字段总数。 +- 每个参数的类型必须与对应字段的类型精确匹配 (无隐式转换)。 +- 适用于 struct 和 union。对于 union,参数只能有一个 (因为只有一个活跃字段),该参数类型必须与某个字段类型兼容 (见联合体处理)。 -函数签名 说明 -@abi.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fn,FT 为 fnret_type> -@abi.ret(T)(%val?) 按目标平台调用约定从当前函数返回,T 为返回值类型,void 时不带参数 -内部函数若未使用 !export 标记,可自由使用直接 ret 指令而不经过 @abi.ret,此时编译器可完全自定义内部调用协议。 +@agg.extract(T, FIELD_INDEX)(%val:T) -> FIELD_T 从聚合值中提取指定索引的字段。FIELD_INDEX 为编译期常量。 +- FIELD_INDEX 必须为非负整数常量,小于类型 T 的字段数。 +- 对于 struct:返回对应字段的值,类型为字段声明类型。 +- 对于 union:由于所有字段共享存储,允许用任意有效字段索引提取,返回值类型为对应字段声明类型。这本身已包含“按不同类型解读同一块存储”的语义,无需额外的 bitcast (但也可结合 @cast.bitcast 使用)。 + +@agg.insert(T, FIELD_INDEX)(%agg:T, %field:FIELD_T) -> T 替换聚合值中指定字段,返回新值 (不可变更新)。T 必须为 struct。 +- 仅适用于 struct 类型。union 是不可变更新无意义 (因为只有一个活跃字段,应使用 construct 重新创建)。 +- FIELD_INDEX 为合法字段索引,%field 类型必须与该字段类型一致。 +- 返回的 T 值其他字段保持不变。 ### 原子操作(可选,现在不实现) -原子操作需要一个 ordering 参数,类型为 u32,使用常量表示内存顺序(可参照 C11 内存模型定义,例如 0=relaxed, 1=acquire, 2=release, 3=acq_rel, 4=seq_cst)。 +原子操作需要一个 ordering 参数,类型为 u32,使用常量表示内存顺序 (可参照 C11 内存模型定义,例如 0=relaxed, 1=acquire, 2=release, 3=acq_rel, 4=seq_cst) 函数签名 说明 @atomic.load(T)(%ptr:ptr, %ordering:u32) -> T 原子加载 @atomic.store(T)(%ptr:ptr, %val:T, %ordering:u32) 原子存储 -@atomic.rmw_add(T)(%ptr:ptr, %val:T, %ordering:u32) -> T 原子交换加(返回旧值) +@atomic.rmw_add(T)(%ptr:ptr, %val:T, %ordering:u32) -> T 原子交换加 (返回旧值) @atomic.rmw_sub(T)(%ptr:ptr, %val:T, %ordering:u32) -> T 原子交换减 @atomic.rmw_and(T), or, xor, xchg 等类似 -@atomic.cmpxchg(T)(%ptr:ptr, %expected:T, %desired:T, %ordering_success:u32, %ordering_failure:u32) -> {old:T, ok:bool} 原子比较交换,返回旧值和成功标志(通过 struct 返回) -### 控制流扩展(间接跳转、选择) +@atomic.cmpxchg(T)(%ptr:ptr, %expected:T, %desired:T, %ordering_success:u32, %ordering_failure:u32) -> {old:T, ok:bool} 原子比较交换,返回旧值和成功标志 (通过 struct 返回) +### 控制流扩展 (间接跳转、选择) 函数签名 说明 -@control.select(T)(%cond:bool, %true_val:T, %false_val:T) -> T 选择操作(无分支,类似三元运算符) -@control.unreachable() -> void 标记不可达代码 -@control.trap() -> void 触发运行时陷阱 +@control.select(T)(%cond:bool, %true_val:T, %false_val:T) -> T 选择操作 (无分支,类似三元运算符) +@control.br(bool, label, label) -> ! 条件分支:根据第一个参数跳转到第二或第三个(标签或者地址)。终止函数 (调用后控制流不返回)。 +@control.jmp(label) -> ! 无条件跳转(跳转到标签或者地址)。终止函数。 +@control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fn,FT 为 fnret_type> +@control.ret(T)(%val?) 按目标平台调用约定从当前函数返回,T 为返回值类型,void 时不带参数 +@control.unreachable() -> ! 标记不可达代码 +@control.trap() -> ! 触发运行时陷阱 ### 调试与内省 函数签名 说明 @dbg.breakpoint() 插入调试断点 -@dbg.declare(%var:%) 声明局部变量的调试信息(可被后端忽略) +@dbg.declare(%var:%) 声明局部变量的调试信息 (可被后端忽略) ## 完整标记系统 (! 前缀) 标记附加在函数定义前,用逗号分隔。所有标记均不影响 IR 控制流语义,仅向后端传递元数据。 @@ -1172,4 +1170,3 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine !naked — 无函数序言/尾声 中断向量、系统调用包装 !noinline — 禁止内联 调试或特殊性能需求 !alwaysinline — 总是内联 简单的包装函数 - diff --git a/stage0/include/color.h b/stage0/include/color.h new file mode 100644 index 0000000..61432b3 --- /dev/null +++ b/stage0/include/color.h @@ -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__ */ diff --git a/stage0/include/core_map.h b/stage0/include/core_map.h index 84a2bca..5b765e1 100644 --- a/stage0/include/core_map.h +++ b/stage0/include/core_map.h @@ -9,7 +9,8 @@ #ifndef nullptr #define nullptr NULL #endif -typedef size_t usize; +typedef uintptr_t usize; +typedef intptr_t isize; #define MAP_TYPEOF __typeof__ @@ -26,150 +27,147 @@ typedef size_t usize; #define MAP_CMP_INT(a, b) ((a) != (b)) static inline usize map_hash_str(const char *s) { - usize h = 5381; - while (*s) - h = ((h << 5) + h) + (unsigned char)*s++; - return h; + usize h = 5381; + while (*s) + h = ((h << 5) + h) + (unsigned char)*s++; + return h; } #define MAP_HASH_STR map_hash_str #define MAP_CMP_STR strcmp /* ---------- 数据结构宏 ---------- */ -#define MAP_SLOT(key_t, val_t) \ - struct { \ - key_t key; \ - val_t val; \ - char state; \ - } +#define MAP_SLOT(key_t, val_t) \ + struct { \ + key_t key; \ + val_t val; \ + char state; \ + } -#define MAP(key_t, val_t) \ - struct { \ - usize size; \ - usize cap; \ - MAP_SLOT(key_t, val_t) * data; \ - usize (*hash)(key_t); \ - int (*cmp)(key_t, key_t); \ - } +#define MAP(key_t, val_t) \ + struct { \ + usize size; \ + usize cap; \ + MAP_SLOT(key_t, val_t) * data; \ + usize (*hash)(key_t); \ + int (*cmp)(key_t, key_t); \ + } /* ---------- 操作宏 ---------- */ /** 初始化,必须提供哈希和比较函数 */ -#define map_init(map, hash_fn, cmp_fn) \ - do { \ - (map).size = 0; \ - (map).cap = 0; \ - (map).data = nullptr; \ - (map).hash = (hash_fn); \ - (map).cmp = (cmp_fn); \ - } while (0) +#define map_init(map, hash_fn, cmp_fn) \ + do { \ + (map).size = 0; \ + (map).cap = 0; \ + (map).data = nullptr; \ + (map).hash = (hash_fn); \ + (map).cmp = (cmp_fn); \ + } while (0) /** 释放内部数组 */ -#define map_free(map) \ - do { \ - free((map).data); \ - (map).data = nullptr; \ - (map).size = (map).cap = 0; \ - } while (0) +#define map_free(map) \ + do { \ + free((map).data); \ + (map).data = nullptr; \ + (map).size = (map).cap = 0; \ + } while (0) /** 遍历所有有效元素 */ -#define map_for(map, idx) \ - for (usize(idx) = 0; (idx) < (map).cap; ++(idx)) \ - if ((map).data[(idx)].state == __MAP_SLOT_OCCUPIED) +#define map_for(map, idx) \ + for (usize(idx) = 0; (idx) < (map).cap; ++(idx)) \ + if ((map).data[(idx)].state == __MAP_SLOT_OCCUPIED) /** * 插入(若键已存在则更新值) * 注意:扩容使用 realloc,失败会 abort(可自行修改错误处理) */ -#define map_put(map, _key, _val) \ - do { \ - /* 扩容 */ \ - if ((map).cap == 0 || \ - (map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \ - usize new_cap = (map).cap == 0 ? 8 : (map).cap * 2; \ - MAP_SLOT(MAP_TYPEOF((map).data->key), \ - MAP_TYPEOF((map).data->val)) *new_data = \ - calloc(new_cap, sizeof(*new_data)); \ - if (!new_data) \ - abort(); \ - /* 重新插入旧元素 */ \ - for (usize _i = 0; _i < (map).cap; ++_i) { \ - if ((map).data[_i].state == __MAP_SLOT_OCCUPIED) { \ - usize _h = (map).hash((map).data[_i].key) & (new_cap - 1); \ - while (new_data[_h].state == __MAP_SLOT_OCCUPIED) \ - _h = (_h + 1) & (new_cap - 1); \ - new_data[_h].key = (map).data[_i].key; \ - new_data[_h].val = (map).data[_i].val; \ - new_data[_h].state = __MAP_SLOT_OCCUPIED; \ - } \ - } \ - free((map).data); \ - (map).data = (void *)new_data; \ - (map).cap = new_cap; \ - } \ - /* 查找或插入 */ \ - usize _mask = (map).cap - 1; \ - usize _idx = (map).hash(_key) & _mask; \ - usize _first_del = (usize) - 1; \ - while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ - if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ - (map).cmp((map).data[_idx].key, _key) == 0) { \ - (map).data[_idx].val = _val; \ - break; \ - } \ - if ((map).data[_idx].state == __MAP_SLOT_DELETED && \ - _first_del == (usize) - 1) \ - _first_del = _idx; \ - _idx = (_idx + 1) & _mask; \ - } \ - if ((map).data[_idx].state == __MAP_SLOT_EMPTY) { \ - usize _target = (_first_del != (usize) - 1) ? _first_del : _idx; \ - (map).data[_target].key = _key; \ - (map).data[_target].val = _val; \ - (map).data[_target].state = __MAP_SLOT_OCCUPIED; \ - ++(map).size; \ - } \ - } while (0) +#define map_put(map, _key, _val) \ + do { \ + /* 扩容 */ \ + if ((map).cap == 0 || (map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \ + usize new_cap = (map).cap == 0 ? 8 : (map).cap * 2; \ + MAP_SLOT(MAP_TYPEOF((map).data->key), MAP_TYPEOF((map).data->val)) *new_data = \ + calloc(new_cap, sizeof(*new_data)); \ + if (!new_data) \ + abort(); \ + /* 重新插入旧元素 */ \ + for (usize _i = 0; _i < (map).cap; ++_i) { \ + if ((map).data[_i].state == __MAP_SLOT_OCCUPIED) { \ + usize _h = (map).hash((map).data[_i].key) & (new_cap - 1); \ + while (new_data[_h].state == __MAP_SLOT_OCCUPIED) \ + _h = (_h + 1) & (new_cap - 1); \ + new_data[_h].key = (map).data[_i].key; \ + new_data[_h].val = (map).data[_i].val; \ + new_data[_h].state = __MAP_SLOT_OCCUPIED; \ + } \ + } \ + free((map).data); \ + (map).data = (void *)new_data; \ + (map).cap = new_cap; \ + } \ + /* 查找或插入 */ \ + usize _mask = (map).cap - 1; \ + usize _idx = (map).hash(_key) & _mask; \ + usize _first_del = (usize) - 1; \ + while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ + if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ + (map).cmp((map).data[_idx].key, _key) == 0) { \ + (map).data[_idx].val = _val; \ + break; \ + } \ + if ((map).data[_idx].state == __MAP_SLOT_DELETED && _first_del == (usize) - 1) \ + _first_del = _idx; \ + _idx = (_idx + 1) & _mask; \ + } \ + if ((map).data[_idx].state == __MAP_SLOT_EMPTY) { \ + usize _target = (_first_del != (usize) - 1) ? _first_del : _idx; \ + (map).data[_target].key = _key; \ + (map).data[_target].val = _val; \ + (map).data[_target].state = __MAP_SLOT_OCCUPIED; \ + ++(map).size; \ + } \ + } while (0) /** * 查询:若找到,*out_val 被赋值为对应值并返回 1;否则返回 0 */ -#define map_get(map, _key, out_val) \ - (({ \ - int _found = 0; \ - if ((map).cap > 0) { \ - usize _mask = (map).cap - 1; \ - usize _idx = (map).hash(_key) & _mask; \ - while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ - if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ - (map).cmp((map).data[_idx].key, _key) == 0) { \ - *out_val = (map).data[_idx].val; \ - _found = 1; \ - break; \ - } \ - _idx = (_idx + 1) & _mask; \ - } \ - } \ - _found; \ - })) +#define map_get(map, _key, out_val) \ + (({ \ + int _found = 0; \ + if ((map).cap > 0) { \ + usize _mask = (map).cap - 1; \ + usize _idx = (map).hash(_key) & _mask; \ + while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ + if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ + (map).cmp((map).data[_idx].key, _key) == 0) { \ + *out_val = (map).data[_idx].val; \ + _found = 1; \ + break; \ + } \ + _idx = (_idx + 1) & _mask; \ + } \ + } \ + _found; \ + })) /** * 删除指定键 */ -#define map_del(map, _key) \ - do { \ - if ((map).cap == 0) \ - break; \ - usize _mask = (map).cap - 1; \ - usize _idx = (map).hash(_key) & _mask; \ - while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ - if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ - (map).cmp((map).data[_idx].key, _key) == 0) { \ - (map).data[_idx].state = __MAP_SLOT_DELETED; \ - --(map).size; \ - break; \ - } \ - _idx = (_idx + 1) & _mask; \ - } \ - } while (0) +#define map_del(map, _key) \ + do { \ + if ((map).cap == 0) \ + break; \ + usize _mask = (map).cap - 1; \ + usize _idx = (map).hash(_key) & _mask; \ + while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ + if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ + (map).cmp((map).data[_idx].key, _key) == 0) { \ + (map).data[_idx].state = __MAP_SLOT_DELETED; \ + --(map).size; \ + break; \ + } \ + _idx = (_idx + 1) & _mask; \ + } \ + } while (0) #endif /* __CORE_MAP_H__ */ diff --git a/stage0/include/core_vec.h b/stage0/include/core_vec.h index a1d2cb2..8c0c6e2 100644 --- a/stage0/include/core_vec.h +++ b/stage0/include/core_vec.h @@ -18,6 +18,7 @@ #define __vec_free free #define __vec_memcpy memcpy #else +#include #include #include #include @@ -32,11 +33,11 @@ typedef size_t usize; #ifndef LOG_FATAL #include -#define LOG_FATAL(...) \ - do { \ - printf(__VA_ARGS__); \ - abort(); \ - } while (0) +#define LOG_FATAL(...) \ + do { \ + printf(__VA_ARGS__); \ + abort(); \ + } while (0) #endif #ifndef Assert @@ -61,12 +62,12 @@ typedef size_t usize; * struct people { VEC(char) name; int age; VEC(struct people) children; * }; */ -#define VEC(type) \ - struct { \ - usize size; \ - usize cap; \ - type *data; \ - } +#define VEC(type) \ + struct { \ + usize size; \ + usize cap; \ + type *data; \ + } /** @defgroup vec_operations 动态数组操作宏 */ @@ -77,20 +78,20 @@ typedef size_t usize; * * @note 此宏不会分配内存,仅做零初始化 */ -#define vec_init(vec) \ - do { \ - (vec).size = 0, (vec).cap = 0, (vec).data = 0; \ - } while (0) +#define vec_init(vec) \ + do { \ + (vec).size = 0, (vec).cap = 0, (vec).data = 0; \ + } while (0) -#define vec_realloc(vec, new_cap) \ - do { \ - void *data = __vec_realloc((vec).data, new_cap * sizeof(*(vec).data)); \ - if (!data) { \ - LOG_FATAL("vector_push: realloc failed\n"); \ - } \ - (vec).cap = new_cap; \ - (vec).data = data; \ - } while (0) +#define vec_realloc(vec, new_cap) \ + do { \ + void *data = __vec_realloc((vec).data, new_cap * sizeof(*(vec).data)); \ + if (!data) { \ + LOG_FATAL("vector_push: realloc failed\n"); \ + } \ + (vec).cap = new_cap; \ + (vec).data = data; \ + } while (0) #define vec_size(vec) ((vec).size) #define vec_cap(vec) ((vec).cap) @@ -105,15 +106,15 @@ typedef size_t usize; * @note 当容量不足时自动扩容为2倍(初始容量为4) * @warning 内存分配失败时会触发LOG_FATAL */ -#define vec_push(vec, value) \ - do { \ - if ((vec).size >= (vec).cap) { \ - usize cap = (vec).cap ? (vec).cap * 2 : 4; \ - vec_realloc(vec, cap); \ - } \ - Assert((vec).data != nullptr); \ - (vec).data[(vec).size++] = value; \ - } while (0) +#define vec_push(vec, value) \ + do { \ + if ((vec).size >= (vec).cap) { \ + usize cap = (vec).cap ? (vec).cap * 2 : 4; \ + vec_realloc(vec, cap); \ + } \ + Assert((vec).data != nullptr); \ + (vec).data[(vec).size++] = value; \ + } while (0) /** * @def vec_pop(vec) @@ -149,43 +150,43 @@ typedef size_t usize; * * @note 释放后需重新初始化才能再次使用 */ -#define vec_free(vec) \ - do { \ - if ((vec).data == nullptr) \ - break; \ - __vec_free((vec).data); \ - (vec).data = nullptr; \ - (vec).size = (vec).cap = 0; \ - } while (0) +#define vec_free(vec) \ + do { \ + if ((vec).data == nullptr) \ + break; \ + __vec_free((vec).data); \ + (vec).data = nullptr; \ + (vec).size = (vec).cap = 0; \ + } while (0) #define vec_unsafe_get_data(vec) ((vec).data) -#define vec_unsafe_from_buffer(vec, buffer, buffer_size) \ - do { \ - (vec).size = buffer_size; \ - (vec).cap = (vec).size; \ - (vec).data = buffer; \ - } while (0) +#define vec_unsafe_from_buffer(vec, buffer, buffer_size) \ + do { \ + (vec).size = buffer_size; \ + (vec).cap = (vec).size; \ + (vec).data = buffer; \ + } while (0) -#define vec_unsafe_from_static_array(vec, array) \ - do { \ - (vec).size = sizeof(array) / sizeof((array)[0]); \ - (vec).cap = (vec).size; \ - (vec).data = array; \ - } while (0) +#define vec_unsafe_from_static_array(vec, array) \ + do { \ + (vec).size = sizeof(array) / sizeof((array)[0]); \ + (vec).cap = (vec).size; \ + (vec).data = array; \ + } while (0) /** * @def vec_sized_realloc(vec, elem_size, new_cap) * @brief 内部宏:按 elem_size 重新分配内存 */ -#define vec_sized_realloc(vec, elem_size, new_cap) \ - do { \ - void *new_data = __vec_realloc((vec).data, (new_cap) * (elem_size)); \ - if (!new_data) \ - LOG_FATAL("vec_sized_realloc: failed\n"); \ - (vec).data = new_data; \ - (vec).cap = new_cap; \ - } while (0) +#define vec_sized_realloc(vec, elem_size, new_cap) \ + do { \ + void *new_data = __vec_realloc((vec).data, (new_cap) * (elem_size)); \ + if (!new_data) \ + LOG_FATAL("vec_sized_realloc: failed\n"); \ + (vec).data = new_data; \ + (vec).cap = new_cap; \ + } while (0) /** * @def vec_sized_push(vec, elem_size, src_ptr) @@ -198,24 +199,23 @@ typedef size_t usize; * @note 使用前需确保 vec.data 类型与 src_ptr 无关,内部会按字节拷贝。 * 推荐声明时为 `VEC(char)` 或 `VEC(unsigned char)`。 */ -#define vec_sized_push(vec, elem_size, src_ptr, copy_size) \ - do { \ - if ((vec).size >= (vec).cap) { \ - usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \ - vec_sized_realloc(vec, elem_size, new_cap); \ - } \ - char *slot = (char *)(vec).data + (vec).size * (elem_size); \ - __vec_memcpy(slot, (src_ptr), (copy_size)); \ - (vec).size++; \ - } while (0) +#define vec_sized_push(vec, elem_size, src_ptr, copy_size) \ + do { \ + if ((vec).size >= (vec).cap) { \ + usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \ + vec_sized_realloc(vec, elem_size, new_cap); \ + } \ + char *slot = (char *)(vec).data + (vec).size * (elem_size); \ + __vec_memcpy(slot, (src_ptr), (copy_size)); \ + (vec).size++; \ + } while (0) /** * @def vec_sized_at_ptr(vec, elem_size, idx) * @brief 获取第 idx 个元素的指针(void*) * @return 指向元素的指针,需转换为具体类型使用 */ -#define vec_sized_at_ptr(vec, elem_size, idx) \ - ((void *)((char *)(vec).data + (idx) * (elem_size))) +#define vec_sized_at_ptr(vec, elem_size, idx) ((void *)((char *)(vec).data + (idx) * (elem_size))) /** * @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 block 循环体语句块 */ -#define vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \ - do { \ - for (usize __i = 0; __i < (vec).size; ++__i) { \ - void *elem_ptr_var = vec_sized_at_ptr(vec, elem_size, __i); \ - block; \ - } \ - } while (0) +#define vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \ + do { \ + for (usize __i = 0; __i < (vec).size; ++__i) { \ + void *elem_ptr_var = vec_sized_at_ptr(vec, elem_size, __i); \ + block; \ + } \ + } while (0) /** * @def vec_sized_pop(vec, elem_size) * @brief 弹出最后一个元素(仅减小 size,不返回数据) */ -#define vec_sized_pop(vec, elem_size) \ - do { \ - if ((vec).size == 0) \ - LOG_FATAL("vec_sized_pop: empty\n"); \ - (vec).size--; \ - } while (0) +#define vec_sized_pop(vec, elem_size) \ + do { \ + if ((vec).size == 0) \ + LOG_FATAL("vec_sized_pop: empty\n"); \ + (vec).size--; \ + } while (0) /** * @def vec_sized_clear(vec) diff --git a/stage0/include/log.c b/stage0/include/log.c new file mode 100644 index 0000000..d35b68f --- /dev/null +++ b/stage0/include/log.c @@ -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; +} diff --git a/stage0/include/log.h b/stage0/include/log.h new file mode 100644 index 0000000..c827e73 --- /dev/null +++ b/stage0/include/log.h @@ -0,0 +1,193 @@ +/** + * @file log.h + * @brief 日志系统核心模块(支持多级日志、断言和异常处理) + */ + +#ifndef __SCC_LOG_IMPL_H__ +#define __SCC_LOG_IMPL_H__ + +#include "color.h" +#include + +#ifdef __SCC_LOG_IMPL_USE_STD_IMPL__ +#include +#include +#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__ */ diff --git a/stage0/include/utils.h b/stage0/include/utils.h new file mode 100644 index 0000000..0f455ce --- /dev/null +++ b/stage0/include/utils.h @@ -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__ */ diff --git a/stage0/spl_mcode.c b/stage0/spl_mcode.c index e36651b..acb32ce 100644 --- a/stage0/spl_mcode.c +++ b/stage0/spl_mcode.c @@ -370,49 +370,6 @@ int spl_prog_add_data(spl_prog_t *prog, void *ptr, usize size) { 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) { if (!prog || !name) 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_type_tag_name(spl_type_t type) { switch (type) { - case SPL_VOID: return "void"; - case SPL_BOOL: return "bool"; - case SPL_I8: return "i8"; - case SPL_U8: return "u8"; + case SPL_VOID: + return "void"; + case SPL_BOOL: + return "bool"; + case SPL_I8: + return "i8"; + case SPL_U8: + return "u8"; case SPL_I16: return "i16"; case SPL_U16: diff --git a/stage0/spl_mcode.h b/stage0/spl_mcode.h index 3f94dc2..8ac3525 100644 --- a/stage0/spl_mcode.h +++ b/stage0/spl_mcode.h @@ -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_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 */ const char *spl_opcode_name(spl_opcode_t opcode); const char *spl_type_tag_name(spl_type_t type); diff --git a/stage0/test_spl_vm.c b/stage0/test_spl_vm.c index d080d10..7ac03a2 100644 --- a/stage0/test_spl_vm.c +++ b/stage0/test_spl_vm.c @@ -5,7 +5,7 @@ */ #include "include/acutest.h" -#include "spl_ir.h" +#include "spl_mcode.h" #include "spl_vm.h" #include @@ -13,7 +13,7 @@ #include /* ================================================================ - * 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 */ diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c new file mode 100644 index 0000000..c7f71a2 --- /dev/null +++ b/stage1/spl_ast.c @@ -0,0 +1 @@ +#include "spl_ast.h" diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h new file mode 100644 index 0000000..90faf3b --- /dev/null +++ b/stage1/spl_ast.h @@ -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 + +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__ */ diff --git a/stage1/spl_comp.c b/stage1/spl_comp.c deleted file mode 100644 index 57d69b5..0000000 --- a/stage1/spl_comp.c +++ /dev/null @@ -1,264 +0,0 @@ -/* spl_comp.c — SPL compiler main logic and codegen helpers */ - -#include "spl_comp.h" -#include "spl_lex_util.h" -#include -#include -#include - -/* ---- 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; -} diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h deleted file mode 100644 index 9f8d028..0000000 --- a/stage1/spl_comp.h +++ /dev/null @@ -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 -#include -#include -#include - -#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__ */ diff --git a/stage1/spl_emit.c b/stage1/spl_emit.c deleted file mode 100644 index 3b61646..0000000 --- a/stage1/spl_emit.c +++ /dev/null @@ -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 - -/* ============================================================ - * 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; -} diff --git a/stage1/spl_emit.h b/stage1/spl_emit.h deleted file mode 100644 index 2344a83..0000000 --- a/stage1/spl_emit.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef __SPL_EMIT_H__ -#define __SPL_EMIT_H__ - -#include "../stage0/spl_ir.h" -#include "spl_type.h" -#include - -/* ============================================================ - * 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__ */ diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c deleted file mode 100644 index be65dec..0000000 --- a/stage1/spl_expr.c +++ /dev/null @@ -1,1624 +0,0 @@ -#include "spl_comp.h" -#include "spl_lex_util.h" -#include -#include -#include - -static int tok_prec(spl_tok_type_t t) { - switch (t) { - case TOK_OR_OR: - return PREC_LOGOR; - case TOK_AND_AND: - return PREC_LOGAND; - case TOK_OR: - return PREC_OR; - case TOK_XOR: - return PREC_XOR; - case TOK_AND: - return PREC_AND; - case TOK_EQ: - case TOK_NEQ: - return PREC_CMPEQ; - case TOK_LT: - case TOK_LE: - case TOK_GT: - case TOK_GE: - return PREC_CMP; - case TOK_L_SH: - case TOK_R_SH: - return PREC_SHIFT; - case TOK_ADD: - case TOK_SUB: - return PREC_ADD; - case TOK_MUL: - case TOK_DIV: - case TOK_MOD: - return PREC_MUL; - case TOK_ASSIGN: - case TOK_ASSIGN_ADD: - case TOK_ASSIGN_SUB: - case TOK_ASSIGN_MUL: - case TOK_ASSIGN_DIV: - case TOK_ASSIGN_MOD: - case TOK_ASSIGN_AND: - case TOK_ASSIGN_OR: - case TOK_ASSIGN_XOR: - case TOK_ASSIGN_L_SH: - case TOK_ASSIGN_R_SH: - return PREC_ASSIGN; - default: - return PREC_MIN; - } -} - -static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op); -static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, int type_idx); -static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left); - -static void emit_slice_create(spl_comp_t *ctx, usize stride) { - emit_pick(&ctx->emit, 2); - emit_pick(&ctx->emit, 2); - emit_push_u64(&ctx->emit, stride); - emit_mul_u64(&ctx->emit); - emit_add_u64(&ctx->emit); - - emit_pick(&ctx->emit, 1); - emit_pick(&ctx->emit, 3); - emit_sub_usize(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); -} - -static void emit_slice_index(spl_comp_t *ctx, int elem_type_idx) { - usize elem_size = spl_type_elem_stride(&ctx->tctx, elem_type_idx); - emit_swap(&ctx->emit); - emit_load_ptr(&ctx->emit); - emit_swap(&ctx->emit); - emit_push_u64(&ctx->emit, elem_size); - emit_mul_u64(&ctx->emit); - emit_add_u64(&ctx->emit); -} - -static int spl_resolve_type_member(spl_comp_t *ctx, int type_idx, const char *field, - spl_expr_result_t *result) { - if (spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM) { - spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx); - vec_for(*items, i) { - spl_type_item_t *it = &vec_at(*items, i); - if (it->item_kind != ITEM_VARIANT) - continue; - if (strcmp(it->name, field) == 0) { - emit_push_i32(&ctx->emit, it->enum_field.value); - int data_type = it->enum_field.type_idx; - if (data_type >= 0) { - *result = (spl_expr_result_t){data_type, 0}; - } else { - *result = (spl_expr_result_t){type_idx, 0}; - } - return 1; - } - } - } - - const char *type_name = spl_type_name(&ctx->tctx, type_idx); - if (type_name) { - char qualified[512]; - int qlen = snprintf(qualified, sizeof(qualified), "%s.%s", type_name, field); - if (qlen > 0 && (usize)qlen < sizeof(qualified)) { - int nested = spl_type_resolve(&ctx->tctx, qualified); - if (nested >= 0) { - *result = (spl_expr_result_t){nested, 1}; - return 1; - } - } - } - - int nested = spl_type_resolve(&ctx->tctx, field); - if (nested >= 0) { - *result = (spl_expr_result_t){nested, 1}; - return 1; - } - - return 0; -} - -static spl_tok_type_t assign_to_binop(spl_tok_type_t t) { - switch (t) { - case TOK_ASSIGN_ADD: - return TOK_ADD; - case TOK_ASSIGN_SUB: - return TOK_SUB; - case TOK_ASSIGN_MUL: - return TOK_MUL; - case TOK_ASSIGN_DIV: - return TOK_DIV; - case TOK_ASSIGN_MOD: - return TOK_MOD; - case TOK_ASSIGN_AND: - return TOK_AND; - case TOK_ASSIGN_OR: - return TOK_OR; - case TOK_ASSIGN_XOR: - return TOK_XOR; - case TOK_ASSIGN_L_SH: - return TOK_L_SH; - case TOK_ASSIGN_R_SH: - return TOK_R_SH; - default: - return (spl_tok_type_t)-1; - } -} - -static int binop_to_sir(spl_tok_type_t t, spl_type_t bt) { - int is_signed = (bt == SPL_I32 || bt == SPL_I64 || bt == SPL_I8 || bt == SPL_I16); - switch (t) { - case TOK_ADD: - return SPL_ADD; - case TOK_SUB: - return SPL_SUB; - case TOK_MUL: - return SPL_MUL; - case TOK_DIV: - return is_signed ? SPL_DIV_S : SPL_DIV_U; - case TOK_MOD: - return is_signed ? SPL_REM_S : SPL_REM_U; - case TOK_AND: - return SPL_AND; - case TOK_OR: - return SPL_OR; - case TOK_XOR: - return SPL_XOR; - case TOK_L_SH: - return SPL_SHL; - case TOK_R_SH: - return is_signed ? SPL_SHR_S : SPL_SHR_U; - case TOK_EQ: - return SPL_EQ; - case TOK_NEQ: - return SPL_NE; - case TOK_LT: - return is_signed ? SPL_SLT : SPL_ULT; - case TOK_LE: - return is_signed ? SPL_SLE : SPL_ULE; - case TOK_GT: - return is_signed ? SPL_SGT : SPL_UGT; - case TOK_GE: - return is_signed ? SPL_SGE : SPL_UGE; - default: - return -1; - } -} - -static int64_t parse_int(const char *s, usize len) { - char buf[64]; - usize clen = len < 63 ? len : 63; - memcpy(buf, s, clen); - buf[clen] = '\0'; - if (clen > 2 && buf[0] == '0') { - if (buf[1] == 'x' || buf[1] == 'X') - return (int64_t)strtoll(buf, NULL, 16); - if (buf[1] == 'b' || buf[1] == 'B') - return (int64_t)strtoll(buf + 2, NULL, 2); - if (buf[1] == 'o' || buf[1] == 'O') - return (int64_t)strtoll(buf + 2, NULL, 8); - } - return (int64_t)strtoll(buf, NULL, 10); -} - -static spl_expr_result_t parse_int_literal(spl_comp_t *ctx) { - spl_tok_t *t = advance(ctx); - int64_t val = parse_int(t->lexeme, t->len); - emit_push_i32(&ctx->emit, (spl_val_t)val); - spl_expr_result_t r = {spl_type_basic(&ctx->tctx, SPL_I32), 0}; - return r; -} - -static spl_expr_result_t parse_float_literal(spl_comp_t *ctx) { - spl_tok_t *t = advance(ctx); - char buf[64]; - usize clen = t->len < 63 ? t->len : 63; - memcpy(buf, t->lexeme, clen); - buf[clen] = '\0'; - double val = strtod(buf, NULL); - emit_push_f64(&ctx->emit, (spl_val_t)(int64_t)val); - (void)val; - spl_expr_result_t r = {spl_type_basic(&ctx->tctx, SPL_F64), 0}; - return r; -} - -static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) { - spl_tok_t *t = advance(ctx); - const char *s = t->lexeme; - usize l = t->len; - int64_t val = 0; - if (l >= 3) { - if (s[1] == '\\' && l >= 4) { - char buf = 0; - const char *cp = s + 1; - spl_decode_escape(&cp, &buf); - val = (unsigned char)buf; - } else { - val = (unsigned char)s[1]; - } - } - emit_push_i32(&ctx->emit, (spl_val_t)val); - spl_expr_result_t r = {spl_type_basic(&ctx->tctx, SPL_I32), 0}; - return r; -} - -static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) { - spl_tok_t *t = advance(ctx); - usize slen = t->len; - if (slen >= 2) { - slen -= 2; - } - char *decoded = malloc(slen + 1); - usize di = 0; - for (usize i = 1; i + 1 < t->len; i++) { - if (t->lexeme[i] == '\\' && i + 1 < t->len - 1) { - char buf = 0; - const char *cp = t->lexeme + i; - spl_decode_escape(&cp, &buf); - decoded[di++] = buf; - i += (usize)(cp - (t->lexeme + i)) - 1; - } else { - decoded[di++] = t->lexeme[i]; - } - } - decoded[di] = '\0'; - int gdi = spl_add_global_data(ctx, decoded, di + 1); - free(decoded); - emit_gaddr(&ctx->emit, gdi - 1); - spl_expr_result_t r = {spl_type_ptr(&ctx->tctx, spl_type_basic(&ctx->tctx, SPL_U8)), 0}; - return r; -} - -static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) { - advance(ctx); - skip_nl(ctx); - - int len_val; - if (!spl_parse_int_literal(ctx, &len_val)) { - spl_comp_err_tok(ctx, peek(ctx), "expected array length"); - spl_expr_result_t r = {-1, 0}; - return r; - } - usize len = (usize)len_val; - - skip_nl(ctx); - if (!expect(ctx, TOK_R_BRACKET)) { - spl_expr_result_t r = {-1, 0}; - return r; - } - skip_nl(ctx); - - int elem_type_idx = spl_type_parse(&ctx->tctx, ctx); - if (elem_type_idx < 0) { - spl_expr_result_t r = {-1, 0}; - return r; - } - - skip_nl(ctx); - if (!expect(ctx, TOK_L_BRACE)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - skip_nl(ctx); - - for (usize i = 0; i < len; i++) { - if (i > 0) { - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - skip_nl(ctx); - } - spl_parse_expr(ctx, PREC_MIN); - skip_nl(ctx); - } - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - - skip_nl(ctx); - if (!expect(ctx, TOK_R_BRACE)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - - int arr_type_idx = spl_type_array(&ctx->tctx, elem_type_idx, len); - return (spl_expr_result_t){arr_type_idx, 0}; -} - -static void parse_slice_inline(spl_comp_t *ctx) { - advance(ctx); - skip_nl(ctx); - skip_nl(ctx); - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - if (peek(ctx)->type == TOK_DOT) - advance(ctx); - spl_tok_t *ftok = advance(ctx); - char fname[256]; - spl_tok_copy_name(ftok, fname, sizeof(fname)); - skip_nl(ctx); - if (peek(ctx)->type == TOK_ASSIGN) - advance(ctx); - skip_nl(ctx); - - emit_dup(&ctx->emit); - if (strcmp(fname, "ptr") == 0) { - spl_parse_expr(ctx, PREC_MIN); - emit_store_ptr(&ctx->emit); - } else if (strcmp(fname, "len") == 0) { - emit_ptr_add(&ctx->emit, sizeof(spl_val_t)); - spl_parse_expr(ctx, PREC_MIN); - emit_store_usize(&ctx->emit); - } - skip_nl(ctx); - } - if (!expect(ctx, TOK_R_BRACE)) - return; - emit_drop(&ctx->emit); -} - -static void parse_one_field_init(spl_comp_t *ctx, spl_type_item_vec_t *items, int base_offset, - usize extra_offset) { - if (peek(ctx)->type == TOK_DOT) - advance(ctx); - spl_tok_t *ftok = advance(ctx); - char fname[256]; - spl_tok_copy_name(ftok, fname, sizeof(fname)); - skip_nl(ctx); - if (peek(ctx)->type == TOK_ASSIGN) - advance(ctx); - skip_nl(ctx); - - int found = 0; - vec_for(*items, fi) { - spl_type_item_t *it = &vec_at(*items, fi); - if (it->item_kind != ITEM_FIELD) - continue; - if (strcmp(it->name, fname) == 0) { - found = 1; - emit_laddr(&ctx->emit, base_offset); - usize byte_off = extra_offset + it->aggregate_field.offset; - emit_ptr_add(&ctx->emit, byte_off); - int ft_idx = it->aggregate_field.type_idx; - if (ft_idx >= 0 && spl_type_kind(&ctx->tctx, ft_idx) == TYPE_SLICE && - peek(ctx)->type == TOK_L_BRACE) { - parse_slice_inline(ctx); - } else if (ft_idx >= 0 && spl_type_kind(&ctx->tctx, ft_idx) == TYPE_ARRAY && - peek(ctx)->type == TOK_L_BRACKET) { - advance(ctx); - skip_nl(ctx); - int len_val; - if (!spl_parse_int_literal(ctx, &len_val)) { - spl_comp_err_tok(ctx, peek(ctx), "expected array length"); - return; - } - usize arr_len = (usize)len_val; - skip_nl(ctx); - if (!expect(ctx, TOK_R_BRACKET)) - return; - skip_nl(ctx); - int elem_type_idx = spl_type_elem_type(&ctx->tctx, ft_idx); - if (!expect(ctx, TOK_L_BRACE)) - return; - skip_nl(ctx); - usize stride = spl_type_elem_stride(&ctx->tctx, elem_type_idx); - spl_type_t st = spl_type_emit_type(&ctx->tctx, elem_type_idx); - for (usize i = 0; i < arr_len; i++) { - if (i > 0) { - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - skip_nl(ctx); - } - emit_dup(&ctx->emit); - emit_ptr_add(&ctx->emit, i * stride); - int saved_aom = ctx->addr_of_mode; - ctx->addr_of_mode = 0; - spl_parse_expr(ctx, PREC_MIN); - ctx->addr_of_mode = saved_aom; - if (elem_type_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_type_idx)) { - emit_copy_addr_to_addr(&ctx->emit, - spl_type_slot_count(&ctx->tctx, elem_type_idx), 1); - } else { - emit_store_type(&ctx->emit, st); - } - skip_nl(ctx); - } - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - skip_nl(ctx); - if (!expect(ctx, TOK_R_BRACE)) - return; - emit_drop(&ctx->emit); - } else if (ft_idx >= 0 && - (spl_type_kind(&ctx->tctx, ft_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, ft_idx) == TYPE_ENUM) && - spl_type_size(&ctx->tctx, ft_idx) > sizeof(spl_val_t)) { - spl_expr_result_t fv; - if (peek(ctx)->type == TOK_L_BRACE) { - fv = spl_parse_struct_literal(ctx, ft_idx); - } else { - fv = spl_parse_expr(ctx, PREC_MIN); - } - (void)fv; - usize nslots = - (spl_type_size(&ctx->tctx, ft_idx) + sizeof(spl_val_t) - 1) / sizeof(spl_val_t); - emit_frame_copy(&ctx->emit, - base_offset + (int)extra_offset + (int)it->aggregate_field.offset, - nslots); - emit_drop(&ctx->emit); - } else { - spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN); - (void)fv; - emit_store_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, ft_idx)); - } - break; - } - } - if (!found) { - spl_comp_err_tok(ctx, ftok, "unknown field '%s' in struct literal", fname); - } -} - -spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, int type_idx) { - usize sz = spl_type_size(&ctx->tctx, type_idx); - int base_offset = fa_alloc(&ctx->emit.frame, sz); - - advance(ctx); - skip_nl(ctx); - - if (spl_type_kind(&ctx->tctx, type_idx) == TYPE_STRUCT) { - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - if (peek(ctx)->type != TOK_DOT) { - if (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) - advance(ctx); - skip_nl(ctx); - continue; - } - parse_one_field_init(ctx, spl_type_items(&ctx->tctx, type_idx), base_offset, 0); - skip_nl(ctx); - } - } else if (spl_type_kind(&ctx->tctx, type_idx) == TYPE_SLICE) { - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - advance(ctx); - spl_tok_t *ftok = advance(ctx); - char fname[256]; - spl_tok_copy_name(ftok, fname, sizeof(fname)); - skip_nl(ctx); - if (peek(ctx)->type == TOK_ASSIGN) - advance(ctx); - skip_nl(ctx); - if (strcmp(fname, "ptr") == 0) { - emit_laddr(&ctx->emit, base_offset); - spl_parse_expr(ctx, PREC_MIN); - emit_store_ptr(&ctx->emit); - } else if (strcmp(fname, "len") == 0) { - emit_laddr(&ctx->emit, base_offset); - emit_ptr_add(&ctx->emit, sizeof(spl_val_t)); - spl_parse_expr(ctx, PREC_MIN); - emit_store_usize(&ctx->emit); - } - skip_nl(ctx); - } - } else if (spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM) { - spl_tok_t *vtok; - if (peek(ctx)->type == TOK_DOT) { - advance(ctx); - vtok = advance(ctx); - } else { - vtok = advance(ctx); - while (peek(ctx)->type == TOK_DOT) { - advance(ctx); - vtok = advance(ctx); - } - } - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - skip_nl(ctx); - if (peek(ctx)->type == TOK_ASSIGN) - advance(ctx); - skip_nl(ctx); - - int found = 0; - spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx); - vec_for(*items, vi) { - spl_type_item_t *v = &vec_at(*items, vi); - if (v->item_kind != ITEM_VARIANT) - continue; - if (strcmp(v->name, vname) == 0) { - found = 1; - emit_laddr(&ctx->emit, base_offset); - emit_push_i32(&ctx->emit, v->enum_field.value); - emit_store_i32(&ctx->emit); - - const usize DATA_OFFSET = ENUM_TAG_SIZE; - int dt_idx = v->enum_field.type_idx; - if (dt_idx >= 0) { - if (spl_type_kind(&ctx->tctx, dt_idx) == TYPE_STRUCT && - peek(ctx)->type == TOK_L_BRACE) { - advance(ctx); - skip_nl(ctx); - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && - peek(ctx)->type != TOK_EOF) { - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - if (peek(ctx)->type != TOK_DOT) - break; - parse_one_field_init(ctx, spl_type_items(&ctx->tctx, dt_idx), - base_offset, DATA_OFFSET); - skip_nl(ctx); - } - if (!expect(ctx, TOK_R_BRACE)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - } else if (dt_idx >= 0 && - (spl_type_kind(&ctx->tctx, dt_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, dt_idx) == TYPE_ENUM) && - spl_type_size(&ctx->tctx, dt_idx) > sizeof(spl_val_t)) { - spl_expr_result_t dv; - if (peek(ctx)->type == TOK_L_BRACE) { - dv = spl_parse_struct_literal(ctx, dt_idx); - } else { - dv = spl_parse_expr(ctx, PREC_MIN); - } - (void)dv; - usize nslots = (spl_type_size(&ctx->tctx, dt_idx) + sizeof(spl_val_t) - 1) / - sizeof(spl_val_t); - emit_frame_copy(&ctx->emit, base_offset + (int)DATA_OFFSET, nslots); - emit_drop(&ctx->emit); - } else { - spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN); - (void)dv; - emit_laddr(&ctx->emit, base_offset); - emit_ptr_add(&ctx->emit, DATA_OFFSET); - spl_type_t bt = spl_type_emit_type(&ctx->tctx, dt_idx); - emit_swap(&ctx->emit); - emit_store_type(&ctx->emit, bt); - } - } - break; - } - } - if (!found) - spl_comp_err_tok(ctx, vtok, "unknown enum variant '%s'", vname); - } - - skip_nl(ctx); - if (!expect(ctx, TOK_R_BRACE)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - - if (sz <= sizeof(spl_val_t)) { - emit_laddr(&ctx->emit, base_offset); - emit_load_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, type_idx)); - return (spl_expr_result_t){type_idx, 0}; - } else { - emit_laddr(&ctx->emit, base_offset); - return (spl_expr_result_t){type_idx, 1}; - } -} - -static int parse_call_args(spl_comp_t *ctx) { - int nargs = 0; - if (peek(ctx)->type != TOK_R_PAREN) { - while (!ctx->has_error) { - spl_parse_expr(ctx, PREC_MIN); - nargs++; - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - continue; - } - break; - } - } - return nargs; -} - -static int types_equal(spl_type_ctx_t *tctx, int a, int b) { - if (a < 0 || b < 0) - return 0; - a = spl_type_resolve_underlying(tctx, a); - b = spl_type_resolve_underlying(tctx, b); - if (a == b) - return 1; - - spl_type_kind_t ak = spl_type_kind(tctx, a); - spl_type_kind_t bk = spl_type_kind(tctx, b); - if (ak != bk) - return 0; - - switch (ak) { - case TYPE_VOID: - return 1; - case TYPE_BASIC: - return spl_type_basic_type(tctx, a) == spl_type_basic_type(tctx, b); - case TYPE_PTR: - return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b)); - case TYPE_ARRAY: - return spl_type_array_len(tctx, a) == spl_type_array_len(tctx, b) && - types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b)); - case TYPE_SLICE: - return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b)); - case TYPE_STRUCT: - case TYPE_UNION: - case TYPE_ENUM: { - const char *an = spl_type_name(tctx, a); - const char *bn = spl_type_name(tctx, b); - return an && bn && strcmp(an, bn) == 0; - } - default: - return 0; - } -} - -static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, int arg_type_idx, - int param_type_idx, int arg_idx) { - if (arg_type_idx < 0 || param_type_idx < 0) - return; - - /* Level 1: structurally equal types */ - if (types_equal(&ctx->tctx, arg_type_idx, param_type_idx)) - return; - - int arg_u = spl_type_resolve_underlying(&ctx->tctx, arg_type_idx); - int param_u = spl_type_resolve_underlying(&ctx->tctx, param_type_idx); - - /* Level 1b: void pointer (*_) accepts any pointer */ - if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) { - int param_elem = spl_type_elem_type(&ctx->tctx, param_u); - int param_elem_u = spl_type_resolve_underlying(&ctx->tctx, param_elem); - if (param_elem_u >= 0 && spl_type_kind(&ctx->tctx, param_elem_u) == TYPE_BASIC && - spl_type_basic_type(&ctx->tctx, param_elem_u) == SPL_VOID && - spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) { - return; - } - } - - /* Level 2: pointer indirection mismatch with same inner type */ - if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) { - int param_elem = spl_type_elem_type(&ctx->tctx, param_u); - if (param_elem < 0) - goto type_mismatch; - - /* 2a: param = *T, arg = T (missing '&') */ - if (spl_type_kind(&ctx->tctx, arg_u) != TYPE_PTR) { - if (types_equal(&ctx->tctx, arg_type_idx, param_elem)) { - const char *is = spl_type_str(&ctx->tctx, param_elem); - fprintf(stderr, - "%s: warning: argument %d of '%s' expects '%s*', " - "got '%s' (missing '&'?)\n", - ctx->fname, arg_idx + 1, fname, is, is); - return; - } - } - - /* 2b: param = *T, arg = **T (extra '&') */ - if (spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) { - int arg_elem = spl_type_elem_type(&ctx->tctx, arg_u); - int arg_elem_u = spl_type_resolve_underlying(&ctx->tctx, arg_elem); - if (spl_type_kind(&ctx->tctx, arg_elem_u) == TYPE_PTR) { - if (types_equal(&ctx->tctx, spl_type_elem_type(&ctx->tctx, arg_elem), param_elem)) { - const char *is = spl_type_str(&ctx->tctx, param_elem); - fprintf(stderr, - "%s: warning: argument %d of '%s' expects '%s*', " - "got '%s**' (extra '&'?)\n", - ctx->fname, arg_idx + 1, fname, is, is); - return; - } - } - } - } - - /* Level 3: general type mismatch → error */ -type_mismatch:; - const char *as = spl_type_str(&ctx->tctx, arg_type_idx); - const char *ps = spl_type_str(&ctx->tctx, param_type_idx); - spl_comp_err_tok(ctx, peek(ctx), "argument %d of '%s' type mismatch: expected '%s', got '%s'", - arg_idx + 1, fname, ps, as); -} - -static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, int *param_type_indices, - int nparams) { - int nargs = 0; - int nlogical = 0; - if (peek(ctx)->type != TOK_R_PAREN) { - while (!ctx->has_error) { - spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN); - if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0) { - int param_u = spl_type_resolve_underlying(&ctx->tctx, param_type_indices[nlogical]); - int arg_u = spl_type_resolve_underlying(&ctx->tctx, arg.type_idx); - if (arg.type_idx >= 0 && spl_type_kind(&ctx->tctx, param_u) == TYPE_BASIC && - spl_type_is_integer(spl_type_basic_type(&ctx->tctx, param_u)) && - spl_type_kind(&ctx->tctx, arg_u) == TYPE_BASIC && - spl_type_is_integer(spl_type_basic_type(&ctx->tctx, arg_u))) { - arg.type_idx = param_type_indices[nlogical]; - } - spl_check_arg_type(ctx, fname, arg.type_idx, param_type_indices[nlogical], - nlogical); - } - - int arg_slots = 1; - if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0 && - arg.type_idx >= 0 && - spl_type_kind(&ctx->tctx, param_type_indices[nlogical]) != TYPE_PTR && - spl_type_needs_multi_slot(&ctx->tctx, param_type_indices[nlogical])) { - usize nslots = (spl_type_size(&ctx->tctx, param_type_indices[nlogical]) + - sizeof(spl_val_t) - 1) / - sizeof(spl_val_t); - for (usize i = 0; i < nslots; i++) { - emit_dup(&ctx->emit); - emit_ptr_add(&ctx->emit, i * sizeof(spl_val_t)); - emit_load_ptr(&ctx->emit); - emit_swap(&ctx->emit); - } - emit_drop(&ctx->emit); - arg_slots = (int)nslots; - } - - nargs += arg_slots; - nlogical++; - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - continue; - } - break; - } - } - return nargs; -} - -static spl_expr_result_t parse_ident(spl_comp_t *ctx) { - spl_tok_t *t = advance(ctx); - char name[256]; - spl_tok_copy_name(t, name, sizeof(name)); - - if (peek(ctx)->type == TOK_L_PAREN) { - int fi = spl_lookup_func(ctx, name); - if (fi < 0) { - /* Not a known function — check if it's a function pointer variable */ - spl_var_info_t *v = spl_lookup_var(ctx, name); - if (v && v->type_idx >= 0 && spl_type_kind(&ctx->tctx, v->type_idx) == TYPE_FN) { - /* Load function pointer value, let postfix handle the call */ - int vt_idx = v->type_idx; - emit_laddr(&ctx->emit, v->offset); - emit_load_ptr(&ctx->emit); - spl_expr_result_t r = {vt_idx, 0}; - return r; - } - spl_comp_err_tok(ctx, t, "unknown function '%s'", name); - spl_expr_result_t r = {-1, 0}; - return r; - } - spl_func_info_t *f = &vec_at(ctx->funcs, fi); - advance(ctx); - - int nargs = parse_call_args_checked(ctx, f->name, f->param_type_indices, f->nparams); - if (!ctx->has_error && nargs < f->nparams) { - spl_comp_err_tok(ctx, peek(ctx), "too few arguments to '%s': expected %d, got %d", - f->name, f->nparams, nargs); - } - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - } else { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - - if (f->is_extern) { - int nidx = spl_ensure_native(ctx, f->name); - emit_push_i32(&ctx->emit, nidx); - emit_ncall(&ctx->emit, nargs); - if (spl_type_kind(&ctx->tctx, f->ret_type_idx) == TYPE_BASIC && - spl_type_basic_type(&ctx->tctx, f->ret_type_idx) == SPL_VOID) { - emit_drop(&ctx->emit); - } - } else { - emit_call_with_fixup(&ctx->emit, nargs, f->func_idx); - } - - spl_expr_result_t r = {f->ret_type_idx, 0}; - - if (spl_type_needs_multi_slot(&ctx->tctx, f->ret_type_idx)) { - usize nslots = spl_type_slot_count(&ctx->tctx, f->ret_type_idx); - int temp_offset = fa_alloc_temp(&ctx->emit.frame, nslots); - emit_frame_copy(&ctx->emit, temp_offset, nslots); - emit_laddr(&ctx->emit, temp_offset); - r.is_lvalue = 1; - } - - return r; - } - - spl_var_info_t *v = spl_lookup_var(ctx, name); - if (v) { - spl_val_t cv = 0; - if (map_get(ctx->const_values, name, &cv)) { - emit_push_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, v->type_idx), cv); - spl_expr_result_t r = {v->type_idx, 0}; - return r; - } - - int vt_idx = v->type_idx; - emit_laddr(&ctx->emit, v->offset); - - spl_expr_result_t r; - spl_tok_type_t next_type = peek(ctx)->type; - if (next_type == TOK_DOT) { - r = (spl_expr_result_t){vt_idx, 1}; - } else { - emit_load_or_addr_type(ctx, &r, vt_idx); - } - return r; - } - - /* Function reference (not a call): get function address */ - { - int fi = spl_lookup_func(ctx, name); - if (fi >= 0) { - spl_func_info_t *f = &vec_at(ctx->funcs, fi); - if (!f->is_extern) { - emit_push_u64(&ctx->emit, f->func_idx); - int fn_ptr_type = - spl_type_fn(&ctx->tctx, spl_type_basic(&ctx->tctx, SPL_USIZE), f->ret_type_idx); - spl_expr_result_t r = {fn_ptr_type, 1}; - return r; - } - } - } - - int ttype_idx = spl_type_resolve(&ctx->tctx, name); - if (ttype_idx >= 0) { - if (peek(ctx)->type == TOK_L_BRACE && - (spl_type_kind(&ctx->tctx, ttype_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, ttype_idx) == TYPE_ENUM)) { - return spl_parse_struct_literal(ctx, ttype_idx); - } - spl_expr_result_t r = {ttype_idx, 0}; - return r; - } - - spl_comp_err_tok(ctx, t, "undefined variable '%s'", name); - spl_expr_result_t r = {-1, 0}; - return r; -} - -static spl_expr_result_t parse_group(spl_comp_t *ctx) { - advance(ctx); - spl_expr_result_t r = spl_parse_expr(ctx, PREC_MIN); - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) - return r; - } - return r; -} - -static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, int type_idx) { - if (spl_type_is_scalar(&ctx->tctx, type_idx)) { - if (!ctx->addr_of_mode) { - emit_load_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, type_idx)); - *result = (spl_expr_result_t){type_idx, 0}; - return; - } - } - *result = (spl_expr_result_t){type_idx, 1}; -} - -static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) { - spl_tok_t *op = advance(ctx); - - if (op->type == TOK_AND) - ctx->addr_of_mode = 1; - spl_expr_result_t right = spl_parse_expr(ctx, PREC_PREFIX); - if (op->type == TOK_AND) - ctx->addr_of_mode = 0; - - switch (op->type) { - case TOK_SUB: - emit_binop(&ctx->emit, SPL_NEG, spl_type_emit_type(&ctx->tctx, right.type_idx)); - break; - case TOK_NOT: - emit_push_i32(&ctx->emit, 0); - emit_binop(&ctx->emit, SPL_EQ, spl_type_emit_type(&ctx->tctx, right.type_idx)); - break; - case TOK_BIT_NOT: - emit_binop(&ctx->emit, SPL_NOT, spl_type_emit_type(&ctx->tctx, right.type_idx)); - break; - case TOK_AND: - if (right.type_idx >= 0 && spl_type_kind(&ctx->tctx, right.type_idx) == TYPE_FN) { - return right; - } - if (!right.is_lvalue) { - spl_comp_err_tok(ctx, peek(ctx), "cannot take address of rvalue"); - spl_expr_result_t _r = {-1, 0}; - return _r; - } - right.type_idx = spl_type_ptr(&ctx->tctx, right.type_idx); - break; - case TOK_MUL: - if (right.type_idx >= 0 && spl_type_kind(&ctx->tctx, right.type_idx) == TYPE_PTR && - spl_type_elem_type(&ctx->tctx, right.type_idx) >= 0) { - if (right.is_lvalue) { - emit_load_ptr(&ctx->emit); - } - emit_load_or_addr_type(ctx, &right, spl_type_elem_type(&ctx->tctx, right.type_idx)); - } - break; - default: - break; - } - - return right; -} - -static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) { - spl_tok_t *tok = peek(ctx); - if (!tok) { - spl_expr_result_t r = {-1, 0}; - return r; - } - - switch (tok->type) { - case TOK_INT_LITERAL: - return parse_int_literal(ctx); - case TOK_FLOAT_LITERAL: - return parse_float_literal(ctx); - case TOK_CHAR_LITERAL: - return parse_char_literal(ctx); - case TOK_STRING_LITERAL: - return parse_string_literal(ctx); - case KW_TRUE: - advance(ctx); - emit_push_i32(&ctx->emit, 1); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; - case KW_FALSE: - advance(ctx); - emit_push_i32(&ctx->emit, 0); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; - case KW_NULL: - advance(ctx); - emit_push_ptr(&ctx->emit, 0); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_PTR), 0}; - case TOK_IDENT: - case KW_BOOL: - case KW_VOID: - case KW_ANY: - return parse_ident(ctx); - case TOK_L_PAREN: - return parse_group(ctx); - case TOK_SUB: - case TOK_NOT: - case TOK_BIT_NOT: - case TOK_AND: - case TOK_MUL: - return parse_prefix_op(ctx); - case TOK_L_BRACKET: - return parse_array_literal(ctx); - case TOK_L_BRACE: - return spl_parse_block_expr(ctx); - case TOK_AT: { - advance(ctx); - skip_nl(ctx); - tok = peek(ctx); - if (!tok || tok->type != TOK_IDENT) { - spl_comp_err_tok(ctx, tok, "expected builtin name after '@'"); - spl_expr_result_t r = {-1, 0}; - return r; - } - char bname[256]; - spl_tok_copy_name(tok, bname, sizeof bname); - advance(ctx); - - if (strcmp(bname, "dbg") == 0) { - if (peek(ctx)->type == TOK_L_PAREN) { - advance(ctx); - int nargs = parse_call_args(ctx); - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - } else { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - for (int i = 0; i < nargs; i++) { - emit_dbg_usize(&ctx->emit); - emit_drop(&ctx->emit); - } - if (nargs == 0) - emit_dbg_void(&ctx->emit); - } else { - emit_dbg_void(&ctx->emit); - } - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_VOID), 0}; - } else if (strcmp(bname, "sizeof") == 0) { - if (!expect(ctx, TOK_L_PAREN)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - int ti = spl_type_parse(&ctx->tctx, ctx); - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - } else { - spl_expr_result_t _r = {-1, 0}; - return _r; - } - if (ti < 0) { - spl_comp_err_tok(ctx, peek(ctx), "@sizeof: invalid type"); - spl_expr_result_t r = {-1, 0}; - return r; - } - usize sz = spl_type_size(&ctx->tctx, ti); - emit_push_usize(&ctx->emit, sz); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_USIZE), 0}; - } else { - spl_comp_err_tok(ctx, peek(ctx), "unknown builtin '@%s'", bname); - spl_expr_result_t r = {-1, 0}; - return r; - } - } - default: - if (peek(ctx)->type > KW_AS && peek(ctx)->type <= KW_ANY) { - return parse_ident(ctx); - } - spl_expr_result_t r = {-1, 0}; - return r; - } -} - -static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left) { - if (left.type_idx < 0) - return left; - - for (;;) { - if (ctx->has_error) - break; - skip_nl(ctx); - spl_tok_type_t opt = peek(ctx)->type; - - if (opt == TOK_DOT) { - advance(ctx); - spl_tok_t *field = advance(ctx); - char fname[256]; - spl_tok_copy_name(field, fname, sizeof(fname)); - - if (left.type_idx >= 0) { - spl_expr_result_t mresult = {-1, 0}; - if (spl_resolve_type_member(ctx, left.type_idx, fname, &mresult)) { - left = mresult; - continue; - } - } - - if (left.type_idx >= 0 && peek(ctx)->type == TOK_L_PAREN) { - int methods_type_idx = left.type_idx; - int is_ptr_self = 0; - if (spl_type_kind(&ctx->tctx, methods_type_idx) == TYPE_PTR) { - int elem_idx = spl_type_elem_type(&ctx->tctx, methods_type_idx); - if (elem_idx >= 0 && (spl_type_kind(&ctx->tctx, elem_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, elem_idx) == TYPE_ENUM)) { - is_ptr_self = 1; - methods_type_idx = elem_idx; - } - } - - int found_method = 0; - spl_type_item_vec_t *m_items = spl_type_items(&ctx->tctx, methods_type_idx); - vec_for(*m_items, mi) { - spl_type_item_t *mit = &vec_at(*m_items, mi); - if (mit->item_kind != ITEM_METHOD) - continue; - if (strcmp(mit->name, fname) == 0) { - spl_func_info_t *func = &vec_at(ctx->funcs, mit->method.func_idx); - - advance(ctx); - found_method = 1; - - int nargs = 0; - - int is_instance = 0; - if (func->nparams > 0 && func->param_type_indices && - func->param_type_indices[0] >= 0 && - spl_type_kind(&ctx->tctx, func->param_type_indices[0]) == TYPE_PTR && - spl_type_elem_type(&ctx->tctx, func->param_type_indices[0]) == - methods_type_idx) { - is_instance = 1; - } - - if (is_instance) { - if (!left.is_lvalue && !is_ptr_self) { - spl_comp_err_tok(ctx, field, - "cannot call instance method '%s' on type", fname); - return left; - } - emit_drop(&ctx->emit); - nargs = 0; - } - - { - int full_np = func->nparams; - nargs += parse_call_args_checked(ctx, func->name, - func->param_type_indices, full_np); - if (is_instance && !ctx->has_error) { - int ok = - (nargs >= full_np) || (nargs == full_np - 1 && full_np == 1); - if (!ok) { - spl_comp_err_tok( - ctx, peek(ctx), - "too few arguments to '%s': expected %d, got %d", - func->name, full_np, nargs); - } - } - } - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) { - spl_expr_result_t _r = left; - return _r; - } - } else { - spl_expr_result_t _r = left; - return _r; - } - - if (func->func_idx < 0) { - fprintf(stderr, "WARN: method call '%s.' with invalid func_idx=%d\n", - func->name, func->func_idx); - } - emit_call_with_fixup(&ctx->emit, nargs, func->func_idx); - - left = (spl_expr_result_t){func->ret_type_idx, 0}; - - if (spl_type_needs_multi_slot(&ctx->tctx, func->ret_type_idx)) { - usize nslots = spl_type_slot_count(&ctx->tctx, func->ret_type_idx); - int temp_offset = fa_alloc_temp(&ctx->emit.frame, nslots); - emit_frame_copy(&ctx->emit, temp_offset, nslots); - emit_laddr(&ctx->emit, temp_offset); - left.is_lvalue = 1; - } - - break; - } - } - if (found_method) - continue; - - /* Indirect call through function pointer: fn_ptr(args) */ - if (left.type_idx >= 0 && peek(ctx)->type == TOK_L_PAREN && - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_FN) { - advance(ctx); /* ( */ - - int nargs = parse_call_args(ctx); - if (!ctx->has_error) { - if (!expect(ctx, TOK_R_PAREN)) { - spl_expr_result_t _r = left; - return _r; - } - } else { - spl_expr_result_t _r = left; - return _r; - } - - /* If left is lvalue, load the function address value first */ - if (left.is_lvalue) { - emit_load_ptr(&ctx->emit); - } - - /* Stack currently: [args..., func_addr]. - * CALLI expects: POP addr, POP nargs, call(addr, nargs). - * After all args are on stack: push nargs, push func_addr. - * But func_addr is already below args? No — we need: - * Stack: [..., func_addr, arg0, ..., argN-1] - * CALLI: POP addr, POP nargs, call(addr, nargs) - * Actually CALLI pops: TOS=addr, TOS-1=nargs. - * So we need: [args..., nargs, addr] - * But currently: [args..., addr] (addr is on TOS, loaded above) - * Push nargs ABOVE addr, then CALLI pops addr, then nargs: - * Stack: [args..., nargs, addr] - * TOS=addr → POP returns addr, then POP returns nargs. ✓ */ - - emit_push_u64(&ctx->emit, nargs); - emit_raw(&ctx->emit, SPL_CALLI, SPL_VOID, 0); - - /* For now, result type is void — we don't know the return type from fn ptr */ - left = (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_VOID), 0}; - continue; - } - } - - if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_STRUCT) { - spl_type_item_vec_t *f_items = spl_type_items(&ctx->tctx, left.type_idx); - int found = 0; - vec_for(*f_items, fi) { - spl_type_item_t *fit = &vec_at(*f_items, fi); - if (fit->item_kind != ITEM_FIELD) - continue; - if (strcmp(fit->name, fname) == 0) { - emit_ptr_add(&ctx->emit, fit->aggregate_field.offset); - emit_load_or_addr_type(ctx, &left, fit->aggregate_field.type_idx); - found = 1; - break; - } - } - if (found) - continue; - } - - if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR) { - int elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); - if (elem_idx >= 0 && spl_type_kind(&ctx->tctx, elem_idx) == TYPE_STRUCT) { - if (left.is_lvalue) { - emit_load_ptr(&ctx->emit); - } - spl_type_item_vec_t *st_items = spl_type_items(&ctx->tctx, elem_idx); - int found = 0; - vec_for(*st_items, si) { - spl_type_item_t *sit = &vec_at(*st_items, si); - if (sit->item_kind != ITEM_FIELD) - continue; - if (strcmp(sit->name, fname) == 0) { - emit_ptr_add(&ctx->emit, sit->aggregate_field.offset); - emit_load_or_addr_type(ctx, &left, sit->aggregate_field.type_idx); - found = 1; - break; - } - } - if (found) - continue; - } - } - - if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { - if (strcmp(fname, "len") == 0) { - if (ctx->addr_of_mode) { - emit_push_u64(&ctx->emit, (spl_val_t)sizeof(spl_val_t)); - emit_add_u64(&ctx->emit); - left = (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_USIZE), 1}; - } else { - emit_push_u64(&ctx->emit, (spl_val_t)sizeof(spl_val_t)); - emit_add_u64(&ctx->emit); - emit_load_usize(&ctx->emit); - left = (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_USIZE), 0}; - } - } else if (strcmp(fname, "ptr") == 0) { - int sl_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); - if (ctx->addr_of_mode) { - left = (spl_expr_result_t){sl_elem_idx >= 0 - ? spl_type_ptr(&ctx->tctx, sl_elem_idx) - : spl_type_basic(&ctx->tctx, SPL_PTR), - 1}; - } else { - emit_load_ptr(&ctx->emit); - left = (spl_expr_result_t){sl_elem_idx >= 0 - ? spl_type_ptr(&ctx->tctx, sl_elem_idx) - : spl_type_basic(&ctx->tctx, SPL_PTR), - 0}; - } - } - continue; - } - - if (strcmp(fname, "*") == 0 && left.type_idx >= 0 && - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR) { - int elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); - if (elem_idx >= 0) { - if (left.is_lvalue) { - emit_load_ptr(&ctx->emit); - } - emit_load_or_addr_type(ctx, &left, elem_idx); - } - continue; - } - - spl_comp_err_tok(ctx, field, "unknown field '%s'", fname); - continue; - } - - if (opt == TOK_L_BRACKET) { - advance(ctx); - if (peek(ctx)->type == TOK_R_BRACKET) { - advance(ctx); - continue; - } - - int saved_aom = ctx->addr_of_mode; - ctx->addr_of_mode = 0; - spl_parse_expr(ctx, PREC_MIN); - ctx->addr_of_mode = saved_aom; - - if (peek(ctx)->type == TOK_RANGE) { - advance(ctx); - spl_expr_result_t end_expr = {-1, 0}; - int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET); - if (has_explicit_end) { - int saved_aom = ctx->addr_of_mode; - ctx->addr_of_mode = 0; - end_expr = spl_parse_expr(ctx, PREC_MIN); - ctx->addr_of_mode = saved_aom; - } - (void)end_expr; - if (!expect(ctx, TOK_R_BRACKET)) - return left; - - if (!has_explicit_end) { - if (left.type_idx >= 0 && - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY) { - emit_push_u64(&ctx->emit, spl_type_array_len(&ctx->tctx, left.type_idx)); - } else if (left.type_idx >= 0 && - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { - emit_pick(&ctx->emit, 1); - emit_push_u64(&ctx->emit, sizeof(spl_val_t)); - emit_add_u64(&ctx->emit); - emit_load_usize(&ctx->emit); - } - } - - if (left.type_idx >= 0 && - (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY || - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE)) { - int rng_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); - usize stride = spl_type_elem_stride(&ctx->tctx, rng_elem_idx); - - if (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { - emit_pick(&ctx->emit, 2); - emit_load_ptr(&ctx->emit); - emit_pick(&ctx->emit, 2); - emit_push_u64(&ctx->emit, stride); - emit_mul_u64(&ctx->emit); - emit_add_u64(&ctx->emit); - emit_pick(&ctx->emit, 1); - emit_pick(&ctx->emit, 3); - emit_sub_usize(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); - emit_rot(&ctx->emit); - emit_drop(&ctx->emit); - } else { - emit_slice_create(ctx, stride); - } - } - left = (spl_expr_result_t){ - left.type_idx >= 0 - ? spl_type_slice(&ctx->tctx, spl_type_elem_type(&ctx->tctx, left.type_idx)) - : -1, - 0}; - continue; - } - - if (!expect(ctx, TOK_R_BRACKET)) - break; - - if (left.type_idx >= 0 && (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY || - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR || - spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE)) { - int idx_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); - /* void* -> treat as u8* */ - if (idx_elem_idx >= 0 && spl_type_kind(&ctx->tctx, idx_elem_idx) == TYPE_BASIC && - spl_type_basic_type(&ctx->tctx, idx_elem_idx) == SPL_VOID) { - idx_elem_idx = spl_type_basic(&ctx->tctx, SPL_U8); - } - - if (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { - emit_slice_index(ctx, idx_elem_idx); - } else { - if (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR && left.is_lvalue) { - emit_swap(&ctx->emit); - emit_load_ptr(&ctx->emit); - emit_swap(&ctx->emit); - } - usize stride = spl_type_elem_stride(&ctx->tctx, idx_elem_idx); - emit_push_u64(&ctx->emit, stride); - emit_mul_u64(&ctx->emit); - emit_add_u64(&ctx->emit); - } - if (idx_elem_idx >= 0) - emit_load_or_addr_type(ctx, &left, idx_elem_idx); - } - continue; - } - - if (opt == KW_AS) { - usize saved = ctx->tok_idx; - int saved_err = ctx->has_error; - char saved_msg[COMP_ERROR_MAX]; - memcpy(saved_msg, ctx->error_msg, COMP_ERROR_MAX); - advance(ctx); /* as */ - skip_nl(ctx); - int target_type_idx = spl_type_parse(&ctx->tctx, ctx); - if (target_type_idx < 0) { - ctx->tok_idx = saved; - ctx->has_error = saved_err; - memcpy(ctx->error_msg, saved_msg, COMP_ERROR_MAX); - break; - } - usize src_sz = spl_type_size(&ctx->tctx, left.type_idx); - usize dst_sz = spl_type_size(&ctx->tctx, target_type_idx); - if (dst_sz > src_sz) { - int src_signed = - spl_type_is_integer(spl_type_basic_type(&ctx->tctx, left.type_idx)); - uint16_t opc = src_signed ? SPL_SEXT : SPL_ZEXT; - emit_raw(&ctx->emit, opc, 0, dst_sz * 8); - } else if (dst_sz < src_sz) { - emit_raw(&ctx->emit, SPL_TRUNC, 0, dst_sz * 8); - } - left = (spl_expr_result_t){target_type_idx, 0}; - continue; - } - - break; - } - return left; -} - -spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { - skip_nl(ctx); - spl_expr_result_t left = parse_primary_expr(ctx); - if (left.type_idx < 0) - return left; - while (!ctx->has_error) { - left = parse_postfix_expr(ctx, left); - - skip_nl(ctx); - spl_tok_type_t opt = peek(ctx)->type; - - int prec = tok_prec(opt); - if (prec == 0 || prec < min_prec) - break; - advance(ctx); - left = parse_infix(ctx, left, opt); - } - - return left; -} - -static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op) { - int prec = tok_prec(op); - int next_prec = prec + 1; - - if (op == TOK_AND_AND) { - spl_val_t bz_addr = emit_bz_here(&ctx->emit); - spl_parse_expr(ctx, next_prec); - spl_val_t jmp_addr = emit_jmp_here(&ctx->emit); - emit_patch_here(&ctx->emit, bz_addr); - emit_push_i32(&ctx->emit, 0); - emit_patch_here(&ctx->emit, jmp_addr); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; - } - if (op == TOK_OR_OR) { - spl_val_t bnz_addr = emit_bnz_here(&ctx->emit); - spl_parse_expr(ctx, next_prec); - spl_val_t jmp_addr = emit_jmp_here(&ctx->emit); - emit_patch_here(&ctx->emit, bnz_addr); - emit_push_i32(&ctx->emit, 1); - emit_patch_here(&ctx->emit, jmp_addr); - return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; - } - - if (op == TOK_ASSIGN || op == TOK_ASSIGN_ADD || op == TOK_ASSIGN_SUB || op == TOK_ASSIGN_MUL || - op == TOK_ASSIGN_DIV || op == TOK_ASSIGN_MOD || op == TOK_ASSIGN_AND || - op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR || op == TOK_ASSIGN_L_SH || - op == TOK_ASSIGN_R_SH) { - - int saved_addr_of_mode = ctx->addr_of_mode; - ctx->addr_of_mode = 0; - spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN); - ctx->addr_of_mode = saved_addr_of_mode; - - if (left.is_lvalue) { - spl_type_t bt = spl_type_emit_type(&ctx->tctx, left.type_idx); - if (op == TOK_ASSIGN && left.type_idx >= 0 && - !spl_type_is_scalar(&ctx->tctx, left.type_idx) && right.is_lvalue) { - emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, left.type_idx), - 0); - } else if (op == TOK_ASSIGN) { - emit_store_type(&ctx->emit, bt); - } else { - emit_pick(&ctx->emit, 1); - emit_load_type(&ctx->emit, bt); - emit_swap(&ctx->emit); - int sop = binop_to_sir(assign_to_binop(op), bt); - if (sop >= 0) - emit_binop(&ctx->emit, sop, bt); - emit_store_type(&ctx->emit, bt); - } - } - return right; - } - - spl_parse_expr(ctx, next_prec); - if ((op == TOK_EQ || op == TOK_NEQ) && left.type_idx >= 0 && - !spl_type_is_scalar(&ctx->tctx, left.type_idx)) { - spl_comp_err_tok(ctx, peek(ctx), "type '%s' does not support comparison", - spl_type_str(&ctx->tctx, left.type_idx)); - } - spl_type_t bt = spl_type_emit_type(&ctx->tctx, left.type_idx); - int sop = binop_to_sir(op, bt); - if (sop >= 0) { - emit_binop(&ctx->emit, sop, bt); - } - int is_compare = (op == TOK_EQ || op == TOK_NEQ || op == TOK_LT || op == TOK_GT || - op == TOK_LE || op == TOK_GE); - int result_type_idx = is_compare ? spl_type_basic(&ctx->tctx, SPL_I32) : left.type_idx; - return (spl_expr_result_t){result_type_idx, 0}; -} - -int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int val_offset, int by_value) { - char vname[256]; - spl_tok_t *vtok = NULL; - - if (peek(ctx)->type == TOK_DOT) { - advance(ctx); - vtok = advance(ctx); - spl_tok_copy_name(vtok, vname, sizeof(vname)); - } else { - vtok = advance(ctx); - spl_tok_copy_name(vtok, vname, sizeof(vname)); - - while (peek(ctx)->type == TOK_DOT) { - int qt_idx = spl_type_resolve(&ctx->tctx, vname); - (void)qt_idx; - advance(ctx); - vtok = advance(ctx); - spl_tok_copy_name(vtok, vname, sizeof(vname)); - } - - goto lookup; - } - -lookup: { - spl_type_item_vec_t *e_items = spl_type_items(&ctx->tctx, enum_type_idx); - vec_for(*e_items, vi) { - spl_type_item_t *vit = &vec_at(*e_items, vi); - if (vit->item_kind != ITEM_VARIANT) - continue; - if (strcmp(vit->name, vname) == 0) { - emit_laddr(&ctx->emit, val_offset); - if (by_value) { - emit_load_type(&ctx->emit, SPL_I32); - } else { - emit_load_ptr(&ctx->emit); - emit_ptr_add(&ctx->emit, 0); - emit_load_type(&ctx->emit, SPL_I32); - } - emit_push_i32(&ctx->emit, vit->enum_field.value); - emit_binop(&ctx->emit, SPL_EQ, SPL_I32); - return (int)vi; - } - } -} - spl_comp_err_tok(ctx, vtok, "unknown variant '%s' in match", vname); - return -1; -} - -void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset) { - emit_laddr(&ctx->emit, val_offset); - emit_load_ptr(&ctx->emit); - spl_parse_expr(ctx, PREC_LOGOR); - emit_binop(&ctx->emit, SPL_EQ, SPL_I32); -} diff --git a/stage1/spl_lex_util.c b/stage1/spl_lex_util.c deleted file mode 100644 index 9a3661d..0000000 --- a/stage1/spl_lex_util.c +++ /dev/null @@ -1,142 +0,0 @@ -/* spl_lex_util.c — Lexer utility functions */ - -#include "spl_lex_util.h" -#include -#include - -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; -} diff --git a/stage1/spl_lex_util.h b/stage1/spl_lex_util.h deleted file mode 100644 index 3ddb43d..0000000 --- a/stage1/spl_lex_util.h +++ /dev/null @@ -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__ */ diff --git a/stage1/spl_lexer.h b/stage1/spl_lexer.h index fb28580..9f5d218 100644 --- a/stage1/spl_lexer.h +++ b/stage1/spl_lexer.h @@ -2,130 +2,7 @@ #ifndef __SPL_LEXER_H__ #define __SPL_LEXER_H__ -#include "../stage0/spl_ir.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; +#include "spl_tok.h" /* Lexer entry point */ spl_tok_vec_t spl_lex(const char *source, const char *fname); diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c deleted file mode 100644 index 4673132..0000000 --- a/stage1/spl_parser.c +++ /dev/null @@ -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 - -/* ============================================================ - * 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); - } -} diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c deleted file mode 100644 index d78a5b7..0000000 --- a/stage1/spl_stmt.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* spl_stmt.c — Statement parser + codegen */ - -#include "spl_comp.h" -#include "spl_lex_util.h" -#include - -/* ============================================================ - * Return statement: ret expr; - * ============================================================ */ - -static void parse_ret_stmt(spl_comp_t *ctx) { - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "return statement"); - spl_tok_t *ret_tok = advance(ctx); /* ret */ - skip_nl(ctx); - - /* Before returning, execute all pending defers from innermost scope outward */ - for (int d = ctx->scope_depth; d >= 1; d--) { - spl_emit_defer_epilogue(ctx, d); - } - - if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_R_BRACE || - peek(ctx)->type == TOK_ENDLINE) { - /* void return */ - emit_return(&ctx->emit, &ctx->tctx, ctx->current_ret_type_idx); - } else { - spl_expr_result_t val = spl_parse_expr(ctx, PREC_MIN); - int void_ty = spl_type_basic(&ctx->tctx, SPL_VOID); - if (ctx->current_ret_type_idx == void_ty) { - spl_comp_err_tok(ctx, ret_tok, "cannot return a value from a void function"); - return; - } else if (val.type_idx == void_ty) { - spl_comp_err_tok(ctx, ret_tok, "expected return value"); - return; - } - spl_emit_ret(ctx, ctx->current_ret_type_idx); - } - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); -} - -/* ============================================================ - * Variable declaration: var name: Type [= expr]; - * ============================================================ */ - -static void parse_var_decl(spl_comp_t *ctx, int is_const) { - advance(ctx); /* var or const */ - skip_nl(ctx); - - spl_tok_t *name_tok = advance(ctx); - char vname[256]; - spl_tok_copy_name(name_tok, vname, sizeof(vname)); - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "variable '%s'", vname); - - int var_type_idx = -1; - int has_init = 0; - - skip_nl(ctx); - - if (peek(ctx)->type == TOK_COLON) { - advance(ctx); /* : */ - skip_nl(ctx); - /* Check for := */ - if (peek(ctx)->type == TOK_ASSIGN) { - /* := is colon-assign */ - has_init = 1; - } else { - var_type_idx = spl_type_parse(&ctx->tctx, ctx); - skip_nl(ctx); - } - } - - if (peek(ctx)->type == TOK_COLON_ASSIGN || peek(ctx)->type == TOK_ASSIGN) { - has_init = 1; - if (peek(ctx)->type == TOK_COLON_ASSIGN) - advance(ctx); - else - advance(ctx); /* = */ - } - - /* Init expression: parse before declare to enable type inference */ - spl_expr_result_t init = {0}; - int inline_lit = 0; - if (has_init) { - skip_nl(ctx); - /* Inline struct/enum/slice literal: var x: Type = { .field = val } - * Don't call spl_parse_expr — { would be consumed as block expression */ - if (var_type_idx >= 0 && peek(ctx)->type == TOK_L_BRACE && - (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM || - spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE)) { - inline_lit = 1; - } else { - init = spl_parse_expr(ctx, PREC_MIN); - } - } - - if (var_type_idx < 0) { - var_type_idx = init.type_idx >= 0 ? init.type_idx : spl_type_basic(&ctx->tctx, SPL_I32); - } - int offset = spl_declare_var(ctx, vname, var_type_idx, is_const); - - /* Store init value */ - if (has_init) { - if (inline_lit && (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT || - spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM || - spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE)) { - /* Inline struct/enum/slice literal: var x: Type = { .field = val } - * Use spl_parse_struct_literal to handle field parsing uniformly. */ - spl_parse_struct_literal(ctx, var_type_idx); - if (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE) { - /* Slice: copy 2 temp slots to variable */ - emit_frame_copy(&ctx->emit, offset, 2); - } else { - spl_emit_store_init(ctx, offset, var_type_idx); - } - } else { - spl_emit_store_init(ctx, offset, var_type_idx); - } - } - - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); -} - -/* ============================================================ - * Block: { stmt; stmt; ... } - * ============================================================ */ - -void spl_parse_block(spl_comp_t *ctx) { - skip_nl(ctx); - if (peek(ctx)->type == TOK_L_BRACE) { - advance(ctx); /* { */ - spl_push_scope(ctx); - - 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); - } - - spl_emit_defer_epilogue(ctx, ctx->scope_depth); - spl_pop_scope(ctx); - if (!ctx->has_error && peek(ctx)->type == TOK_R_BRACE) - advance(ctx); - } else { - /* Single statement */ - spl_parse_stmt(ctx); - } -} - -/* Forward declaration for block expr */ -static int is_assign_op(spl_tok_type_t t); -static int lookahead_is_assign(spl_comp_t *ctx); - -/* ============================================================ - * Block expression: { stmts; [trailing_expr] } - * Parses a block and returns the trailing expression type. - * Like Rust/Zig: the last expression without semicolon is the block's value. - * ============================================================ */ - -spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) { - advance(ctx); /* { */ - spl_push_scope(ctx); - - spl_expr_result_t result = {0}; /* void by default */ - - skip_nl(ctx); - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) { - advance(ctx); - skip_nl(ctx); - continue; - } - - spl_tok_type_t t = peek(ctx)->type; - int is_keyword = - (t == KW_RET || t == KW_VAR || t == KW_CONST || t == KW_IF || t == KW_WHILE || - t == KW_LOOP || t == KW_FOR || t == KW_BREAK || t == KW_CONTINUE || t == KW_DEFER || - t == KW_MATCH || t == KW_TYPE || t == TOK_L_BRACE || t == TOK_AT || t == TOK_SHARP || - t == TOK_LINE_COMMENT); - - if (is_keyword) { - /* Keyword statement — produces void */ - spl_parse_stmt(ctx); - result = (spl_expr_result_t){0}; - } else { - /* Expression — look ahead for assignment */ - usize before = ctx->tok_idx; - int is_assign = lookahead_is_assign(ctx); - int saved_addr = ctx->addr_of_mode; - if (is_assign) - ctx->addr_of_mode = 1; - spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); - ctx->addr_of_mode = saved_addr; - - /* Safety: if no token was consumed, advance to prevent infinite loop */ - if (ctx->tok_idx == before) { - advance(ctx); - result = (spl_expr_result_t){0}; - skip_nl(ctx); - continue; - } - - skip_nl(ctx); - if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) { - /* Expression statement: drop value, consume ; */ - if (!is_assign && expr.type_idx >= 0 && - spl_type_emit_type(&ctx->tctx, expr.type_idx) != SPL_VOID) - emit_drop(&ctx->emit); - while (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) - advance(ctx); - result = (spl_expr_result_t){0}; - } else { - /* Trailing expression — this is the block's value */ - result = expr; - } - } - skip_nl(ctx); - } - - spl_emit_defer_epilogue(ctx, ctx->scope_depth); - spl_pop_scope(ctx); - if (!expect(ctx, TOK_R_BRACE)) - return result; - return result; -} - -/* ============================================================ - * If statement: if expr { ... } [else { ... }] - * ============================================================ */ - -static void parse_if_stmt(spl_comp_t *ctx) { - advance(ctx); /* if */ - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "if statement"); - skip_nl(ctx); - spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN); - (void)cond; - - spl_val_t bz_addr = emit_bz_here(&ctx->emit); - skip_nl(ctx); - spl_parse_block(ctx); - - spl_val_t jmp_addr = 0; - skip_nl(ctx); - if (peek(ctx)->type == KW_ELSE) { - jmp_addr = emit_jmp_here(&ctx->emit); - emit_patch_here(&ctx->emit, bz_addr); - advance(ctx); /* else */ - skip_nl(ctx); - spl_parse_block(ctx); - emit_patch_here(&ctx->emit, jmp_addr); - } else { - emit_patch_here(&ctx->emit, bz_addr); - } -} - -/* ============================================================ - * Loop context helpers (save/restore loop state for while/loop/for) - * ============================================================ */ - -typedef struct { - int saved_loop; - usize saved_continue; - usize saved_bp_count; - spl_val_t loop_start; -} spl_loop_save_t; - -static void loop_enter(spl_comp_t *ctx, spl_loop_save_t *save) { - save->loop_start = vec_size(ctx->prog.insns); - save->saved_loop = ctx->in_loop; - save->saved_continue = ctx->continue_target; - save->saved_bp_count = ctx->break_patch_count; - ctx->in_loop = 1; - ctx->continue_target = save->loop_start; -} - -static void loop_exit(spl_comp_t *ctx, spl_loop_save_t *save) { - spl_val_t here = vec_size(ctx->prog.insns); - emit_jmp(&ctx->emit, (spl_val_t)((isize)save->loop_start - (isize)here - 1)); - for (usize i = save->saved_bp_count; i < ctx->break_patch_count; i++) - emit_patch_here(&ctx->emit, ctx->break_patches[i]); - ctx->break_patch_count = save->saved_bp_count; - ctx->in_loop = save->saved_loop; - ctx->continue_target = save->saved_continue; -} - -/* ============================================================ - * While statement: while expr { ... } - * ============================================================ */ - -static void parse_while_stmt(spl_comp_t *ctx) { - advance(ctx); /* while */ - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "while statement"); - skip_nl(ctx); - - spl_loop_save_t save; - loop_enter(ctx, &save); - spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN); - (void)cond; - spl_val_t bz_addr = emit_bz_here(&ctx->emit); - skip_nl(ctx); - spl_parse_block(ctx); - loop_exit(ctx, &save); - emit_patch_here(&ctx->emit, bz_addr); -} - -/* ============================================================ - * Loop statement: loop { ... } - * ============================================================ */ - -static void parse_loop_stmt(spl_comp_t *ctx) { - spl_loop_save_t save; - loop_enter(ctx, &save); - advance(ctx); /* loop */ - skip_nl(ctx); - spl_parse_block(ctx); - loop_exit(ctx, &save); -} - -/* ============================================================ - * For loop: for begin..end as i { ... } - * ============================================================ */ - -static void parse_for_stmt(spl_comp_t *ctx) { - advance(ctx); /* for */ - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "for statement"); - skip_nl(ctx); - - /* Parse the iteration expression(s) */ - spl_expr_result_t start_expr = spl_parse_expr(ctx, PREC_MIN); - - if (peek(ctx)->type == TOK_RANGE) { - /* ===== Numeric range: for begin..end as i { body } ===== */ - advance(ctx); /* .. */ - spl_parse_expr(ctx, PREC_MIN); /* end expression */ - /* Stack: [begin, end] */ - - skip_nl(ctx); - if (peek(ctx)->type != KW_AS) { - skip_nl(ctx); - spl_parse_block(ctx); - return; - } - advance(ctx); /* as */ - - spl_tok_t *ivar = advance(ctx); - char iname[256]; - spl_tok_copy_name(ivar, iname, sizeof(iname)); - - spl_push_scope(ctx); - int ioffset = spl_declare_var(ctx, iname, spl_type_basic(&ctx->tctx, SPL_USIZE), 0); - - /* Stack: [begin, end]; swap so TOS = begin */ - emit_swap(&ctx->emit); - /* Store begin to i */ - emit_store_to_laddr(&ctx->emit, ioffset, SPL_USIZE); - /* Stack: [end] */ - - /* Condition: i < end */ - spl_loop_save_t save; - loop_enter(ctx, &save); - emit_laddr(&ctx->emit, ioffset); - emit_load_usize(&ctx->emit); - emit_pick(&ctx->emit, 1); - emit_ult_usize(&ctx->emit); - spl_val_t bz_addr = emit_bz_here(&ctx->emit); - - skip_nl(ctx); - spl_parse_block(ctx); /* body */ - - /* Increment: i = i + 1 */ - emit_laddr(&ctx->emit, ioffset); - emit_laddr(&ctx->emit, ioffset); - emit_load_usize(&ctx->emit); - emit_push_usize(&ctx->emit, 1); - emit_add_usize(&ctx->emit); - emit_store_usize(&ctx->emit); - - loop_exit(ctx, &save); - - /* Exit: patch bz, drop end */ - emit_patch_here(&ctx->emit, bz_addr); - emit_drop(&ctx->emit); /* [] */ - - spl_emit_defer_epilogue(ctx, ctx->scope_depth); - spl_pop_scope(ctx); - return; - } - - /* ===== Slice iteration: for slice [as val |, range as val, idx] ===== */ - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); /* , */ - spl_parse_expr(ctx, PREC_MIN); /* parse start of range (e.g. 0) */ - if (peek(ctx)->type == TOK_RANGE) { - advance(ctx); /* .. */ - /* consume optional end expression */ - if (peek(ctx)->type != KW_AS && peek(ctx)->type != TOK_COMMA && - peek(ctx)->type != TOK_L_BRACE && peek(ctx)->type != TOK_ENDLINE && - peek(ctx)->type != TOK_EOF) - spl_parse_expr(ctx, PREC_MIN); - } - /* Range pushed a value; we manage our own idx, drop it */ - emit_drop(&ctx->emit); - } - - if (peek(ctx)->type != KW_AS) { - skip_nl(ctx); - spl_parse_block(ctx); - return; - } - advance(ctx); /* as */ - - /* Parse val variable name */ - spl_tok_t *vtok = advance(ctx); - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - - /* Parse optional idx variable name */ - char iname[256] = {0}; - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - spl_tok_t *itok = advance(ctx); - spl_tok_copy_name(itok, iname, sizeof(iname)); - } - - /* Stack: [slice_addr] or whatever the slice expression left */ - spl_push_scope(ctx); - - int idx_offset = -1; - if (iname[0]) - idx_offset = spl_declare_var(ctx, iname, spl_type_basic(&ctx->tctx, SPL_USIZE), 0); - - int elem_type_idx = -1; - if (start_expr.type_idx >= 0) { - if (spl_type_kind(&ctx->tctx, start_expr.type_idx) == TYPE_SLICE) - elem_type_idx = spl_type_elem_type(&ctx->tctx, start_expr.type_idx); - else if (spl_type_kind(&ctx->tctx, start_expr.type_idx) == TYPE_PTR && - spl_type_elem_type(&ctx->tctx, start_expr.type_idx) >= 0) - elem_type_idx = spl_type_elem_type(&ctx->tctx, start_expr.type_idx); - } - if (elem_type_idx < 0) - elem_type_idx = spl_type_basic(&ctx->tctx, SPL_I32); - int val_offset = spl_declare_var(ctx, vname, elem_type_idx, 0); - - /* Extract ptr and len from slice, push index=0: stack [ptr, len, idx] */ - emit_dup(&ctx->emit); - emit_load_ptr(&ctx->emit); - emit_swap(&ctx->emit); - emit_ptr_add(&ctx->emit, sizeof(spl_val_t)); - emit_load_usize(&ctx->emit); - emit_push_usize(&ctx->emit, 0); - /* Stack: [ptr, len, idx=0] */ - - spl_loop_save_t save; - loop_enter(ctx, &save); - - /* Condition: idx < len */ - emit_pick(&ctx->emit, 1); /* copy len */ - emit_pick(&ctx->emit, 1); /* copy idx */ - emit_swap(&ctx->emit); /* [idx, len] → [len, idx] → SWAP → [idx, len] */ - emit_ult_usize(&ctx->emit); - spl_val_t bz_addr = emit_bz_here(&ctx->emit); - - /* Store current idx to idx variable */ - if (idx_offset >= 0) { - emit_pick(&ctx->emit, 0); /* copy idx (TOS) */ - emit_store_to_laddr(&ctx->emit, idx_offset, SPL_USIZE); - } - - /* Load slice[idx] and store to val */ - emit_pick(&ctx->emit, 2); /* copy ptr: [ptr, len, idx, ptr] */ - emit_pick(&ctx->emit, 1); /* copy idx: [ptr, len, idx, ptr, idx] */ - usize elem_byte_size = elem_type_idx >= 0 ? spl_type_size(&ctx->tctx, elem_type_idx) : 4; - emit_push_u64(&ctx->emit, elem_byte_size); - emit_mul_u64(&ctx->emit); - emit_add_u64(&ctx->emit); - if (elem_type_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_type_idx) && - spl_type_size(&ctx->tctx, elem_type_idx) > sizeof(spl_val_t)) { - emit_frame_copy(&ctx->emit, val_offset, spl_type_slot_count(&ctx->tctx, elem_type_idx)); - } else { - spl_type_t elem_bt = - elem_type_idx >= 0 ? spl_type_emit_type(&ctx->tctx, elem_type_idx) : SPL_I32; - emit_load_type(&ctx->emit, elem_bt); - emit_store_to_laddr(&ctx->emit, val_offset, elem_bt); - } - - skip_nl(ctx); - spl_parse_block(ctx); /* body */ - - /* Increment idx */ - emit_pick(&ctx->emit, 0); /* copy idx */ - emit_push_usize(&ctx->emit, 1); - emit_add_usize(&ctx->emit); - emit_swap(&ctx->emit); - emit_drop(&ctx->emit); /* replace old idx with new */ - - loop_exit(ctx, &save); - - /* Exit: patch bz, drop idx, len, ptr */ - emit_patch_here(&ctx->emit, bz_addr); - emit_drop(&ctx->emit); /* drop idx */ - emit_drop(&ctx->emit); /* drop len */ - emit_drop(&ctx->emit); /* drop ptr */ - - spl_pop_scope(ctx); -} - -/* ============================================================ - * Break / Continue - * ============================================================ */ - -static void parse_break_stmt(spl_comp_t *ctx) { - spl_tok_t *tok = advance(ctx); /* break */ - if (!ctx->in_loop) { - spl_comp_err_tok(ctx, tok, "break outside loop"); - return; - } - /* Emit JMP with placeholder, add to patch list */ - spl_val_t addr = emit_jmp_here(&ctx->emit); - if (ctx->break_patch_cap <= ctx->break_patch_count) { - usize new_cap = ctx->break_patch_cap ? ctx->break_patch_cap * 2 : 8; - ctx->break_patches = realloc(ctx->break_patches, new_cap * sizeof(usize)); - ctx->break_patch_cap = new_cap; - } - ctx->break_patches[ctx->break_patch_count++] = addr; - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); -} - -static void parse_continue_stmt(spl_comp_t *ctx) { - spl_tok_t *tok = advance(ctx); /* continue */ - if (!ctx->in_loop) { - spl_comp_err_tok(ctx, tok, "continue outside loop"); - return; - } - /* Emit JMP with relative offset to continue_target */ - spl_val_t here = vec_size(ctx->prog.insns); - emit_jmp(&ctx->emit, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1)); - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); -} - -/* ============================================================ - * Defer statement: defer { ... } or defer expr; - * ============================================================ */ - -static void parse_defer_stmt(spl_comp_t *ctx) { - advance(ctx); /* defer */ - skip_nl(ctx); - - /* Record current position for defer (emits a JMP skip placeholder) */ - spl_emit_defer(ctx); - - /* Parse the deferred statement/block */ - if (peek(ctx)->type == TOK_L_BRACE) { - spl_parse_block(ctx); - } else { - spl_parse_stmt(ctx); - } - - /* Emit JMP exit placeholder — will be patched at scope exit */ - if (ctx->defer_count > 0) { - spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count - 1]; - e->jmp_exit = emit_jmp_here(&ctx->emit); - } -} - -/* ============================================================ - * Match statement helpers - * ============================================================ */ - -/* Parse an enum variant pattern in a match arm: .VariantName - * Delegates comparison to expr layer (spl_emit_match_enum_cmp). - * Returns the variant item index, or -1 on error. */ -static int parse_match_enum_variant(spl_comp_t *ctx, int enum_type_idx, int val_offset, - int by_value) { - return spl_emit_match_enum_cmp(ctx, enum_type_idx, val_offset, by_value); -} - -/* Parse a value pattern in a match arm (non-enum). - * Delegates comparison to expr layer (spl_emit_match_value_cmp). - * Uses PREC_LOGOR internally to prevent => from being consumed as assignment. */ -static void parse_match_value_pattern(spl_comp_t *ctx, int val_offset) { - spl_emit_match_value_cmp(ctx, val_offset); -} - -/* Parse enum variant data bindings: - * [var] — global binding: var = entire payload struct - * [.field = var, ...] — field-by-name binding - * (name1, name2, ...) — (legacy) positional field binding - * Declares local variables and loads corresponding field data - * from the matched value's data area (offset 4+). - * Sets *scope_pushed = 1 if bindings declared. */ -static void parse_match_enum_bindings(spl_comp_t *ctx, int enum_type_idx, int variant_item_idx, - int val_offset, int *scope_pushed) { - if (peek(ctx)->type == TOK_L_BRACKET) { - /* ---- New syntax: [var] or [.field = var, ...] ---- */ - advance(ctx); /* [ */ - skip_nl(ctx); - if (peek(ctx)->type == TOK_R_BRACKET) { - if (!expect(ctx, TOK_R_BRACKET)) - return; - } - - spl_push_scope(ctx); - *scope_pushed = 1; - - spl_type_item_t *var_item = spl_type_item_at(&ctx->tctx, enum_type_idx, variant_item_idx); - int data_type_idx = var_item ? var_item->enum_field.type_idx : -1; - - if (peek(ctx)->type == TOK_DOT) { - /* [.field = var, ...] — field-by-name binding */ - for (;;) { - advance(ctx); /* . */ - spl_tok_t *ftok = advance(ctx); - char fname[256]; - spl_tok_copy_name(ftok, fname, sizeof(fname)); - skip_nl(ctx); - - if (peek(ctx)->type == TOK_ASSIGN) - advance(ctx); - skip_nl(ctx); - - spl_tok_t *vtok = advance(ctx); - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - - int field_type = -1; - usize field_off = 0; - if (data_type_idx >= 0 && spl_type_kind(&ctx->tctx, data_type_idx) == TYPE_STRUCT) { - spl_type_item_vec_t *data_items = spl_type_items(&ctx->tctx, data_type_idx); - vec_for(*data_items, di) { - spl_type_item_t *fit = &vec_at(*data_items, di); - if (fit->item_kind == ITEM_FIELD && strcmp(fit->name, fname) == 0) { - field_type = fit->aggregate_field.type_idx; - field_off = fit->aggregate_field.offset; - break; - } - } - } - if (field_type < 0) { - spl_comp_err_tok(ctx, ftok, "unknown field '%s' in enum variant", fname); - break; - } - - int boffset = spl_declare_var(ctx, vname, field_type, 0); - emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, ENUM_TAG_SIZE + field_off, - field_type, boffset); - - skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - break; - } - } else { - /* [var] — global binding: entire payload as one variable */ - spl_tok_t *vtok = advance(ctx); - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - - if (data_type_idx >= 0) { - int boffset = spl_declare_var(ctx, vname, data_type_idx, 0); - emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, ENUM_TAG_SIZE, data_type_idx, - boffset); - } - } - - if (!expect(ctx, TOK_R_BRACKET)) - return; - return; - } - - /* ---- Legacy syntax: (name1, name2, ...) ---- */ - advance(ctx); /* ( */ - skip_nl(ctx); - if (peek(ctx)->type == TOK_R_PAREN) { - if (!expect(ctx, TOK_R_PAREN)) - return; - } - - spl_push_scope(ctx); - *scope_pushed = 1; - - spl_type_item_t *var_item = spl_type_item_at(&ctx->tctx, enum_type_idx, variant_item_idx); - int data_type_idx = var_item ? var_item->enum_field.type_idx : -1; - - if (data_type_idx >= 0 && spl_type_kind(&ctx->tctx, data_type_idx) == TYPE_STRUCT) { - /* Multi-field struct destructuring: one binding per struct field */ - spl_type_item_vec_t *data_items = spl_type_items(&ctx->tctx, data_type_idx); - int bi = 0; - for (;;) { - spl_tok_t *btok = advance(ctx); - char bname[256]; - spl_tok_copy_name(btok, bname, sizeof(bname)); - - int btype_idx = spl_type_basic(&ctx->tctx, SPL_I32); - usize field_byte_off = ENUM_TAG_SIZE; /* skip tag */ - { - int fcount = 0; - vec_for(*data_items, di) { - spl_type_item_t *fit = &vec_at(*data_items, di); - if (fit->item_kind == ITEM_FIELD) { - if (fcount == bi) { - btype_idx = fit->aggregate_field.type_idx; - field_byte_off = ENUM_TAG_SIZE + fit->aggregate_field.offset; - break; - } - fcount++; - } - } - } - int boffset = spl_declare_var(ctx, bname, btype_idx, 0); - emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, field_byte_off, btype_idx, - boffset); - - bi++; - skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - break; - } - } else if (data_type_idx >= 0) { - /* Single-value binding */ - spl_tok_t *btok = advance(ctx); - char bname[256]; - spl_tok_copy_name(btok, bname, sizeof(bname)); - - int boffset = spl_declare_var(ctx, bname, data_type_idx, 0); - emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, ENUM_TAG_SIZE, data_type_idx, boffset); - } - - if (!expect(ctx, TOK_R_PAREN)) - return; -} - -/* ============================================================ - * Match statement: - * Enum: match expr { .Variant(bindings) => stmt, ... } - * Value: match expr { lit, lit => stmt, ..., _ => stmt } - * - * Built as enhanced if-else: each arm is a condition chain. - * Fallthrough (comma-separated patterns) uses BNZ for OR. - * ============================================================ */ - -static void parse_match_stmt(spl_comp_t *ctx) { - advance(ctx); /* match */ - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "match expression"); - skip_nl(ctx); - - spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); - - /* Determine match type */ - int is_enum_match = 0; - int enum_type_idx = -1; - int type_idx = expr.type_idx; - if (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM) { - is_enum_match = 1; - enum_type_idx = type_idx; - } else if (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_PTR && - spl_type_elem_type(&ctx->tctx, type_idx) >= 0 && - spl_type_kind(&ctx->tctx, spl_type_elem_type(&ctx->tctx, type_idx)) == TYPE_ENUM) { - is_enum_match = 1; - enum_type_idx = spl_type_elem_type(&ctx->tctx, type_idx); - } else if (!(type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_BASIC && - spl_type_is_integer(spl_type_basic_type(&ctx->tctx, type_idx)))) { - spl_comp_err_tok(ctx, peek(ctx), "match expression must be an enum or integer type"); - return; - } - - /* Scalar enums store the raw tag directly; others store a pointer */ - int match_by_value = (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM && - spl_type_is_scalar(&ctx->tctx, type_idx)); - - /* Save match value to temp slot */ - int val_offset = fa_alloc_temp(&ctx->emit.frame, 1); - emit_store_to_laddr(&ctx->emit, val_offset, spl_type_emit_type(&ctx->tctx, type_idx)); - - skip_nl(ctx); - if (peek(ctx)->type == TOK_L_BRACE) - advance(ctx); /* { */ - - /* Collect JMP-to-end addresses for patching */ - enum { MAX_MATCH_ARMS = 128 }; - spl_val_t jmp_to_end[MAX_MATCH_ARMS]; - int n_jmps = 0; - - skip_nl(ctx); - while (!ctx->has_error && peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - - spl_val_t bz_addr = 0; - int scope_pushed = 0; - int has_parens = 0; - spl_val_t body_start = 0; - spl_val_t bnz_addrs[128]; - int n_bnz = 0; - int arm_variant_item = -1; - - /* --- Parse arm pattern(s): comma-separated with fallthrough --- */ - if (peek(ctx)->type == KW_ANY) { - /* _ default arm: always matches, skip comparison */ - advance(ctx); - } else { - for (;;) { - if (is_enum_match) { - arm_variant_item = - parse_match_enum_variant(ctx, enum_type_idx, val_offset, match_by_value); - if (ctx->has_error) - break; - skip_nl(ctx); - if (peek(ctx)->type == TOK_L_PAREN || peek(ctx)->type == TOK_L_BRACKET) { - has_parens = 1; - break; /* bindings → must be last in fallthrough group */ - } - } else { - parse_match_value_pattern(ctx, val_offset); - } - - /* Check for more comma-separated patterns */ - skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - if (peek(ctx)->type != TOK_ASSIGN) { - if (n_bnz < 128) - bnz_addrs[n_bnz++] = - emit_bnz_here(&ctx->emit); /* fallthrough to body */ - continue; - } - break; - } - break; - } - - /* Last pattern: BZ past body if no match */ - if (!ctx->has_error) { - bz_addr = emit_bz_here(&ctx->emit); - body_start = vec_size(ctx->prog.insns); - } - } - - /* --- Parse enum bindings (only for last variant) --- */ - if (is_enum_match && has_parens && arm_variant_item >= 0) { - parse_match_enum_bindings(ctx, enum_type_idx, arm_variant_item, val_offset, - &scope_pushed); - } - - skip_nl(ctx); - - /* => (two tokens: = >) */ - if (peek(ctx)->type == TOK_ASSIGN) { - advance(ctx); - if (peek(ctx)->type == TOK_GT) - advance(ctx); - } - skip_nl(ctx); - - /* Parse arm body (reuses stmt infrastructure) */ - spl_parse_stmt(ctx); - - /* Pop scope if bindings were declared */ - if (scope_pushed) { - spl_emit_defer_epilogue(ctx, ctx->scope_depth); - spl_pop_scope(ctx); - } - - /* JMP to end (skip remaining arms) */ - if (n_jmps < MAX_MATCH_ARMS) - jmp_to_end[n_jmps++] = emit_jmp_here(&ctx->emit); - - /* Patch BZ to here (next arm or end) */ - if (bz_addr) - emit_patch_here(&ctx->emit, bz_addr); - - /* Patch BNZ fallthroughs to body start */ - for (int i = 0; i < n_bnz; i++) { - spl_val_t offset = body_start - bnz_addrs[i] - 1; - emit_patch(&ctx->emit, bnz_addrs[i], offset); - } - - skip_nl(ctx); - } - - if (!expect(ctx, TOK_R_BRACE)) - return; - - /* Patch all JMPs to end */ - for (int i = 0; i < n_jmps; i++) - emit_patch_here(&ctx->emit, jmp_to_end[i]); - - /* Release temp slot */ - fa_free(&ctx->emit.frame, val_offset); -} - -/* ============================================================ - * Extern declaration: #[extern("vm")] fn name(...) ret; - * ============================================================ */ - -static void parse_extern_decl(spl_comp_t *ctx) { - int tt = peek(ctx)->type; - advance(ctx); /* @ or # */ - skip_nl(ctx); - if (tt == TOK_AT) { - /* @extern(vm) fn ... */ - 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 */ - skip_nl(ctx); - if (peek(ctx)->type == TOK_R_PAREN) - advance(ctx); - } - } - } else { - /* #[extern("vm")] fn ... (legacy) */ - if (!expect(ctx, TOK_L_BRACKET)) - return; - 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) { - 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; - - /* Count params (we don't store them for extern) */ - int nparams = 0; - skip_nl(ctx); - if (peek(ctx)->type != TOK_R_PAREN) { - while (1) { - advance(ctx); /* param name */ - skip_nl(ctx); - if (peek(ctx)->type == TOK_COLON) { - advance(ctx); /* : */ - skip_nl(ctx); - spl_type_parse(&ctx->tctx, ctx); /* skip type */ - } - nparams++; - skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - skip_nl(ctx); - continue; - } - if (peek(ctx)->type == TOK_ELLIPSIS) { - advance(ctx); - skip_nl(ctx); - } /* variadic */ - break; - } - } - if (!expect(ctx, TOK_R_PAREN)) - return; - skip_nl(ctx); - - /* Return type */ - 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); - } - - spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, 0); - - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); - } -} - -/* ============================================================ - * Expression statement (may include assignment) - * ============================================================ */ - -/* Check if token type is an assignment operator */ -static int is_assign_op(spl_tok_type_t t) { - return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB || t == TOK_ASSIGN_MUL || - t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD || t == TOK_ASSIGN_AND || - t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR || t == TOK_ASSIGN_L_SH || - t == TOK_ASSIGN_R_SH; -} - -/* Scan ahead to check if the expression at current position is an assignment. - * Returns 1 if an assignment operator is found before a statement terminator - * or function-call paren. */ -static int lookahead_is_assign(spl_comp_t *ctx) { - usize look = ctx->tok_idx; - while (look < vec_size(ctx->toks)) { - spl_tok_type_t t = vec_at(ctx->toks, look).type; - if (t == TOK_SEMICOLON || t == TOK_ENDLINE || t == TOK_L_BRACE || t == TOK_R_BRACE || - t == TOK_EOF) - break; - if (t == TOK_L_PAREN) - break; - if (is_assign_op(t)) - return 1; - look++; - } - return 0; -} - -static void parse_expr_stmt(spl_comp_t *ctx) { - skip_nl(ctx); - if (peek(ctx)->type == KW_RET) { - parse_ret_stmt(ctx); - return; - } - - usize prev = ctx->tok_idx; - - /* Look ahead for assignment operator */ - int is_assign = lookahead_is_assign(ctx); - - if (is_assign) - ctx->addr_of_mode = 1; - spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); - if (is_assign) - ctx->addr_of_mode = 0; - - if (!is_assign && expr.type_idx >= 0 && - spl_type_emit_type(&ctx->tctx, expr.type_idx) != SPL_VOID) - emit_drop(&ctx->emit); - if (peek(ctx)->type == TOK_SEMICOLON) - advance(ctx); - /* Safety: if no token was consumed, advance to prevent infinite loop */ - if (ctx->tok_idx == prev) - advance(ctx); -} - -/* ============================================================ - * Main statement dispatcher - * ============================================================ */ - -void spl_parse_stmt(spl_comp_t *ctx) { - skip_nl(ctx); - - if (peek(ctx)->type == TOK_EOF || peek(ctx)->type == TOK_R_BRACE) - return; - - switch (peek(ctx)->type) { - case KW_RET: - parse_ret_stmt(ctx); - break; - case KW_VAR: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "variable declaration"); - parse_var_decl(ctx, 0); - break; - case KW_CONST: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "constant declaration"); - parse_var_decl(ctx, 1); - break; - case KW_IF: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "if statement"); - parse_if_stmt(ctx); - break; - case KW_WHILE: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "while statement"); - parse_while_stmt(ctx); - break; - case KW_LOOP: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "loop statement"); - parse_loop_stmt(ctx); - break; - case KW_FOR: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "for statement"); - parse_for_stmt(ctx); - break; - case KW_BREAK: - parse_break_stmt(ctx); - break; - case KW_CONTINUE: - parse_continue_stmt(ctx); - break; - case KW_DEFER: - parse_defer_stmt(ctx); - break; - case KW_MATCH: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "match expression"); - parse_match_stmt(ctx); - break; - case KW_TYPE: - parse_type_decl(ctx); - break; - case TOK_L_BRACE: - spl_parse_block(ctx); - break; - case TOK_LINE_COMMENT: - advance(ctx); - break; - case TOK_AT: { /* @extern(...) or @dbg/@@sizeof expression */ - usize saved = ctx->tok_idx; - advance(ctx); /* @ */ - skip_nl(ctx); - spl_tok_t *t = peek(ctx); - if (t && t->type == KW_EXTERN) { - ctx->tok_idx = saved; - parse_extern_decl(ctx); - } else { - ctx->tok_idx = saved; - parse_expr_stmt(ctx); - } - break; - } - case TOK_SHARP: /* #[extern(...)] (legacy) */ - parse_extern_decl(ctx); - break; - default: - snprintf(ctx->parse_context, sizeof(ctx->parse_context), "expression statement"); - parse_expr_stmt(ctx); - break; - } -} diff --git a/stage1/spl_tok.h b/stage1/spl_tok.h new file mode 100644 index 0000000..a240c7b --- /dev/null +++ b/stage1/spl_tok.h @@ -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__ */ diff --git a/stage1/spl_type.c b/stage1/spl_type.c deleted file mode 100644 index a68b568..0000000 --- a/stage1/spl_type.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* spl_type.c — Type system: arena, constructors, layout, accessors */ - -#include "spl_type.h" -#include "spl_comp.h" -#include "spl_lex_util.h" -#include -#include -#include - -/* ============================================================ - * Lifecycle - * ============================================================ */ - -void spl_type_ctx_init(spl_type_ctx_t *tctx) { - memset(tctx, 0, sizeof(*tctx)); - memset(tctx->basic_cache, 0, sizeof(tctx->basic_cache)); - vec_init(tctx->types); - map_init(tctx->type_map, MAP_HASH_STR, MAP_CMP_STR); - - /* Create root type (compilation unit) */ - spl_type_info_t root; - memset(&root, 0, sizeof(root)); - root.name = strdup("$root"); - root.kind = TYPE_STRUCT; - root.resolved = 1; - root.byte_size = 0; - root.slot_count = 0; - root.parent_type_idx = -1; - vec_init(root.items); - vec_push(tctx->types, root); - tctx->root_type_idx = 0; - tctx->current_type_idx = 0; -} - -void spl_type_ctx_drop(spl_type_ctx_t *tctx) { - if (!tctx) - return; - vec_for(tctx->types, i) { - spl_type_info_t *t = &vec_at(tctx->types, i); - free(t->name); - vec_for(t->items, j) { free((void *)vec_at(t->items, j).name); } - vec_free(t->items); - } - vec_free(tctx->types); - map_free(tctx->type_map); -} - -/* ============================================================ - * Internal: add a type to arena, return index - * ============================================================ */ - -static int spl_type_add(spl_type_ctx_t *tctx, spl_type_info_t t) { - vec_push(tctx->types, t); - return (int)vec_size(tctx->types) - 1; -} - -/* ============================================================ - * Basic type → type_idx lookup (memoized singleton per basic type) - * ============================================================ */ - -static int spl_basic_byte_size(spl_type_t bt) { - switch (bt) { - case SPL_VOID: - return 0; - case SPL_I8: - case SPL_U8: - return 1; - case SPL_I16: - case SPL_U16: - return 2; - case SPL_I32: - case SPL_U32: - case SPL_F32: - return 4; - case SPL_F64: - case SPL_I64: - case SPL_U64: - return 8; - case SPL_ISIZE: - case SPL_USIZE: - case SPL_PTR: - return (int)sizeof(spl_val_t); - default: - return 0; - } -} - -int spl_type_basic(spl_type_ctx_t *tctx, spl_type_t bt) { - if (bt >= SPL_TYPE_COUNT) - return -1; - - /* Use memoized singletons for basic types */ - if (bt < SPL_TYPE_COUNT && tctx->basic_cache[bt] != 0) - return tctx->basic_cache[bt]; - - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_BASIC; - t.basic_type = bt; - t.byte_size = (usize)spl_basic_byte_size(bt); - t.slot_count = t.byte_size == 0 ? 0 : 1; - t.resolved = 1; - vec_init(t.items); - - int idx = spl_type_add(tctx, t); - if (bt < SPL_TYPE_COUNT) - tctx->basic_cache[bt] = idx; - return idx; -} - -/* ============================================================ - * Name → basic type - * ============================================================ */ - -int spl_type_is_integer(spl_type_t bt) { - switch (bt) { - case SPL_I8: - case SPL_U8: - case SPL_I16: - case SPL_U16: - case SPL_I32: - case SPL_U32: - case SPL_I64: - case SPL_U64: - case SPL_ISIZE: - case SPL_USIZE: - return 1; - default: - return 0; - } -} - -static spl_type_t name_to_basic_type(const char *name, usize len) { - if (len == 3 && memcmp(name, "i32", 3) == 0) - return SPL_I32; - if (len == 3 && memcmp(name, "u32", 3) == 0) - return SPL_U32; - if (len == 2 && memcmp(name, "i8", 2) == 0) - return SPL_I8; - if (len == 2 && memcmp(name, "u8", 2) == 0) - return SPL_U8; - if (len == 3 && memcmp(name, "i16", 3) == 0) - return SPL_I16; - if (len == 3 && memcmp(name, "u16", 3) == 0) - return SPL_U16; - if (len == 3 && memcmp(name, "i64", 3) == 0) - return SPL_I64; - if (len == 3 && memcmp(name, "u64", 3) == 0) - return SPL_U64; - if (len == 4 && memcmp(name, "bool", 4) == 0) - return SPL_I32; - if (len == 4 && memcmp(name, "void", 4) == 0) - return SPL_VOID; - if (len == 5 && memcmp(name, "isize", 5) == 0) - return SPL_ISIZE; - if (len == 5 && memcmp(name, "usize", 5) == 0) - return SPL_USIZE; - if (len == 2 && memcmp(name, "f3", 2) == 0 && name[2] == '2') - return SPL_F32; - if (len == 2 && memcmp(name, "f6", 2) == 0 && name[2] == '4') - return SPL_F64; - if (len == 3 && memcmp(name, "ptr", 3) == 0) - return SPL_PTR; - return SPL_TYPE_COUNT; -} - -/* ============================================================ - * Constructors — PTR / ARRAY / SLICE - * - * Encode element info in items[0].aggregate_field: - * type_idx = element type index - * offset = array length (for ARRAY) - * ============================================================ */ - -int spl_type_ptr(spl_type_ctx_t *tctx, int elem_type_idx) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_PTR; - t.byte_size = sizeof(spl_val_t); - t.slot_count = 1; - t.resolved = 1; - vec_init(t.items); - - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.item_kind = ITEM_FIELD; - item.aggregate_field.type_idx = elem_type_idx; - item.aggregate_field.offset = 0; - vec_push(t.items, item); - - return spl_type_add(tctx, t); -} - -int spl_type_array(spl_type_ctx_t *tctx, int elem_type_idx, usize len) { - spl_type_info_t *elem = (elem_type_idx >= 0) ? &vec_at(tctx->types, elem_type_idx) : NULL; - - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_ARRAY; - t.byte_size = elem ? elem->byte_size * len : 0; - t.slot_count = elem ? elem->slot_count * len : 0; - t.resolved = 1; - vec_init(t.items); - - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.item_kind = ITEM_FIELD; - item.aggregate_field.type_idx = elem_type_idx; - item.aggregate_field.offset = len; - vec_push(t.items, item); - - return spl_type_add(tctx, t); -} - -int spl_type_slice(spl_type_ctx_t *tctx, int elem_type_idx) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_SLICE; - t.byte_size = sizeof(spl_val_t) * 2; - t.slot_count = 2; - t.resolved = 1; - vec_init(t.items); - - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.item_kind = ITEM_FIELD; - item.aggregate_field.type_idx = elem_type_idx; - item.aggregate_field.offset = 0; - vec_push(t.items, item); - - return spl_type_add(tctx, t); -} - -/* ============================================================ - * Constructors — STRUCT / UNION / ENUM - * ============================================================ */ - -int spl_type_struct(spl_type_ctx_t *tctx, const char *name) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_STRUCT; - if (name) - t.name = strdup(name); - t.resolved = 0; - vec_init(t.items); - - int idx = spl_type_add(tctx, t); - if (name) - map_put(tctx->type_map, strdup(name), idx); - return idx; -} - -int spl_type_union(spl_type_ctx_t *tctx, const char *name) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_UNION; - if (name) - t.name = strdup(name); - t.resolved = 0; - vec_init(t.items); - - int idx = spl_type_add(tctx, t); - if (name) - map_put(tctx->type_map, strdup(name), idx); - return idx; -} - -int spl_type_enum(spl_type_ctx_t *tctx, const char *name) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_ENUM; - if (name) - t.name = strdup(name); - t.byte_size = ENUM_TAG_SIZE; /* tag */ - t.slot_count = 1; - t.resolved = 0; - vec_init(t.items); - - int idx = spl_type_add(tctx, t); - if (name) - map_put(tctx->type_map, strdup(name), idx); - return idx; -} - -int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_NAME; - if (name) - t.name = strdup(name); - t.resolved = 0; - vec_init(t.items); - - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.item_kind = ITEM_FIELD; - item.aggregate_field.type_idx = target_type_idx; - item.aggregate_field.offset = 0; - vec_push(t.items, item); - - int idx = spl_type_add(tctx, t); - if (name) - map_put(tctx->type_map, strdup(name), idx); - return idx; -} - -int spl_type_fn(spl_type_ctx_t *tctx, int params_type_idx, int ret_type_idx) { - spl_type_info_t t; - memset(&t, 0, sizeof(t)); - t.kind = TYPE_FN; - t.byte_size = sizeof(spl_val_t); - t.slot_count = 1; - t.resolved = 1; - vec_init(t.items); - - spl_type_item_t pi; - memset(&pi, 0, sizeof(pi)); - pi.item_kind = ITEM_FIELD; - pi.aggregate_field.type_idx = params_type_idx; - pi.aggregate_field.offset = 0; - vec_push(t.items, pi); - - spl_type_item_t ri; - memset(&ri, 0, sizeof(ri)); - ri.item_kind = ITEM_FIELD; - ri.aggregate_field.type_idx = ret_type_idx; - ri.aggregate_field.offset = sizeof(spl_val_t); - vec_push(t.items, ri); - - return spl_type_add(tctx, t); -} - -/* ============================================================ - * Item management - * ============================================================ */ - -void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, int field_type_idx) { - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.name = strdup(name); - item.item_kind = ITEM_FIELD; - item.aggregate_field.type_idx = field_type_idx; - item.aggregate_field.offset = 0; - vec_push(t->items, item); - /* Adding field after layout was computed → needs recompute */ - if (t->resolved == 1) - t->resolved = 0; -} - -void spl_type_add_var(spl_type_ctx_t *tctx, int type_idx, const char *name, int var_type_idx) { - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.name = strdup(name); - item.item_kind = ITEM_VAR; - item.aggregate_field.type_idx = var_type_idx; - item.aggregate_field.offset = 0; - vec_push(t->items, item); -} - -void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, int data_type_idx) { - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.name = strdup(name); - item.item_kind = ITEM_VARIANT; - item.enum_field.type_idx = data_type_idx; - item.enum_field.value = vec_size(t->items); - vec_push(t->items, item); - if (t->resolved == 1) - t->resolved = 0; -} - -void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx) { - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - - /* Deduplicate: update existing method entry */ - vec_for(t->items, i) { - spl_type_item_t *it = &vec_at(t->items, i); - if (it->item_kind == ITEM_METHOD && it->name && strcmp(it->name, name) == 0) { - it->method.func_idx = func_idx; - return; - } - } - - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.name = strdup(name); - item.item_kind = ITEM_METHOD; - item.method.func_idx = func_idx; - vec_push(t->items, item); -} - -void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name, - int child_type_idx) { - spl_type_info_t *t = &vec_at(tctx->types, parent_idx); - spl_type_item_t item; - memset(&item, 0, sizeof(item)); - item.name = strdup(name); - item.item_kind = ITEM_NESTED_TYPE; - item.nested_type.type_idx = child_type_idx; - vec_push(t->items, item); - - vec_at(tctx->types, child_type_idx).parent_type_idx = parent_idx; -} - -/* ============================================================ - * Layout computation - * ============================================================ */ - -void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (t->resolved == 1) - return; - if (t->resolved == 2) { - fprintf(stderr, "error: circular type dependency in '%s'\n", t->name ? t->name : "?"); - return; - } - - t->resolved = 2; /* mark as in-progress */ - - switch (t->kind) { - case TYPE_STRUCT: { - usize offset = 0; - vec_for(t->items, i) { - spl_type_item_t *it = &vec_at(t->items, i); - if (it->item_kind == ITEM_VAR) - continue; - if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) { - spl_type_compute_layout(tctx, it->aggregate_field.type_idx); - spl_type_info_t *ft = &vec_at(tctx->types, it->aggregate_field.type_idx); - it->aggregate_field.offset = offset; - offset += ft->byte_size; - } - } - t->byte_size = offset; - usize slot_sz = sizeof(spl_val_t); - t->slot_count = (offset + slot_sz - 1) / slot_sz; - if (t->slot_count < 1) - t->slot_count = 1; - t->resolved = 1; - break; - } - case TYPE_UNION: { - usize max_sz = 0; - vec_for(t->items, i) { - spl_type_item_t *it = &vec_at(t->items, i); - if (it->item_kind == ITEM_VAR) - continue; - if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) { - spl_type_compute_layout(tctx, it->aggregate_field.type_idx); - spl_type_info_t *ft = &vec_at(tctx->types, it->aggregate_field.type_idx); - it->aggregate_field.offset = 0; - if (ft->byte_size > max_sz) - max_sz = ft->byte_size; - } - } - t->byte_size = max_sz; - usize slot_sz = sizeof(spl_val_t); - t->slot_count = (max_sz + slot_sz - 1) / slot_sz; - if (t->slot_count < 1) - t->slot_count = 1; - t->resolved = 1; - break; - } - case TYPE_ENUM: { - usize max_dsize = 0; - vec_for(t->items, i) { - spl_type_item_t *it = &vec_at(t->items, i); - if (it->item_kind == ITEM_VARIANT && it->enum_field.type_idx >= 0) { - spl_type_compute_layout(tctx, it->enum_field.type_idx); - spl_type_info_t *dt = &vec_at(tctx->types, it->enum_field.type_idx); - if (dt->byte_size > max_dsize) - max_dsize = dt->byte_size; - } - } - usize total = ENUM_TAG_SIZE + max_dsize; - usize slot_sz = sizeof(spl_val_t); - t->byte_size = total; - t->slot_count = (total + slot_sz - 1) / slot_sz; - if (t->slot_count < 1) - t->slot_count = 1; - t->resolved = 1; - break; - } - case TYPE_NAME: { - int target = spl_type_elem_type(tctx, type_idx); - if (target >= 0) { - spl_type_compute_layout(tctx, target); - spl_type_info_t *at = &vec_at(tctx->types, target); - t->byte_size = at->byte_size; - t->slot_count = at->slot_count; - } - t->resolved = 1; - break; - } - default: - break; - } -} - -/* ============================================================ - * Accessors - * ============================================================ */ - -spl_type_kind_t spl_type_kind(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0 || (usize)type_idx >= vec_size(tctx->types)) - return TYPE_VOID; - return vec_at(tctx->types, type_idx).kind; -} - -spl_type_t spl_type_basic_type(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0 || (usize)type_idx >= vec_size(tctx->types)) - return SPL_I32; - return vec_at(tctx->types, type_idx).basic_type; -} - -const char *spl_type_name(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0 || (usize)type_idx >= vec_size(tctx->types)) - return NULL; - return vec_at(tctx->types, type_idx).name; -} - -usize spl_type_size(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return 0; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (!t->resolved) - spl_type_compute_layout(tctx, type_idx); - return t->byte_size; -} - -usize spl_type_slot_count(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return 0; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (!t->resolved) - spl_type_compute_layout(tctx, type_idx); - return t->slot_count; -} - -usize spl_type_elem_stride(spl_type_ctx_t *tctx, int elem_type_idx) { - return spl_type_size(tctx, elem_type_idx); -} - -int spl_type_elem_type(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return -1; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (vec_size(t->items) > 0) - return vec_at(t->items, 0).aggregate_field.type_idx; - return -1; -} - -usize spl_type_array_len(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return 0; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (t->kind == TYPE_ARRAY && vec_size(t->items) > 0) - return vec_at(t->items, 0).aggregate_field.offset; - return 0; -} - -/* ============================================================ - * Classification helpers - * ============================================================ */ - -int spl_type_is_scalar(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return 1; - type_idx = spl_type_resolve_underlying(tctx, type_idx); - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (t->kind == TYPE_BASIC || t->kind == TYPE_PTR || t->kind == TYPE_FN) - return 1; - if (t->kind == TYPE_ENUM) { - vec_for(t->items, i) { - if (vec_at(t->items, i).enum_field.type_idx >= 0) - return 0; /* has data — aggregate */ - } - return 1; /* simple enum — scalar */ - } - return 0; -} - -int spl_type_needs_multi_slot(spl_type_ctx_t *tctx, int type_idx) { - return !spl_type_is_scalar(tctx, type_idx) && spl_type_slot_count(tctx, type_idx) > 1; -} - -int spl_type_is_aggregate(spl_type_ctx_t *tctx, int type_idx) { - return !spl_type_is_scalar(tctx, type_idx); -} - -int spl_type_has_inline_literal(spl_type_ctx_t *tctx, int type_idx) { - spl_type_kind_t k = spl_type_kind(tctx, type_idx); - return k == TYPE_STRUCT || k == TYPE_ENUM || k == TYPE_SLICE; -} - -int spl_type_resolve_underlying(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return -1; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (t->kind == TYPE_NAME) { - int target = spl_type_elem_type(tctx, type_idx); - if (target >= 0) - return spl_type_resolve_underlying(tctx, target); - } - return type_idx; -} - -spl_type_t spl_type_emit_type(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return SPL_I32; - type_idx = spl_type_resolve_underlying(tctx, type_idx); - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (t->kind == TYPE_BASIC) - return t->basic_type; - if (t->kind == TYPE_PTR) - return SPL_PTR; - if (t->kind == TYPE_ENUM) { - vec_for(t->items, i) { - if (vec_at(t->items, i).enum_field.type_idx >= 0) - return SPL_PTR; - } - return SPL_I32; - } - return SPL_PTR; -} - -#define TYPE_STR_BUF_COUNT 8 -#define TYPE_STR_BUF_SIZE 64 - -const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) { - static char b[TYPE_STR_BUF_COUNT][TYPE_STR_BUF_SIZE]; - static int bi = 0; - int my = (bi++) % TYPE_STR_BUF_COUNT; - - if (type_idx < 0) - return ""; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - switch (t->kind) { - case TYPE_VOID: - return "void"; - case TYPE_BASIC: { - switch (t->basic_type) { - case SPL_I32: - return "i32"; - case SPL_U32: - return "u32"; - case SPL_I8: - return "i8"; - case SPL_U8: - return "u8"; - case SPL_I16: - return "i16"; - case SPL_U16: - return "u16"; - case SPL_I64: - return "i64"; - case SPL_U64: - return "u64"; - case SPL_F32: - return "f32"; - case SPL_F64: - return "f64"; - case SPL_PTR: - return "ptr"; - case SPL_ISIZE: - return "isize"; - case SPL_USIZE: - return "usize"; - case SPL_VOID: - return "void"; - default: - return ""; - } - } - case TYPE_PTR: - snprintf(b[my], TYPE_STR_BUF_SIZE, "*%s", - spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); - return b[my]; - case TYPE_ARRAY: - snprintf(b[my], TYPE_STR_BUF_SIZE, "[%zu]%s", spl_type_array_len(tctx, type_idx), - spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); - return b[my]; - case TYPE_SLICE: - snprintf(b[my], TYPE_STR_BUF_SIZE, "[]%s", - spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); - return b[my]; - case TYPE_STRUCT: - case TYPE_UNION: - case TYPE_ENUM: - return t->name ? t->name : ""; - case TYPE_NAME: - return t->name ? t->name : ""; - case TYPE_FN: - return "fn"; - default: - return ""; - } -} - -/* ============================================================ - * Item iteration - * ============================================================ */ - -int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, spl_type_item_kind_t kind) { - if (type_idx < 0) - return 0; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - int count = 0; - vec_for(t->items, i) { - if (vec_at(t->items, i).item_kind == kind) - count++; - } - return count; -} - -spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx, int item_index) { - if (type_idx < 0) - return NULL; - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - if (item_index < 0 || (usize)item_index >= vec_size(t->items)) - return NULL; - return &vec_at(t->items, item_index); -} - -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) { - if (type_idx < 0) { - if (count) - *count = 0; - return NULL; - } - spl_type_info_t *t = &vec_at(tctx->types, type_idx); - int found = 0; - spl_type_item_t *first = NULL; - vec_for(t->items, i) { - if (vec_at(t->items, i).item_kind == kind) { - if (!first) - first = &vec_at(t->items, i); - found++; - } - } - if (count) - *count = found; - return first; -} - -spl_type_item_vec_t *spl_type_items(spl_type_ctx_t *tctx, int type_idx) { - if (type_idx < 0) - return NULL; - return &vec_at(tctx->types, type_idx).items; -} - -/* ============================================================ - * Type resolution - * ============================================================ */ - -int spl_type_resolve(spl_type_ctx_t *tctx, const char *name) { - if (!tctx || !name) - return -1; - - /* 1. Walk from current type up through parent chain */ - int current = tctx->current_type_idx; - while (current >= 0) { - int found = spl_type_resolve_in(tctx, current, name); - if (found >= 0) - return found; - current = vec_at(tctx->types, current).parent_type_idx; - } - - /* 2. Fallback to flat type_map */ - int found = -1; - if (map_get(tctx->type_map, name, &found)) - return found; - return -1; -} - -int spl_type_resolve_in(spl_type_ctx_t *tctx, int parent_idx, const char *name) { - if (parent_idx < 0 || !name) - return -1; - spl_type_info_t *t = &vec_at(tctx->types, parent_idx); - vec_for(t->items, i) { - spl_type_item_t *it = &vec_at(t->items, i); - if (it->item_kind == ITEM_NESTED_TYPE && it->name && strcmp(it->name, name) == 0) - return it->nested_type.type_idx; - } - return -1; -} - -/* ============================================================ - * Parse type from token stream - * - * Needs both tctx (for type construction/resolution) and - * spl_comp_t (for token stream access). - * ============================================================ */ - -int spl_type_parse(spl_type_ctx_t *tctx, struct spl_comp *ctx) { - spl_tok_t *tok = &vec_at(ctx->toks, ctx->tok_idx); - - /* Pointer type: '*T' */ - if (tok->type == TOK_MUL) { - ctx->tok_idx++; - int elem = spl_type_parse(tctx, ctx); - if (elem < 0) - return -1; - return spl_type_ptr(tctx, elem); - } - - /* Array / Slice type: '[N]T' or '[]T' */ - if (tok->type == TOK_L_BRACKET) { - ctx->tok_idx++; - tok = &vec_at(ctx->toks, ctx->tok_idx); - - if (tok->type == TOK_R_BRACKET) { - ctx->tok_idx++; - int elem = spl_type_parse(tctx, ctx); - if (elem < 0) - return -1; - return spl_type_slice(tctx, elem); - } - - int len_val; - if (!spl_parse_int_literal(ctx, &len_val)) { - spl_comp_err_tok(ctx, peek(ctx), "expected array length"); - return -1; - } - usize len = (usize)len_val; - - if (vec_at(ctx->toks, ctx->tok_idx).type != TOK_R_BRACKET) { - spl_comp_err_tok(ctx, peek(ctx), "expected ']'"); - return -1; - } - ctx->tok_idx++; - - int elem = spl_type_parse(tctx, ctx); - if (elem < 0) - return -1; - return spl_type_array(tctx, elem, len); - } - - /* Inline struct/union: struct { field: type, ... } */ - if (tok->type == KW_STRUCT || tok->type == KW_UNION) { - int is_union = (tok->type == KW_UNION); - ctx->tok_idx++; - int ti = is_union ? spl_type_union(tctx, NULL) : spl_type_struct(tctx, NULL); - if (peek(ctx)->type == TOK_L_BRACE) { - advance(ctx); - while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - spl_tok_t *ftok = advance(ctx); - if (peek(ctx)->type == TOK_COLON) { - advance(ctx); - int ftype = spl_type_parse(tctx, ctx); - char fname[256]; - spl_tok_copy_name(ftok, fname, sizeof(fname)); - if (ftype >= 0) - spl_type_add_field(tctx, ti, fname, ftype); - } - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - } - if (peek(ctx)->type == TOK_R_BRACE) - advance(ctx); - } - spl_type_compute_layout(tctx, ti); - return ti; - } - - /* Inline enum: enum { A, B, C, ... } */ - if (tok->type == KW_ENUM) { - ctx->tok_idx++; - int ti = spl_type_enum(tctx, NULL); - if (peek(ctx)->type == TOK_L_BRACE) { - advance(ctx); - while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { - spl_tok_t *vtok = advance(ctx); - if (peek(ctx)->type == TOK_COLON) { - advance(ctx); - int dtype = spl_type_parse(tctx, ctx); - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - spl_type_add_variant(tctx, ti, vname, dtype); - } else { - char vname[256]; - spl_tok_copy_name(vtok, vname, sizeof(vname)); - spl_type_add_variant(tctx, ti, vname, -1); - } - if (peek(ctx)->type == TOK_COMMA) - advance(ctx); - } - if (peek(ctx)->type == TOK_R_BRACE) - advance(ctx); - } - spl_type_compute_layout(tctx, ti); - return ti; - } - - /* Inline function type: fn(params...) rettype */ - if (tok->type == KW_FN) { - ctx->tok_idx++; - if (!expect(ctx, TOK_L_PAREN)) - return -1; - - /* Parse comma-separated parameter types */ - int param_types[64]; /* max 64 params */ - int nparams = 0; - if (peek(ctx)->type != TOK_R_PAREN) { - for (;;) { - int pt = spl_type_parse(tctx, ctx); - if (pt >= 0 && nparams < 64) - param_types[nparams++] = pt; - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - continue; - } - break; - } - } - if (!expect(ctx, TOK_R_PAREN)) - return -1; - - int ret_type = spl_type_parse(tctx, ctx); - if (ret_type < 0) - ret_type = spl_type_basic(tctx, SPL_VOID); - - /* Store param types in a synthetic array type (slot 0 = count, slot 1..N = params) */ - int params_arr = spl_type_array(tctx, spl_type_basic(tctx, SPL_USIZE), nparams); - return spl_type_fn(tctx, params_arr, ret_type); - } - - /* Identifier: basic type or named type */ - if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) { - const char *name = tok->lexeme; - usize len = tok->len; - - spl_type_t bt = name_to_basic_type(name, len); - if (bt != SPL_TYPE_COUNT) { - ctx->tok_idx++; - return spl_type_basic(tctx, bt); - } - - char id_buf[256]; - usize cplen = len < 255 ? len : 255; - memcpy(id_buf, name, cplen); - id_buf[cplen] = '\0'; - - int found = spl_type_resolve(tctx, id_buf); - if (found < 0 && tctx->current_type_idx >= 0) { - const char *cur_type_name = spl_type_name(tctx, tctx->current_type_idx); - if (cur_type_name) { - char qualified[512]; - snprintf(qualified, sizeof(qualified), "%s.%s", cur_type_name, id_buf); - found = spl_type_resolve(tctx, qualified); - } - } - if (found >= 0) { - ctx->tok_idx++; - - while (ctx->tok_idx < vec_size(ctx->toks)) { - spl_tok_t *next = &vec_at(ctx->toks, ctx->tok_idx); - if (next->type != TOK_DOT) - break; - if (ctx->tok_idx + 1 >= vec_size(ctx->toks)) - break; - spl_tok_t *ntok = &vec_at(ctx->toks, ctx->tok_idx + 1); - - char part[256]; - usize plen = ntok->len < 255 ? ntok->len : 255; - memcpy(part, ntok->lexeme, plen); - part[plen] = '\0'; - - char qualified[512]; - snprintf(qualified, sizeof(qualified), "%s.%s", id_buf, part); - - int qfound = spl_type_resolve(tctx, qualified); - if (qfound >= 0) { - found = qfound; - strncpy(id_buf, qualified, sizeof(id_buf) - 1); - ctx->tok_idx += 2; - } else { - int bfound = spl_type_resolve(tctx, part); - if (bfound >= 0) { - found = bfound; - strncpy(id_buf, part, sizeof(id_buf) - 1); - ctx->tok_idx += 2; - } else { - break; - } - } - } - return found; - } - - if (tok->type == KW_ANY) { - ctx->tok_idx++; - int ti = spl_type_basic(tctx, SPL_VOID); /* placeholder */ - return ti; - } - - spl_comp_err_tok(ctx, tok, "unknown type '%s'", id_buf); - ctx->tok_idx++; - return -1; - } - - spl_comp_err_tok(ctx, peek(ctx), "expected type"); - return -1; -} diff --git a/stage1/spl_type.h b/stage1/spl_type.h deleted file mode 100644 index 264490f..0000000 --- a/stage1/spl_type.h +++ /dev/null @@ -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__ */ diff --git a/stage1/splc0.c b/stage1/splc0.c index 220dd61..c0487e1 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -1,13 +1,4 @@ -/* splc0.c — Stage 1 SPL compiler (bootstrap) - * Usage: - * splc0 — compile - * splc0 --dump-tokens — dump tokens - * splc0 --help — help - */ - -#include "../stage0/spl_ir.h" -#include "spl_comp.h" -#include "spl_lex_util.h" +/* splc0.c — SPL compiler CLI */ #include #include #include @@ -33,75 +24,19 @@ static char *read_file(const char *path, long *out_len) { return buf; } -static int cmd_dump_tokens(int argc, char **argv) { - if (argc < 1) { - fprintf(stderr, "Usage: splc0 --dump-tokens \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 \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) { if (argc < 2) { - fprintf(stderr, "Usage: splc0 [--dump-tokens|--help] [output.sir]\n"); + fprintf(stderr, "Usage: splc0 [--dump ] [out]\n"); return 1; } - - if (strcmp(argv[1], "--dump-tokens") == 0) { - return cmd_dump_tokens(argc - 2, argv + 2); - } + if (strcmp(argv[1], "--dump") == 0) + // return cmd_dump(argc - 2, argv + 2); + return 0; if (strcmp(argv[1], "--help") == 0) { - printf("SPL Compiler (stage1 bootstrap)\n"); - printf(" splc0 - compile\n"); - printf(" splc0 --dump-tokens - dump token stream\n"); + printf("splc0 compile\n"); + printf("splc0 --dump dump: tokens,cst,ast,ir,mcode,all\n"); return 0; } - - return cmd_compile(argc - 1, argv + 1); + // return cmd_compile(argc - 1, argv + 1); + return 0; } diff --git a/stage1/splc_cli.c b/stage1/splc_cli.c index 06893ba..40433ce 100644 --- a/stage1/splc_cli.c +++ b/stage1/splc_cli.c @@ -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_vm.h" -#include "spl_comp.h" #include #include @@ -11,28 +10,31 @@ int main(int argc, const char **argv) { int argi = 1; - if (argi >= argc) { - fprintf(stderr, "Usage: spc_vm [entry] [--trace]\n"); - return 1; - } - - const char *path = argv[argi++]; - - /* Parse flags: --entry , --trace */ + /* Parse flags: --entry , --trace, -d */ const char *entry = "main"; int trace = 0; + int debug_addr = 0; for (int i = argi; i < argc; i += 1) { if (strcmp(argv[i], "--entry") == 0 && i + 1 < argc) { entry = argv[++i]; } else if (strcmp(argv[i], "--trace") == 0) { 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 - * remaining positional args as argv[1..], just like a native exe. */ - int spl_argc = argc - (argi - 1); + if (argi >= argc) { + fprintf(stderr, "Usage: spc_vm [-d] [--trace] [args...]\n"); + return 1; + } + + const char *path = argv[argi++]; const char **spl_argv = argv + (argi - 1); + int spl_argc = (int)(argc - (argi - 1)); spl_prog_t prog; 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_comp_register(&prog); spl_vm_t vm; spl_vm_init(&vm); @@ -56,6 +57,7 @@ int main(int argc, const char **argv) { return 1; } spl_vm_set_trace(&vm, trace); + if (debug_addr) spl_vm_set_debug(&vm, 1); int ret = spl_vm_run_until(&vm, 0); spl_vm_drop(&vm); diff --git a/stage1/test16_methods.spl b/stage1/test16_methods.spl index 5bf8c3f..0ad1560 100644 --- a/stage1/test16_methods.spl +++ b/stage1/test16_methods.spl @@ -24,8 +24,8 @@ type Expr = enum { fn eval(self: *Expr) i32 { match self { - .Int(val) => ret val, - .Add(left, right) => ret eval(left) + eval(right), + .Int[val] => ret val, + .Add[.left = left, .right = right] => ret eval(left) + eval(right), } ret 0; } diff --git a/stage1/test18_match.spl b/stage1/test18_match.spl index 5f89aee..f177e67 100644 --- a/stage1/test18_match.spl +++ b/stage1/test18_match.spl @@ -79,7 +79,7 @@ fn test_optional_match() i32 { var o: Optional = Optional { .Some = 42 }; match o { - .Some(val) => { + .Some[val] => { if val != 42 { ret 1; } }, .None => { @@ -90,7 +90,7 @@ fn test_optional_match() i32 { o = Optional { .None }; var is_none: i32 = 0; match o { - .Some(val) => {}, + .Some[val] => {}, .None => { is_none = 1; } } if is_none != 1 { ret 3; } @@ -98,7 +98,7 @@ fn test_optional_match() i32 { /* 多次提取不同值 */ o = Optional { .Some = 99 }; match o { - .Some(val) => { + .Some[val] => { if val != 99 { ret 4; } }, .None => { ret 5; } @@ -115,10 +115,10 @@ fn test_shape_match() i32 { /* Circle: 单数据 */ var s: Shape = Shape { .Circle = 10 }; match s { - .Circle(r) => { + .Circle[r] => { if r != 10 { ret 1; } }, - .Rect(w, h) => { + .Rect[.x = w, .y = h] => { ret 2; } } @@ -126,8 +126,8 @@ fn test_shape_match() i32 { /* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */ s = Shape { .Rect = Point { .x = 3, .y = 4 } }; match s { - .Circle(r) => { ret 3; }, - .Rect(w, h) => { + .Circle[r] => { ret 3; }, + .Rect[.x = w, .y = h] => { if w != 3 { ret 4; } if h != 4 { ret 5; } } @@ -143,16 +143,16 @@ fn test_shape_match() i32 { fn test_action_result_match() i32 { var r: ActionResult = ActionResult { .Success = 200 }; match r { - .Success(code) => { + .Success[code] => { if code != 200 { ret 1; } }, .NotFound => { ret 2; }, - .Timeout(ms) => { + .Timeout[ms] => { ret 3; }, - .Error(msg) => { + .Error[msg] => { ret 4; } } @@ -160,21 +160,21 @@ fn test_action_result_match() i32 { r = ActionResult { .NotFound }; var found: i32 = 1; match r { - .Success(code) => { found = 0; }, + .Success[code] => { found = 0; }, .NotFound => { }, - .Timeout(ms) => { found = 0; }, - .Error(msg) => { found = 0; } + .Timeout[ms] => { found = 0; }, + .Error[msg] => { found = 0; } } if found != 1 { ret 5; } r = ActionResult { .Timeout = 5000 }; match r { - .Success(code) => { ret 6; }, + .Success[code] => { ret 6; }, .NotFound => { ret 7; }, - .Timeout(ms) => { + .Timeout[ms] => { if ms != 5000 { ret 8; } }, - .Error(msg) => { ret 9; } + .Error[msg] => { ret 9; } } ret 0; @@ -252,7 +252,7 @@ fn test_match_in_loop() i32 { } match o { - .Some(val) => { + .Some[val] => { sum = sum + val; }, .None => { } diff --git a/stage1/test20_complex.spl b/stage1/test20_complex.spl index 43301e6..d459353 100644 --- a/stage1/test20_complex.spl +++ b/stage1/test20_complex.spl @@ -253,13 +253,13 @@ fn test_enum_complex() i32 { /* Verify active variant */ match s { - .Active(val) => { + .Active[val] => { if val != 42 { ret 1; } }, .Inactive => { ret 2; }, - .Pending(px, py) => { + .Pending[.x = px, .y = py] => { ret 3; } } @@ -268,18 +268,18 @@ fn test_enum_complex() i32 { var s2: Status = Status { .Inactive }; var is_inactive: i32 = 0; match s2 { - .Active(val) => {}, + .Active[val] => {}, .Inactive => { is_inactive = 1; }, - .Pending(px, py) => {} + .Pending[.x = px, .y = py] => {} } if is_inactive != 1 { ret 4; } /* Test Pending variant with struct data */ var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } }; match s3 { - .Active(val) => { ret 5; }, + .Active[val] => { ret 5; }, .Inactive => { ret 6; }, - .Pending(px, py) => { + .Pending[.x = px, .y = py] => { if px != 7 { ret 7; } if py != 8 { ret 8; } }