Sii 完整指南

本指南系统介绍了 Sii 2.x 的各个方面,从基础语法到高级特性,从开发环境到生产部署。

Sii 1.x 用户

Sii 1.x 版本的指南位于 旧的站点。本指南针对 Sii 2.x 版本。

1. 快速入门

Sii 是一门现代静态类型编程工具,设计目标是让开发者用一份代码编译到多个目标平台。Sii 编译器 siic 使用 Rust 编写,具备以下核心特性:

你的第一个 Sii 程序

// hello.sii
func main(): void {
    sii.io.print("Hello, Sii!");
}

编译并运行:

# 编译到 JavaScript
siic hello.sii hello.js

# 编译到 TypeScript
siic hello.sii hello.ts --ts

# 编译到原生可执行文件
siic native hello.sii -o hello
./hello

2. 安装与 CLI

下载页面获取对应平台的 siic 编译器和 sii-runtime-server 运行时。

编译器命令概览

命令说明
siic <input> <output>编译到 JavaScript(默认)
siic <input> <output> --ts编译到 TypeScript
siic <input> <output> --wasm编译到 WebAssembly (WAT)
siic <input> <output> --llvm编译到 LLVM IR
siic native <input> -o <output>编译到原生可执行文件
siic watch <input> <output>监听模式,文件变化自动重编译
siic serve <input> [--port=<n>]启动开发服务器(含热重载)
siic serve ... --proxy <url>开发服务器 + 反向代理
siic --version查看版本
siic --help查看帮助

3. 基本概念

标识符与关键字

标识符由字母、数字和下划线组成,不能以数字开头。Sii 是大小写敏感的。

Sii 的保留关键字:

类别关键字
声明let const func class crob
控制流if else forloop while break continue back
模块share cite from as
操作new remake push rmv typeins
字面量true false

变量声明:let 与 const

// let — 可变变量
let x: int = 42;
x = 100;            // 允许重新赋值

// const — 不可变常量(建议默认使用)
const PI: singlef = 3.14159;
const name: string = "Sii";

// 类型推断 — 当有初始值时类型标注可省略
let autoInt = 42;           // 推断为 int
let autoStr = "hello";      // 推断为 string
const autoBool = true;      // 推断为 bool

作用域

Sii 使用块级作用域({ })。内部作用域可以访问外部变量,但反之不行。

let outer: int = 10;

if (outer > 5) {
    let inner: int = 20;
    sii.io.print(outer.toString());   // ok — 访问外部变量
    sii.io.print(inner.toString());   // ok
}

// sii.io.print(inner);  // 错误 — inner 不在作用域内

注释

// 单行注释

/* 多行注释
   可以跨越多行 */

// 文档注释(建议用于 share 函数)
// 计算两数之和
share func add(a: int, b: int): int { back a + b; }

4. 类型系统

Sii 拥有丰富的类型系统,所有类型在编译时确定。

基础类型

类型关键字大小说明示例
整数int32 位有符号整数42, -7
单精度浮点singlef32 位单精度浮点数3.14
双精度浮点multif64 位双精度浮点数3.14159265
布尔bool1 位truefalsetrue
短字符串str短字符串类型'c'
字符串string动态字符串"Hello"
空类型void无返回值
未知类型unknown类型未知(谨慎使用)

复合类型

类型关键字说明示例
数组arr<T>泛型数组,元素类型统一arr<int>, arr<string>
对象obj动态键值对对象{ name: "Andy", age: 25 }
类实例class<Name>指定类的实例class<Point>

类型别名

// 使用 type 前缀定义类型别名
let type UserID = int;
let type Point3D = obj;

let id: UserID = 1001;
let point: Point3D = { x: 1, y: 2, z: 3 };

类型检查:typeins()

typeins() 用于在运行时检查变量的实际类型,返回 bool

let val: unknown = getSomeValue();

if (typeins(val, "int")) {
    // val 是 int 类型
    sii.io.print("整数: " + (val as int).toString());
}
if (typeins(val, "string")) {
    // val 是 string 类型
    sii.io.print("字符串: " + (val as string));
}

类型转换

let n: int = 42;
let s: string = n.toString();     // int → string
let f: singlef = n.toSinglef();   // int → singlef
let d: multif = n.toMultif();     // int → multif

let pi: singlef = 3.14;
let piInt: int = pi.toInt();      // singlef → int (截断)
最佳实践

尽量使用具体类型而不是 unknown。类型系统是 Sii 的核心优势 — 充分利用它来在编译时捕获错误。

5. 函数

函数声明

// 基本函数 — func 关键字,参数需要类型标注
func add(a: int, b: int): int {
    back a + b;
}

// 无返回值
func log(msg: string): void {
    sii.io.print(msg);
    // back 可省略
}

// 无参数
func getVersion(): string {
    back "2.0.0";
}

返回值:back 关键字

Sii 使用 back 关键字返回函数结果(等价于其他编程环境的 return)。

func max(a: int, b: int): int {
    if (a > b) {
        back a;
    }
    back b;
}

func greet(name: string): string {
    back "Hello, " + name + "!";
}

递归函数

func factorial(n: int): int {
    if (n <= 1) { back 1; }
    back n * factorial(n - 1);
}

func fibonacci(n: int): int {
    if (n <= 1) { back n; }
    back fibonacci(n - 1) + fibonacci(n - 2);
}
设计哲学

Sii 鼓励纯函数 — 相同输入总是产生相同输出,无副作用。带副作用的函数(如 I/O 操作)应明确标注。

6. 控制流

if / else if / else

let score: int = 85;

if (score >= 90) {
    sii.io.print("优秀");
} else if (score >= 60) {
    sii.io.print("及格");
} else {
    sii.io.print("不及格");
}

注意:条件表达式不需要括号,但这里为了清晰保留。两种写法均可。

forloop — C 风格 for 循环

// 标准 forloop
forloop (let i = 0; i < 10; i = i + 1) {
    sii.io.print(i.toString());
}

// 遍历数组
let items: arr<string> = ["a", "b", "c"];
forloop (let i = 0; i < items.length().toInt(); i = i + 1) {
    sii.io.print(items[i]);
}

while 循环

let count: int = 3;
while (count > 0) {
    sii.io.print(count.toString());
    count = count.toDn(1);  // 自减
}

break 与 continue

forloop (let i = 0; i < 100; i = i + 1) {
    if (i == 5) { continue; }   // 跳过本次迭代
    if (i == 10) { break; }      // 终止循环
    sii.io.print(i.toString());
}

自增/自减方法

方法语义等价 JS说明
x.toUp(n)先用后加x++返回原值,然后 x = x + n
x.getUp(n)先加后用++xx = x + n,返回新值
x.toDn(n)先用后减x--返回原值,然后 x = x - n
x.getDn(n)先减后用--xx = x - n,返回新值

7. 类与对象

class — 结构体定义

class 在 Sii 中用于定义数据结构(类似 C 的 struct),只包含字段,不含方法。

// 声明一个类(数据结构)
class Point {
    x: int;
    y: int;
}

class User {
    id: int;
    name: string;
    email: string;
    active: bool;
}

// 创建实例
let origin = new Point();
origin.x = 0;
origin.y = 0;

let user = new User();
user.name = "Alice";

crob — 封装对象(字段 + 方法)

crob 是 Sii 的核心对象创建机制。它基于一个 class 创建封装对象,可以添加字段值方法。

class Person {
    name: string;
    age: int;
}

// 简单 crob
crob alice(class: Person, right: true) {
    name = "Alice";
    age = 28;
}

// 封装 crob — 包含方法
crob bob(class: Person, right: true) {
    name = "Bob";
    age = 32;

    func greet(): string {
        back "Hi, I'm " + name + ", age " + age.toString();
    }

    func haveBirthday(): void {
        age = age.getUp(1);
    }
}

// 调用方法
let greeting = bob.greet();
bob.haveBirthday();
参数说明
class: ClassName指定基础数据结构
right: true/falsetrue=封装(外部不可直接访问字段),false=开放

remake — 重构对象

// 基于已有的 crob 创建新对象,修改部分字段
remake alice {
    age = 29;  // 年龄更新
    // name 保持不变
}

this 关键字

this 在 crob 方法中引用当前对象实例:

crob counter(class: Box, right: true) {
    value = 0;

    func increment(): int {
        value = value.getUp(1);
        back this.value;  // 等价于直接 back value
    }
}

8. 数组与集合

数组字面量

let nums: arr<int> = [1, 2, 3, 4, 5];
let names: arr<string> = ["Alice", "Bob", "Charlie"];
let empty: arr<int> = [];

索引访问

let first = nums[0];      // 读取
nums[2] = 10;              // 修改(可变数组)
let last = nums[nums.length().toInt() - 1];

push — 追加元素

push 6 => nums[nums.length().toInt()];
push "Diana" => names[names.length().toInt()];

rmv — 删除元素

rmv nums[2];    // 删除索引 2 的元素
rmv names[0];   // 删除第一个元素

数组遍历

let items: arr<string> = ["a", "b", "c", "d"];

// 方式 1:forloop
forloop (let i = 0; i < items.length().toInt(); i = i + 1) {
    sii.io.print("[" + i.toString() + "] " + items[i]);
}

// 方式 2:while
let j = 0;
while (j < items.length().toInt()) {
    sii.io.print(items[j]);
    j = j.getUp(1);
}

数组方法

方法说明返回值
.length()获取数组长度multif(需 .toInt()
.cutIt(start, end)切片,返回新数组arr<T>
.splice(start, deleteCount, ...items)删除/插入元素被删除的元素数组
let nums: arr<int> = [1, 2, 3, 4, 5];
let slice = nums.cutIt(1, 3);  // [2, 3]
nums.splice(2, 1);              // 删除索引 2 的元素 → [1, 2, 4, 5]

9. 模块系统

share — 导出

使用 share 关键字导出函数和类(只有函数和类可以被导出):

// math.sii
share func add(a: int, b: int): int { back a + b; }
share func sub(a: int, b: int): int { back a - b; }
share class Point { x: int; y: int; }

// 内部辅助函数(不导出)
func internalHelper(): void { /* ... */ }

cite — 导入

使用 cite 关键字从其他 Sii 文件导入:

// 默认导入(导入文件中所有 share 的内容)
cite math from "./math.sii";

// 命名导入 — 只导入特定符号
cite { add, sub } from "./math.sii";

// 别名导入
cite add as myAdd from "./math.sii";
cite { add, sub as subtract } from "./math.sii";

// 导入运行时模块
cite sii.io as io;
cite sii.db as db;

外部库引用(lib.库名)

// 引用已安装的外部库
cite math from "lib.math";        // 引用 math 库的默认导出
cite { sin, cos } from "lib.math"; // 命名引用

外部库通过 sii install <库名> 安装,存储在用户级库目录中。

建议

尽量使用命名导入cite { ... } from ...),这样编译器和读者都能清楚知道依赖了哪些符号。

10. 异常处理

Sii 没有传统的 try-catch 异常机制。错误处理通过返回值检查错误码来完成,这是一种显式的错误处理风格。

错误码体系

范围类别说明
1000-1999类型错误类型不匹配、类型转换失败
2000-2999语法错误语法解析错误
3000-3999运行时错误空指针、越界访问
4000-4999I/O 错误文件不存在、权限不足
5000-5999网络错误连接失败、超时
6000-6999数据库错误连接失败、查询错误
7000-7999系统错误系统调用失败

检查错误

// 文件操作返回值检查
let content = sii.readText("config.json");
if (typeins(content, "string")) {
    // 读取成功
    sii.io.print(content as string);
} else {
    // 读取失败
    sii.io.print("无法读取配置文件");
}

// 使用 typeins 验证返回值
let result = performOperation();
if (typeins(result, "int")) {
    let code = result as int;
    if (code == 0) {
        sii.io.print("操作成功");
    } else {
        sii.io.print("错误码: " + code.toString());
    }
}

11. 标准库

Sii 提供丰富的内置标准库,通过 sii.* 命名空间访问。

11.1 控制台 I/O

方法说明
sii.io.print(...args)打印到控制台
sii.io.readLine()读取一行输入
sii.io.readInt()读取整数输入
sii.io.readSinglef()读取单精度浮点输入
sii.io.readMultif()读取双精度浮点输入
// 基本输出
sii.io.print("Hello, World!");
sii.io.print("The answer is", 42);

// 读取输入
let name = sii.io.readLine();
sii.io.print("你好, " + name + "!");

11.2 文件系统

方法说明
sii.readText(path)读取文本文件,返回 string
sii.writeText(path, content)写入文本文件
sii.exists(path)检查文件/目录是否存在
sii.mkdirs(path)递归创建目录
sii.pathJoin(...segments)拼接路径
sii.cwd()获取当前工作目录
// 读取文件
let config = sii.readText("config.json");
let data = sii.jsonParse(config);

// 写入文件
let json = sii.jsonStringify({ version: "2.0", debug: true });
sii.writeText("output.json", json);

// 路径操作
let logPath = sii.pathJoin(sii.cwd(), "logs", "app.log");
if (!sii.exists(logPath)) {
    sii.mkdirs(sii.pathJoin(sii.cwd(), "logs"));
    sii.writeText(logPath, "");
}

11.3 JSON 处理

方法说明
sii.jsonParse(jsonStr)解析 JSON 字符串为 obj
sii.jsonStringify(obj)将对象序列化为 JSON 字符串

11.4 网络编程

HTTP 客户端

方法说明
sii.get(url)发送 GET 请求
sii.post(url, body)发送 POST 请求
// GET 请求
let resp = sii.get("https://api.example.com/data");
sii.io.print(resp);

// POST 请求
let result = sii.post("https://api.example.com/submit", jsonData);

HTTP 服务器

方法说明
sii.listen(port)启动 HTTP 服务器监听指定端口
sii.get(path, handler)注册 GET 路由
sii.post(path, handler)注册 POST 路由
sii.put(path, handler)注册 PUT 路由
sii.delete(path, handler)注册 DELETE 路由
sii.options(path, handler)注册 OPTIONS 路由
sii.head(path, handler)注册 HEAD 路由
sii.respText(res, text)返回纯文本响应
sii.respJson(res, obj)返回 JSON 响应
sii.respHtml(res, html)返回 HTML 响应
func main(): void {
    sii.listen(3000);

    // 路由注册
    sii.get("/", func(): string {
        back "Welcome to Sii Server!";
    });

    sii.get("/api/users", func(): string {
        let users = sii.jsonStringify([
            { id: 1, name: "Alice" },
            { id: 2, name: "Bob" }
        ]);
        back users;
    });

    sii.post("/api/submit", func(): string {
        // 处理 POST 数据...
        back sii.jsonStringify({ ok: true });
    });

    sii.io.print("服务器已启动: http://127.0.0.1:3000");
}

11.5 数据库操作

Sii 提供链式查询 API,支持 MySQL、PostgreSQL 和 SQLite。

方法说明
sii.db.connect(type, dsn)连接数据库
sii.db.table(name)选择表
.where(col, op, val)添加 WHERE 条件
.orderBy(col, dir)排序
.limit(n)限制返回行数
.find()执行查询,返回结果数组
// 连接数据库
sii.db.connect("mysql", "mysql://user:pass@localhost/mydb");
// 或
sii.db.connect("postgresql", "postgresql://user:pass@localhost/mydb");
// 或
sii.db.connect("sqlite", "sqlite:data.db");

// 链式查询
let rows = sii.db.table("users")
    .where("age", ">=", 18)
    .where("status", "=", "active")
    .orderBy("created_at", "DESC")
    .limit(10)
    .find();

// 遍历结果
forloop (let i = 0; i < rows.length().toInt(); i = i + 1) {
    let user = rows[i];
    sii.io.print(user.name + " - " + user.email);
}

11.6 系统命令与工具

方法说明
sii.exec(cmd)执行系统命令,返回退出码
sii.execOut(cmd)执行系统命令,返回 stdout 输出
sii.env(key)读取环境变量
sii.now()获取当前时间戳
sii.log(msg)输出日志(INFO 级别)
sii.warn(msg)输出警告(WARN 级别)
sii.error(msg)输出错误(ERROR 级别)
// 执行命令
let code = sii.exec("echo hello");
let gitLog = sii.execOut("git log --oneline -5");

// 环境变量
let home = sii.env("HOME");
let path = sii.env("PATH");

// 日志
sii.log("应用启动");
sii.warn("配置项缺失,使用默认值");
sii.error("数据库连接失败");

12. 编译与构建

编译目标

目标命令输出适用场景
JavaScriptsiic in.sii out.js.jsWeb 前端、Node.js 服务
TypeScriptsiic in.sii out.ts --ts.tsTypeScript 项目
WebAssemblysiic in.sii out.wat --wasm.wat浏览器高性能场景
LLVM IRsiic in.sii out.ll --llvm.ll需要进一步优化的场景
原生siic native in.sii -o out可执行文件CLI 工具、高性能服务

监听模式

# 文件变化自动重编译
siic watch hello.sii hello.js

# 可同时指定多个编译目标
siic watch hello.sii hello.js
# 在另一个终端
siic watch hello.sii hello.ts --ts

开发服务器

# 启动开发服务器(默认端口 4173)
siic serve hello.sii

# 指定端口
siic serve hello.sii --port=8080

# 带反向代理(将 API 请求代理到后端)
siic serve hello.sii --proxy=http://localhost:3001

原生编译详解

siic native 使用 Cranelift 代码生成器将 Sii 源码编译为机器码,链接 libsii_rt_core.a 生成独立可执行文件。

# 编译为原生可执行文件
siic native hello.sii -o hello
./hello

# 交叉编译到其他平台
siic native hello.sii -o hello.exe -t=x64-windows
siic native hello.sii -o hello_arm -t=arm64-linux
前置要求

原生编译需要系统安装 C 编译器(gcc 或 clang),且 libsii_rt_core.a 位于 siic 同级目录的 ../lib/ 下。

LLVM 工具链(可选)

平台安装方式
Ubuntu/Debiansudo apt install llvm-dev clang
macOSbrew install llvm
Windows下载 LLVM 安装包或通过 winget install LLVM.LLVM

13. VS Code 扩展 (Sii Assistant)

Sii Assistant 是官方 VS Code 扩展,为 .sii 文件提供语法高亮、智能补全、悬停文档,以及一键编译和运行能力。

安装

下载页面获取最新 .vsix 文件,然后:

# 命令行安装
code --install-extension sii-lang-vscode-0.0.2.vsix

# 或在 VS Code 界面中
# 扩展面板 (Ctrl+Shift+X) → ... 菜单 → "从 VSIX 安装..."
前置依赖

扩展本身不捆绑编译器。使用前请确保已安装 siicnode,且它们在系统 PATH 中可被找到(或通过扩展设置指定路径)。

功能一览

功能说明
语法高亮关键字、类型、字符串、注释、数字等完整着色
自动补全关键字 + 标准库函数 + sii.* 模块 + sii.db.* 数据库 API
悬停文档关键字和常用函数显示用法说明与示例
代码折叠基于 { } 块的自动折叠
括号匹配{} [] () 自动配对与包围
一键编译命令面板中直接编译到 JS / TS / WASM / LLVM IR / 原生
一键运行自动编译到 JS → 启动运行时 → 执行(自动检测 sii.* 调用)
右键菜单.sii 文件上右键直接编译或运行

编译命令

打开 .sii 文件后,通过命令面板 (Ctrl+Shift+P) 或右键菜单使用:

命令输出
Sii: Compile to JavaScript.js 文件,同目录输出
Sii: Compile to TypeScript.ts 文件,同目录输出
Sii: Compile to WebAssembly.wat 文件,同目录输出
Sii: Compile to LLVM IR.ll 文件,同目录输出
Sii: Compile to Executable原生可执行文件,同目录输出
Sii: Run编译到 JS → 自动启停运行时 → 执行

扩展设置

在 VS Code 设置中搜索 "Sii" 可配置以下选项:

设置项默认值说明
sii.compiler.pathsiicSii 编译器路径
sii.runtime.pathsii-runtime-server运行时服务器路径
sii.runtime.urlhttp://127.0.0.1:3000运行时服务器地址
sii.runtime.autoStartfalseRun 时是否自动启动运行时
sii.node.pathnodeNode.js 路径
快捷提示

首次使用建议先运行 Sii: Auto-detect Tool Configuration,扩展会自动扫描系统中的 siicsii-runtime-server 位置并写入设置。
也可用 Sii: Validate Tool Configuration 检查当前工具链是否配置正确。

14. 部署与运行

运行时服务器

当编译目标为 JavaScript、TypeScript 或 WebAssembly 时,需要 sii-runtime-server 提供 I/O、数据库等后端能力。

# 启动运行时服务器
./sii-runtime-server --port=4174 &

# 运行编译后的 JS 程序
node app.js

# 或使用 siic serve 一键启动
siic serve app.sii --port=4173 --proxy=http://localhost:4174

Docker 部署

# Dockerfile
FROM node:20-alpine
COPY sii-runtime-server /usr/local/bin/
COPY app.js /app/
WORKDIR /app
CMD ["sh", "-c", "sii-runtime-server & sleep 1 && node app.js"]
# 构建和运行
docker build -t sii-app .
docker run -p 3000:3000 sii-app

systemd 服务(Linux)

# /etc/systemd/system/sii-app.service
[Unit]
Description=Sii Application
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/sii-runtime-server --port=4174
Restart=always
User=app

[Install]
WantedBy=multi-user.target

原生二进制部署

使用 siic native 编译出的可执行文件完全独立,无需运行时服务器。直接复制到目标机器即可运行:

# 编译
siic native app.sii -o myapp

# 部署
scp myapp user@server:/opt/myapp/
ssh user@server /opt/myapp/myapp

15. 附录

关键字完整列表

关键字用途
let声明可变变量
const声明不可变常量
func声明函数
back函数返回值
class声明数据结构
crob创建封装对象
remake重构对象
new实例化 class
this当前实例引用
share导出符号
cite导入符号
from指定导入来源
as导入别名
if else条件分支
forloopC 风格 for 循环
whilewhile 循环
break跳出循环
continue跳过当前迭代
push数组追加
rmv数组删除
typeins运行时类型检查
true false布尔字面量
void unknown特殊类型

运算符优先级(从高到低)

优先级运算符说明
1() [] .调用、索引、成员访问
2- !一元负号、逻辑非
3* / %乘、除、取模
4+ -加、减
5< <= > >=比较
6== !=等于、不等于
7&&逻辑与
8||逻辑或
9=赋值

标准库速查表

模块常用方法
sii.ioprint, readLine, readInt
文件sii.readText, sii.writeText, sii.exists, sii.mkdirs, sii.pathJoin, sii.cwd
JSONsii.jsonParse, sii.jsonStringify
HTTP 客户端sii.get, sii.post
HTTP 服务器sii.listen, sii.get, sii.post, sii.respText, sii.respJson
数据库sii.db.connect, sii.db.table().where().find()
系统sii.exec, sii.execOut, sii.env, sii.now
日志sii.log, sii.warn, sii.error

常见问题 (FAQ)

Q: Sii 和 TypeScript 有什么区别?

Sii 是一套独立的编程工具链,拥有自己的编译器、类型系统和运行时。它可以编译到 TypeScript,但本身不是 TypeScript 的超集。Sii 的类型系统更加严格,语法更简洁,并且支持原生编译。

Q: 什么时候应该用原生编译?

当你需要最高性能、最小启动时间,或者希望分发独立的二进制文件(无需 Node.js 或运行时服务器)时,使用 siic native

Q: 编译后的 JS 代码必须依赖运行时服务器吗?

如果 Sii 代码中使用了 I/O、数据库、HTTP 服务器等需要系统级支持的功能,则需要运行时服务器。纯计算逻辑(不涉及这些)编译后的 JS 代码可以独立运行。

Q: 如何安装第三方库?

使用 sii install <库名> 命令安装,然后在代码中通过 cite ... from "lib.库名" 引用。

Q: Sii 1.x 的代码能在 Sii 2.x 上运行吗?

大部分语法是兼容的。Sii 2.x 是全新编译器实现,某些细节行为可能有差异。建议参考本指南适配。