feat: 搭建原生函数基础设施
This commit is contained in:
@@ -57,6 +57,7 @@ pub(crate) struct CompileCtx {
|
||||
pub(crate) switch_stack: Vec<Label>,
|
||||
pub(crate) label_counter: u32,
|
||||
pub(crate) projected_pc: usize,
|
||||
pub(crate) builtin_reg_map: Vec<(String, u8)>,
|
||||
}
|
||||
|
||||
impl CompileCtx {
|
||||
@@ -72,6 +73,7 @@ impl CompileCtx {
|
||||
switch_stack: Vec::new(),
|
||||
label_counter: 0,
|
||||
projected_pc: 0,
|
||||
builtin_reg_map: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +166,19 @@ impl CompileCtx {
|
||||
pub(crate) fn current_switch(&self) -> Option<&Label> {
|
||||
self.switch_stack.last()
|
||||
}
|
||||
|
||||
pub(crate) fn pre_register_builtins(&mut self) {
|
||||
let builtins = [
|
||||
"NaN", "undefined", "Object", "Array", "String", "Number", "Boolean",
|
||||
"Function", "Error", "Math", "JSON", "Promise", "parseInt", "parseFloat",
|
||||
"isNaN", "isFinite",
|
||||
];
|
||||
for name in &builtins {
|
||||
let reg = self.alloc_reg();
|
||||
self.symbols.pre_register_global(name, reg);
|
||||
self.builtin_reg_map.push((name.to_string(), reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
@@ -173,6 +188,7 @@ impl Compiler {
|
||||
|
||||
pub fn compile(&self, program: &oxide_parser::Program) -> Result<CompiledModule, String> {
|
||||
let mut ctx = CompileCtx::new();
|
||||
ctx.pre_register_builtins();
|
||||
|
||||
for stmt in &program.body {
|
||||
self.count_statement(stmt, &mut ctx);
|
||||
@@ -205,6 +221,7 @@ impl Compiler {
|
||||
bytecode: ctx.bytecode,
|
||||
constants: ctx.constants,
|
||||
n_registers: ctx.max_regs,
|
||||
builtin_reg_map: ctx.builtin_reg_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,13 +199,14 @@ impl Compiler {
|
||||
}
|
||||
Expression::CallExpression(call) => {
|
||||
self.count_expression(&call.callee, ctx);
|
||||
ctx.alloc_reg();
|
||||
for arg in &call.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
self.count_expression(expr, ctx);
|
||||
}
|
||||
}
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 1; // CALL
|
||||
ctx.projected_pc += 2; // CALL + extension word (arg_count)
|
||||
}
|
||||
Expression::AssignmentExpression(assign) => {
|
||||
if let oxide_parser::AssignmentTarget::StaticMemberExpression(member) = &assign.left
|
||||
|
||||
@@ -668,10 +668,10 @@ impl Compiler {
|
||||
ctx.emit(opcode::encode(op, var_reg, rhs, 0));
|
||||
Ok(var_reg)
|
||||
} else {
|
||||
return Err(format!(
|
||||
Err(format!(
|
||||
"compound assignment operator {:?} not supported",
|
||||
assign.operator
|
||||
));
|
||||
))
|
||||
}
|
||||
} else {
|
||||
let val_reg = self.emit_expression(&assign.right, ctx)?;
|
||||
@@ -738,6 +738,37 @@ impl Compiler {
|
||||
Ok(r)
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => self.emit_expression(&p.expression, ctx),
|
||||
Expression::CallExpression(call) => {
|
||||
let callee_reg = self.emit_expression(&call.callee, ctx)?;
|
||||
let this_idx = ctx.add_constant(Constant::Undefined);
|
||||
let this_reg = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(
|
||||
OpCode::LOAD_CONST,
|
||||
this_reg,
|
||||
(this_idx & 0xFF) as u8,
|
||||
((this_idx >> 8) & 0xFF) as u8,
|
||||
));
|
||||
let mut arg_regs = Vec::new();
|
||||
for arg in &call.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
arg_regs.push(self.emit_expression(expr, ctx)?);
|
||||
}
|
||||
}
|
||||
let first_arg_reg = if arg_regs.is_empty() {
|
||||
0u8
|
||||
} else {
|
||||
arg_regs[0]
|
||||
};
|
||||
let result_reg = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(
|
||||
OpCode::CALL,
|
||||
callee_reg,
|
||||
this_reg,
|
||||
first_arg_reg,
|
||||
));
|
||||
ctx.emit(arg_regs.len() as u32);
|
||||
Ok(result_reg)
|
||||
}
|
||||
_ => Err(format!("unsupported expression type: {:?}", expr)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,15 @@ fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) {
|
||||
std::mem::discriminant(&un.operator).hash(h);
|
||||
hash_expression(&un.argument, h);
|
||||
}
|
||||
Expression::CallExpression(_) => {
|
||||
Expression::CallExpression(call) => {
|
||||
2u8.hash(h);
|
||||
(call.arguments.len() as u32).hash(h);
|
||||
hash_expression(&call.callee, h);
|
||||
for arg in &call.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
hash_expression(expr, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::LogicalExpression(log) => {
|
||||
3u8.hash(h);
|
||||
|
||||
@@ -16,6 +16,7 @@ pub struct CompiledModule {
|
||||
pub bytecode: Vec<opcode::Instr>,
|
||||
pub constants: Vec<Constant>,
|
||||
pub n_registers: u8,
|
||||
pub builtin_reg_map: Vec<(String, u8)>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CompiledModule {
|
||||
|
||||
@@ -73,6 +73,13 @@ impl SymbolTable {
|
||||
reg_for_new
|
||||
}
|
||||
|
||||
pub fn pre_register_global(&mut self, name: &str, reg: u8) {
|
||||
self.scopes[0].entry(name.to_string()).or_insert(Binding {
|
||||
reg,
|
||||
initialized: true,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_var(&mut self, name: &str) {
|
||||
let current = self.scopes.last_mut().unwrap();
|
||||
if let Some(b) = current.get_mut(name) {
|
||||
|
||||
Reference in New Issue
Block a user