w3cos-compiler 技术文档
版本: 0.1.0
位置: crates/w3cos-compiler/
一、概述
w3cos-compiler 是 W3C OS 的核心编译器,负责将 TypeScript 源代码转换为 Rust 代码,最终通过 rustc/LLVM 编译为原生二进制文件。
TypeScript (.ts/.tsx) → w3cos-compiler → Rust 源码 (.rs) → rustc/LLVM → 原生二进制
设计目标
- AOT 编译: 无运行时、无解释器、无 V8
- 零开销抽象: TS 代码直接映射为原生机器码
- 双模式支持: UI 应用 + 通用 TS 逻辑
二、模块结构
w3cos-compiler/
├── src/
│ ├── lib.rs # 入口:compile_to_rust() / compile()
│ ├── parser.rs # 解析 TS/JSON 为内部 AST
│ ├── codegen.rs # 从 AST 生成 Rust 代码
│ ├── ts_transpiler.rs # 通用 TypeScript → Rust 转译 (基于 SWC)
│ └── ts_types.rs # TypeScript 类型推断系统
├── Cargo.toml
└── tests/
核心依赖
| 依赖 |
用途 |
swc_ecma_parser |
TypeScript 词法/语法分析 |
swc_ecma_ast |
TypeScript AST 表示 |
swc_common |
源码映射、错误报告 |
anyhow |
错误处理 |
三、两种编译模式
编译器自动检测输入类型并选择相应模式:
模式 A: UI DSL (组件树)
检测条件:
- JSON 格式输入
- 导入
@w3cos/std
- 使用
<Column>, <Text>, <Button> 等 TSX 组件
输出: 链接 w3cos-runtime 的 GUI 应用
// 输入:app.tsx
import { Column, Text, Button } from "@w3cos/std"
export default Column({
style: { gap: 20, padding: 48, background: "#0f0f1a" },
children: [
Text("W3C OS", { style: { fontSize: 42, color: "#e94560" } }),
Button("Get Started", { style: { background: "#e94560" } })
]
})
use w3cos_std::{Component, Style};
use w3cos_std::style::*;
use w3cos_std::color::Color;
fn main() {
w3cos_runtime::run_app(build_ui).expect("W3C OS app crashed");
}
fn build_ui() -> Component {
Component::column(
Style {
gap: 20_f32,
padding: Edges::all(48_f32),
background: Color::from_hex("#0f0f1a"),
..Style::default()
},
vec![
Component::text("W3C OS", Style {
font_size: 42_f32,
color: Color::from_hex("#e94560"),
..Style::default()
}),
Component::button("Get Started", Style {
background: Color::from_hex("#e94560"),
..Style::default()
}),
]
)
}
模式 B: 通用 TypeScript
检测条件:
- 包含
function, const, let, interface 等
- 无
@w3cos/std 导入
- 纯逻辑代码
输出: 独立 CLI 二进制
interface User {
name: string;
age: number;
}
function greet(name: string): string {
return "Hello, " + name + "!";
}
function fibonacci(n: number): number {
if (n <= 1) { return n; }
let a: number = 0;
let b: number = 1;
for (let i = 2; i < n; i++) {
let temp = b;
b = a + b;
a = temp;
}
return b;
}
console.log(greet("W3C OS"));
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct User {
pub name: String,
pub age: i64,
}
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn fibonacci(n: i64) -> i64 {
if n <= 1 { return n; }
let mut a: i64 = 0;
let mut b: i64 = 1;
for i in 2..n {
let temp = b;
b = a + b;
a = temp;
}
b
}
fn main() {
let message = greet("W3C OS");
println!("{}", message);
}
四、核心 API
compile_to_rust()
将 TypeScript 源码转换为 Rust 代码字符串(无文件 I/O)。
pub fn compile_to_rust(ts_source: &str) -> Result<String> {
if is_ui_dsl(ts_source) {
let tree = parser::parse(ts_source)?;
codegen::generate(&tree)
} else {
ts_transpiler::transpile(ts_source)
}
}
compile()
将 TypeScript 源文件编译为独立的 Rust 项目。
pub fn compile(ts_source: &str, output_dir: &std::path::Path) -> Result<()> {
let is_ui = is_ui_dsl(ts_source);
let rust_code = compile_to_rust(ts_source)?;
std::fs::create_dir_all(output_dir.join("src"))?;
if is_ui {
let cargo_toml = codegen::generate_cargo_toml(output_dir)?;
std::fs::write(output_dir.join("Cargo.toml"), cargo_toml)?;
} else {
let cargo_toml = generate_standalone_cargo_toml()?;
std::fs::write(output_dir.join("Cargo.toml"), cargo_toml)?;
}
std::fs::write(output_dir.join("src/main.rs"), rust_code)?;
Ok(())
}
is_ui_dsl()
启发式检测输入是否为 UI DSL。
fn is_ui_dsl(source: &str) -> bool {
let trimmed = source.trim();
if trimmed.starts_with('{') || trimmed.starts_with('[') {
return true;
}
let has_ui_import = trimmed.contains("@w3cos/std");
let has_component_call = ["Column(", "Row(", "Text(", "Button("]
.iter()
.any(|pat| trimmed.contains(pat));
let has_tsx_component = ["<Column", "<Row", "<Text", "<Button"]
.iter()
.any(|pat| trimmed.contains(pat));
if has_ui_import && (has_component_call || has_tsx_component) {
return true;
}
let body = extract_body(trimmed);
body.starts_with("Column(") || body.starts_with("<Column")
&& !body.contains("function ")
&& !body.contains("const ")
}
五、TypeScript 支持范围
✅ 已支持特性
| 类别 |
特性 |
| 语法 |
函数、变量、常量、箭头函数 |
| 类型 |
string, number, boolean, 数组,接口,类型别名 |
| 控制流 |
if/else, for, for...in, for...of, while |
| 表达式 |
二元运算、一元运算、赋值、更新 (++, --) |
| 数据结构 |
数组字面量、对象字面量 |
| 内置函数 |
console.log() → println!() |
| 数组方法 |
.push(), .pop(), .length |
| 字符串 |
模板字面量、字符串拼接 |
| TSX |
组件语法、属性、子元素 |
❌ 不支持的特性
| 特性 |
原因 |
eval() |
非 AOT 兼容 |
innerHTML |
XSS 风险,非 AOT 兼容 |
document.write() |
非 AOT 兼容 |
动态 import() |
需要运行时支持 |
class (部分) |
复杂继承未完全支持 |
| 泛型 |
类型擦除后等价 Rust |
六、类型推断系统
编译器使用静态类型推断将 TypeScript 类型映射为 Rust 类型:
| TypeScript |
Rust |
string |
String |
number |
i64 / f64 |
boolean |
bool |
number[] |
Vec<i64> |
string[] |
Vec<String> |
T[] |
Vec<T> |
{ name: string } |
struct { name: String } |
T | null |
Option<T> |
any |
serde_json::Value |
Map<K, V> |
HashMap<K, V> |
推断示例
let count: number = 42;
let name: string = "W3C";
let items: number[] = [1, 2, 3];
interface User {
name: string;
age: number;
email?: string;
}
七、代码生成策略
UI DSL 代码生成
fn gen_node(node: &Node, depth: usize, signal_names: &[&str]) -> String {
let indent = " ".repeat(depth + 1);
let style_code = gen_style(&node.style, depth + 1);
match &node.kind {
NodeKind::Text(content) => {
let text = node.text.as_deref().unwrap_or(content.as_str());
format!("{indent}Component::text({text:?}, {style_code})")
}
NodeKind::Button(label) => {
let lbl = node.label.as_deref().unwrap_or(label.as_str());
if let Some(ref action_str) = node.on_click {
let action = gen_event_action(action_str, signal_names);
format!("{indent}Component::button_with_click({lbl:?}, {style_code}, {action})")
} else {
format!("{indent}Component::button({lbl:?}, {style_code})")
}
}
NodeKind::Column => {
let children_code = if node.children.is_empty() {
"vec![]".to_string()
} else {
let items: Vec<String> = node.children
.iter()
.map(|c| gen_node(c, depth + 2, signal_names))
.collect();
format!("vec![\n{},\n{indent}]", items.join(",\n"))
};
format!("{indent}Component::column({style_code}, {children_code})")
}
}
}
通用 TS 代码生成
fn transpile_for(&mut self, for_stmt: &ForStmt) -> Result<()> {
if let Some(range) = detect_range_for(for_stmt) {
self.push_indent();
self.push(&format!("for {} in ", range.var));
self.transpile_expr(&range.start)?;
self.push("..");
self.transpile_expr(&range.end)?;
self.push(" {\n");
self.indent += 1;
self.transpile_stmt_body(&for_stmt.body)?;
self.indent -= 1;
self.line("}");
return Ok(());
}
}
八、使用示例
CLI 使用
w3cos build examples/showcase/app.tsx -o showcase --release
w3cos build examples/general-ts/app.ts -o myapp --release
./showcase
./myapp
库 API 使用
use w3cos_compiler::compile_to_rust;
let ts_source = r#"
Column({
style: { gap: 8, padding: 16 },
children: [
Text("Title", { style: { font_size: 24 } }),
Button("Submit", { style: { background: "#e94560" } })
]
})
"#;
let rust_code = compile_to_rust(ts_source).unwrap();
println!("{}", rust_code);
九、测试覆盖
单元测试
#[test]
fn compile_general_ts_showcase() {
let input = r#"
interface User {
name: string;
age: number;
email?: string;
}
function greet(name: string): string {
return "Hello, " + name + "!";
}
function fibonacci(n: number): number {
if (n <= 1) { return n; }
let a: number = 0;
let b: number = 1;
for (let i = 2; i < n; i++) {
let temp = b;
b = a + b;
a = temp;
}
return b;
}
console.log(greet("W3C OS"));
"#;
let rust = compile_to_rust(input).unwrap();
assert!(rust.contains("struct User"));
assert!(rust.contains("fn greet("));
assert!(rust.contains("fn fibonacci("));
assert!(rust.contains("fn main()"));
assert!(rust.contains("for i in"));
assert!(rust.contains("println!"));
}
十、性能指标
| 指标 |
数值 |
| 编译速度 (UI DSL) |
~50-100ms |
| 编译速度 (通用 TS) |
~200-500ms (含 SWC 解析) |
| 输出二进制大小 |
2.4 MB (release) |
| 启动时间 |
< 100ms |
十一、未来规划
| 版本 |
特性 |
| v0.2 |
完整 React Hooks 支持 |
| v0.3 |
CSS @keyframes 动画 |
| v0.4 |
增量编译 (watch 模式) |
| v0.5 |
热重载开发服务器 |
十二、相关文件