feat: 实现for-of与解构赋值

This commit is contained in:
爱特每羊队
2026-06-14 23:45:12 +08:00
parent c766d69d0a
commit 21e3693c63
15 changed files with 891 additions and 81 deletions
+47 -14
View File
@@ -44,6 +44,8 @@ pub(crate) enum Label {
DoWhileEnd(u32),
ForInStart(u32),
ForInEnd(u32),
ForOfStart(u32),
ForOfEnd(u32),
SwitchEnd(u32),
SwitchCase(u32, u32),
CatchBody(u32),
@@ -86,6 +88,23 @@ pub(crate) enum FunctionBodyContext {
ClassElement,
}
pub(crate) enum ParamSpec<'a> {
Identifier(String),
Pattern {
synthetic_name: String,
pattern: &'a oxide_parser::BindingPattern<'a>,
},
}
impl ParamSpec<'_> {
pub(crate) fn register_name(&self) -> &str {
match self {
Self::Identifier(name) => name,
Self::Pattern { synthetic_name, .. } => synthetic_name,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum ConstantKey {
Number(u64),
@@ -366,18 +385,23 @@ impl Compiler {
pub(crate) fn extract_function_parts<'a>(
&self, function: &'a oxide_parser::Function<'a>,
) -> Result<(Vec<String>, &'a [Statement<'a>]), String> {
let mut param_names = Vec::new();
for param in &function.params.items {
) -> Result<(Vec<ParamSpec<'a>>, &'a [Statement<'a>]), String> {
let mut param_specs = Vec::new();
for (idx, param) in function.params.items.iter().enumerate() {
match &param.pattern {
oxide_parser::BindingPattern::BindingIdentifier(bi) => {
param_names.push(bi.name.to_string());
param_specs.push(ParamSpec::Identifier(bi.name.to_string()));
}
pattern => {
param_specs.push(ParamSpec::Pattern {
synthetic_name: format!("@@param_{idx}"),
pattern,
});
}
_ => return Err("destructuring parameters not supported".into()),
}
}
let body_stmts: &[Statement] = if let Some(body) = &function.body { &body.statements } else { &[] };
Ok((param_names, body_stmts))
Ok((param_specs, body_stmts))
}
/// Compile a function body (used for FD, FE, and arrow functions).
@@ -388,8 +412,8 @@ impl Compiler {
/// (true for arrow functions, which have lexical super) or reset to false
/// (false for regular functions, which create a new super scope).
pub(crate) fn compile_function_body<'a>(
&self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool,
is_arrow: bool,
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, is_arrow: bool,
) -> Result<CompiledModule, String> {
let body_context = if is_arrow {
FunctionBodyContext::Arrow
@@ -397,7 +421,7 @@ impl Compiler {
FunctionBodyContext::Ordinary
};
self.compile_function_body_with_bindings(
param_names,
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
@@ -407,8 +431,8 @@ impl Compiler {
}
pub(crate) fn compile_function_body_with_bindings<'a>(
&self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool,
extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext,
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext,
) -> Result<CompiledModule, String> {
let mut ctx = CompileCtx::new();
@@ -467,7 +491,8 @@ impl Compiler {
let param_base = ctx.next_reg;
// Register parameters as initialized.
for name in param_names {
for spec in param_specs {
let name = spec.register_name();
let reg = ctx.alloc_reg();
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
}
@@ -480,11 +505,19 @@ impl Compiler {
ctx.reset_regs();
// Emit pass - reallocate params (same order = same regs after reset)
for name in param_names {
for spec in param_specs {
let name = spec.register_name();
let reg = ctx.alloc_reg();
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
}
for spec in param_specs {
if let ParamSpec::Pattern { synthetic_name, pattern } = spec {
let src_reg = ctx.lookup(synthetic_name)?;
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, &mut ctx)?;
}
}
// Emit body statements.
// Capture the last statement's expression result for expression-body arrows.
let mut last_result_reg = None;
@@ -530,7 +563,7 @@ impl Compiler {
bytecode: ctx.bytecode,
constants: ctx.constants,
n_registers: ctx.max_regs,
n_args: param_names.len() as u8,
n_args: param_specs.len() as u8,
param_base,
builtin_reg_map: ctx.builtin_reg_map,
sub_modules: ctx.sub_modules,