Compare commits

..

5 Commits

Author SHA1 Message Date
zzy
8ac59dfaa1 stage1 完成sema词法 2026-08-04 10:20:57 +08:00
zzy
74d7376039 stage1 完成ast 定义sema 2026-08-03 12:39:28 +08:00
zzy
a4ec5656d2 stage1 完整ast 部分ir 定义 2026-08-01 22:48:42 +08:00
zzy
b43042c88d stage1 重构代码 2026-08-01 21:15:47 +08:00
zzy
a77eade06f stage0 更改名称spl_ir -> spl_mcode spl_cli提供debug模式 提供临时语言规范 2026-07-29 12:05:18 +08:00
52 changed files with 8335 additions and 6753 deletions

8
.gitignore vendored
View File

@@ -2,3 +2,11 @@
!.gitignore
build/
*.sir
*.o
*.obj
*.exe
*.out

1175
SPL.md Normal file

File diff suppressed because it is too large Load Diff

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

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

View File

@@ -9,7 +9,8 @@
#ifndef nullptr
#define nullptr NULL
#endif
typedef size_t usize;
typedef uintptr_t usize;
typedef intptr_t isize;
#define MAP_TYPEOF __typeof__
@@ -83,11 +84,9 @@ static inline usize map_hash_str(const char *s) {
#define map_put(map, _key, _val) \
do { \
/* 扩容 */ \
if ((map).cap == 0 || \
(map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \
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 = \
MAP_SLOT(MAP_TYPEOF((map).data->key), MAP_TYPEOF((map).data->val)) *new_data = \
calloc(new_cap, sizeof(*new_data)); \
if (!new_data) \
abort(); \
@@ -116,8 +115,7 @@ static inline usize map_hash_str(const char *s) {
(map).data[_idx].val = _val; \
break; \
} \
if ((map).data[_idx].state == __MAP_SLOT_DELETED && \
_first_del == (usize) - 1) \
if ((map).data[_idx].state == __MAP_SLOT_DELETED && _first_del == (usize) - 1) \
_first_del = _idx; \
_idx = (_idx + 1) & _mask; \
} \

View File

@@ -18,6 +18,7 @@
#define __vec_free free
#define __vec_memcpy memcpy
#else
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -214,8 +215,7 @@ typedef size_t usize;
* @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)

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

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

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

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

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

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

View File

@@ -4,23 +4,32 @@
* Built-in syscalls are auto-registered via spl_syscall_register().
*
* Usage:
* spl_cli <file.sir> [entry_point]
* spl_cli [-d] <file.sir> [entry_point]
*/
#include "spl_ir.h"
#include "spl_mcode.h"
#include "spl_syscall.h"
#include "spl_vm.h"
#include <stdio.h>
#include <string.h>
int main(int argc, const char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: spl_cli <file.sir> [entry_point]\n");
int debug_mode = 0;
int arg_idx = 1;
if (argc >= 2 && strcmp(argv[1], "-d") == 0) {
debug_mode = 1;
arg_idx = 2;
}
if (arg_idx >= argc) {
fprintf(stderr, "Usage: spl_cli [-d] <file.sir> [entry_point]\n");
return 1;
}
const char *path = argv[1];
const char *entry = argc >= 3 ? argv[2] : "main";
const char *path = argv[arg_idx];
const char *entry = argc >= arg_idx + 2 ? argv[arg_idx + 1] : "main";
spl_prog_t prog;
if (spl_prog_load_from_file(path, &prog) != 0) {
@@ -32,6 +41,7 @@ int main(int argc, const char **argv) {
spl_vm_t vm;
spl_vm_init(&vm);
if (debug_mode) spl_vm_set_debug(&vm, 1);
if (spl_vm_load_prog(&vm, &prog) != 0) {
fprintf(stderr, "vm: prog '%s' not found\n", entry);
spl_prog_drop(&prog);

View File

@@ -3,7 +3,7 @@
* Usage: spl_disasm <file.sir>
*/
#include "spl_ir.h"
#include "spl_mcode.h"
#include <stdio.h>
int main(int argc, const char **argv) {

View File

@@ -1,4 +1,4 @@
/* spl_ir.c — SIR binary serialization, deserialization, and utilities
/* spl_mcode.c — SPL VM machine code binary serialization, deserialization, and utilities
*
* Binary format (all metadata fields are spl_val_t = uint64_t LE):
* [HEADER] magic(8) nfuncs(8) ninsns(8) nnatives(8) nstrs(8) ndata(8)
@@ -9,7 +9,7 @@
* [STRTAB] each: slen(8) str(slen bytes, padded to 8)
*/
#include "spl_ir.h"
#include "spl_mcode.h"
void spl_prog_init(spl_prog_t *prog) {
if (!prog)
@@ -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;
@@ -447,6 +404,8 @@ 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:

View File

@@ -1,8 +1,8 @@
/* spl_ir.h - SPL Intermediate Representation: instruction set and binary format
/* spl_mcode.h - SPL VM Machine Code: instruction set and binary format
*/
#ifndef __SPL_IR_H__
#define __SPL_IR_H__
#ifndef __SPL_MCODE_H__
#define __SPL_MCODE_H__
#include "include/core_map.h"
#include "include/core_vec.h"
@@ -14,6 +14,7 @@ typedef intptr_t isize;
typedef enum {
SPL_VOID,
SPL_BOOL,
SPL_I8,
SPL_U8,
SPL_I16,
@@ -207,17 +208,10 @@ 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);
void spl_ins_dump(spl_ins_t *ins, spl_val_t addr);
#endif /* __SPL_IR_H__ */
#endif /* __SPL_MCODE_H__ */

View File

@@ -10,7 +10,7 @@
#include "spl_syscall.h"
#include "include/core_map.h"
#include "include/core_vec.h"
#include "spl_ir.h"
#include "spl_mcode.h"
#include "spl_vm.h"
#include <stdio.h>
@@ -128,7 +128,7 @@ static spl_val_t vm_read_file(int nargs, spl_val_t *args) {
const char *path = (const char *)(uintptr_t)args[0];
if (path == nullptr) {
fprintf(stderr, "filepath can't be null");
return 1;
return 0;
}
FILE *f = fopen(path, "rb");
if (!f) {

View File

@@ -12,7 +12,7 @@
#ifndef __SPL_SYSCALL_H__
#define __SPL_SYSCALL_H__
#include "spl_ir.h"
#include "spl_mcode.h"
/* Register all known built-in syscalls into prog->natives[].
* Entries whose name matches a known syscall get their impl_fn set;

View File

@@ -5,7 +5,7 @@
*/
#include "spl_vm.h"
#include "spl_ir.h"
#include "spl_mcode.h"
#include <stdio.h>
#include <stdlib.h>
@@ -45,6 +45,7 @@ static int spl_type_size(spl_type_t t) {
switch (t) {
case SPL_VOID:
return 0;
case SPL_BOOL:
case SPL_I8:
case SPL_U8:
return 1;
@@ -80,6 +81,16 @@ static int spl_type_size(spl_type_t t) {
return -1; \
} while (0)
#define CHECK_ADDR(addr, label) do { \
if (vm->debug_addr && (uintptr_t)(addr) < 0x1000) { \
fprintf(stderr, "vm: %s at ip=%zd: LOW ADDR=%p sp=%zd fp=%zd\n", \
label, vm->ip - 1, (void*)(uintptr_t)(addr), vm->sp, vm->fp); \
spl_vm_stackdump(vm, vm->sp); \
spl_vm_backtrace(vm, vm->fp); \
vm->exit_code = 1; return -1; \
} \
} while(0)
/* ================================================================
* Stack push/pop (stacks.data is pre-allocated in init)
* ================================================================ */
@@ -547,6 +558,7 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
vm->prog = NULL;
vm->trace = 0;
vm->debug = 1;
vm->debug_addr = 0;
vm->exit_code = 0;
}
@@ -584,6 +596,7 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) {
if (!vm)
return;
vm->debug = enabled ? 1 : 0;
vm->debug_addr = enabled ? 1 : 0;
}
#define STACK_CANARY(vm) (vm)->stacks.data[(vm)->fp - 1]
@@ -922,6 +935,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
/* ========== Indirect Memory (load/store with types) ========== */
case SPL_LOAD: {
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "LOAD");
spl_val_t _v = 0;
usize _sz = spl_type_size(ins->type);
memcpy(&_v, _addr, _sz);
@@ -936,6 +950,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
case SPL_STORE: {
spl_val_t _v = POP();
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "STORE");
memcpy(_addr, &_v, spl_type_size(ins->type));
break;
}

View File

@@ -4,7 +4,7 @@
#define __SPL_VM_H__
#include "include/core_vec.h"
#include "spl_ir.h"
#include "spl_mcode.h"
#include <stdint.h>
#define SPL_STACK_CANARY ((spl_val_t)0xDEADBEEFCAFEBABEull)
@@ -30,6 +30,7 @@ typedef struct {
int exit_code;
int trace; /* non-zero to print each instruction */
int debug; /* non-zero to enable canary checks */
int debug_addr; /* non-zero to check for low-address memory access */
spl_prog_t *prog;
char error_msg[1024];
struct {

View File

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

View File

@@ -1,452 +0,0 @@
# SPL — 语法与语义
## 概述
类 C 语法的系统编程语言,受 Rust/Zig 启发。编译为 SIRSPL 中间表示),一种基于栈的字节码。多阶段引导:
```
C → splc0(C) → splc1(SPL) → splc2(SPL) → ...
```
---
## 词法结构
### 注释
```
// 行注释
/* 块注释 */
```
### 标识符
`[a-zA-Z_][a-zA-Z0-9_]*`
### 关键字
```
as asm bool break catch comptime const continue
defer else enum errdefer false fn for
if loop match null ret struct
test true try type union var void
while _
```
### 字面量
| 种类 | 示例 | 类型 |
|-------------|---------------------------------|---------|
| 整数 | `42` `0xFF` `0b1010` `0o77` | i32 |
| 字符 | `'A'` `'\n'` `'\\'` | i32 |
| 字符串 | `"hello"` `"line\n"` | i8* |
| 布尔 | `true` `false` | bool |
| 空 | `null` | null/0/undefinded |
### 运算符
| 类别 | 符号 |
|------------|------------------------------------------------------------|
| 算术 | `+` `-` `*` `/` `%` |
| 位运算 | `&` `\|` `^` `~` `<<` `>>` |
| 比较 | `==` `!=` `<` `<=` `>` `>=` |
| 逻辑 | `&&` `\|\|` `!` |
| 赋值 | `=` `+=` `-=` `*=` `/=` `%=` `&=` `\|=` `^=` `<<=` `>>=` |
| 其他 | `&`(取地址) `*`(解引用) `.` `->` `<-` `..` `...` `:` `:=` `?` |
---
## 类型系统
### 基本类型
| 名称 | SIR 类型 | 大小(字节) |
|--------|-------------|-------------|
| void | SPL_VOID | 0 |
| bool | SPL_I32 | 4 |
| i8 | SPL_I8 | 1 |
| u8 | SPL_U8 | 1 |
| i16 | SPL_I16 | 2 |
| u16 | SPL_U16 | 2 |
| i32 | SPL_I32 | 4 |
| u32 | SPL_U32 | 4 |
| i64 | SPL_I64 | 8 |
| u64 | SPL_U64 | 8 |
| isize | SPL_ISIZE | sizeof(ptr) |
| usize | SPL_USIZE | sizeof(ptr) |
| f32 | SPL_F32 | 4 |
| f64 | SPL_F64 | 8 |
| ptr | SPL_PTR | 8 |
| _ | SPL_ ... | (推断) |
`_` 是通配符类型——用作类型推断的占位符。在大多数声明上下文中无效。
### 指针类型
写作 `*T`。示例:`*i32``*u8``*void`
同类型指针会去重。
### 数组类型
写作 `[N]T`。示例:`[10]i32`。数组是值类型(存在于栈槽或全局数据中)。`T` 可以是任意类型。
数组/复合类型 在VM堆上申请内存 `N * sizeof(T)`
### 切片类型
写作 `[]T`。示例:`[]i32``[]u8`。切片是数组的一段连续视图,底层实现为胖指针:
```
[]T = struct { ptr: *T, len: i32 }
```
栈上占 **2 个槽位**(指针 + 长度)。通过切片表达式从数组创建:
```
var arr: [10]i32 = ...;
var slice: []i32 = arr[3..7]; // 取 arr[3..7) 视图
var full: []i32 = arr[0..]; // 省略结束值 = 到末尾
```
此外,切片也可以从另一个切片再切片得到,长度限制为原切片的 len。
### 聚合类型
```
type Name = struct { field: Type, ... };
type Name = union { field: Type, ... };
type Name = enum { A, B, C, ... };
```
- **struct**:字段按顺序排列(默认由 SPL 定义布局,可通过 `#[extern("vm")]` 覆盖)
- **union**所有字段共享同一偏移sizeof = 最大字段大小)
- **enum**:无字段,值为从 0 开始的整数常量
聚合类型在堆上分配,如果需要栈分配那么栈上占用 `size` 个槽位struct 为各字段大小之和union 为最大字段大小enum 为 1
`type Name = ExistingType;` 形式用于定义简单类型别名,但目前仅支持聚合类型的别名定义。
### 聚合类型拓展与match
```
type Expr = enum {
Int: i32,
Add: struct { left: *Expr, right: *Expr },
fn eval(self: *Expr) i32 {
match self {
.Int(val) => ret val,
.Add(left, right) => ret eval(left) + eval(right),
}
ret 0;
}
}
type Point = struct {
x: i32,
y: i32,
type Test = enum {
TestEnum0,
TestEnum1
}
fn init(x: i32, y: i32) Point {
ret Point { .x = x, .y = y };
}
fn dump(self: *Point) void {
vm_printf("Point: %d %d", self.x, self.y);
}
}
```
这里面包括聚合类型声明除了成员以外任何东西,即整个编译模块也属于聚合类型,将类型抽象化。
其中这里面还包括调用时支持第一个参数self匹配类型时自动填充。
暂时默认全部pub即全部暴露没有不暴露的。
复合enum支持match等语法解包
```
match self {
.Int(val) => ret val,
.Add(left, right) => ret eval(left) + eval(right),
}
```
---
## 声明
### 函数
```
fn name(param: Type, ...) ReturnType {
body...
}
fn name(param: Type, ...) ReturnType; // 前向声明一般来说不需要
```
函数参数在栈上按声明顺序从左到右排列。参数通过 `LADDR fp+idx` 访问。
### 原生函数VM 互操作)
```
#[extern("vm")]
fn vm_function(arg: Type, ...) ReturnType;
```
声明一个可通过 NCALL 调用的外部 VM 函数。运行时须链接或通过 `spl_syscall_register()` 注册实现。
### 类型别名
```
type Name = struct/union/enum { ... };
type Name = ExistingType;
```
### 变量
```
var name: Type = expr;
```
变量在当前函数栈帧上分配空间。声明时若带 `= expr` 则将表达式值存入栈槽。
### 常量
```
const name: Type = expr;
```
在 splc0 中常量也被分配栈空间(行为与 var 相同)。编译时可求值的常量会被记录到 `consts` 映射表,允许在局部作用域中引用。
### 短声明
```
var name := expr; // 类型推断为 expr 的 type
const name := const_expr; // 类型推断为 expr 的 type
```
语法糖:声明变量/常量并立即赋初始值,类型从表达式推断。
---
## 内置指令(@ 前缀)
`@` 开头的标识符用于编译器内置操作:
### @import
```
@import("path")
```
在编译时导入另一个 SPL 源文件。路径相对于当前源文件目录。用于模块化编译。
### @sizeof
```
@sizeof(T)
```
返回类型 `T` 的大小字节编译期常量。可用于分配内存、I/O 缓冲区。splc0 中暂未实现。
### @offsetof
```
@offsetof(T, field)
```
返回结构体 `T` 中字段 `field` 的字节偏移。实现泛型/运行时反射时有用。splc0 中暂未实现。
### @panic
```
@panic("message")
```
编译期中断输出错误信息并终止编译。splc0 中暂未实现。
### @assert
```
@assert(expr)
```
编译期断言——若 `expr` 为假则中断编译。splc0 中暂未实现。
### @embed
```
@embed("file")
```
在编译时将文件内容作为字节数组嵌入程序。splc0 中暂未实现。
---
## 语句
### 块
```
{ statement; statement; ... }
```
创建新作用域——局部声明的变量在退出时被丢弃符号表弹出且defer也是基于块作用域的
块可以返回值,只需要最后一个表达式没有分号。
### 表达式语句
```
expr;
```
### 赋值
```
name = expr;
name += expr;
name.field = expr;
name[expr] = expr;
```
支持 `=``+=``-=``*=``/=``%=``&=``|=``^=``<<=``>>=`
### 返回
```
ret expr;
ret; // void 返回(仅限 void 函数)
```
RET 指令会根据函数返回类型携带或不带返回值。
### If / Else
```
if expr statement
if expr statement else statement
```
`expr` 必须求值为 booli32或者成功语义。`statement` 可以是块 `{ }`
实现:`BZ` 跳转到 else 分支,`JMP` 跳过 else 分支。
### While
```
while expr { ... }
```
实现:在循环顶部求值 `expr``BZ` 跳转到循环结束,循环体末尾 `JMP` 跳回顶部。
### Loop
```
loop { ... }
```
无限循环。使用 `break` 退出,`continue` 重新开始。
### Break / Continue
```
break;
continue;
```
break 通过链表记录所有跳出位置,在循环结束后统一回填目标地址。
### Defer
```
defer { ... }
defer statement;
```
作用域退出时延迟执行
### For Range
```
for 0..N as i { body }
for slice as val { body }
for slice, 0.. as val, idx { body }
```
Range for 循环。支持三种形式:
1. **数值区间** `for begin..end as i``i``begin``end-1`,步长 1
2. **切片遍历** `for slice as val`:遍历切片的每个元素
3. **带索引的切片遍历** `for slice, 0.. as val, idx`:同时获得元素值和索引
展开实现:
```
// for 0..N as i { body }
var i: i32 = 0;
while i < N {
// body...
i = i + 1;
}
// for slice, 0.. as val, idx { body }
var idx: i32 = 0;
var _len: i32 = slice.len;
var _ptr: *T = slice.ptr;
while idx < _len {
var val: T = _ptr[idx];
// body...
idx = idx + 1;
}
```
---
## 表达式(优先级爬升)
### 运算符优先级表
| 优先级 | 运算符 | 结合性 |
|--------|-------------------------|----------|
| 1 | `\|\|` | 左结合 |
| 2 | `&&` | 左结合 |
| 3 | `\|` | 左结合 |
| 4 | `^` | 左结合 |
| 5 | `&` | 左结合 |
| 6 | `==` `!=` | 左结合 |
| 7 | `<` `<=` `>` `>=` | 左结合 |
| 8 | `<<` `>>` | 左结合 |
| 9 | `+` `-` | 左结合 |
| 10 | `*` `/` `%` | 左结合 |
| 前缀 | `-` `!` `~` `&` `*` | 右结合 |
| 后缀 | `.field` `[expr]` | 左结合 |
**`||``&&` 的短路求值**`||``BNZ` 左侧为真时跳过右侧;`&&``BZ` 左侧为假时跳过右侧。
### 主要表达式
```
字面量 → PUSH 立即数
标识符 → LADDR 局部变量地址(可选 LD64 取值)
标识符(args) → 函数调用
(expr) → 分组
```
- 标识符引用局部变量时:数组/聚合类型压入地址其他类型压入值LADDR + LD64
- 函数调用时 push 参数从左到右push 函数地址CALL nargs
### 后缀表达式
```
expr.field → 结构体成员访问(计算字节偏移)(可以单层解引用即 推断c语言的 -> 但是只能单层)
expr[expr] → 数组/指针索引
expr[begin..end] → 切片表达式(从数组/切片创建视图)
expr.* → 解引用LD64
```
- **`.field`**:根据类型布局计算字节偏移。结构体:地址 + 偏移,嵌套结构体保留地址。指针指向的结构体:先 LD64 解引用获取堆地址,再加字段偏移。
- **`[expr]`**:指针索引用元素字节大小做乘法,数组索引用槽位大小做乘法。最后 ADD 得到元素地址LD* 加载值。
### 前缀表达式
```
-expr → 算术取反NEG
!expr → 逻辑非expr == 0 → EQ + PUSH 0
~expr → 按位取反NOT
&expr → 取地址LADDR仅限标识符
```
---
## 调用约定
> 见 ../stage0/spl_ir.h
---
## SIR 指令集
> 见 ../stage0/spl_ir.h
---
## 内存模型
- **栈**:向上增长。每个槽位为 `spl_val_t`uintptr_t8 字节)。
- **帧指针**fp当前函数参数的基址。
- **栈指针**sp栈顶。
- **金丝雀**:存储在 `data[fp-1]`(若 fp > 0——对编译后的代码不可见。
- **全局数据**gdata按索引引用的字节块。字符串、静态数据等。
---
## 编译期执行Comptime
```
comptime { ... }
```
在编译时执行代码,通过将编译后的 .sir 文件加载到子 VM 中。通过以下系统调用实现:
```
vm_new() → ptr // 创建子 VM
vm_drop(vm) // 销毁子 VM
vm_load(vm, path) → ptr // 加载 .sir返回 prog
vm_push(vm, val) // 将参数压入子 VM 栈
vm_call(vm, name, nargs) // 调用函数
vm_run(vm) → i32 // 运行子 VM返回退出码
```
splc0 中尚未实现。)

3426
stage1/spl_ast.c Normal file

File diff suppressed because it is too large Load Diff

346
stage1/spl_ast.h Normal file
View File

@@ -0,0 +1,346 @@
#ifndef __SPL_AST_H__
#define __SPL_AST_H__
#include "../stage0/include/utils.h"
#include "spl_lexer.h"
#include "spl_tok.h"
typedef enum {
SPL_AST_CONTAINER_ITEM,
SPL_AST_FN_DECL,
SPL_AST_FN_DEFINE,
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_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 {
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
spl_ast_node_ref_t self; /* self */
spl_ast_node_ref_vec_t members; /* container_decl 列表 */
} container_item;
struct {
const char *ident;
spl_ast_node_ref_vec_t expr_list;
} attr_item;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
const char *name;
spl_ast_node_ref_vec_t param_list; /* param_decl */
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_vec_t block; /* block_item */
} fn_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
const char *name;
spl_ast_node_ref_t type_expr;
} param_decl;
struct {
const char *name;
spl_ast_node_ref_t type_expr;
} type_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
const char *name;
spl_ast_node_ref_t type_expr;
} member_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
const char *name;
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_t expr;
} var_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
spl_ast_node_ref_t type_expr;
const char *name;
spl_ast_node_ref_t expr;
} const_decl;
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_CONSTDECL,
SPL_AST_TYPEDECL,
SPL_AST_EXPR_STATEMENT,
} kind;
union {
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_vec_t if_block; /* block_item */
spl_ast_node_ref_vec_t else_block; /* block_item */
} if_statement;
struct {
spl_ast_node_ref_t packed_expr;
spl_ast_node_ref_vec_t if_block; /* block_item */
spl_ast_node_ref_vec_t else_block; /* block_item */
} ifvar_statement;
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_vec_t while_block; /* block_item */
} while_statement;
struct {
spl_ast_node_ref_vec_t loop_block; /* block_item */
} loop_statement;
struct {
spl_ast_node_ref_vec_t expr_vec;
VEC(char *) ident_vec;
spl_ast_node_ref_vec_t block; /* block_item */
} for_statement;
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_vec_t paced_exprs; /* packed_expr */
spl_ast_node_ref_vec_t match_block; /* block_item */
} match_statement;
struct {
spl_ast_node_ref_t expr;
} ret_statement;
struct {
} break_statement;
struct {
} continue_statement;
struct {
spl_ast_node_ref_vec_t block_or_statement; /* block_item/statement */
} defer_statement;
spl_ast_node_ref_t var_decl;
spl_ast_node_ref_t const_decl;
spl_ast_node_ref_t type_decl;
spl_ast_node_ref_t expr_statement;
};
} block_item;
struct {
const char *ident;
const char *bind_ident;
spl_ast_node_ref_t expr;
} packed_expr;
struct {
enum {
SPL_AST_ASSIGN_EXPR,
SPL_AST_ASSIGN_ADD_EXPR,
SPL_AST_ASSIGN_sUB_EXPR,
SPL_AST_ASSIGN_MUL_EXPR,
SPL_AST_ASSIGN_DIV_EXPR,
SPL_AST_ASSIGN_MOD_EXPR,
SPL_AST_ASSIGN_AND_EXPR,
SPL_AST_ASSIGN_OR_EXPR,
SPL_AST_ASSIGN_XOR_EXPR,
SPL_AST_ASSIGN_LSHIFT_EXPR,
SPL_AST_ASSIGN_USHIFT_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_CMPNE_EXPR,
SPL_AST_CMP_LE_EXPR,
SPL_AST_CMP_GE_EXPR,
SPL_AST_CMP_LT_EXPR,
SPL_AST_CMP_GT_EXPR,
SPL_AST_RANGE_EXPR,
SPL_AST_LSHIFT_EXPR,
SPL_AST_RSHIFT_EXPR,
SPL_AST_ADD_EXPR,
SPL_AST_SUB_EXPR,
SPL_AST_MUL_EXPR,
SPL_AST_DIV_EXPR,
SPL_AST_MOD_EXPR,
SPL_AST_PREFIX_EXPR, /* left ref node */
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_MINUS_EXPR,
SPL_AST_BANG_EXPR,
SPL_AST_TILDE_EXPR,
SPL_AST_AMPERSAND_EXPR,
SPL_AST_ASTERISK_EXPR,
} kind;
spl_ast_node_ref_t postfix_expr;
} prefix_expr;
struct {
enum {
SPL_AST_CALL_EXPR,
SPL_AST_FIELD_EXPR,
SPL_AST_DEREF_EXPR,
SPL_AST_INDEX_EXPR,
SPL_AST_SLICE_EXPR,
SPL_AST_AS_EXPR,
} kind;
spl_ast_node_ref_t primary_expr;
union {
spl_ast_node_ref_vec_t call_expr;
const char *field_expr; /* field/method */
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,
} kind;
union {
isize integer_expr;
double float_expr;
char char_lit_expr;
const char *string_lit_expr; /* parsed c string */
const char *ident;
struct {
const char *name;
spl_ast_node_ref_vec_t expr; /* aggregate_init_item */
} aggregate_init;
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_vec_t block_expr; /* block_item */
};
} primary_expr;
struct {
const char *ident;
spl_ast_node_ref_t expr;
} aggregate_init_item;
struct {
spl_ast_node_ref_vec_t type_prefixs; /* prefix_type */
spl_ast_node_ref_vec_t attr_list; /* attr_item */
enum {
SPL_AST_BASE_TYPE_FN,
SPL_AST_BASE_TYPE_PATH,
SPL_AST_TYPE_STRUCT,
SPL_AST_TYPE_UNION,
SPL_AST_TYPE_ENUM,
} kind;
const char *spl_base_type;
union {
spl_ast_node_ref_vec_t type_path; /* type_atom */
struct {
spl_ast_node_ref_vec_t param_list; /* param_decl */
spl_ast_node_ref_t type_expr;
} fn_type;
spl_ast_node_ref_vec_t aggregate_list; /* container_decl */
};
} type_expr;
struct {
/* ASTERISK = 1, [] = 2, else = 0*/
int pointer;
/* if array_size != 0 then pointer == 2 */
int array_size;
} prefix_type;
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__ */

1
stage1/spl_ast2ir.c Normal file
View File

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

4
stage1/spl_ast2ir.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef __SPL_AST2IR_H__
#define __SPL_AST2IR_H__
#endif /* __SPL_AST2IR_H__ */

View File

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

View File

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

26
stage1/spl_dumptree.c Normal file
View File

@@ -0,0 +1,26 @@
/* spl_dumptree.c 可配置的树形打印模块(只用基本 ASCII*/
#include "spl_dumptree.h"
#include <stdarg.h>
const spl_dumptree_style_t spl_dumptree_ascii_style = {
"| ",
"|-",
"`-",
" ",
};
void spl_dumptree_print(const spl_dumptree_style_t *st, const char *prefix, int is_last,
const char *fmt, ...) {
va_list ap;
printf("%s%s ", prefix, is_last ? st->last_branch : st->branch);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
}
void spl_dumptree_child_prefix(const spl_dumptree_style_t *st, const char *prefix, int is_last,
char *out, size_t cap) {
snprintf(out, cap, "%s%s", prefix, is_last ? st->space : st->vertical);
}

31
stage1/spl_dumptree.h Normal file
View File

@@ -0,0 +1,31 @@
/* spl_dumptree.h 可配置的树形打印模块(只用基本 ASCII*/
#ifndef __SPL_DUMPTREE_H__
#define __SPL_DUMPTREE_H__
#include <stddef.h>
#include <stdio.h>
/* 可配置的缩进字符串 */
typedef struct {
const char *vertical; /* "| " */
const char *branch; /* "|-" */
const char *last_branch; /* "`-" */
const char *space; /* " " */
} spl_dumptree_style_t;
/* 默认 ASCII 风格 */
extern const spl_dumptree_style_t spl_dumptree_ascii_style;
/* 打印一行节点标签prefix + 分支符 + label
* prefix 已累积的缩进骨架(不含分支符)
* is_last 本节点是否为同级最后一个子节点
* fmt printf 风格 label */
void spl_dumptree_print(const spl_dumptree_style_t *st, const char *prefix, int is_last,
const char *fmt, ...);
/* 生成子节点的缩进骨架parent_prefix + (parent_is_last ? space : vertical) */
void spl_dumptree_child_prefix(const spl_dumptree_style_t *st, const char *prefix, int is_last,
char *out, size_t cap);
#endif /* __SPL_DUMPTREE_H__ */

View File

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

View File

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

File diff suppressed because it is too large Load Diff

1
stage1/spl_ir.c Normal file
View File

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

127
stage1/spl_ir.h Normal file
View File

@@ -0,0 +1,127 @@
#ifndef __SPL_IR_H__
#define __SPL_IR_H__
#include "../stage0/include/utils.h"
/* clang-format off */
#define SPL_IR_FN_TABLE \
X(arith.add, V0, SPL_IR_ARITH_ADD) \
X(arith.sub, V0, SPL_IR_ARITH_SUB) \
X(arith.mul, V0, SPL_IR_ARITH_MUL) \
X(arith.div, V0, SPL_IR_ARITH_DIV) \
X(arith.rem, V0, SPL_IR_ARITH_REM) \
X(arith.neg, V0, SPL_IR_ARITH_NEG) \
X(arith.abs, V0, SPL_IR_ARITH_ABS) \
X(arith.and, V0, SPL_IR_ARITH_AND) \
X(arith.or, V0, SPL_IR_ARITH_OR) \
X(arith.xor, V0, SPL_IR_ARITH_XOR) \
X(arith.shl, V0, SPL_IR_ARITH_SHL) \
X(arith.shr, V0, SPL_IR_ARITH_SHR) \
X(arith.not, V0, SPL_IR_ARITH_NOT) \
X(cmp.eq, V0, SPL_IR_CMP_EQ) \
X(cmp.ne, V0, SPL_IR_CMP_NE) \
X(cmp.lt, V0, SPL_IR_CMP_LT) \
X(cmp.le, V0, SPL_IR_CMP_LE) \
X(cmp.gt, V0, SPL_IR_CMP_GT) \
X(cmp.ge, V0, SPL_IR_CMP_GE) \
X(cast.trunc, V0, SPL_IR_CAST_TRUNC) \
X(cast.zext, V0, SPL_IR_CAST_ZEXT) \
X(cast.sext, V0, SPL_IR_CAST_SEXT) \
X(cast.fext, V0, SPL_IR_CAST_FEXT) \
X(cast.ftrunc, V0, SPL_IR_CAST_FTRUNC) \
X(cast.bitcast, V0, SPL_IR_CAST_BITCAST) \
X(cast.ptr2int, V0, SPL_IR_CAST_PTR2INT) \
X(cast.int2ptr, V0, SPL_IR_CAST_INT2PTR) \
X(cast.bool2int, V0, SPL_IR_CAST_BOOL2INT) \
X(case.int2float, V0, SPL_IR_CASE_INT2FLOAT) \
X(case.float2int, V0, SPL_IR_CASE_FLOAT2INT) \
X(mem.alloca, V0, SPL_IR_MEM_ALLOCA) \
X(mem.load, V0, SPL_IR_MEM_LOAD) \
X(mem.store, V0, SPL_IR_MEM_STORE) \
X(mem.offset, V0, SPL_IR_MEM_OFFSET) \
X(mem.copy, V0, SPL_IR_MEM_COPY) \
X(mem.set, V0, SPL_IR_MEM_SET) \
X(mem.fence, V0, SPL_IR_MEM_FENCE) \
X(type.const, V0, SPL_IR_TYPE_CONST) \
X(type.bitsizeof, V0, SPL_IR_TYPE_BITSIZEOF) \
X(type.sizeof, V0, SPL_IR_TYPE_SIZEOF) \
X(type.alignof, V0, SPL_IR_TYPE_ALIGNOF) \
X(type.offsetof, V0, SPL_IR_TYPE_OFFSETOF) \
X(type.field_count, V0, SPL_IR_TYPE_FIELD_COUNT) \
X(agg.construct, V0, SPL_IR_AGG_CONSTRUCT) \
X(agg.extract, V0, SPL_IR_AGG_EXTRACT) \
X(agg.insert, V0, SPL_IR_AGG_INSERT) \
X(atomic.load, V0, SPL_IR_ATOMIC_LOAD) \
X(atomic.store, V0, SPL_IR_ATOMIC_STORE) \
X(atomic.rmw_add, V0, SPL_IR_ATOMIC_RMW_ADD) \
X(atomic.rmw_sub, V0, SPL_IR_ATOMIC_RMW_SUB) \
X(atomic.rmw_and, V0, SPL_IR_ATOMIC_RMW_AND) \
X(atomic.rmw_or, V0, SPL_IR_ATOMIC_RMW_OR) \
X(atomic.rmw_xor, V0, SPL_IR_ATOMIC_RMW_XOR) \
X(atomic.rmw_xchg, V0, SPL_IR_ATOMIC_RMW_XCHG) \
X(atomic.cmpxchg, V0, SPL_IR_ATOMIC_CMPXCHG) \
X(control.select, V0, SPL_IR_CONTROL_SELECT) \
X(control.br, V0, SPL_IR_CONTROL_BR) \
X(control.jmp, V0, SPL_IR_CONTROL_JMP) \
X(control.call, V0, SPL_IR_CONTROL_CALL) \
X(control.ret, V0, SPL_IR_CONTROL_RET) \
X(control.unreachable, V0, SPL_IR_CONTROL_UNREACHABLE) \
X(control.trap, V0, SPL_IR_CONTROL_TRAP) \
X(dbg.breakpoint, V0, SPL_IR_DBG_BREAKPOINT) \
X(dbg.declare, V0, SPL_IR_DBG_DECLARE)
typedef enum {
#ifdef X
#undef X
#endif
#define X(a, b, c) c,
SPL_IR_FN_TABLE
#undef X
} spl_ir_kind_t;
/* clang-format on */
typedef struct {
spl_ir_kind_t kind;
} spl_ir_node_t;
typedef VEC(spl_ir_node_t) spl_ir_node_vec_t;
typedef usize spl_ir_node_ref_t; /* 0 is error */
typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t;
typedef struct {
enum {
SPL_IR_ATTR_NONE,
SPL_IR_ATTR_LINK, /* 不实现 */
SPL_IR_ATTR_ABI, /* 只有 C ABI 支持 */
SPL_IR_ATTR_SYMBOL, /* 不实现 */
SPL_IR_ATTR_NAKED, /* 不实现 */
SPL_IR_ATTR_NOINLINE, /* 不实现 */
SPL_IR_ATTR_ALWAYSINLINE, /* 不实现 */
};
} spl_ir_attr_t;
typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t;
typedef struct {
const char *name;
spl_ir_attr_t attr;
spl_ir_node_vec_t nodes;
spl_ir_node_ref_vec_t labels;
} spl_ir_func_t;
typedef usize spl_ir_func_ref_t; /* 0 is error */
typedef VEC(spl_ir_func_t) spl_ir_func_vec_t;
typedef struct {
spl_ir_func_vec_t funcs;
} spl_ir_t;
void spl_ir_init(spl_ir_t *ir);
void spl_ir_drop(spl_ir_t *ir);
spl_ir_node_ref_t spl_ir_alloc_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id);
spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir);
spl_ir_node_t *spl_ir_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id, spl_ir_node_ref_t node_id);
spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id);
void spl_ir_dump(spl_ir_t *ir);
#endif /* __SPL_IR_H__ */

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
/* spl_lexer.c — SPL lexical analyzer */
#include "spl_lexer.h"
#include "spl_tok.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -395,6 +396,7 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
/* Two-char operators */
TRY_OP2('=', '=', TOK_EQ, TOK_ASSIGN)
TRY_OP2('=', '>', TOK_FAT_ARROW, TOK_ASSIGN)
TRY_OP2('!', '=', TOK_NEQ, TOK_NOT)
TRY_OP2('<', '=', TOK_LE, TOK_LT)
TRY_OP2('>', '=', TOK_GE, TOK_GT)

View File

@@ -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);

View File

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

1867
stage1/spl_sema.c Normal file

File diff suppressed because it is too large Load Diff

35
stage1/spl_sema.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef __SPL_SEMA_H__
#define __SPL_SEMA_H__
#include "spl_ast.h"
#include "spl_type.h"
typedef usize spl_scope_id_t; /* 0 is error */
typedef struct {
spl_scope_id_t parent;
MAP(const char *, spl_def_id_t) symbols;
} spl_scope_node_t;
typedef VEC(spl_scope_node_t) spl_scope_node_vec_t;
typedef struct {
spl_ast_t *ast;
spl_type_t type;
spl_scope_node_vec_t scopes;
spl_scope_id_t root_scope;
spl_scope_id_t current_scope;
spl_def_id_t root_def;
int error_count;
} spl_sema_t;
void spl_sema_init(spl_sema_t *sema);
void spl_sema_drop(spl_sema_t *sema);
void spl_sema_run(spl_sema_t *sema);
void spl_sema_check(spl_sema_t *sema);
spl_scope_id_t spl_sema_scope_alloc(spl_sema_t *sema);
bool spl_sema_scope_insert(spl_sema_t *sema, spl_scope_id_t id, const char *symbol_name,
spl_def_id_t symbol_val);
typedef VEC(const char *) spl_symbol_path_t;
spl_def_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path);
#endif /* __SPL_SEMA_H__ */

File diff suppressed because it is too large Load Diff

122
stage1/spl_tok.h Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,213 +1,122 @@
#ifndef __SPL_TYPE_H__
#define __SPL_TYPE_H__
#include "../stage0/spl_ir.h"
#include "spl_lexer.h"
#include "../stage0/include/utils.h"
/* ============================================================
* Type kinds
* ============================================================ */
typedef usize spl_type_id_t; /* 0 is error */
typedef VEC(spl_type_id_t) spl_type_id_vec_t;
typedef usize spl_def_id_t; /* 0 is error */
typedef VEC(spl_def_id_t) spl_def_id_vec_t;
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 {
enum {
SPL_TYPE_VOID,
SPL_TYPE_BOOL,
SPL_TYPE_INT,
SPL_TYPE_FLOAT,
SPL_TYPE_PTR,
SPL_TYPE_SLICE,
SPL_TYPE_RANGE,
SPL_TYPE_ARRAY,
SPL_TYPE_STRUCT,
SPL_TYPE_UNION,
SPL_TYPE_ENUM,
SPL_TYPE_FN,
SPL_TYPE_ID,
} kind;
union {
struct {
usize bits;
int is_signed;
} int_type;
struct {
usize bits;
} float_type;
spl_type_id_t ptr_pointee;
spl_type_id_t slice_element;
spl_type_id_t range_element;
struct {
spl_type_id_t element;
usize len;
} array_type;
spl_type_id_vec_t agg_field_types;
struct {
spl_type_id_vec_t variants;
spl_type_id_t tag_type;
} enum_type; // ADT
struct {
spl_type_id_vec_t params;
spl_type_id_t ret;
} fn_type;
spl_type_id_t type_id;
};
} spl_type_node_t;
typedef VEC(spl_type_node_t) spl_type_node_vec_t;
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.
* ============================================================ */
spl_def_id_t def_id;
spl_type_id_t type_id;
usize scope_id;
} spl_var_def_t;
typedef VEC(spl_var_def_t) spl_var_def_vec_t;
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;
enum {
SPL_DEF_NONE,
SPL_DEF_BUILTIN,
SPL_DEF_VAR,
SPL_DEF_FN_PARAMS,
SPL_DEF_AGG, // include enum variants
SPL_DEF_DISTINCT, // newtype
SPL_DEF_ALIAS, // sametypes
} kind;
spl_type_id_t type_id;
union {
spl_var_def_t var_def;
spl_var_def_vec_t agg_def; // include enum variants
spl_var_def_vec_t fn_params_def;
spl_var_def_t type_def;
};
int source_loc;
enum {
SPL_FLAG_NONE,
} flag;
} spl_def_node_t;
typedef VEC(spl_def_node_t) spl_def_node_vec_t;
/* ============================================================
* Lifecycle
* ============================================================ */
/*
SPL 设计是严格区分类型做到类型和名称无关即
type (类型名) = (匿名类型)
好处是递归使用可以直接操作类型名的映射的提前分配的匿名类型的id
*/
typedef struct {
spl_type_node_vec_t type_table;
spl_def_node_vec_t def_table;
} spl_type_t;
void spl_type_ctx_init(spl_type_ctx_t *tctx);
void spl_type_ctx_drop(spl_type_ctx_t *tctx);
void spl_type_init(spl_type_t *type);
void spl_type_drop(spl_type_t *type);
/* ============================================================
* Constructors — all return type_idx (index into tctx->types)
* ============================================================ */
void spl_type_def_dump(spl_type_t *type, spl_def_id_t id);
void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id);
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);
spl_type_id_t spl_type_alloc(spl_type_t *type);
spl_type_node_t *spl_type_node(spl_type_t *type, spl_type_id_t id);
spl_def_id_t spl_type_def_alloc(spl_type_t *type);
spl_def_node_t *spl_type_def(spl_type_t *type, spl_def_id_t id);
/* ============================================================
* 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);
spl_type_id_t spl_type_void(spl_type_t *type);
spl_type_id_t spl_type_bool(spl_type_t *type);
spl_type_id_t spl_type_int(spl_type_t *type, usize bits, int is_signed);
spl_type_id_t spl_type_float(spl_type_t *type, usize bits);
spl_type_id_t spl_type_ptr(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_slice(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_range(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_array(spl_type_t *type, spl_type_id_t val, usize len);
spl_type_id_t spl_type_tid(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_agg(spl_type_t *type, spl_type_id_vec_t fields);
spl_type_id_t spl_type_enum(spl_type_t *type, spl_type_id_vec_t variants, spl_type_id_t tag);
spl_type_id_t spl_type_fn(spl_type_t *type, spl_type_id_vec_t params, spl_type_id_t ret);
#endif /* __SPL_TYPE_H__ */

View File

@@ -1,17 +1,20 @@
/* splc0.c — Stage 1 SPL compiler (bootstrap)
* Usage:
* splc0 <input.spl> <output.sir> — compile
* splc0 --dump-tokens <input.spl> — dump tokens
* splc0 --help — help
/* splc0.c — SPL compiler CLI (stage 1, 引导用)
*
* splc0 --dump tokens|ast|all <file> dump 前端产物
* splc0 <in> <out> 编译 (阶段 B 实现)
*/
#define __SCC_LOG_IMPL_IMPORT_SRC__
#include "../stage0/include/utils.h"
#include "../stage0/spl_ir.h"
#include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "spl_ast.h"
#include "spl_lexer.h"
#include "spl_sema.h"
#include "spl_tok.h"
static char *read_file(const char *path, long *out_len) {
FILE *f = fopen(path, "rb");
if (!f) {
@@ -33,75 +36,112 @@ 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 <file.spl>\n");
return 1;
static const char *const tok_type_names[] = {
#define X(name, enum_name, dummy) #enum_name,
KEYWORD_TABLE
#undef X
#define X(name, enum_name, dummy) #enum_name,
TOKEN_TABLE
#undef X
};
static void dump_tokens(const char *src, const char *fname) {
spl_tok_vec_t toks = spl_lex(src, fname);
printf("tokens got (%zu)\n", toks.size);
for (usize i = 0; i < toks.size; i++) {
const spl_tok_t *t = &toks.data[i];
printf("[%s] %.*s (%zu:%zu)\n", tok_type_names[t->type], (int)t->len, t->lexeme, t->line,
t->col);
}
vec_free(toks);
}
static void dump_ast(const char *src, const char *fname) {
spl_tok_vec_t toks = spl_lex(src, fname);
spl_ast_t ast;
spl_ast_init(&ast, &toks);
spl_ast_prase(&ast);
spl_ast_valid(&ast);
spl_ast_dump(&ast, ast.root);
spl_ast_drop(&ast);
}
static void dump_sema(const char *src, const char *fname) {
spl_tok_vec_t toks = spl_lex(src, fname);
spl_ast_t ast;
spl_ast_init(&ast, &toks);
spl_ast_prase(&ast);
spl_ast_valid(&ast);
spl_sema_t sema;
spl_sema_init(&sema);
sema.ast = &ast;
spl_sema_run(&sema);
spl_sema_check(&sema);
printf("Sema root_scope=%zu scopes=%zu errors=%d\n", sema.root_scope, sema.scopes.size,
sema.error_count);
for (usize i = 0; i < sema.scopes.size; i++) {
printf("scope[%zu] parent=%zu\n", i, sema.scopes.data[i].parent);
map_for(sema.scopes.data[i].symbols, mi) {
printf(" %s -> def#%zu\n", sema.scopes.data[i].symbols.data[mi].key,
sema.scopes.data[i].symbols.data[mi].val);
}
}
printf("TypeTable:\n");
for (usize i = 0; i < sema.type.type_table.size; i++) {
printf(" id#%zu type=", i);
spl_type_pure_dump(&sema.type, i);
printf("\n");
}
printf("DefTable:\n");
for (usize i = 0; i < sema.type.def_table.size; i++) {
printf(" def#%zu ", i);
spl_type_def_dump(&sema.type, i);
printf("\n");
}
spl_sema_drop(&sema);
spl_ast_drop(&ast);
}
static int cmd_dump(const char *flags, const char *path) {
long len;
char *src = read_file(argv[0], &len);
char *src = read_file(path, &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);
int do_tokens = strstr(flags, "tokens") != NULL || strcmp(flags, "all") == 0;
int do_ast = strstr(flags, "ast") != NULL || strcmp(flags, "all") == 0;
int do_sema = strstr(flags, "sema") != NULL || strcmp(flags, "all") == 0;
if (do_tokens)
dump_tokens(src, path);
if (do_ast)
dump_ast(src, path);
if (do_sema)
dump_sema(src, path);
free(src);
return 0;
}
static int cmd_compile(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: splc0 <input.spl> <output.sir>\n");
return 1;
}
const char *inpath = argv[0];
const char *outpath = argv[1];
long len;
char *src = read_file(inpath, &len);
if (!src)
return 1;
spl_comp_t ctx;
spl_comp_init(&ctx);
int ret = 0;
if (spl_compile(&ctx, src, inpath) != 0) {
fprintf(stderr, "compilation failed: %s\n", ctx.error_msg);
ret = 1;
goto cleanup;
}
if (spl_prog_store_to_file(outpath, &ctx.prog) != 0) {
fprintf(stderr, "failed to write '%s'\n", outpath);
ret = 1;
goto cleanup;
}
printf("compiled %s -> %s\n", inpath, outpath);
cleanup:
spl_comp_drop(&ctx);
free(src);
return ret;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: splc0 [--dump-tokens|--help] <input.spl> [output.sir]\n");
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n");
return 1;
}
if (strcmp(argv[1], "--dump-tokens") == 0) {
return cmd_dump_tokens(argc - 2, argv + 2);
}
if (strcmp(argv[1], "--help") == 0) {
printf("SPL Compiler (stage1 bootstrap)\n");
printf(" splc0 <input.spl> <output.sir> - compile\n");
printf(" splc0 --dump-tokens <file.spl> - dump token stream\n");
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, 阶段 B)\n");
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,all\n");
return 0;
}
return cmd_compile(argc - 1, argv + 1);
int argi = 1;
if (argi >= argc) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n");
return 1;
}
if (strcmp(argv[argi], "--dump") == 0) {
if (argc < argi + 3) {
LOG_INFO("splc0: --dump need <flags> <file>\n");
return 1;
}
return cmd_dump(argv[argi + 1], argv[argi + 2]);
}
LOG_FATAL("splc0: compile todo\n");
return 1;
}

View File

@@ -1,9 +1,8 @@
/* spc_vm.c — VM launcher for stage 1 */
/* spc_vm.c 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 <stdio.h>
#include <string.h>
@@ -11,28 +10,31 @@
int main(int argc, const char **argv) {
int argi = 1;
if (argi >= argc) {
fprintf(stderr, "Usage: spc_vm <file.sir> [entry] [--trace]\n");
return 1;
}
const char *path = argv[argi++];
/* Parse flags: --entry <name>, --trace */
/* Parse flags: --entry <name>, --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] <file.sir> [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,12 +57,12 @@ 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);
spl_prog_drop(&prog);
if (ret < 0)
return (int)vm.exit_code;
return (int)vm.exit_code;
}

View File

@@ -30,10 +30,10 @@ fn main() i32 {
if nl != 10 { ret 6; }
/* 布尔字面量 */
var t: i32 = true;
if t != 1 { ret 7; }
var f: i32 = false;
if f != 0 { ret 8; }
var t: bool = true;
if !t { ret 7; }
var f: bool = false;
if f { ret 8; }
/* null 指针 */
var np: *i32 = null;

View File

@@ -16,11 +16,11 @@ fn main() i32 {
/* 比较结果为 0/1 */
var eq := (42 == 42);
if eq != 1 { ret 9; }
if !eq { ret 9; }
var ne := (42 == 43);
if ne != 0 { ret 10; }
if ne { ret 10; }
var lt := (5 < 10);
if lt != 1 { ret 11; }
if !lt { ret 11; }
/* ---- 逻辑运算 ---- */
if (true) {} else { ret 12; }
@@ -30,9 +30,9 @@ fn main() i32 {
/* 逻辑非 */
var not_t := !true;
if not_t != 0 { ret 16; }
if not_t { ret 16; }
var not_f := !false;
if not_f != 1 { ret 17; }
if !not_f { ret 17; }
// /* ---- 短路求值 ---- */
// var short1 := 0;

View File

@@ -81,7 +81,7 @@ fn test_param_pass_token() i32 {
ret 0;
}
fn test_get_tag(tok: Token) i32 {
fn test_get_tag(tok: Token) Tag {
ret tok.tag;
}

View File

@@ -5,8 +5,8 @@
* 字符串字面量、字符串参数传递
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
@extern(vm) fn vm_strlen(s: *i8) i32;
@extern(vm) fn vm_strcmp(a: *i8, b: *i8) i32;
@extern(vm) fn vm_strlen(s: *u8) i32;
@extern(vm) fn vm_strcmp(a: *u8, b: *u8) i32;
fn main() i32 {
/* vm_printf 输出测试 */

View File

@@ -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[sub] => { ret eval(sub.left) + eval(sub.right); }
}
ret 0;
}
@@ -39,7 +39,7 @@ fn main() i32 {
/* enum 方法 + match */
var expr_l := Expr { .Int = 3 };
var expr_r := Expr { .Int = 4 };
var expr := Expr { .Add = { .left = expr_l, .right = expr_r } };
var expr := Expr { .Add = .{ .left = expr_l, .right = expr_r } };
var result := expr.eval(&expr);
vm_printf("eval result: %d\n", result);
if result != 7 { ret 1; }

View File

@@ -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[p] => {
ret 2;
}
}
@@ -126,10 +126,10 @@ 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) => {
if w != 3 { ret 4; }
if h != 4 { ret 5; }
.Circle[r] => { ret 3; },
.Rect[p] => {
if p.x != 3 { ret 4; }
if p.y != 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 => { }

View File

@@ -8,7 +8,7 @@ fn test_string() i32 {
* String test: str is []u8
* ============================ */
var data: *u8 = "hello";
var s: []u8 = { .ptr = data, .len = 5 };
var s: []u8 = .{ .ptr = data, .len = 5 };
if s.len != 5 { ret 100; }
if s[0] != 104 { ret 101; } /* 'h' */
@@ -147,7 +147,7 @@ fn main() i32 {
var data: [5]i32;
data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50;
var p: *i32 = &data[2];
var from_ptr: []i32 = { .ptr = p, .len = 2 };
var from_ptr: []i32 = .{ .ptr = p, .len = 2 };
var from_ptr2: []i32;
from_ptr2.ptr = p;
from_ptr2.len = 2;

View File

@@ -78,7 +78,7 @@ fn test_slice_in_struct() i32 {
raw[0] = 65; raw[1] = 66; raw[2] = 67; raw[3] = 68;
/* Bug fix: { .ptr = ..., .len = ... } inside struct literal */
var b: Buffer = Buffer { .data = { .ptr = &raw[0], .len = 4 }, .len = 4 };
var b: Buffer = Buffer { .data = .{ .ptr = &raw[0], .len = 4 }, .len = 4 };
if b.len != 4 { ret 1; }
if b.data[0] != 65 { ret 2; }
@@ -90,7 +90,7 @@ fn test_slice_in_struct() i32 {
if raw[0] != 90 { ret 5; }
/* Initialize with shorter slice */
var b2: Buffer = Buffer { .data = { .ptr = &raw[2], .len = 2 }, .len = 2 };
var b2: Buffer = Buffer { .data = .{ .ptr = &raw[2], .len = 2 }, .len = 2 };
if b2.len != 2 { ret 6; }
if b2.data[0] != 67 { ret 7; }
@@ -211,7 +211,7 @@ fn test_complex_nesting() i32 {
var bundle: Bundle = Bundle {
.name = &str_data[0],
.buf = Buffer { .data = { .ptr = &str_data[1], .len = 3 }, .len = 3 },
.buf = Buffer { .data = .{ .ptr = &str_data[1], .len = 3 }, .len = 3 },
.row = MatrixRow { .items = [4]i32{1, 2, 3, 4} },
.pt = Point { .x = -5, .y = 15 }
};
@@ -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[p] => {
ret 3;
}
}
@@ -268,20 +268,20 @@ 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[p] => {}
}
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) => {
if px != 7 { ret 7; }
if py != 8 { ret 8; }
.Pending[p] => {
if p.x != 7 { ret 7; }
if p.y != 8 { ret 8; }
}
}