bf74795e01
Introduces a new `RecordLayout` system for efficient and type-safe record handling. Key changes: - `RecordLayout` struct with `O(1)` field lookup using FMap optimization. - Field accessors (`.name`) are now first-class callable values. - Parser recognizes dot-prefixed identifiers as field accessors. - Binder and TypeChecker handle field accessors. - Optimizer transforms field accessor calls into specialized `GetField` nodes. - VM executes `GetField` efficiently by directly accessing record values. - Adds a new `records.myc` example showcasing record features. - Improves comparison logic for records to use pointer equality for layout.
177 lines
5.5 KiB
Rust
177 lines
5.5 KiB
Rust
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx};
|
|
use crate::ast::types::{Identity, Value};
|
|
use crate::ast::vm::Closure;
|
|
use std::collections::HashSet;
|
|
|
|
// --- PathTracker ---
|
|
#[derive(Default)]
|
|
pub struct PathTracker {
|
|
pub inlining_depth: usize,
|
|
pub inlining_stack: HashSet<GlobalIdx>,
|
|
pub identity_stack: HashSet<Identity>,
|
|
}
|
|
|
|
impl PathTracker {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn enter_lambda(&mut self, identity: &Identity) -> bool {
|
|
if self.identity_stack.contains(identity) {
|
|
return false;
|
|
}
|
|
self.identity_stack.insert(identity.clone());
|
|
true
|
|
}
|
|
|
|
pub fn exit_lambda(&mut self, identity: &Identity) {
|
|
self.identity_stack.remove(identity);
|
|
}
|
|
}
|
|
|
|
// --- UsageInfo ---
|
|
#[derive(Default)]
|
|
pub struct UsageInfo {
|
|
pub used: HashSet<Address>,
|
|
pub assigned: HashSet<Address>,
|
|
pub used_identities: HashSet<Identity>,
|
|
}
|
|
|
|
impl UsageInfo {
|
|
pub fn is_assigned(&self, addr: &Address) -> bool {
|
|
self.assigned.contains(addr)
|
|
}
|
|
|
|
pub fn is_used(&self, addr: &Address) -> bool {
|
|
self.used.contains(addr)
|
|
}
|
|
|
|
pub fn collect(&mut self, node: &AnalyzedNode) {
|
|
match &node.kind {
|
|
BoundKind::Destructure { pattern, value } => {
|
|
self.collect_pattern(pattern);
|
|
self.collect(value);
|
|
}
|
|
BoundKind::Constant(v) => {
|
|
if let Value::Object(obj) = v
|
|
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
|
{
|
|
self.used_identities
|
|
.insert(closure.function_node.identity.clone());
|
|
self.collect(&closure.function_node);
|
|
}
|
|
}
|
|
BoundKind::Get { addr, .. } => {
|
|
self.used.insert(*addr);
|
|
}
|
|
BoundKind::Set { addr, value } => {
|
|
self.assigned.insert(*addr);
|
|
self.collect(value);
|
|
}
|
|
BoundKind::GetField { rec, .. } => {
|
|
self.collect(rec);
|
|
}
|
|
BoundKind::Lambda {
|
|
params,
|
|
body,
|
|
upvalues,
|
|
..
|
|
} => {
|
|
self.used_identities.insert(node.identity.clone());
|
|
|
|
let mut inner_info = UsageInfo::default();
|
|
inner_info.collect(params);
|
|
inner_info.collect(body);
|
|
|
|
// Propagate globals and identities
|
|
for addr in &inner_info.used {
|
|
if let Address::Global(_) = addr {
|
|
self.used.insert(*addr);
|
|
}
|
|
}
|
|
for addr in &inner_info.assigned {
|
|
if let Address::Global(_) = addr {
|
|
self.assigned.insert(*addr);
|
|
}
|
|
}
|
|
self.used_identities.extend(inner_info.used_identities);
|
|
|
|
// 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.0 as usize)
|
|
{
|
|
self.used.insert(*parent_addr);
|
|
}
|
|
}
|
|
// 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.0 as usize)
|
|
{
|
|
self.assigned.insert(*parent_addr);
|
|
}
|
|
}
|
|
}
|
|
BoundKind::Block { exprs } => {
|
|
for e in exprs {
|
|
self.collect(e);
|
|
}
|
|
}
|
|
BoundKind::If {
|
|
cond,
|
|
then_br,
|
|
else_br,
|
|
} => {
|
|
self.collect(cond);
|
|
self.collect(then_br);
|
|
if let Some(e) = else_br {
|
|
self.collect(e);
|
|
}
|
|
}
|
|
BoundKind::Call { callee, args } => {
|
|
self.collect(callee);
|
|
self.collect(args);
|
|
}
|
|
BoundKind::Tuple { elements } => {
|
|
for e in elements {
|
|
self.collect(e);
|
|
}
|
|
}
|
|
BoundKind::Record { fields } => {
|
|
for (k, v) in fields {
|
|
self.collect(k);
|
|
self.collect(v);
|
|
}
|
|
}
|
|
BoundKind::Define { value, .. } => {
|
|
self.collect(value);
|
|
}
|
|
BoundKind::Expansion { bound_expanded, .. } => {
|
|
self.collect(bound_expanded);
|
|
}
|
|
BoundKind::Again { args } => {
|
|
self.collect(args);
|
|
}
|
|
BoundKind::Nop | BoundKind::FieldAccessor(_) | BoundKind::Extension(_) => {}
|
|
}
|
|
}
|
|
|
|
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
|
match &node.kind {
|
|
BoundKind::Define { addr, .. } => {
|
|
self.assigned.insert(*addr);
|
|
}
|
|
BoundKind::Set { addr, .. } => {
|
|
self.assigned.insert(*addr);
|
|
}
|
|
BoundKind::Tuple { elements } => {
|
|
for el in elements {
|
|
self.collect_pattern(el);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|