refactor: CompileCtx 拆分为 LabelCtx/ScopeCtx,字面量域改用注册表入口

This commit is contained in:
2026-06-25 19:46:35 +08:00
parent d195d7615c
commit f7bcfd3846
17 changed files with 180 additions and 113 deletions
+64 -66
View File
@@ -1,5 +1,6 @@
use std::collections::HashMap;
use crate::emit_ctx::{LabelCtx, ScopeCtx};
use crate::symbol_table::{Binding, SymbolTable};
use oxide_bytecode::module::CompiledModule;
use oxide_bytecode::opcode::{self, OpCode};
@@ -145,18 +146,9 @@ pub(crate) struct CompileCtx {
next_reg: u8,
pub(crate) max_regs: u8,
reserved_reg_start: u8,
symbols: SymbolTable,
pub(crate) label_map: HashMap<Label, usize>,
pub(crate) loop_stack: Vec<(Label, Label)>,
#[allow(dead_code)]
pub(crate) switch_stack: Vec<Label>,
/// Active labeled-statement scopes (resolves `break label` / `continue label`).
pub(crate) label_scopes: Vec<LabelScope>,
/// Label names awaiting binding to the next emitted loop's continue target.
pub(crate) pending_loop_labels: Vec<String>,
pub(crate) label_counter: u32,
pub(crate) labels: LabelCtx,
pub(crate) scopes: ScopeCtx,
pub(crate) projected_pc: usize,
pub(crate) builtin_reg_map: Vec<(String, u8)>,
pub(crate) sub_modules: Vec<CompiledModule>,
/// Register holding `this` in the enclosing function context.
/// Used by arrow functions to capture lexical `this`.
@@ -166,8 +158,6 @@ pub(crate) struct CompileCtx {
pub(crate) in_instance_method: bool,
pub(crate) in_static_method: bool,
pub(crate) static_block_this_reg: Option<u8>,
pub(crate) private_name_map: Vec<(String, u32)>,
pub(crate) next_private_name_id: u32,
pub(crate) after_super_insert: Option<Vec<opcode::Instr>>,
pub(crate) after_super_inserted: bool,
/// Set when alloc_reg() overflows into the reserved this/new.target range (≥254).
@@ -220,23 +210,27 @@ impl CompileCtx {
next_reg: 1,
max_regs: 1,
reserved_reg_start: 1,
symbols: SymbolTable::new(),
label_map: HashMap::new(),
loop_stack: Vec::new(),
switch_stack: Vec::new(),
label_scopes: Vec::new(),
pending_loop_labels: Vec::new(),
label_counter: 0,
labels: LabelCtx {
label_map: HashMap::new(),
loop_stack: Vec::new(),
switch_stack: Vec::new(),
label_scopes: Vec::new(),
pending_loop_labels: Vec::new(),
label_counter: 0,
},
scopes: ScopeCtx {
symbols: SymbolTable::new(),
builtin_reg_map: Vec::new(),
private_name_map: Vec::new(),
next_private_name_id: 1,
},
projected_pc: 0,
builtin_reg_map: Vec::new(),
sub_modules: Vec::new(),
enclosing_this_reg: 254, // conventional this register at top level
in_derived_constructor: false,
in_instance_method: false,
in_static_method: false,
static_block_this_reg: None,
private_name_map: Vec::new(),
next_private_name_id: 1,
after_super_insert: None,
after_super_inserted: false,
reg_overflow: false,
@@ -339,7 +333,7 @@ impl CompileCtx {
pub(crate) fn reset_regs(&mut self) {
self.next_reg = self.builtin_reg_floor().max(self.reserved_reg_start);
self.projected_pc = 0;
self.label_counter = 0;
self.labels.label_counter = 0;
}
pub(crate) fn reg_checkpoint(&self) -> u8 {
@@ -395,48 +389,49 @@ impl CompileCtx {
}
pub(crate) fn resolve_label(&self, label: Label) -> Result<usize, String> {
self.label_map
self.labels
.label_map
.get(&label)
.copied()
.ok_or_else(|| format!("Label {:?} not found in bytecode map", label))
}
pub(crate) fn push_scope(&mut self) {
self.symbols.push_scope();
self.scopes.symbols.push_scope();
}
pub(crate) fn pop_scope(&mut self) {
self.symbols.pop_scope();
self.scopes.symbols.pop_scope();
}
pub(crate) fn declare(
&mut self, name: &str, reg: u8, kind: VariableDeclarationKind, is_const: bool,
) -> Result<(), String> {
self.symbols.declare(name, reg, kind, is_const)
self.scopes.symbols.declare(name, reg, kind, is_const)
}
pub(crate) fn declare_initialized(
&mut self, name: &str, reg: u8, kind: VariableDeclarationKind, is_const: bool,
) -> Result<(), String> {
self.symbols.declare_initialized(name, reg, kind, is_const)
self.scopes.symbols.declare_initialized(name, reg, kind, is_const)
}
#[allow(dead_code)]
pub(crate) fn push_scope_with_kind(&mut self, kind: ScopeKind) {
self.symbols.push_scope_with_kind(kind);
self.scopes.symbols.push_scope_with_kind(kind);
}
pub(crate) fn lookup(&self, name: &str) -> Result<u8, String> {
self.symbols.lookup(name)
self.scopes.symbols.lookup(name)
}
pub(crate) fn lookup_or_builtin(&mut self, name: &str) -> Result<u8, String> {
match self.symbols.lookup(name) {
match self.scopes.symbols.lookup(name) {
Ok(reg) => Ok(reg),
Err(err) if Self::is_known_builtin(name) && err.contains("is not defined") => {
let reg = self.alloc_reg();
self.symbols.pre_register_global(name, reg);
self.builtin_reg_map.push((name.to_string(), reg));
self.scopes.symbols.pre_register_global(name, reg);
self.scopes.builtin_reg_map.push((name.to_string(), reg));
Ok(reg)
}
Err(err) => Err(err),
@@ -444,58 +439,58 @@ impl CompileCtx {
}
pub(crate) fn lookup_or_global(&mut self, name: &str) -> u8 {
if let Some(reg) = self.symbols.lookup_any(name) {
if let Some(reg) = self.scopes.symbols.lookup_any(name) {
return reg;
}
let reg = self.alloc_reg();
self.symbols.lookup_or_global(name, reg)
self.scopes.symbols.lookup_or_global(name, reg)
}
pub(crate) fn lookup_const_flag(&self, name: &str) -> bool {
self.symbols.lookup_is_const(name)
self.scopes.symbols.lookup_is_const(name)
}
pub(crate) fn init_var(&mut self, name: &str) {
self.symbols.init_var(name);
self.scopes.symbols.init_var(name);
}
pub(crate) fn next_label_id(&mut self) -> u32 {
let id = self.label_counter;
self.label_counter += 1;
let id = self.labels.label_counter;
self.labels.label_counter += 1;
id
}
pub(crate) fn push_loop(&mut self, break_label: Label, continue_label: Label) {
self.loop_stack.push((break_label, continue_label));
self.labels.loop_stack.push((break_label, continue_label));
}
pub(crate) fn pop_loop(&mut self) {
self.loop_stack.pop();
self.labels.loop_stack.pop();
}
pub(crate) fn current_loop(&self) -> Option<&(Label, Label)> {
self.loop_stack.last()
self.labels.loop_stack.last()
}
pub(crate) fn push_switch(&mut self, break_label: Label) {
self.switch_stack.push(break_label);
self.labels.switch_stack.push(break_label);
}
pub(crate) fn pop_switch(&mut self) {
self.switch_stack.pop();
self.labels.switch_stack.pop();
}
pub(crate) fn current_switch(&self) -> Option<&Label> {
self.switch_stack.last()
self.labels.switch_stack.last()
}
pub(crate) fn push_label_scope(
&mut self, name: &str, break_label: Label, continue_label: Option<Label>,
) -> Result<(), String> {
if self.label_scopes.iter().any(|s| s.name == name) {
if self.labels.label_scopes.iter().any(|s| s.name == name) {
return Err(format!("SyntaxError: Label '{name}' has already been declared"));
}
self.label_scopes.push(LabelScope {
self.labels.label_scopes.push(LabelScope {
name: name.to_string(),
break_label,
continue_label,
@@ -504,31 +499,33 @@ impl CompileCtx {
}
pub(crate) fn pop_label_scope(&mut self) {
self.label_scopes.pop();
self.labels.label_scopes.pop();
}
pub(crate) fn find_label(&self, name: &str) -> Option<&LabelScope> {
self.label_scopes.iter().rev().find(|s| s.name == name)
self.labels.label_scopes.iter().rev().find(|s| s.name == name)
}
/// Queue a label name to be bound to the continue target of the next loop
/// emitted as the labeled statement's body. Rejects duplicates in the active
/// or pending sets.
pub(crate) fn queue_loop_label(&mut self, name: &str) -> Result<(), String> {
if self.label_scopes.iter().any(|s| s.name == name) || self.pending_loop_labels.iter().any(|n| n == name) {
if self.labels.label_scopes.iter().any(|s| s.name == name)
|| self.labels.pending_loop_labels.iter().any(|n| n == name)
{
return Err(format!("SyntaxError: Label '{name}' has already been declared"));
}
self.pending_loop_labels.push(name.to_string());
self.labels.pending_loop_labels.push(name.to_string());
Ok(())
}
/// Drain queued loop labels into active scopes bound to this loop's break and
/// continue targets. Returns how many scopes were pushed (to pop after).
pub(crate) fn take_pending_loop_labels(&mut self, break_label: Label, continue_label: Label) -> usize {
let names = std::mem::take(&mut self.pending_loop_labels);
let names = std::mem::take(&mut self.labels.pending_loop_labels);
let count = names.len();
for name in names {
self.label_scopes.push(LabelScope {
self.labels.label_scopes.push(LabelScope {
name,
break_label,
continue_label: Some(continue_label),
@@ -539,12 +536,12 @@ impl CompileCtx {
pub(crate) fn pop_label_scopes(&mut self, n: usize) {
for _ in 0..n {
self.label_scopes.pop();
self.labels.label_scopes.pop();
}
}
pub(crate) fn is_builtin(&self, name: &str) -> bool {
self.builtin_reg_map.iter().any(|(n, _)| n == name)
self.scopes.builtin_reg_map.iter().any(|(n, _)| n == name)
}
pub(crate) fn is_known_builtin(name: &str) -> bool {
@@ -552,7 +549,8 @@ impl CompileCtx {
}
fn builtin_reg_floor(&self) -> u8 {
self.builtin_reg_map
self.scopes
.builtin_reg_map
.iter()
.map(|(_, reg)| reg.saturating_add(1))
.max()
@@ -662,9 +660,9 @@ impl Compiler {
// Inherit parent's builtin_reg_map so builtin identifiers (Math, Object, etc.)
// resolve to the correct pre-allocated registers in the sub-module's register file.
ctx.builtin_reg_map = parent_ctx.builtin_reg_map.clone();
ctx.private_name_map = parent_ctx.private_name_map.clone();
ctx.next_private_name_id = parent_ctx.next_private_name_id;
ctx.scopes.builtin_reg_map = parent_ctx.scopes.builtin_reg_map.clone();
ctx.scopes.private_name_map = parent_ctx.scopes.private_name_map.clone();
ctx.scopes.next_private_name_id = parent_ctx.scopes.next_private_name_id;
// Propagate enclosing_this_reg so nested arrow functions capture the correct `this`.
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
@@ -683,8 +681,8 @@ impl Compiler {
// Inherit parent's global scope entries so previously-declared function names
// are visible from within the body.
let mut inherited_reg_start = 1u8.max(ctx.builtin_reg_floor());
for (name, binding) in &parent_ctx.symbols.scopes[0].bindings {
ctx.symbols.scopes[0].bindings.insert(
for (name, binding) in &parent_ctx.scopes.symbols.scopes[0].bindings {
ctx.scopes.symbols.scopes[0].bindings.insert(
name.clone(),
Binding {
reg: binding.reg,
@@ -695,7 +693,7 @@ impl Compiler {
inherited_reg_start = inherited_reg_start.max(binding.reg.saturating_add(1));
}
for (name, reg) in extra_bindings {
ctx.symbols.scopes[0].bindings.insert(
ctx.scopes.symbols.scopes[0].bindings.insert(
(*name).to_string(),
Binding {
reg: *reg,
@@ -820,7 +818,7 @@ impl Compiler {
n_registers: ctx.max_regs,
n_args: param_specs.len() as u8,
param_base,
builtin_reg_map: ctx.builtin_reg_map,
builtin_reg_map: ctx.scopes.builtin_reg_map,
sub_modules: ctx.sub_modules,
is_arrow: false,
captured_this_const_idx: 0,
@@ -890,8 +888,8 @@ impl Compiler {
constants: ctx.constants,
n_registers: ctx.max_regs,
n_args: 0,
param_base: ctx.builtin_reg_map.len() as u8,
builtin_reg_map: ctx.builtin_reg_map,
param_base: ctx.scopes.builtin_reg_map.len() as u8,
builtin_reg_map: ctx.scopes.builtin_reg_map,
sub_modules: ctx.sub_modules,
is_arrow: false,
captured_this_const_idx: 0,
@@ -72,7 +72,7 @@ impl Compiler {
self.count_expression(right, ctx);
ctx.count_ic_set_with_ext(); // IC_SET_PROP + 3 ext
ctx.projected_pc += 1; // LOAD_VAR result <- rhs
ctx.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
}
fn count_computed_member_logical_assignment(
@@ -88,7 +88,7 @@ impl Compiler {
self.count_expression(right, ctx);
ctx.projected_pc += 1; // SET_PROP_DYNAMIC
ctx.projected_pc += 1; // LOAD_VAR result <- rhs
ctx.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
}
fn count_identifier_logical_assignment(
@@ -101,6 +101,6 @@ impl Compiler {
self.count_expression(right, ctx);
ctx.projected_pc += 1; // STORE_VAR
ctx.projected_pc += 1; // LOAD_VAR result <- rhs
ctx.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
}
}
@@ -10,8 +10,8 @@ impl Compiler {
ctx.alloc_reg();
ctx.projected_pc += 1; // LOAD_VAR result <- chain value
ctx.projected_pc += 1; // JMP over short-circuit writer
ctx.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
ctx.projected_pc += 1; // LOAD_CONST undefined
ctx.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc);
}
}
@@ -15,10 +15,10 @@ impl Compiler {
ctx.alloc_reg(); // result register
ctx.projected_pc += 1; // LOAD_VAR result <- consequent
ctx.projected_pc += 1; // JMP to end
ctx.label_map.insert(else_label, ctx.projected_pc);
ctx.labels.label_map.insert(else_label, ctx.projected_pc);
self.count_expression(&cond.alternate, ctx);
ctx.projected_pc += 1; // LOAD_VAR result <- alternate
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
}
pub(in crate::counter) fn count_sequence_expression(&self, expr: &Expression, ctx: &mut CompileCtx) {
@@ -49,7 +49,7 @@ impl Compiler {
ctx.projected_pc += 1; // JMP_IF_FALSE, JMP_IF_TRUE, or JMP_IF_NULLISH
if matches!(log.operator, LogicalOperator::Coalesce) {
ctx.projected_pc += 1; // JMP over RHS on non-nullish
ctx.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
}
self.count_expression(&log.right, ctx);
ctx.projected_pc += 1; // LOAD_VAR (overwrite)
@@ -58,7 +58,7 @@ impl Compiler {
LogicalOperator::Or => Label::TernaryElse(id),
LogicalOperator::Coalesce => Label::TernaryEnd(id),
};
ctx.label_map.insert(skip_label, ctx.projected_pc);
ctx.labels.label_map.insert(skip_label, ctx.projected_pc);
}
}
}
@@ -1,6 +1,17 @@
use super::*;
impl Compiler {
/// Domain entry point: count any literal expression. The central
/// `count_expression` match delegates all literal variants here in one arm.
/// Numeric/String/Boolean/Null share the default single-`LOAD_CONST` shape;
/// RegExp emits three instructions.
pub(in crate::counter) fn count_literal(&self, expr: &Expression, ctx: &mut CompileCtx) {
match expr {
Expression::RegExpLiteral(_) => self.count_regexp_literal(ctx),
_ => self.count_default_expression(ctx),
}
}
pub(in crate::counter) fn count_this_expression(&self, ctx: &mut CompileCtx) {
ctx.alloc_reg();
ctx.projected_pc += 1; // LOAD_VAR from reg 254
@@ -38,7 +38,11 @@ impl Compiler {
Expression::ThisExpression(_) => self.count_this_expression(ctx),
Expression::Identifier(_) => self.count_identifier_expression(expr, ctx),
Expression::UpdateExpression(_) => self.count_update_expression(expr, ctx),
Expression::RegExpLiteral(_) => self.count_regexp_literal(ctx),
Expression::NumericLiteral(_)
| Expression::StringLiteral(_)
| Expression::BooleanLiteral(_)
| Expression::NullLiteral(_)
| Expression::RegExpLiteral(_) => self.count_literal(expr, ctx),
_ => self.count_default_expression(ctx),
}
}
@@ -166,7 +166,7 @@ impl Compiler {
LogicalOperator::Coalesce => {
ctx.projected_pc += 1; // JMP_IF_NULLISH to store body
ctx.projected_pc += 1; // JMP to end on non-nullish
ctx.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc);
}
}
}
@@ -43,7 +43,7 @@ impl Compiler {
// LabeledEnd target right after the body for `break label`.
let id = ctx.next_label_id();
self.count_statement(&stmt.body, ctx);
ctx.label_map.insert(Label::LabeledEnd(id), ctx.projected_pc);
ctx.labels.label_map.insert(Label::LabeledEnd(id), ctx.projected_pc);
}
}
}
@@ -14,11 +14,11 @@ impl Compiler {
if stmt.alternate.is_some() {
ctx.projected_pc += 1; // JMP (skip else)
}
ctx.label_map.insert(else_label, ctx.projected_pc);
ctx.labels.label_map.insert(else_label, ctx.projected_pc);
if let Some(alt_stmt) = &stmt.alternate {
self.count_statement(alt_stmt, ctx);
ctx.projected_pc += 1; // LOAD_VAR result <- alternate
}
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
}
}
@@ -39,7 +39,7 @@ impl Compiler {
ctx.projected_pc += 1; // JMP
}
ctx.label_map.insert(catch_label, ctx.projected_pc);
ctx.labels.label_map.insert(catch_label, ctx.projected_pc);
if let Some(catch) = &stmt.handler {
ctx.push_scope();
if let Some(_param) = &catch.param {
@@ -55,7 +55,7 @@ impl Compiler {
if let Some(finally) = &stmt.finalizer {
let finally_label = Label::FinallyBody(id);
ctx.label_map.insert(finally_label, ctx.projected_pc);
ctx.labels.label_map.insert(finally_label, ctx.projected_pc);
for fs in &finally.body {
self.count_statement(fs, ctx);
}
@@ -63,6 +63,6 @@ impl Compiler {
ctx.projected_pc += 1; // TRY_FINALLY_END
}
ctx.label_map.insert(try_end_label, ctx.projected_pc);
ctx.labels.label_map.insert(try_end_label, ctx.projected_pc);
}
}
@@ -8,12 +8,12 @@ impl Compiler {
let start_label = Label::WhileStart(id);
let end_label = Label::WhileEnd(id);
ctx.label_map.insert(start_label, ctx.projected_pc);
ctx.labels.label_map.insert(start_label, ctx.projected_pc);
self.count_expression(&stmt.test, ctx);
ctx.projected_pc += 1; // JMP_IF_FALSE
self.count_statement(&stmt.body, ctx);
ctx.projected_pc += 1; // JMP (backward)
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
}
pub(in crate::counter) fn count_do_while_statement(
@@ -23,11 +23,11 @@ impl Compiler {
let start_label = Label::DoWhileStart(id);
let end_label = Label::DoWhileEnd(id);
ctx.label_map.insert(start_label, ctx.projected_pc);
ctx.labels.label_map.insert(start_label, ctx.projected_pc);
self.count_statement(&stmt.body, ctx);
self.count_expression(&stmt.test, ctx);
ctx.projected_pc += 1; // JMP_IF_TRUE (backward)
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
}
pub(in crate::counter) fn count_for_statement(&self, stmt: &oxide_parser::ForStatement<'_>, ctx: &mut CompileCtx) {
@@ -51,18 +51,18 @@ impl Compiler {
}
}
}
ctx.label_map.insert(start_label, ctx.projected_pc);
ctx.labels.label_map.insert(start_label, ctx.projected_pc);
if let Some(test) = &stmt.test {
self.count_expression(test, ctx);
ctx.projected_pc += 1; // JMP_IF_FALSE
}
self.count_statement(&stmt.body, ctx);
ctx.label_map.insert(update_label, ctx.projected_pc);
ctx.labels.label_map.insert(update_label, ctx.projected_pc);
if let Some(update) = &stmt.update {
self.count_expression(update, ctx);
}
ctx.projected_pc += 1; // JMP (backward)
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
}
pub(in crate::counter) fn count_for_in_statement(
@@ -75,7 +75,7 @@ impl Compiler {
self.count_expression(&stmt.right, ctx);
ctx.count_instr(); // FOR_IN_INIT
ctx.label_map.insert(start_label, ctx.projected_pc);
ctx.labels.label_map.insert(start_label, ctx.projected_pc);
ctx.count_instr(); // FOR_IN_DONE
ctx.count_jump(); // JMP_IF_FALSE
ctx.count_jump(); // JMP cleanup
@@ -98,7 +98,7 @@ impl Compiler {
self.count_statement(&stmt.body, ctx);
ctx.count_jump(); // JMP back to start
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
ctx.count_instr(); // FOR_IN_CLEANUP
}
@@ -111,7 +111,7 @@ impl Compiler {
self.count_expression(&stmt.right, ctx);
ctx.count_instr(); // FOR_OF_INIT
ctx.label_map.insert(start_label, ctx.projected_pc);
ctx.labels.label_map.insert(start_label, ctx.projected_pc);
ctx.alloc_reg(); // has_reg
ctx.count_instr(); // FOR_OF_DONE
ctx.count_jump(); // JMP_IF_FALSE
@@ -137,7 +137,7 @@ impl Compiler {
}
self.count_statement(&stmt.body, ctx);
ctx.count_jump(); // JMP back
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
ctx.count_instr(); // FOR_OF_CLOSE
}
}
@@ -29,13 +29,13 @@ impl Compiler {
for (case_idx, case) in cases.iter().enumerate() {
let case_label = Label::SwitchCase(id, case_idx as u32);
ctx.label_map.insert(case_label, ctx.projected_pc);
ctx.labels.label_map.insert(case_label, ctx.projected_pc);
for s in &case.consequent {
self.count_statement(s, ctx);
}
}
ctx.label_map.insert(end_label, ctx.projected_pc);
ctx.labels.label_map.insert(end_label, ctx.projected_pc);
ctx.pop_switch();
}
}
+38
View File
@@ -0,0 +1,38 @@
//! Grouped `CompileCtx` sub-contexts.
//!
//! Splits the compiler's central `CompileCtx` so syntax-domain workers borrow
//! only the slice they need: `LabelCtx` for jump-target resolution, `ScopeCtx`
//! for identifier binding. `PatternCtx` is reserved for destructuring work.
//! Execution-stream fields (bytecode, registers, pc, …) stay flat on
//! `CompileCtx`.
use std::collections::HashMap;
use crate::compiler::{Label, LabelScope};
use crate::symbol_table::SymbolTable;
/// Jump-target / labeled-statement resolution state.
pub(crate) struct LabelCtx {
pub(crate) label_map: HashMap<Label, usize>,
pub(crate) loop_stack: Vec<(Label, Label)>,
#[allow(dead_code)]
pub(crate) switch_stack: Vec<Label>,
/// Active labeled-statement scopes (resolves `break label` / `continue label`).
pub(crate) label_scopes: Vec<LabelScope>,
/// Label names awaiting binding to the next emitted loop's continue target.
pub(crate) pending_loop_labels: Vec<String>,
pub(crate) label_counter: u32,
}
/// Identifier-binding state: symbols, builtin registers, private names.
pub(crate) struct ScopeCtx {
pub(crate) symbols: SymbolTable,
pub(crate) builtin_reg_map: Vec<(String, u8)>,
pub(crate) private_name_map: Vec<(String, u32)>,
pub(crate) next_private_name_id: u32,
}
/// Reserved for destructuring-pattern state (Phase 15). Intentionally empty
/// today; named so future pattern work has a home without touching `ScopeCtx`.
#[allow(dead_code)]
pub(crate) struct PatternCtx;
@@ -1,6 +1,20 @@
use super::*;
impl Compiler {
/// Domain entry point: emit any literal expression. The central
/// `emit_expression` match delegates all literal variants here in one arm;
/// adding a new literal kind only touches this file plus that one arm.
pub(in crate::emitter) fn emit_literal(&self, expr: &Expression, ctx: &mut CompileCtx) -> Result<u8, String> {
match expr {
Expression::NumericLiteral(n) => self.emit_numeric_literal_expression(n, ctx),
Expression::StringLiteral(s) => self.emit_string_literal_expression(s, ctx),
Expression::BooleanLiteral(b) => self.emit_boolean_literal_expression(b, ctx),
Expression::NullLiteral(_) => self.emit_null_literal_expression(ctx),
Expression::RegExpLiteral(lit) => self.emit_reg_exp_literal_expression(lit, ctx),
_ => self.emit_unsupported_expression(expr, ctx),
}
}
pub(in crate::emitter) fn emit_numeric_literal_expression(
&self, n: &oxide_parser::NumericLiteral, ctx: &mut CompileCtx,
) -> Result<u8, String> {
+15 -14
View File
@@ -217,7 +217,8 @@ impl Compiler {
}
fn private_name_id(&self, name: &str, ctx: &CompileCtx) -> Result<u32, String> {
ctx.private_name_map
ctx.scopes
.private_name_map
.iter()
.find_map(|(n, id)| (n == name).then_some(*id))
.ok_or_else(|| format!("private name #{name} is not defined"))
@@ -640,8 +641,8 @@ impl Compiler {
if private_names.iter().any(|(existing, _)| existing == &name) {
return Err(format!("duplicate private name #{name}"));
}
let id = ctx.next_private_name_id;
ctx.next_private_name_id = ctx.next_private_name_id.saturating_add(1);
let id = ctx.scopes.next_private_name_id;
ctx.scopes.next_private_name_id = ctx.scopes.next_private_name_id.saturating_add(1);
private_names.push((name, id));
}
if method.kind == MethodDefinitionKind::Constructor {
@@ -658,8 +659,8 @@ impl Compiler {
if private_names.iter().any(|(existing, _)| existing == &name) {
return Err(format!("duplicate private name #{name}"));
}
let id = ctx.next_private_name_id;
ctx.next_private_name_id = ctx.next_private_name_id.saturating_add(1);
let id = ctx.scopes.next_private_name_id;
ctx.scopes.next_private_name_id = ctx.scopes.next_private_name_id.saturating_add(1);
private_names.push((name, id));
}
if !prop.r#static {
@@ -682,9 +683,9 @@ impl Compiler {
};
let saved_derived = ctx.in_derived_constructor;
let saved_private_names = ctx.private_name_map.clone();
let saved_private_names = ctx.scopes.private_name_map.clone();
ctx.in_derived_constructor = is_derived;
ctx.private_name_map = private_names.clone();
ctx.scopes.private_name_map = private_names.clone();
let mut ctor_module = if let Some(method) = constructor_method {
let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?;
@@ -784,7 +785,7 @@ impl Compiler {
module.bytecode.push(opcode::encode(OpCode::SUPER_CALL, 0, 0, 0));
module.bytecode.push(0);
let mut field_ctx = CompileCtx::new();
field_ctx.private_name_map = private_names.clone();
field_ctx.scopes.private_name_map = private_names.clone();
for field in &instance_fields {
if let PropertyKey::PrivateIdentifier(private) = &field.key {
self.emit_private_field_init(254, private.name.as_str(), field.value.as_ref(), &mut field_ctx)?;
@@ -912,7 +913,7 @@ impl Compiler {
}
}
ctx.private_name_map = saved_private_names;
ctx.scopes.private_name_map = saved_private_names;
Ok(ctor_reg)
}
@@ -978,10 +979,11 @@ impl Compiler {
}
pub(crate) fn emit_expression(&self, expr: &Expression, ctx: &mut CompileCtx) -> Result<u8, String> {
match expr {
Expression::NumericLiteral(n) => self.emit_numeric_literal_expression(n, ctx),
Expression::StringLiteral(s) => self.emit_string_literal_expression(s, ctx),
Expression::BooleanLiteral(b) => self.emit_boolean_literal_expression(b, ctx),
Expression::NullLiteral(_) => self.emit_null_literal_expression(ctx),
Expression::NumericLiteral(_)
| Expression::StringLiteral(_)
| Expression::BooleanLiteral(_)
| Expression::NullLiteral(_)
| Expression::RegExpLiteral(_) => self.emit_literal(expr, ctx),
Expression::PrivateInExpression(pin) => self.emit_private_in_expression(pin, ctx),
Expression::BinaryExpression(bin) => self.emit_binary_expression(bin, ctx),
Expression::UnaryExpression(un) => self.emit_unary_expression(un, ctx),
@@ -1005,7 +1007,6 @@ impl Compiler {
Expression::ParenthesizedExpression(p) => self.emit_parenthesized_expression(p, ctx),
Expression::CallExpression(call) => self.emit_call_expression(call, ctx),
Expression::ThisExpression(_) => self.emit_this_expression(ctx),
Expression::RegExpLiteral(lit) => self.emit_reg_exp_literal_expression(lit, ctx),
Expression::SequenceExpression(seq) => self.emit_sequence_expression(seq, ctx),
_ => self.emit_unsupported_expression(expr, ctx),
}
@@ -60,7 +60,7 @@ impl Compiler {
};
let catch_label_pc = ctx.bytecode.len();
ctx.label_map.insert(catch_label, catch_label_pc);
ctx.labels.label_map.insert(catch_label, catch_label_pc);
if let Some(try_begin_pc) = try_begin_pos {
let offset = catch_label_pc as isize - (try_begin_pc as isize);
@@ -90,7 +90,7 @@ impl Compiler {
if has_finally {
let finally_label = Label::FinallyBody(id);
let finally_label_pc = ctx.bytecode.len();
ctx.label_map.insert(finally_label, finally_label_pc);
ctx.labels.label_map.insert(finally_label, finally_label_pc);
if let Some(fb_pos) = try_finally_begin_pos {
let offset = finally_label_pc as isize - (fb_pos as isize);
let offset = ctx.checked_jump_offset(offset);
@@ -118,7 +118,7 @@ impl Compiler {
}
let try_end_pc = ctx.bytecode.len();
ctx.label_map.insert(try_end_label, try_end_pc);
ctx.labels.label_map.insert(try_end_label, try_end_pc);
Ok(Some(result_reg))
}
+1
View File
@@ -2,6 +2,7 @@
pub mod compiler;
pub mod counter;
pub mod emit_ctx;
pub mod emitter;
pub mod hash;
pub mod symbol_table;