Refactor address types to use newtype wrappers
This commit introduces newtype wrappers for `LocalSlot`, `UpvalueIdx`, and `GlobalIdx` to improve type safety and clarity. These wrappers replace direct use of `u32` for indices, making the code more robust and easier to understand. The changes include: - Defining `LocalSlot`, `UpvalueIdx`, and `GlobalIdx` structs. - Implementing `Display` for these new types to provide user-friendly output. - Updating the `Address` enum to use these new types. - Modifying various compiler components (analyzer, binder, optimizer, type checker, environment, VM) to use the new types. - Adjusting tests to accommodate the changes.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
;; Benchmark: 129ns
|
||||
;; Benchmark-Repeat: 15510
|
||||
(do
|
||||
(macro wrap [f] `(fn [x] (~f x)))
|
||||
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, NodeMetrics, TypedNode};
|
||||
use crate::ast::compiler::bound_nodes::{
|
||||
Address, AnalyzedNode, BoundKind, GlobalIdx, NodeMetrics, TypedNode,
|
||||
};
|
||||
use crate::ast::types::Purity;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Analyzer<'a> {
|
||||
global_purity: &'a HashMap<u32, Purity>,
|
||||
global_purity: &'a HashMap<GlobalIdx, Purity>,
|
||||
/// Stack of currently visiting lambdas to detect direct recursion.
|
||||
lambda_stack: Vec<crate::ast::types::Identity>,
|
||||
/// Map of global index to its Lambda identity if known.
|
||||
globals_to_lambdas: HashMap<u32, crate::ast::types::Identity>,
|
||||
globals_to_lambdas: HashMap<GlobalIdx, crate::ast::types::Identity>,
|
||||
/// Set of identities that were found to be recursive.
|
||||
recursive_identities: HashSet<crate::ast::types::Identity>,
|
||||
}
|
||||
|
||||
impl<'a> Analyzer<'a> {
|
||||
pub fn analyze(node: &TypedNode, global_purity: &'a HashMap<u32, Purity>) -> AnalyzedNode {
|
||||
pub fn analyze(
|
||||
node: &TypedNode,
|
||||
global_purity: &'a HashMap<GlobalIdx, Purity>,
|
||||
) -> AnalyzedNode {
|
||||
let mut analyzer = Self {
|
||||
global_purity,
|
||||
lambda_stack: Vec::new(),
|
||||
|
||||
+19
-14
@@ -1,4 +1,6 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, DeclarationKind};
|
||||
use crate::ast::compiler::bound_nodes::{
|
||||
Address, BoundKind, BoundNode, DeclarationKind, GlobalIdx, LocalSlot, UpvalueIdx,
|
||||
};
|
||||
use crate::ast::nodes::{Node, Symbol, UntypedKind};
|
||||
use crate::ast::types::{Identity, StaticType};
|
||||
use std::cell::RefCell;
|
||||
@@ -7,7 +9,7 @@ use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct LocalInfo {
|
||||
slot: u32,
|
||||
slot: LocalSlot,
|
||||
identity: Identity,
|
||||
// Note: Binder doesn't strictly need the type anymore,
|
||||
// but it might be useful for built-ins during resolution.
|
||||
@@ -29,14 +31,14 @@ impl CompilerScope {
|
||||
}
|
||||
}
|
||||
|
||||
fn define(&mut self, sym: &Symbol, identity: Identity) -> Result<u32, String> {
|
||||
fn define(&mut self, sym: &Symbol, identity: Identity) -> Result<LocalSlot, String> {
|
||||
if self.locals.contains_key(sym) {
|
||||
return Err(format!(
|
||||
"Variable '{}' is already defined in this scope level.",
|
||||
sym.name
|
||||
));
|
||||
}
|
||||
let slot = self.slot_count;
|
||||
let slot = LocalSlot(self.slot_count);
|
||||
self.locals.insert(
|
||||
sym.clone(),
|
||||
LocalInfo {
|
||||
@@ -81,7 +83,7 @@ impl FunctionCompiler {
|
||||
&mut self,
|
||||
name: &Symbol,
|
||||
identity: Identity,
|
||||
globals: &Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
|
||||
globals: &Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
|
||||
) -> Result<Address, String> {
|
||||
match self.kind {
|
||||
ScopeKind::Root => {
|
||||
@@ -93,8 +95,8 @@ impl FunctionCompiler {
|
||||
));
|
||||
}
|
||||
let idx = globals_map.len() as u32;
|
||||
globals_map.insert(name.clone(), (idx, identity));
|
||||
Ok(Address::Global(idx))
|
||||
globals_map.insert(name.clone(), (GlobalIdx(idx), identity));
|
||||
Ok(Address::Global(GlobalIdx(idx)))
|
||||
}
|
||||
ScopeKind::Local => {
|
||||
let slot = self.scope.define(name, identity)?;
|
||||
@@ -103,11 +105,11 @@ impl FunctionCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_upvalue(&mut self, addr: Address) -> u32 {
|
||||
fn add_upvalue(&mut self, addr: Address) -> UpvalueIdx {
|
||||
if let Some(idx) = self.upvalues.iter().position(|&a| a == addr) {
|
||||
return idx as u32;
|
||||
return UpvalueIdx(idx as u32);
|
||||
}
|
||||
let idx = self.upvalues.len() as u32;
|
||||
let idx = UpvalueIdx(self.upvalues.len() as u32);
|
||||
self.upvalues.push(addr);
|
||||
idx
|
||||
}
|
||||
@@ -116,13 +118,13 @@ impl FunctionCompiler {
|
||||
pub struct Binder {
|
||||
functions: Vec<FunctionCompiler>,
|
||||
// Globals mapping: Symbol -> (Index, DefinitionIdentity)
|
||||
globals: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
|
||||
globals: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
|
||||
// Map of Declaration Identity -> List of Lambda Identities that capture it
|
||||
capture_map: HashMap<Identity, std::collections::HashSet<Identity>>,
|
||||
}
|
||||
|
||||
impl Binder {
|
||||
pub fn new(globals: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>) -> Self {
|
||||
pub fn new(globals: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>) -> Self {
|
||||
let mut binder = Self {
|
||||
functions: Vec::new(),
|
||||
globals,
|
||||
@@ -130,13 +132,16 @@ impl Binder {
|
||||
};
|
||||
binder.functions.push(FunctionCompiler::new(
|
||||
ScopeKind::Root,
|
||||
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation { line: 0, col: 0 }),
|
||||
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation {
|
||||
line: 0,
|
||||
col: 0,
|
||||
}),
|
||||
));
|
||||
binder
|
||||
}
|
||||
|
||||
pub fn bind_root(
|
||||
globals: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
|
||||
globals: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
|
||||
node: &Node<UntypedKind>,
|
||||
) -> Result<(BoundNode, HashMap<Identity, Vec<Identity>>), String> {
|
||||
let mut binder = Self::new(globals);
|
||||
|
||||
@@ -2,11 +2,38 @@ use crate::ast::nodes::{Node, Symbol};
|
||||
use crate::ast::types::{Identity, StaticType, Value};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct LocalSlot(pub u32);
|
||||
|
||||
impl std::fmt::Display for LocalSlot {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "L{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct UpvalueIdx(pub u32);
|
||||
|
||||
impl std::fmt::Display for UpvalueIdx {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "U{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct GlobalIdx(pub u32);
|
||||
|
||||
impl std::fmt::Display for GlobalIdx {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "G{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Address {
|
||||
Local(u32), // Stack-Slot index (relative to frame base)
|
||||
Upvalue(u32), // Index in the closure's upvalue array
|
||||
Global(u32), // Index in the global environment vector
|
||||
Local(LocalSlot), // Stack-Slot index (relative to frame base)
|
||||
Upvalue(UpvalueIdx), // Index in the closure's upvalue array
|
||||
Global(GlobalIdx), // Index in the global environment vector
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
||||
@@ -101,7 +101,9 @@ impl Dumper {
|
||||
if !captured_by.is_empty() {
|
||||
for capturer in captured_by {
|
||||
self.write_indent();
|
||||
let loc = capturer.location.unwrap_or(crate::ast::types::SourceLocation { line: 0, col: 0 });
|
||||
let loc = capturer
|
||||
.location
|
||||
.unwrap_or(crate::ast::types::SourceLocation { line: 0, col: 0 });
|
||||
self.output.push_str(&format!(
|
||||
"- Capturer: Lambda at line {}, col {}\n",
|
||||
loc.line, loc.col
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode};
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, GlobalIdx};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A pass that collects all global function definitions (lambdas) into a registry.
|
||||
/// This allows the Specializer to retrieve the original AST of a function for monomorphization.
|
||||
pub struct LambdaCollector<'a, T> {
|
||||
registry: &'a mut HashMap<u32, BoundNode<T>>,
|
||||
registry: &'a mut HashMap<GlobalIdx, BoundNode<T>>,
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> LambdaCollector<'a, T> {
|
||||
/// Performs a full traversal of the AST and populates the provided registry.
|
||||
pub fn collect(node: &BoundNode<T>, registry: &'a mut HashMap<u32, BoundNode<T>>) {
|
||||
pub fn collect(node: &BoundNode<T>, registry: &'a mut HashMap<GlobalIdx, BoundNode<T>>) {
|
||||
let mut collector = Self { registry };
|
||||
collector.visit(node);
|
||||
}
|
||||
|
||||
@@ -716,8 +716,11 @@ mod tests {
|
||||
global_names.insert(
|
||||
Symbol::from("*"),
|
||||
(
|
||||
0,
|
||||
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation { line: 0, col: 0 }),
|
||||
crate::ast::compiler::bound_nodes::GlobalIdx(0),
|
||||
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation {
|
||||
line: 0,
|
||||
col: 0,
|
||||
}),
|
||||
),
|
||||
);
|
||||
let globals = Rc::new(RefCell::new(global_names));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, NodeMetrics};
|
||||
use crate::ast::compiler::bound_nodes::{
|
||||
Address, AnalyzedNode, BoundKind, GlobalIdx, LocalSlot, NodeMetrics, UpvalueIdx,
|
||||
};
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::types::{Purity, StaticType, Value};
|
||||
use crate::ast::vm::Closure;
|
||||
@@ -10,13 +12,13 @@ pub struct Optimizer {
|
||||
pub enabled: bool,
|
||||
max_passes: usize,
|
||||
pub globals: Option<Rc<RefCell<Vec<Value>>>>,
|
||||
pub global_purity: Option<Rc<RefCell<HashMap<u32, Purity>>>>,
|
||||
pub lambda_registry: Option<Rc<RefCell<HashMap<u32, AnalyzedNode>>>>,
|
||||
pub global_purity: Option<Rc<RefCell<HashMap<GlobalIdx, Purity>>>>,
|
||||
pub lambda_registry: Option<Rc<RefCell<HashMap<GlobalIdx, AnalyzedNode>>>>,
|
||||
}
|
||||
|
||||
struct PathTracker {
|
||||
inlining_depth: usize,
|
||||
inlining_stack: HashSet<u32>,
|
||||
inlining_stack: HashSet<GlobalIdx>,
|
||||
identity_stack: HashSet<crate::ast::types::Identity>,
|
||||
}
|
||||
|
||||
@@ -75,12 +77,15 @@ impl Optimizer {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_purity(mut self, purity: Rc<RefCell<HashMap<u32, Purity>>>) -> Self {
|
||||
pub fn with_purity(mut self, purity: Rc<RefCell<HashMap<GlobalIdx, Purity>>>) -> Self {
|
||||
self.global_purity = Some(purity);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_registry(mut self, registry: Rc<RefCell<HashMap<u32, AnalyzedNode>>>) -> Self {
|
||||
pub fn with_registry(
|
||||
mut self,
|
||||
registry: Rc<RefCell<HashMap<GlobalIdx, AnalyzedNode>>>,
|
||||
) -> Self {
|
||||
self.lambda_registry = Some(registry);
|
||||
self
|
||||
}
|
||||
@@ -146,7 +151,7 @@ impl Optimizer {
|
||||
&& let Some(globals_rc) = &self.globals
|
||||
{
|
||||
let globals = globals_rc.borrow();
|
||||
if let Some(val) = globals.get(idx as usize)
|
||||
if let Some(val) = globals.get(idx.0 as usize)
|
||||
&& self.is_inlinable_value(val, addr)
|
||||
{
|
||||
return self.make_constant_node(val.clone(), &node);
|
||||
@@ -304,8 +309,10 @@ impl Optimizer {
|
||||
{
|
||||
let mut closure_sub = SubstitutionMap::new();
|
||||
for (i, cell) in closure.upvalues.iter().enumerate() {
|
||||
closure_sub
|
||||
.add_value(Address::Upvalue(i as u32), cell.borrow().clone());
|
||||
closure_sub.add_value(
|
||||
Address::Upvalue(UpvalueIdx(i as u32)),
|
||||
cell.borrow().clone(),
|
||||
);
|
||||
}
|
||||
|
||||
path.inlining_depth += 1;
|
||||
@@ -480,7 +487,8 @@ impl Optimizer {
|
||||
}
|
||||
|
||||
if let Some(val) = inlined_val {
|
||||
next_inner_subs.add_value(Address::Upvalue(old_idx as u32), val);
|
||||
next_inner_subs
|
||||
.add_value(Address::Upvalue(UpvalueIdx(old_idx as u32)), val);
|
||||
mapping.push(None);
|
||||
} else {
|
||||
mapping.push(Some(new_upvalues.len() as u32));
|
||||
@@ -579,7 +587,7 @@ impl Optimizer {
|
||||
..
|
||||
} => {
|
||||
sub.slot_mapping.insert(*slot, *slot);
|
||||
sub.next_slot = sub.next_slot.max(*slot + 1);
|
||||
sub.next_slot = sub.next_slot.max(slot.0 + 1);
|
||||
}
|
||||
BoundKind::Tuple { elements } => {
|
||||
for el in elements {
|
||||
@@ -684,7 +692,7 @@ impl Optimizer {
|
||||
BoundKind::Get {
|
||||
addr: Address::Global(idx),
|
||||
..
|
||||
} => self.globals.as_ref()?.borrow().get(*idx as usize)?.clone(),
|
||||
} => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(),
|
||||
BoundKind::Constant(val) => val.clone(),
|
||||
_ => return None,
|
||||
};
|
||||
@@ -737,7 +745,7 @@ impl Optimizer {
|
||||
Some(self.visit_node(body, sub, path))
|
||||
}
|
||||
|
||||
fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<u32>) {
|
||||
fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<LocalSlot>) {
|
||||
match &node.kind {
|
||||
BoundKind::Define {
|
||||
addr: Address::Local(slot),
|
||||
@@ -802,7 +810,7 @@ impl Optimizer {
|
||||
// Ensure local slots are mapped even if no constant/AST is substituted
|
||||
if let Address::Local(slot) = addr {
|
||||
sub.slot_mapping.insert(*slot, *slot);
|
||||
sub.next_slot = sub.next_slot.max(*slot + 1);
|
||||
sub.next_slot = sub.next_slot.max(slot.0 + 1);
|
||||
}
|
||||
*offset += 1;
|
||||
}
|
||||
@@ -895,7 +903,7 @@ impl Optimizer {
|
||||
// Map used upvalues to parent scope
|
||||
for addr in &inner_info.used {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = upvalues.get(*idx as usize)
|
||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||
{
|
||||
info.used.insert(*parent_addr);
|
||||
}
|
||||
@@ -903,7 +911,7 @@ impl Optimizer {
|
||||
// Map assigned upvalues to parent scope
|
||||
for addr in &inner_info.assigned {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = upvalues.get(*idx as usize)
|
||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||
{
|
||||
info.assigned.insert(*parent_addr);
|
||||
}
|
||||
@@ -954,11 +962,11 @@ impl Optimizer {
|
||||
struct SubstitutionMap {
|
||||
values: HashMap<Address, Value>,
|
||||
ast_substitutions: HashMap<Address, AnalyzedNode>,
|
||||
slot_mapping: HashMap<u32, u32>,
|
||||
slot_mapping: HashMap<LocalSlot, LocalSlot>,
|
||||
assigned: HashSet<Address>,
|
||||
next_slot: u32,
|
||||
used: HashSet<Address>,
|
||||
captured_slots: HashSet<u32>,
|
||||
captured_slots: HashSet<LocalSlot>,
|
||||
}
|
||||
|
||||
impl SubstitutionMap {
|
||||
@@ -978,11 +986,11 @@ impl SubstitutionMap {
|
||||
self.ast_substitutions.insert(addr, node);
|
||||
}
|
||||
|
||||
fn map_slot(&mut self, old_slot: u32) -> u32 {
|
||||
fn map_slot(&mut self, old_slot: LocalSlot) -> LocalSlot {
|
||||
if let Some(&new_slot) = self.slot_mapping.get(&old_slot) {
|
||||
return new_slot;
|
||||
}
|
||||
let new_slot = self.next_slot;
|
||||
let new_slot = LocalSlot(self.next_slot);
|
||||
self.slot_mapping.insert(old_slot, new_slot);
|
||||
self.next_slot += 1;
|
||||
new_slot
|
||||
@@ -1009,10 +1017,10 @@ impl SubstitutionMap {
|
||||
|
||||
fn reindex_addr(&self, addr: Address, mapping: &[Option<u32>]) -> Address {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(res) = mapping.get(idx as usize)
|
||||
&& let Some(res) = mapping.get(idx.0 as usize)
|
||||
&& let Some(new_idx) = res
|
||||
{
|
||||
Address::Upvalue(*new_idx)
|
||||
Address::Upvalue(UpvalueIdx(*new_idx))
|
||||
} else {
|
||||
addr
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, TypedNode};
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, GlobalIdx, TypedNode};
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::types::StaticType;
|
||||
use std::collections::HashMap;
|
||||
@@ -12,7 +12,7 @@ struct TypeContext<'a> {
|
||||
/// Types of captured variables (passed from outer scope)
|
||||
upvalue_types: Vec<StaticType>,
|
||||
/// Access to global types for unified resolution
|
||||
global_types: &'a std::cell::RefCell<HashMap<u32, StaticType>>,
|
||||
global_types: &'a std::cell::RefCell<HashMap<GlobalIdx, StaticType>>,
|
||||
/// The expected parameters of the current function (for 'again' validation)
|
||||
current_params_ty: Option<StaticType>,
|
||||
}
|
||||
@@ -21,7 +21,7 @@ impl<'a> TypeContext<'a> {
|
||||
fn new(
|
||||
slot_count: u32,
|
||||
upvalue_types: Vec<StaticType>,
|
||||
global_types: &'a std::cell::RefCell<HashMap<u32, StaticType>>,
|
||||
global_types: &'a std::cell::RefCell<HashMap<GlobalIdx, StaticType>>,
|
||||
parent: Option<&'a TypeContext<'a>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -35,9 +35,9 @@ impl<'a> TypeContext<'a> {
|
||||
|
||||
fn get_type(&self, addr: Address) -> StaticType {
|
||||
match addr {
|
||||
Address::Local(idx) => self
|
||||
Address::Local(slot) => self
|
||||
.slots
|
||||
.get(idx as usize)
|
||||
.get(slot.0 as usize)
|
||||
.cloned()
|
||||
.unwrap_or(StaticType::Any),
|
||||
Address::Global(idx) => self
|
||||
@@ -48,7 +48,7 @@ impl<'a> TypeContext<'a> {
|
||||
.unwrap_or(StaticType::Any),
|
||||
Address::Upvalue(idx) => self
|
||||
.upvalue_types
|
||||
.get(idx as usize)
|
||||
.get(idx.0 as usize)
|
||||
.cloned()
|
||||
.unwrap_or(StaticType::Any),
|
||||
}
|
||||
@@ -56,9 +56,9 @@ impl<'a> TypeContext<'a> {
|
||||
|
||||
fn set_type(&mut self, addr: Address, ty: StaticType) {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
if let Some(slot) = self.slots.get_mut(idx as usize) {
|
||||
*slot = ty;
|
||||
Address::Local(slot) => {
|
||||
if let Some(entry) = self.slots.get_mut(slot.0 as usize) {
|
||||
*entry = ty;
|
||||
}
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
@@ -70,11 +70,11 @@ impl<'a> TypeContext<'a> {
|
||||
}
|
||||
|
||||
pub struct TypeChecker {
|
||||
global_types: Rc<std::cell::RefCell<HashMap<u32, StaticType>>>,
|
||||
global_types: Rc<std::cell::RefCell<HashMap<GlobalIdx, StaticType>>>,
|
||||
}
|
||||
|
||||
impl TypeChecker {
|
||||
pub fn new(global_types: Rc<std::cell::RefCell<HashMap<u32, StaticType>>>) -> Self {
|
||||
pub fn new(global_types: Rc<std::cell::RefCell<HashMap<GlobalIdx, StaticType>>>) -> Self {
|
||||
Self { global_types }
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -8,7 +8,7 @@ use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, BoundNode};
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, BoundNode, GlobalIdx};
|
||||
use crate::ast::compiler::dumper::Dumper;
|
||||
use crate::ast::compiler::lambda_collector::LambdaCollector;
|
||||
use crate::ast::compiler::macros::{MacroEvaluator, MacroExpander, MacroRegistry};
|
||||
@@ -22,21 +22,21 @@ use crate::ast::types::{
|
||||
};
|
||||
|
||||
pub struct Environment {
|
||||
pub global_names: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
|
||||
pub global_types: Rc<RefCell<HashMap<u32, StaticType>>>,
|
||||
pub global_purity: Rc<RefCell<HashMap<u32, Purity>>>,
|
||||
pub global_names: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
|
||||
pub global_types: Rc<RefCell<HashMap<GlobalIdx, StaticType>>>,
|
||||
pub global_purity: Rc<RefCell<HashMap<GlobalIdx, Purity>>>,
|
||||
pub global_values: Rc<RefCell<Vec<Value>>>,
|
||||
pub prng: Rc<RefCell<fastrand::Rng>>,
|
||||
pub function_registry: Rc<RefCell<HashMap<u32, BoundNode>>>,
|
||||
pub typed_function_registry: Rc<RefCell<HashMap<u32, AnalyzedNode>>>,
|
||||
pub function_registry: Rc<RefCell<HashMap<GlobalIdx, BoundNode>>>,
|
||||
pub typed_function_registry: Rc<RefCell<HashMap<GlobalIdx, AnalyzedNode>>>,
|
||||
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
||||
pub debug_mode: bool,
|
||||
pub optimization: bool,
|
||||
}
|
||||
|
||||
struct EnvFunctionRegistry {
|
||||
registry: Rc<RefCell<HashMap<u32, BoundNode>>>,
|
||||
analyzed_registry: Rc<RefCell<HashMap<u32, AnalyzedNode>>>,
|
||||
registry: Rc<RefCell<HashMap<GlobalIdx, BoundNode>>>,
|
||||
analyzed_registry: Rc<RefCell<HashMap<GlobalIdx, AnalyzedNode>>>,
|
||||
}
|
||||
|
||||
impl FunctionRegistry for EnvFunctionRegistry {
|
||||
@@ -57,8 +57,8 @@ impl FunctionRegistry for EnvFunctionRegistry {
|
||||
}
|
||||
|
||||
struct RuntimeMacroEvaluator {
|
||||
global_names: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
|
||||
global_types: Rc<RefCell<HashMap<u32, StaticType>>>,
|
||||
global_names: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
|
||||
global_types: Rc<RefCell<HashMap<GlobalIdx, StaticType>>>,
|
||||
global_values: Rc<RefCell<Vec<Value>>>,
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ impl Environment {
|
||||
let mut values = self.global_values.borrow_mut();
|
||||
let mut purity = self.global_purity.borrow_mut();
|
||||
|
||||
let idx = values.len() as u32;
|
||||
let idx = GlobalIdx(values.len() as u32);
|
||||
let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 });
|
||||
names.insert(Symbol::from(name), (idx, identity));
|
||||
types.insert(idx, ty);
|
||||
@@ -164,7 +164,7 @@ impl Environment {
|
||||
let mut values = self.global_values.borrow_mut();
|
||||
let mut purity = self.global_purity.borrow_mut();
|
||||
|
||||
let idx = values.len() as u32;
|
||||
let idx = GlobalIdx(values.len() as u32);
|
||||
let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 });
|
||||
names.insert(Symbol::from(name), (idx, identity));
|
||||
types.insert(idx, ty);
|
||||
|
||||
+25
-25
@@ -506,9 +506,9 @@ impl VM {
|
||||
|
||||
fn capture_upvalue(&mut self, addr: Address) -> Result<Rc<RefCell<Value>>, String> {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
Address::Local(slot) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
let abs_index = frame.stack_base + (idx as usize);
|
||||
let abs_index = frame.stack_base + (slot.0 as usize);
|
||||
if abs_index < self.stack.len() {
|
||||
if let Value::Cell(cell) = &self.stack[abs_index] {
|
||||
Ok(cell.clone())
|
||||
@@ -519,15 +519,15 @@ impl VM {
|
||||
Ok(cell)
|
||||
}
|
||||
} else {
|
||||
Err(format!("Stack underflow capture local {}", idx))
|
||||
Err(format!("Stack underflow capture local {}", slot))
|
||||
}
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure) = &frame.closure {
|
||||
let idx = idx as usize;
|
||||
if idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[idx].clone())
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[u_idx].clone())
|
||||
} else {
|
||||
Err(format!("Upvalue access out of bounds capture {}", idx))
|
||||
}
|
||||
@@ -541,23 +541,23 @@ impl VM {
|
||||
|
||||
fn get_value(&self, addr: Address) -> Result<Value, String> {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
Address::Local(slot) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
let abs_index = frame.stack_base + (idx as usize);
|
||||
let abs_index = frame.stack_base + (slot.0 as usize);
|
||||
if abs_index < self.stack.len() {
|
||||
match &self.stack[abs_index] {
|
||||
Value::Cell(cell) => Ok(cell.borrow().clone()),
|
||||
val => Ok(val.clone()),
|
||||
}
|
||||
} else {
|
||||
Err(format!("Stack underflow access local {}", idx))
|
||||
Err(format!("Stack underflow access local {}", slot))
|
||||
}
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
let idx = idx as usize;
|
||||
let g_idx = idx.0 as usize;
|
||||
let globals = self.globals.borrow();
|
||||
if idx < globals.len() {
|
||||
Ok(globals[idx].clone())
|
||||
if g_idx < globals.len() {
|
||||
Ok(globals[g_idx].clone())
|
||||
} else {
|
||||
Err(format!("Global access out of bounds {}", idx))
|
||||
}
|
||||
@@ -565,9 +565,9 @@ impl VM {
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure) = &frame.closure {
|
||||
let idx = idx as usize;
|
||||
if idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[idx].borrow().clone())
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[u_idx].borrow().clone())
|
||||
} else {
|
||||
Err(format!("Upvalue access out of bounds {}", idx))
|
||||
}
|
||||
@@ -580,9 +580,9 @@ impl VM {
|
||||
|
||||
fn set_value(&mut self, addr: Address, value: Value) -> Result<(), String> {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
Address::Local(slot) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
let abs_index = frame.stack_base + (idx as usize);
|
||||
let abs_index = frame.stack_base + (slot.0 as usize);
|
||||
if abs_index < self.stack.len() {
|
||||
if let Value::Cell(cell) = &self.stack[abs_index] {
|
||||
*cell.borrow_mut() = value;
|
||||
@@ -592,25 +592,25 @@ impl VM {
|
||||
} else if abs_index == self.stack.len() {
|
||||
self.stack.push(value);
|
||||
} else {
|
||||
return Err(format!("Stack gap write local {}", idx));
|
||||
return Err(format!("Stack gap write local {}", slot));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
let idx = idx as usize;
|
||||
let g_idx = idx.0 as usize;
|
||||
let mut globals = self.globals.borrow_mut();
|
||||
if idx >= globals.len() {
|
||||
globals.resize(idx + 1, Value::Void);
|
||||
if g_idx >= globals.len() {
|
||||
globals.resize(g_idx + 1, Value::Void);
|
||||
}
|
||||
globals[idx] = value;
|
||||
globals[g_idx] = value;
|
||||
Ok(())
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure) = &frame.closure {
|
||||
let idx = idx as usize;
|
||||
if idx < closure.upvalues.len() {
|
||||
*closure.upvalues[idx].borrow_mut() = value;
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
*closure.upvalues[u_idx].borrow_mut() = value;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Upvalue assignment out of bounds {}", idx))
|
||||
|
||||
@@ -431,6 +431,9 @@ mod tests {
|
||||
dump
|
||||
);
|
||||
// The definitions add1, add2, w1, w2 should be gone after dead code elimination
|
||||
assert!(!dump.contains("Define Variable"), "Definitions should be removed by DCE");
|
||||
assert!(
|
||||
!dump.contains("Define Variable"),
|
||||
"Definitions should be removed by DCE"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user