Refactor: Use new NodeKind and clean up Binder definitions
The Binder and related types have been refactored to use the new `NodeKind` enum instead of the previous `BoundKind`. This commit updates all references to use the new structure, ensuring consistency across the compiler's AST representation. Key changes include: - Replacing `BoundKind` with `NodeKind` in the Binder's `bind` and `visit` methods. - Updating pattern matching and field access to reflect the new enum variants (e.g., `NodeKind::Def` instead of `BoundKind::Define`). - Adjusting identifier bindings to use the new `IdentifierBinding` enum. - Reflecting changes in `DefBinding`, `AssignBinding`, and `LambdaBinding` structures. - Ensuring all newly created nodes use `NodeKind` and the appropriate metadata.
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
;; Benchmark: 19.9us
|
|
||||||
;; Benchmark-Repeat: 110
|
|
||||||
(do
|
(do
|
||||||
(repeat n 10 (print n)
|
(repeat n 10 (print n)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{
|
use crate::ast::compiler::bound_nodes::{
|
||||||
Address, AnalyzedNode, BoundKind, GlobalIdx, Node, NodeMetrics, TypedNode, TypedPhase,
|
Address, AnalyzedNode, GlobalIdx, IdentifierBinding, Node,
|
||||||
|
NodeKind, NodeMetrics, TypedNode, TypedPhase,
|
||||||
};
|
};
|
||||||
use crate::ast::types::Purity;
|
use crate::ast::types::Purity;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@@ -36,18 +37,23 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
fn collect_globals(&mut self, node: &TypedNode) {
|
fn collect_globals(&mut self, node: &TypedNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
addr: Address::Global(global_index),
|
pattern,
|
||||||
value,
|
value,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if let BoundKind::Lambda { .. } = &value.kind {
|
if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr: Address::Global(global_index), .. },
|
||||||
|
..
|
||||||
|
} = &pattern.kind
|
||||||
|
&& let NodeKind::Lambda { .. } = &value.kind
|
||||||
|
{
|
||||||
self.globals_to_lambdas
|
self.globals_to_lambdas
|
||||||
.insert(*global_index, value.identity.clone());
|
.insert(*global_index, value.identity.clone());
|
||||||
}
|
}
|
||||||
self.collect_globals(value);
|
self.collect_globals(value);
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
self.collect_globals(e);
|
self.collect_globals(e);
|
||||||
}
|
}
|
||||||
@@ -64,32 +70,31 @@ impl<'a> Analyzer<'a> {
|
|||||||
let mut is_recursive = false;
|
let mut is_recursive = false;
|
||||||
|
|
||||||
let (new_kind, purity) = match &node.kind {
|
let (new_kind, purity) = match &node.kind {
|
||||||
BoundKind::Constant(v) => (BoundKind::Constant(v.clone()), Purity::Pure),
|
NodeKind::Constant(v) => (NodeKind::Constant(v.clone()), Purity::Pure),
|
||||||
BoundKind::Nop => (BoundKind::Nop, Purity::Pure),
|
NodeKind::Nop => (NodeKind::Nop, Purity::Pure),
|
||||||
|
|
||||||
BoundKind::Get { addr, name } => {
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
let p = match addr {
|
let p = if let IdentifierBinding::Reference(Address::Global(idx)) = binding {
|
||||||
Address::Global(idx) => {
|
self.root_purity.get(idx.0 as usize).cloned().unwrap_or(Purity::Pure)
|
||||||
self.root_purity.get(idx.0 as usize).cloned().unwrap_or(Purity::Pure)
|
} else {
|
||||||
}
|
Purity::Pure
|
||||||
_ => Purity::Pure,
|
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
BoundKind::Get {
|
NodeKind::Identifier {
|
||||||
addr: *addr,
|
symbol: symbol.clone(),
|
||||||
name: name.clone(),
|
binding: binding.clone(),
|
||||||
},
|
},
|
||||||
p,
|
p,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(*k), Purity::Pure),
|
NodeKind::FieldAccessor(k) => (NodeKind::FieldAccessor(*k), Purity::Pure),
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => {
|
NodeKind::GetField { rec, field } => {
|
||||||
let rec_m = self.visit(rec.clone());
|
let rec_m = self.visit(rec.clone());
|
||||||
let p = rec_m.ty.purity;
|
let p = rec_m.ty.purity;
|
||||||
(
|
(
|
||||||
BoundKind::GetField {
|
NodeKind::GetField {
|
||||||
rec: Rc::new(rec_m),
|
rec: Rc::new(rec_m),
|
||||||
field: *field,
|
field: *field,
|
||||||
},
|
},
|
||||||
@@ -97,38 +102,37 @@ impl<'a> Analyzer<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
|
let target_m = self.visit(target.clone());
|
||||||
let val_m = self.visit(value.clone());
|
let val_m = self.visit(value.clone());
|
||||||
(
|
(
|
||||||
BoundKind::Set {
|
NodeKind::Assign {
|
||||||
addr: *addr,
|
target: Rc::new(target_m),
|
||||||
value: Rc::new(val_m),
|
value: Rc::new(val_m),
|
||||||
|
info: info.clone(),
|
||||||
},
|
},
|
||||||
Purity::Impure,
|
Purity::Impure,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by,
|
info,
|
||||||
} => {
|
} => {
|
||||||
|
let pat_m = self.visit(pattern.clone());
|
||||||
let val_m = self.visit(value.clone());
|
let val_m = self.visit(value.clone());
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name: name.clone(),
|
pattern: Rc::new(pat_m),
|
||||||
addr: *addr,
|
|
||||||
kind: *kind,
|
|
||||||
value: Rc::new(val_m),
|
value: Rc::new(val_m),
|
||||||
captured_by: captured_by.clone(),
|
info: info.clone(),
|
||||||
},
|
},
|
||||||
Purity::Impure,
|
Purity::Impure,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -142,7 +146,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
p = p.min(em.ty.purity);
|
p = p.min(em.ty.purity);
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond: Rc::new(cond_m),
|
cond: Rc::new(cond_m),
|
||||||
then_br: Rc::new(then_m),
|
then_br: Rc::new(then_m),
|
||||||
else_br: else_m.map(Rc::new),
|
else_br: else_m.map(Rc::new),
|
||||||
@@ -151,11 +155,10 @@ impl<'a> Analyzer<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => {
|
} => {
|
||||||
self.lambda_stack.push(node.identity.clone());
|
self.lambda_stack.push(node.identity.clone());
|
||||||
let params_m = self.visit(params.clone());
|
let params_m = self.visit(params.clone());
|
||||||
@@ -164,34 +167,21 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
is_recursive = self.recursive_identities.contains(&node.identity);
|
is_recursive = self.recursive_identities.contains(&node.identity);
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params: Rc::new(params_m),
|
params: Rc::new(params_m),
|
||||||
upvalues: upvalues.clone(),
|
|
||||||
body: Rc::new(body_m),
|
body: Rc::new(body_m),
|
||||||
positional_count: *positional_count,
|
info: info.clone(),
|
||||||
},
|
},
|
||||||
Purity::Pure,
|
Purity::Pure,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Destructure { pattern, value } => {
|
NodeKind::Call { callee, args } => {
|
||||||
let pat_m = self.visit(pattern.clone());
|
|
||||||
let val_m = self.visit(value.clone());
|
|
||||||
(
|
|
||||||
BoundKind::Destructure {
|
|
||||||
pattern: Rc::new(pat_m),
|
|
||||||
value: Rc::new(val_m),
|
|
||||||
},
|
|
||||||
Purity::Impure,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => {
|
|
||||||
let callee_m = self.visit(callee.clone());
|
let callee_m = self.visit(callee.clone());
|
||||||
let args_m = self.visit(args.clone());
|
let args_m = self.visit(args.clone());
|
||||||
|
|
||||||
if let BoundKind::Get {
|
if let NodeKind::Identifier {
|
||||||
addr: Address::Global(idx),
|
binding: IdentifierBinding::Reference(Address::Global(idx)),
|
||||||
..
|
..
|
||||||
} = &callee.kind
|
} = &callee.kind
|
||||||
&& let Some(lambda_id) = self.globals_to_lambdas.get(idx)
|
&& let Some(lambda_id) = self.globals_to_lambdas.get(idx)
|
||||||
@@ -201,8 +191,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
is_recursive = true;
|
is_recursive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let p_func = if let BoundKind::Get {
|
let p_func = if let NodeKind::Identifier {
|
||||||
addr: Address::Global(idx),
|
binding: IdentifierBinding::Reference(Address::Global(idx)),
|
||||||
..
|
..
|
||||||
} = &callee.kind
|
} = &callee.kind
|
||||||
{
|
{
|
||||||
@@ -215,7 +205,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
};
|
};
|
||||||
let p = callee_m.ty.purity.min(args_m.ty.purity).min(p_func);
|
let p = callee_m.ty.purity.min(args_m.ty.purity).min(p_func);
|
||||||
(
|
(
|
||||||
BoundKind::Call {
|
NodeKind::Call {
|
||||||
callee: Rc::new(callee_m),
|
callee: Rc::new(callee_m),
|
||||||
args: Rc::new(args_m),
|
args: Rc::new(args_m),
|
||||||
},
|
},
|
||||||
@@ -223,23 +213,22 @@ impl<'a> Analyzer<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Again { args } => {
|
NodeKind::Again { args } => {
|
||||||
let args_m = self.visit(args.clone());
|
let args_m = self.visit(args.clone());
|
||||||
if let Some(lambda_id) = self.lambda_stack.last() {
|
if let Some(lambda_id) = self.lambda_stack.last() {
|
||||||
self.recursive_identities.insert(lambda_id.clone());
|
self.recursive_identities.insert(lambda_id.clone());
|
||||||
is_recursive = true;
|
is_recursive = true;
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::Again {
|
NodeKind::Again {
|
||||||
args: Rc::new(args_m),
|
args: Rc::new(args_m),
|
||||||
},
|
},
|
||||||
Purity::Impure,
|
Purity::Impure,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs,
|
inputs,
|
||||||
lambda,
|
lambda,
|
||||||
out_type,
|
|
||||||
} => {
|
} => {
|
||||||
let mut analyzed_inputs = Vec::with_capacity(inputs.len());
|
let mut analyzed_inputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
@@ -247,16 +236,15 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
let a_lambda = Rc::new(self.visit(lambda.clone()));
|
let a_lambda = Rc::new(self.visit(lambda.clone()));
|
||||||
(
|
(
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: analyzed_inputs,
|
inputs: analyzed_inputs,
|
||||||
lambda: a_lambda,
|
lambda: a_lambda,
|
||||||
out_type: out_type.clone(),
|
|
||||||
},
|
},
|
||||||
Purity::Impure,
|
Purity::Impure,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let mut new_exprs = Vec::with_capacity(exprs.len());
|
let mut new_exprs = Vec::with_capacity(exprs.len());
|
||||||
let mut p = Purity::Pure;
|
let mut p = Purity::Pure;
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
@@ -264,10 +252,10 @@ impl<'a> Analyzer<'a> {
|
|||||||
p = p.min(em.ty.purity);
|
p = p.min(em.ty.purity);
|
||||||
new_exprs.push(Rc::new(em));
|
new_exprs.push(Rc::new(em));
|
||||||
}
|
}
|
||||||
(BoundKind::Block { exprs: new_exprs }, p)
|
(NodeKind::Block { exprs: new_exprs }, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let mut new_elements = Vec::with_capacity(elements.len());
|
let mut new_elements = Vec::with_capacity(elements.len());
|
||||||
let mut p = Purity::Pure;
|
let mut p = Purity::Pure;
|
||||||
for e in elements {
|
for e in elements {
|
||||||
@@ -276,46 +264,53 @@ impl<'a> Analyzer<'a> {
|
|||||||
new_elements.push(Rc::new(em));
|
new_elements.push(Rc::new(em));
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: new_elements,
|
elements: new_elements,
|
||||||
},
|
},
|
||||||
p,
|
p,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let mut new_values = Vec::with_capacity(values.len());
|
let mut new_fields = Vec::with_capacity(fields.len());
|
||||||
let mut p = Purity::Pure;
|
let mut p = Purity::Pure;
|
||||||
for v in values {
|
for (key_node, val_node) in fields {
|
||||||
let vm = self.visit(v.clone());
|
let km = self.visit(key_node.clone());
|
||||||
|
let vm = self.visit(val_node.clone());
|
||||||
p = p.min(vm.ty.purity);
|
p = p.min(vm.ty.purity);
|
||||||
new_values.push(Rc::new(vm));
|
new_fields.push((Rc::new(km), Rc::new(vm)));
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::Record {
|
NodeKind::Record {
|
||||||
|
fields: new_fields,
|
||||||
layout: layout.clone(),
|
layout: layout.clone(),
|
||||||
values: new_values,
|
|
||||||
},
|
},
|
||||||
p,
|
p,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => {
|
} => {
|
||||||
let expanded_m = self.visit(bound_expanded.clone());
|
let expanded_m = self.visit(expanded.clone());
|
||||||
(
|
(
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call: original_call.clone(),
|
original_call: original_call.clone(),
|
||||||
bound_expanded: Rc::new(expanded_m.clone()),
|
expanded: Rc::new(expanded_m.clone()),
|
||||||
},
|
},
|
||||||
expanded_m.ty.purity,
|
expanded_m.ty.purity,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Extension(_) => (BoundKind::Nop, Purity::Impure),
|
NodeKind::Extension(_) => (NodeKind::Nop, Purity::Impure),
|
||||||
BoundKind::Error => (BoundKind::Error, Purity::Impure),
|
NodeKind::Error => (NodeKind::Error, Purity::Impure),
|
||||||
|
|
||||||
|
// Syntax-only variants should not appear in typed phases
|
||||||
|
NodeKind::MacroDecl { .. }
|
||||||
|
| NodeKind::Template(_)
|
||||||
|
| NodeKind::Placeholder(_)
|
||||||
|
| NodeKind::Splice(_) => (NodeKind::Error, Purity::Impure),
|
||||||
};
|
};
|
||||||
|
|
||||||
Node {
|
Node {
|
||||||
@@ -334,10 +329,10 @@ trait NodeExt {
|
|||||||
fn for_each_child<F: FnMut(&TypedNode)>(&self, f: F);
|
fn for_each_child<F: FnMut(&TypedNode)>(&self, f: F);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeExt for BoundKind<TypedPhase> {
|
impl NodeExt for NodeKind<TypedPhase> {
|
||||||
fn for_each_child<F: FnMut(&TypedNode)>(&self, mut f: F) {
|
fn for_each_child<F: FnMut(&TypedNode)>(&self, mut f: F) {
|
||||||
match self {
|
match self {
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -348,37 +343,43 @@ impl NodeExt for BoundKind<TypedPhase> {
|
|||||||
f(e);
|
f(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Define { value, .. } | BoundKind::Set { value, .. } => {
|
NodeKind::Def { pattern, value, .. } => {
|
||||||
|
f(pattern);
|
||||||
f(value);
|
f(value);
|
||||||
}
|
}
|
||||||
BoundKind::GetField { rec, .. } => {
|
NodeKind::Assign { target, value, .. } => {
|
||||||
|
f(target);
|
||||||
|
f(value);
|
||||||
|
}
|
||||||
|
NodeKind::GetField { rec, .. } => {
|
||||||
f(rec);
|
f(rec);
|
||||||
}
|
}
|
||||||
BoundKind::Lambda { params, body, .. } => {
|
NodeKind::Lambda { params, body, .. } => {
|
||||||
f(params);
|
f(params);
|
||||||
f(body);
|
f(body);
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
f(callee);
|
f(callee);
|
||||||
f(args);
|
f(args);
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
f(e);
|
f(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for e in elements {
|
for e in elements {
|
||||||
f(e);
|
f(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Record { values, .. } => {
|
NodeKind::Record { fields, .. } => {
|
||||||
for v in values {
|
for (key, val) in fields {
|
||||||
f(v);
|
f(key);
|
||||||
|
f(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
NodeKind::Expansion { expanded, .. } => {
|
||||||
f(bound_expanded);
|
f(expanded);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
+135
-96
@@ -1,9 +1,10 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{
|
use crate::ast::compiler::bound_nodes::{
|
||||||
Address, BoundKind, BoundPhase, DeclarationKind, GlobalIdx, Node, UpvalueIdx, VirtualId,
|
Address, AssignBinding, BoundPhase, DeclarationKind, DefBinding, GlobalIdx,
|
||||||
|
IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx, VirtualId,
|
||||||
};
|
};
|
||||||
use crate::ast::diagnostics::Diagnostics;
|
use crate::ast::diagnostics::Diagnostics;
|
||||||
use crate::ast::nodes::{Symbol, SyntaxKind, SyntaxNode};
|
use crate::ast::nodes::{SyntaxKind, SyntaxNode, Symbol};
|
||||||
use crate::ast::types::{Identity, StaticType, Purity};
|
use crate::ast::types::{Identity, Purity, StaticType};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -177,7 +178,7 @@ impl Binder {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: &Symbol,
|
name: &Symbol,
|
||||||
identity: Identity,
|
identity: Identity,
|
||||||
_kind: crate::ast::compiler::bound_nodes::DeclarationKind,
|
_kind: DeclarationKind,
|
||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> Option<Address<VirtualId>> {
|
) -> Option<Address<VirtualId>> {
|
||||||
let current_fn_idx = self.functions.len() - 1;
|
let current_fn_idx = self.functions.len() - 1;
|
||||||
@@ -213,27 +214,27 @@ impl Binder {
|
|||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> Node<BoundPhase> {
|
) -> Node<BoundPhase> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Nop => self.make_node(node.identity.clone(), BoundKind::Nop),
|
SyntaxKind::Nop => self.make_node(node.identity.clone(), NodeKind::Nop),
|
||||||
SyntaxKind::Constant(v) => {
|
SyntaxKind::Constant(v) => {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Constant(v.clone()))
|
self.make_node(node.identity.clone(), NodeKind::Constant(v.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Identifier(sym) => {
|
SyntaxKind::Identifier { symbol: sym, .. } => {
|
||||||
if let Some(addr) = self.resolve_variable(sym, diag, &node.identity) {
|
if let Some(addr) = self.resolve_variable(sym, diag, &node.identity) {
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Get {
|
NodeKind::Identifier {
|
||||||
addr,
|
symbol: sym.clone(),
|
||||||
name: sym.clone(),
|
binding: IdentifierBinding::Reference(addr),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::FieldAccessor(k) => {
|
SyntaxKind::FieldAccessor(k) => {
|
||||||
self.make_node(node.identity.clone(), BoundKind::FieldAccessor(*k))
|
self.make_node(node.identity.clone(), NodeKind::FieldAccessor(*k))
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::If {
|
SyntaxKind::If {
|
||||||
@@ -256,7 +257,7 @@ impl Binder {
|
|||||||
|
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond: Rc::new(cond),
|
cond: Rc::new(cond),
|
||||||
then_br: Rc::new(then_br),
|
then_br: Rc::new(then_br),
|
||||||
else_br: else_br_bound,
|
else_br: else_br_bound,
|
||||||
@@ -264,35 +265,45 @@ impl Binder {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Def { target, value } => {
|
SyntaxKind::Def { pattern: target, value, .. } => {
|
||||||
if ctx == ExprContext::Expression {
|
if ctx == ExprContext::Expression {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
"Statement 'def' cannot be used as an expression.",
|
"Statement 'def' cannot be used as an expression.",
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let SyntaxKind::Identifier(ref name) = target.kind {
|
if let SyntaxKind::Identifier { symbol: ref name, .. } = target.kind {
|
||||||
let addr_opt = self.declare_variable(
|
let addr_opt = self.declare_variable(
|
||||||
name,
|
name,
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
crate::ast::compiler::bound_nodes::DeclarationKind::Variable,
|
DeclarationKind::Variable,
|
||||||
diag,
|
diag,
|
||||||
);
|
);
|
||||||
let val_node = self.bind(value, ExprContext::Expression, diag);
|
let val_node = self.bind(value, ExprContext::Expression, diag);
|
||||||
|
|
||||||
if let Some(addr) = addr_opt {
|
if let Some(addr) = addr_opt {
|
||||||
|
let pattern_node = self.make_node(
|
||||||
|
target.identity.clone(),
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol: name.clone(),
|
||||||
|
binding: IdentifierBinding::Declaration {
|
||||||
|
addr,
|
||||||
|
kind: DeclarationKind::Variable,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name: name.clone(),
|
pattern: Rc::new(pattern_node),
|
||||||
addr,
|
|
||||||
kind: crate::ast::compiler::bound_nodes::DeclarationKind::Variable,
|
|
||||||
value: Rc::new(val_node),
|
value: Rc::new(val_node),
|
||||||
captured_by: Vec::new(),
|
info: DefBinding {
|
||||||
|
captured_by: Vec::new(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let val_node = self.bind(value, ExprContext::Expression, diag);
|
let val_node = self.bind(value, ExprContext::Expression, diag);
|
||||||
@@ -300,36 +311,48 @@ impl Binder {
|
|||||||
|
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Destructure {
|
NodeKind::Def {
|
||||||
pattern: Rc::new(target_node),
|
pattern: Rc::new(target_node),
|
||||||
value: Rc::new(val_node),
|
value: Rc::new(val_node),
|
||||||
|
info: DefBinding {
|
||||||
|
captured_by: Vec::new(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Assign { target, value } => {
|
SyntaxKind::Assign { target, value, .. } => {
|
||||||
let val_node = self.bind(value, ExprContext::Expression, diag);
|
let val_node = self.bind(value, ExprContext::Expression, diag);
|
||||||
|
|
||||||
if let SyntaxKind::Identifier(sym) = &target.kind {
|
if let SyntaxKind::Identifier { symbol: sym, .. } = &target.kind {
|
||||||
if let Some(addr) = self.resolve_variable(sym, diag, &target.identity) {
|
if let Some(addr) = self.resolve_variable(sym, diag, &target.identity) {
|
||||||
|
let target_node = self.make_node(
|
||||||
|
target.identity.clone(),
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol: sym.clone(),
|
||||||
|
binding: IdentifierBinding::Reference(addr),
|
||||||
|
},
|
||||||
|
);
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Set {
|
NodeKind::Assign {
|
||||||
addr,
|
target: Rc::new(target_node),
|
||||||
value: Rc::new(val_node),
|
value: Rc::new(val_node),
|
||||||
|
info: AssignBinding { addr: Some(addr) },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let target_node = self.bind_assign_pattern(target.as_ref(), diag);
|
let target_node = self.bind_assign_pattern(target.as_ref(), diag);
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Destructure {
|
NodeKind::Assign {
|
||||||
pattern: Rc::new(target_node),
|
target: Rc::new(target_node),
|
||||||
value: Rc::new(val_node),
|
value: Rc::new(val_node),
|
||||||
|
info: AssignBinding { addr: None },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -344,15 +367,14 @@ impl Binder {
|
|||||||
Rc::new(self.bind(lambda.as_ref(), ExprContext::Expression, diag));
|
Rc::new(self.bind(lambda.as_ref(), ExprContext::Expression, diag));
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: bound_inputs,
|
inputs: bound_inputs,
|
||||||
lambda: bound_lambda,
|
lambda: bound_lambda,
|
||||||
out_type: crate::ast::types::StaticType::Any,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Lambda { params, body } => {
|
SyntaxKind::Lambda { params, body, .. } => {
|
||||||
let identity = node.identity.clone();
|
let identity = node.identity.clone();
|
||||||
self.functions
|
self.functions
|
||||||
.push(FunctionCompiler::new(identity.clone(), vec![], 0));
|
.push(FunctionCompiler::new(identity.clone(), vec![], 0));
|
||||||
@@ -363,18 +385,21 @@ impl Binder {
|
|||||||
|
|
||||||
fn count_params(node: &Node<BoundPhase>) -> Option<u32> {
|
fn count_params(node: &Node<BoundPhase>) -> Option<u32> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define {
|
NodeKind::Identifier {
|
||||||
kind: DeclarationKind::Parameter,
|
binding: IdentifierBinding::Declaration {
|
||||||
|
kind: DeclarationKind::Parameter,
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
} => Some(1),
|
} => Some(1),
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
for e in elements {
|
for e in elements {
|
||||||
total += count_params(e)?;
|
total += count_params(e)?;
|
||||||
}
|
}
|
||||||
Some(total)
|
Some(total)
|
||||||
}
|
}
|
||||||
BoundKind::Nop => Some(0),
|
NodeKind::Nop => Some(0),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,11 +408,13 @@ impl Binder {
|
|||||||
|
|
||||||
self.make_node(
|
self.make_node(
|
||||||
identity,
|
identity,
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params: Rc::new(params_bound),
|
params: Rc::new(params_bound),
|
||||||
upvalues: compiled_fn.upvalues,
|
|
||||||
body: Rc::new(body_bound),
|
body: Rc::new(body_bound),
|
||||||
positional_count,
|
info: LambdaBinding {
|
||||||
|
upvalues: compiled_fn.upvalues,
|
||||||
|
positional_count,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -398,7 +425,7 @@ impl Binder {
|
|||||||
|
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Call {
|
NodeKind::Call {
|
||||||
callee: Rc::new(callee),
|
callee: Rc::new(callee),
|
||||||
args: Rc::new(args),
|
args: Rc::new(args),
|
||||||
},
|
},
|
||||||
@@ -411,12 +438,12 @@ impl Binder {
|
|||||||
"'again' is only allowed inside a function or lambda.",
|
"'again' is only allowed inside a function or lambda.",
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
return self.make_node(node.identity.clone(), BoundKind::Error);
|
return self.make_node(node.identity.clone(), NodeKind::Error);
|
||||||
}
|
}
|
||||||
let args = self.bind(args.as_ref(), ExprContext::Expression, diag);
|
let args = self.bind(args.as_ref(), ExprContext::Expression, diag);
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Again {
|
NodeKind::Again {
|
||||||
args: Rc::new(args),
|
args: Rc::new(args),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -436,7 +463,7 @@ impl Binder {
|
|||||||
self.functions.last_mut().unwrap().pop_scope();
|
self.functions.last_mut().unwrap().pop_scope();
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Block { exprs: bound_exprs },
|
NodeKind::Block { exprs: bound_exprs },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,24 +474,24 @@ impl Binder {
|
|||||||
}
|
}
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: bound_elems,
|
elements: bound_elems,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Record { fields } => {
|
SyntaxKind::Record { fields, .. } => {
|
||||||
let mut bound_values = Vec::new();
|
let mut bound_fields = Vec::new();
|
||||||
let mut layout_fields = Vec::new();
|
let mut layout_fields = Vec::new();
|
||||||
|
|
||||||
for (k, v) in fields {
|
for (k, v) in fields {
|
||||||
let key_node = self.bind(k, ExprContext::Expression, diag);
|
let key_node = self.bind(k, ExprContext::Expression, diag);
|
||||||
let val_node = self.bind(v, ExprContext::Expression, diag);
|
let val_node = self.bind(v, ExprContext::Expression, diag);
|
||||||
|
|
||||||
if let BoundKind::Constant(crate::ast::types::Value::Keyword(kw)) =
|
if let NodeKind::Constant(crate::ast::types::Value::Keyword(kw)) =
|
||||||
key_node.kind
|
&key_node.kind
|
||||||
{
|
{
|
||||||
layout_fields.push((kw, crate::ast::types::StaticType::Any));
|
layout_fields.push((*kw, crate::ast::types::StaticType::Any));
|
||||||
} else {
|
} else {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
format!(
|
format!(
|
||||||
@@ -474,27 +501,27 @@ impl Binder {
|
|||||||
Some(key_node.identity.clone()),
|
Some(key_node.identity.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
bound_values.push(Rc::new(val_node));
|
bound_fields.push((Rc::new(key_node), Rc::new(val_node)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = crate::ast::types::RecordLayout::get_or_create(layout_fields);
|
let layout = crate::ast::types::RecordLayout::get_or_create(layout_fields);
|
||||||
|
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Record {
|
NodeKind::Record {
|
||||||
|
fields: bound_fields,
|
||||||
layout,
|
layout,
|
||||||
values: bound_values,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Expansion { call, expanded } => {
|
SyntaxKind::Expansion { original_call, expanded } => {
|
||||||
let bound_expanded = self.bind(expanded.as_ref(), ctx, diag);
|
let bound_expanded = self.bind(expanded.as_ref(), ctx, diag);
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call: Rc::from(call.as_ref().clone()),
|
original_call: original_call.clone(),
|
||||||
bound_expanded: Rc::new(bound_expanded),
|
expanded: Rc::new(bound_expanded),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -510,7 +537,7 @@ impl Binder {
|
|||||||
),
|
),
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Extension(_) => {
|
SyntaxKind::Extension(_) => {
|
||||||
@@ -518,11 +545,18 @@ impl Binder {
|
|||||||
"Custom extensions not supported in Binder yet",
|
"Custom extensions not supported in Binder yet",
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
|
}
|
||||||
|
SyntaxKind::GetField { .. } => {
|
||||||
|
diag.push_error(
|
||||||
|
"GetField not expected in SyntaxPhase",
|
||||||
|
Some(node.identity.clone()),
|
||||||
|
);
|
||||||
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
SyntaxKind::Error => Node {
|
SyntaxKind::Error => Node {
|
||||||
identity: node.identity.clone(),
|
identity: node.identity.clone(),
|
||||||
kind: BoundKind::Error,
|
kind: NodeKind::Error,
|
||||||
ty: (),
|
ty: (),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -605,20 +639,17 @@ impl Binder {
|
|||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> Node<BoundPhase> {
|
) -> Node<BoundPhase> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Identifier(sym) => {
|
SyntaxKind::Identifier { symbol: sym, .. } => {
|
||||||
if let Some(addr) = self.declare_variable(sym, node.identity.clone(), kind, diag) {
|
if let Some(addr) = self.declare_variable(sym, node.identity.clone(), kind, diag) {
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Define {
|
NodeKind::Identifier {
|
||||||
name: sym.clone(),
|
symbol: sym.clone(),
|
||||||
addr,
|
binding: IdentifierBinding::Declaration { addr, kind },
|
||||||
kind,
|
|
||||||
value: Rc::new(self.make_node(node.identity.clone(), BoundKind::Nop)),
|
|
||||||
captured_by: Vec::new(),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SyntaxKind::Tuple { elements } => {
|
SyntaxKind::Tuple { elements } => {
|
||||||
@@ -628,7 +659,7 @@ impl Binder {
|
|||||||
}
|
}
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: bound_elems,
|
elements: bound_elems,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -638,7 +669,7 @@ impl Binder {
|
|||||||
format!("Invalid node in pattern: {:?}", node.kind),
|
format!("Invalid node in pattern: {:?}", node.kind),
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,17 +680,17 @@ impl Binder {
|
|||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> Node<BoundPhase> {
|
) -> Node<BoundPhase> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Identifier(sym) => {
|
SyntaxKind::Identifier { symbol: sym, .. } => {
|
||||||
if let Some(addr) = self.resolve_variable(sym, diag, &node.identity) {
|
if let Some(addr) = self.resolve_variable(sym, diag, &node.identity) {
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Set {
|
NodeKind::Identifier {
|
||||||
addr,
|
symbol: sym.clone(),
|
||||||
value: Rc::new(self.make_node(node.identity.clone(), BoundKind::Nop)),
|
binding: IdentifierBinding::Reference(addr),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SyntaxKind::Tuple { elements } => {
|
SyntaxKind::Tuple { elements } => {
|
||||||
@@ -669,7 +700,7 @@ impl Binder {
|
|||||||
}
|
}
|
||||||
self.make_node(
|
self.make_node(
|
||||||
node.identity.clone(),
|
node.identity.clone(),
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: bound_elems,
|
elements: bound_elems,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -679,12 +710,12 @@ impl Binder {
|
|||||||
format!("Invalid node in assignment pattern: {:?}", node.kind),
|
format!("Invalid node in assignment pattern: {:?}", node.kind),
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
self.make_node(node.identity.clone(), BoundKind::Error)
|
self.make_node(node.identity.clone(), NodeKind::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_node(&self, identity: Identity, kind: BoundKind<BoundPhase>) -> Node<BoundPhase> {
|
fn make_node(&self, identity: Identity, kind: NodeKind<BoundPhase>) -> Node<BoundPhase> {
|
||||||
Node {
|
Node {
|
||||||
identity,
|
identity,
|
||||||
kind,
|
kind,
|
||||||
@@ -708,17 +739,21 @@ mod tests {
|
|||||||
let mut diagnostics = Diagnostics::new();
|
let mut diagnostics = Diagnostics::new();
|
||||||
let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap();
|
let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap();
|
||||||
|
|
||||||
if let BoundKind::Lambda { body, .. } = &bound.kind {
|
if let NodeKind::Lambda { body, .. } = &bound.kind {
|
||||||
if let BoundKind::Block { exprs } = &body.kind {
|
if let NodeKind::Block { exprs } = &body.kind {
|
||||||
let x_decl = &exprs[0];
|
let x_decl = &exprs[0];
|
||||||
if let BoundKind::Define { addr, .. } = &x_decl.kind {
|
if let NodeKind::Def { pattern, .. } = &x_decl.kind {
|
||||||
assert!(matches!(addr, Address::Local(_)));
|
if let NodeKind::Identifier { binding: IdentifierBinding::Declaration { addr, .. }, .. } = &pattern.kind {
|
||||||
assert!(
|
assert!(matches!(addr, Address::Local(_)));
|
||||||
captures.contains_key(&x_decl.identity),
|
assert!(
|
||||||
"Variable 'x' should have capturers"
|
captures.contains_key(&x_decl.identity),
|
||||||
);
|
"Variable 'x' should have capturers"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Def pattern should be an Identifier with Declaration binding");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("First expression should be Define");
|
panic!("First expression should be Def");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("Lambda body should be a Block");
|
panic!("Lambda body should be a Block");
|
||||||
@@ -737,17 +772,21 @@ mod tests {
|
|||||||
let mut diagnostics = Diagnostics::new();
|
let mut diagnostics = Diagnostics::new();
|
||||||
let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap();
|
let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap();
|
||||||
|
|
||||||
if let BoundKind::Lambda { body, .. } = &bound.kind {
|
if let NodeKind::Lambda { body, .. } = &bound.kind {
|
||||||
if let BoundKind::Block { exprs } = &body.kind {
|
if let NodeKind::Block { exprs } = &body.kind {
|
||||||
let x_decl = &exprs[0];
|
let x_decl = &exprs[0];
|
||||||
if let BoundKind::Define { addr, .. } = &x_decl.kind {
|
if let NodeKind::Def { pattern, .. } = &x_decl.kind {
|
||||||
assert!(matches!(addr, Address::Local(_)));
|
if let NodeKind::Identifier { binding: IdentifierBinding::Declaration { addr, .. }, .. } = &pattern.kind {
|
||||||
assert!(
|
assert!(matches!(addr, Address::Local(_)));
|
||||||
!captures.contains_key(&x_decl.identity),
|
assert!(
|
||||||
"Variable 'x' should NOT have any capturers"
|
!captures.contains_key(&x_decl.identity),
|
||||||
);
|
"Variable 'x' should NOT have any capturers"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Def pattern should be an Identifier with Declaration binding");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("First expression should be Define");
|
panic!("First expression should be Def");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("Lambda body should be a Block");
|
panic!("Lambda body should be a Block");
|
||||||
|
|||||||
@@ -181,11 +181,39 @@ impl CompilerPhase for RuntimePhase {
|
|||||||
type RecordLayout = Arc<crate::ast::types::RecordLayout>;
|
type RecordLayout = Arc<crate::ast::types::RecordLayout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bound AST node, decorated with phase-specific information P.
|
/// Convenience alias for all post-binding phases that share the same
|
||||||
|
/// concrete binding, def, assign, lambda, and record-layout types.
|
||||||
|
/// Covers `BoundPhase`, `TypedPhase`, `AnalyzedPhase` (but not `SyntaxPhase` or `RuntimePhase`).
|
||||||
|
pub trait BoundLike:
|
||||||
|
CompilerPhase<
|
||||||
|
LocalAddress = VirtualId,
|
||||||
|
Binding = IdentifierBinding<VirtualId>,
|
||||||
|
DefInfo = DefBinding,
|
||||||
|
AssignInfo = AssignBinding<VirtualId>,
|
||||||
|
LambdaInfo = LambdaBinding<VirtualId>,
|
||||||
|
RecordLayout = Arc<crate::ast::types::RecordLayout>,
|
||||||
|
>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> BoundLike for P where
|
||||||
|
P: CompilerPhase<
|
||||||
|
LocalAddress = VirtualId,
|
||||||
|
Binding = IdentifierBinding<VirtualId>,
|
||||||
|
DefInfo = DefBinding,
|
||||||
|
AssignInfo = AssignBinding<VirtualId>,
|
||||||
|
LambdaInfo = LambdaBinding<VirtualId>,
|
||||||
|
RecordLayout = Arc<crate::ast::types::RecordLayout>,
|
||||||
|
>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A unified AST node, decorated with phase-specific information P.
|
||||||
|
/// Replaces both `SyntaxNode` (parser output) and the old bound AST node.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Node<P: CompilerPhase = BoundPhase> {
|
pub struct Node<P: CompilerPhase = BoundPhase> {
|
||||||
pub identity: Identity,
|
pub identity: Identity,
|
||||||
pub kind: BoundKind<P>,
|
pub kind: NodeKind<P>,
|
||||||
pub ty: P::Metadata,
|
pub ty: P::Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +446,7 @@ impl<P: CompilerPhase> BoundKind<P> {
|
|||||||
BoundKind::Destructure { .. } => "DESTRUCTURE".to_string(),
|
BoundKind::Destructure { .. } => "DESTRUCTURE".to_string(),
|
||||||
BoundKind::Lambda { params, upvalues, .. } => {
|
BoundKind::Lambda { params, upvalues, .. } => {
|
||||||
let p_str = match ¶ms.kind {
|
let p_str = match ¶ms.kind {
|
||||||
BoundKind::Tuple { elements } => format!("p:{}", elements.len()),
|
NodeKind::Tuple { elements } => format!("p:{}", elements.len()),
|
||||||
_ => "p:1".to_string(),
|
_ => "p:1".to_string(),
|
||||||
};
|
};
|
||||||
format!("LAMBDA({}, Captures:{})", p_str, upvalues.len())
|
format!("LAMBDA({}, Captures:{})", p_str, upvalues.len())
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{BoundKind, CompilerPhase, Node};
|
use crate::ast::compiler::bound_nodes::{CompilerPhase, DefBinding, Node, NodeKind};
|
||||||
use crate::ast::types::Identity;
|
use crate::ast::types::Identity;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -6,118 +6,111 @@ use std::rc::Rc;
|
|||||||
pub struct CapturePass;
|
pub struct CapturePass;
|
||||||
|
|
||||||
impl CapturePass {
|
impl CapturePass {
|
||||||
pub fn apply<P: CompilerPhase>(node: Node<P>, capture_map: &HashMap<Identity, Vec<Identity>>) -> Node<P> {
|
pub fn apply<P: CompilerPhase<DefInfo = DefBinding>>(node: Node<P>, capture_map: &HashMap<Identity, Vec<Identity>>) -> Node<P> {
|
||||||
Self::transform(node, capture_map)
|
Self::transform(node, capture_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform<P: CompilerPhase>(mut node: Node<P>, capture_map: &HashMap<Identity, Vec<Identity>>) -> Node<P> {
|
fn transform<P: CompilerPhase<DefInfo = DefBinding>>(mut node: Node<P>, capture_map: &HashMap<Identity, Vec<Identity>>) -> Node<P> {
|
||||||
node.kind = match node.kind {
|
node.kind = match node.kind {
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
mut captured_by,
|
mut info,
|
||||||
} => {
|
} => {
|
||||||
if let Some(capturers) = capture_map.get(&node.identity) {
|
if let Some(capturers) = capture_map.get(&node.identity) {
|
||||||
captured_by.extend(capturers.iter().cloned());
|
info.captured_by.extend(capturers.iter().cloned());
|
||||||
}
|
}
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern: Rc::new(Self::transform(pattern.as_ref().clone(), capture_map)),
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)),
|
value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)),
|
||||||
captured_by,
|
info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => BoundKind::Lambda {
|
} => NodeKind::Lambda {
|
||||||
params: Rc::new(Self::transform(params.as_ref().clone(), capture_map)),
|
params: Rc::new(Self::transform(params.as_ref().clone(), capture_map)),
|
||||||
upvalues,
|
|
||||||
body: Rc::new(Self::transform(body.as_ref().clone(), capture_map)),
|
body: Rc::new(Self::transform(body.as_ref().clone(), capture_map)),
|
||||||
positional_count,
|
info,
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => BoundKind::Call {
|
NodeKind::Call { callee, args } => NodeKind::Call {
|
||||||
callee: Rc::new(Self::transform(callee.as_ref().clone(), capture_map)),
|
callee: Rc::new(Self::transform(callee.as_ref().clone(), capture_map)),
|
||||||
args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)),
|
args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Again { args } => BoundKind::Again {
|
NodeKind::Again { args } => NodeKind::Again {
|
||||||
args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)),
|
args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => BoundKind::If {
|
} => NodeKind::If {
|
||||||
cond: Rc::new(Self::transform(cond.as_ref().clone(), capture_map)),
|
cond: Rc::new(Self::transform(cond.as_ref().clone(), capture_map)),
|
||||||
then_br: Rc::new(Self::transform(then_br.as_ref().clone(), capture_map)),
|
then_br: Rc::new(Self::transform(then_br.as_ref().clone(), capture_map)),
|
||||||
else_br: else_br
|
else_br: else_br
|
||||||
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map))),
|
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map))),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Destructure { pattern, value } => BoundKind::Destructure {
|
NodeKind::Assign { target, value, info } => NodeKind::Assign {
|
||||||
pattern: Rc::new(Self::transform(pattern.as_ref().clone(), capture_map)),
|
target: Rc::new(Self::transform(target.as_ref().clone(), capture_map)),
|
||||||
value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)),
|
value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)),
|
||||||
|
info,
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs,
|
inputs,
|
||||||
lambda,
|
lambda,
|
||||||
out_type,
|
|
||||||
} => {
|
} => {
|
||||||
let mut t_inputs = Vec::with_capacity(inputs.len());
|
let mut t_inputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
t_inputs.push(Rc::new(Self::transform(input.as_ref().clone(), capture_map)));
|
t_inputs.push(Rc::new(Self::transform(input.as_ref().clone(), capture_map)));
|
||||||
}
|
}
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: t_inputs,
|
inputs: t_inputs,
|
||||||
lambda: Rc::new(Self::transform(lambda.as_ref().clone(), capture_map)),
|
lambda: Rc::new(Self::transform(lambda.as_ref().clone(), capture_map)),
|
||||||
out_type,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Block { exprs } => BoundKind::Block {
|
NodeKind::Block { exprs } => NodeKind::Block {
|
||||||
exprs: exprs
|
exprs: exprs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map)))
|
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map)))
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => BoundKind::Tuple {
|
NodeKind::Tuple { elements } => NodeKind::Tuple {
|
||||||
elements: elements
|
elements: elements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map)))
|
.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map)))
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Record { layout, values } => BoundKind::Record {
|
NodeKind::Record { fields, layout } => NodeKind::Record {
|
||||||
layout,
|
fields: fields
|
||||||
values: values
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| Rc::new(Self::transform(v.as_ref().clone(), capture_map)))
|
.map(|(k, v)| (k, Rc::new(Self::transform(v.as_ref().clone(), capture_map))))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
layout,
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => BoundKind::Expansion {
|
} => NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded: Rc::new(Self::transform(
|
expanded: Rc::new(Self::transform(
|
||||||
bound_expanded.as_ref().clone(),
|
expanded.as_ref().clone(),
|
||||||
capture_map,
|
capture_map,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => BoundKind::GetField {
|
NodeKind::GetField { rec, field } => NodeKind::GetField {
|
||||||
rec: Rc::new(Self::transform(rec.as_ref().clone(), capture_map)),
|
rec: Rc::new(Self::transform(rec.as_ref().clone(), capture_map)),
|
||||||
field,
|
field,
|
||||||
},
|
},
|
||||||
|
|||||||
+74
-73
@@ -1,4 +1,4 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{BoundKind, CompilerPhase, Node};
|
use crate::ast::compiler::bound_nodes::{CompilerPhase, Node, NodeKind};
|
||||||
|
|
||||||
/// Human-readable AST dumper for the bound AST.
|
/// Human-readable AST dumper for the bound AST.
|
||||||
pub struct Dumper {
|
pub struct Dumper {
|
||||||
@@ -32,73 +32,41 @@ impl Dumper {
|
|||||||
|
|
||||||
fn visit<P: CompilerPhase>(&mut self, node: &Node<P>) {
|
fn visit<P: CompilerPhase>(&mut self, node: &Node<P>) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Nop => self.log("Nop", node),
|
NodeKind::Nop => self.log("Nop", node),
|
||||||
BoundKind::Constant(v) => {
|
NodeKind::Constant(v) => {
|
||||||
self.log(&format!("Constant: {}", v), node);
|
self.log(&format!("Constant: {}", v), node);
|
||||||
}
|
}
|
||||||
BoundKind::Get { addr, name } => {
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
self.log(&format!("Get: {} ({:?})", name.name, addr), node)
|
self.log(&format!("Identifier: {} ({:?})", symbol.name, binding), node)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::FieldAccessor(k) => self.log(&format!("FieldAccessor: .{}", k.name()), node),
|
NodeKind::FieldAccessor(k) => self.log(&format!("FieldAccessor: .{}", k.name()), node),
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => {
|
NodeKind::GetField { rec, field } => {
|
||||||
self.log(&format!("GetField: .{}", field.name()), node);
|
self.log(&format!("GetField: .{}", field.name()), node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
self.visit(rec);
|
self.visit(rec);
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
self.log(&format!("Set: {:?}", addr), node);
|
self.log(&format!("Assign: {:?}", info), node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
|
self.write_indent();
|
||||||
|
self.output.push_str("Target:\n");
|
||||||
|
self.visit(target);
|
||||||
|
self.write_indent();
|
||||||
|
self.output.push_str("Value:\n");
|
||||||
self.visit(value);
|
self.visit(value);
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by,
|
info,
|
||||||
} => {
|
} => {
|
||||||
let k_str = match kind {
|
self.log(&format!("Def ({:?})", info), node);
|
||||||
crate::ast::compiler::bound_nodes::DeclarationKind::Variable => "Variable",
|
|
||||||
crate::ast::compiler::bound_nodes::DeclarationKind::Parameter => "Parameter",
|
|
||||||
};
|
|
||||||
let capture_info = if captured_by.is_empty() {
|
|
||||||
String::from("not captured")
|
|
||||||
} else {
|
|
||||||
format!("captured by {} lambdas", captured_by.len())
|
|
||||||
};
|
|
||||||
self.log(
|
|
||||||
&format!(
|
|
||||||
"Define {} (Name: '{}', Address: {:?}, {})",
|
|
||||||
k_str, name.name, addr, capture_info
|
|
||||||
),
|
|
||||||
node,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.indent += 1;
|
|
||||||
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 });
|
|
||||||
self.output.push_str(&format!(
|
|
||||||
"- Capturer: Lambda at line {}, col {}\n",
|
|
||||||
loc.line, loc.col
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.visit(value);
|
|
||||||
self.indent -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundKind::Destructure { pattern, value } => {
|
|
||||||
self.log("Destructure", node);
|
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
self.write_indent();
|
self.write_indent();
|
||||||
self.output.push_str("Pattern:\n");
|
self.output.push_str("Pattern:\n");
|
||||||
@@ -109,7 +77,7 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -133,28 +101,23 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
..
|
info,
|
||||||
} => {
|
} => {
|
||||||
self.log(&format!("Lambda (Upvalues: {})", upvalues.len()), node);
|
self.log(&format!("Lambda ({:?})", info), node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
|
|
||||||
self.write_indent();
|
self.write_indent();
|
||||||
self.output.push_str("Parameters:\n");
|
self.output.push_str("Parameters:\n");
|
||||||
self.visit(params);
|
self.visit(params);
|
||||||
|
|
||||||
if !upvalues.is_empty() {
|
|
||||||
self.write_indent();
|
|
||||||
self.output.push_str(&format!("Upvalues: {:?}\n", upvalues));
|
|
||||||
}
|
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
self.log("Call", node);
|
self.log("Call", node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
|
|
||||||
@@ -169,13 +132,13 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Again { args } => {
|
NodeKind::Again { args } => {
|
||||||
self.log("Again", node);
|
self.log("Again", node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
self.visit(args);
|
self.visit(args);
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
BoundKind::Pipe { inputs, lambda, .. } => {
|
NodeKind::Pipe { inputs, lambda } => {
|
||||||
self.log("Pipe", node);
|
self.log("Pipe", node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
@@ -185,7 +148,7 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
self.log("Block", node);
|
self.log("Block", node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
@@ -194,7 +157,7 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
self.log("Tuple", node);
|
self.log("Tuple", node);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
for el in elements {
|
for el in elements {
|
||||||
@@ -203,35 +166,73 @@ impl Dumper {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
self.log(
|
self.log(
|
||||||
&format!("Record (Layout: {} fields)", layout.fields.len()),
|
&format!("Record (Layout: {:?})", layout),
|
||||||
node,
|
node,
|
||||||
);
|
);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
for v in values {
|
for (key, val) in fields {
|
||||||
self.visit(v);
|
self.write_indent();
|
||||||
|
self.output.push_str("Key:\n");
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(key);
|
||||||
|
self.indent -= 1;
|
||||||
|
self.write_indent();
|
||||||
|
self.output.push_str("Value:\n");
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(val);
|
||||||
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => {
|
} => {
|
||||||
self.log(
|
self.log(
|
||||||
&format!("Expansion (Original: {:?})", original_call.kind),
|
&format!("Expansion (Original: {:?})", original_call.kind),
|
||||||
node,
|
node,
|
||||||
);
|
);
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
self.visit(bound_expanded);
|
self.visit(expanded);
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Extension(ext) => {
|
NodeKind::MacroDecl { name, params, body } => {
|
||||||
|
self.log(&format!("MacroDecl: {}", name.name), node);
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(params);
|
||||||
|
self.visit(body);
|
||||||
|
self.indent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Template(inner) => {
|
||||||
|
self.log("Template", node);
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(inner);
|
||||||
|
self.indent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Placeholder(inner) => {
|
||||||
|
self.log("Placeholder", node);
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(inner);
|
||||||
|
self.indent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Splice(inner) => {
|
||||||
|
self.log("Splice", node);
|
||||||
|
self.indent += 1;
|
||||||
|
self.visit(inner);
|
||||||
|
self.indent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Extension(ext) => {
|
||||||
self.log(&ext.display_name(), node);
|
self.log(&ext.display_name(), node);
|
||||||
}
|
}
|
||||||
BoundKind::Error => {
|
NodeKind::Error => {
|
||||||
self.log("ERROR_NODE", node);
|
self.log("ERROR_NODE", node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, CompilerPhase, GlobalIdx, Node};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, BoundLike, GlobalIdx, IdentifierBinding, Node, NodeKind,
|
||||||
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// A pass that collects all global function definitions (lambdas) into a registry.
|
/// 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.
|
/// This allows the Specializer to retrieve the original AST of a function for monomorphization.
|
||||||
pub struct LambdaCollector<'a, P: CompilerPhase> {
|
pub struct LambdaCollector<'a, P: BoundLike> {
|
||||||
registry: &'a mut HashMap<GlobalIdx, Rc<Node<P>>>,
|
registry: &'a mut HashMap<GlobalIdx, Rc<Node<P>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, P: CompilerPhase> LambdaCollector<'a, P> {
|
impl<'a, P> LambdaCollector<'a, P>
|
||||||
|
where
|
||||||
|
P: BoundLike,
|
||||||
|
{
|
||||||
/// Performs a full traversal of the AST and populates the provided registry.
|
/// Performs a full traversal of the AST and populates the provided registry.
|
||||||
pub fn collect(node: &Node<P>, registry: &'a mut HashMap<GlobalIdx, Rc<Node<P>>>) {
|
pub fn collect(node: &Node<P>, registry: &'a mut HashMap<GlobalIdx, Rc<Node<P>>>) {
|
||||||
let mut collector = Self { registry };
|
let mut collector = Self { registry };
|
||||||
@@ -17,21 +22,28 @@ impl<'a, P: CompilerPhase> LambdaCollector<'a, P> {
|
|||||||
|
|
||||||
fn visit(&mut self, node: &Node<P>) {
|
fn visit(&mut self, node: &Node<P>) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
self.visit(expr);
|
self.visit(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Define { addr, value, .. } => {
|
NodeKind::Def { pattern, value, .. } => {
|
||||||
// Register global function definitions (lambdas)
|
// Register global function definitions (lambdas)
|
||||||
if let Address::Global(global_index) = addr {
|
if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration {
|
||||||
|
addr: Address::Global(global_index),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} = &pattern.kind
|
||||||
|
{
|
||||||
let mut current = value;
|
let mut current = value;
|
||||||
while let BoundKind::Expansion { bound_expanded, .. } = ¤t.kind {
|
while let NodeKind::Expansion { expanded, .. } = ¤t.kind {
|
||||||
current = bound_expanded;
|
current = expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Lambda { .. } = ¤t.kind {
|
if let NodeKind::Lambda { .. } = ¤t.kind {
|
||||||
self.registry
|
self.registry
|
||||||
.insert(*global_index, (*current).clone());
|
.insert(*global_index, (*current).clone());
|
||||||
}
|
}
|
||||||
@@ -39,15 +51,15 @@ impl<'a, P: CompilerPhase> LambdaCollector<'a, P> {
|
|||||||
self.visit(value);
|
self.visit(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { value, info, .. } => {
|
||||||
// Also track assignments to globals if they hold lambdas.
|
// Also track assignments to globals if they hold lambdas.
|
||||||
if let Address::Global(global_index) = addr {
|
if let Some(Address::Global(global_index)) = &info.addr {
|
||||||
let mut current = value;
|
let mut current = value;
|
||||||
while let BoundKind::Expansion { bound_expanded, .. } = ¤t.kind {
|
while let NodeKind::Expansion { expanded, .. } = ¤t.kind {
|
||||||
current = bound_expanded;
|
current = expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Lambda { .. } = ¤t.kind {
|
if let NodeKind::Lambda { .. } = ¤t.kind {
|
||||||
self.registry
|
self.registry
|
||||||
.insert(*global_index, (*current).clone());
|
.insert(*global_index, (*current).clone());
|
||||||
}
|
}
|
||||||
@@ -55,7 +67,7 @@ impl<'a, P: CompilerPhase> LambdaCollector<'a, P> {
|
|||||||
self.visit(value);
|
self.visit(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -67,30 +79,30 @@ impl<'a, P: CompilerPhase> LambdaCollector<'a, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda { params, body, .. } => {
|
NodeKind::Lambda { params, body, .. } => {
|
||||||
self.visit(params);
|
self.visit(params);
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
self.visit(callee);
|
self.visit(callee);
|
||||||
self.visit(args);
|
self.visit(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.visit(el);
|
self.visit(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Record { values, .. } => {
|
NodeKind::Record { fields, .. } => {
|
||||||
for v in values {
|
for (_, v) in fields {
|
||||||
self.visit(v);
|
self.visit(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
NodeKind::Expansion { expanded, .. } => {
|
||||||
self.visit(bound_expanded);
|
self.visit(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {} // Leaf nodes
|
_ => {} // Leaf nodes
|
||||||
|
|||||||
+126
-74
@@ -1,4 +1,8 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, ExecNode, Node, RuntimeMetadata, StackOffset, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, AssignBinding, ExecNode,
|
||||||
|
IdentifierBinding, LambdaBinding, Node, NodeKind, RuntimeMetadata,
|
||||||
|
StackOffset, VirtualId,
|
||||||
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ impl Lowering {
|
|||||||
// If the top-level node is a Lambda, it already has its internal stack_size
|
// If the top-level node is a Lambda, it already has its internal stack_size
|
||||||
// calculated during transform(). For non-lambdas (like raw expressions),
|
// calculated during transform(). For non-lambdas (like raw expressions),
|
||||||
// we use the allocator's next_slot to determine the required root stack size.
|
// we use the allocator's next_slot to determine the required root stack size.
|
||||||
if !matches!(exec_node.kind, BoundKind::Lambda { .. }) {
|
if !matches!(exec_node.kind, NodeKind::Lambda { .. }) {
|
||||||
exec_node.ty.stack_size = allocator.next_slot;
|
exec_node.ty.stack_size = allocator.next_slot;
|
||||||
}
|
}
|
||||||
exec_node
|
exec_node
|
||||||
@@ -59,40 +63,61 @@ impl Lowering {
|
|||||||
let mut lambda_stack_size = 0;
|
let mut lambda_stack_size = 0;
|
||||||
|
|
||||||
let new_kind = match &node.kind {
|
let new_kind = match &node.kind {
|
||||||
BoundKind::Call { callee, args } => BoundKind::Call {
|
NodeKind::Call { callee, args } => {
|
||||||
callee: Rc::new(Self::transform(callee.clone(), false, allocator)),
|
// Optimized Field Access: Call { callee: FieldAccessor, args: Tuple[1] } → GetField
|
||||||
args: Rc::new(Self::transform(args.clone(), false, allocator)),
|
if let NodeKind::FieldAccessor(k) = &callee.kind
|
||||||
},
|
&& let NodeKind::Tuple { elements } = &args.kind
|
||||||
|
&& elements.len() == 1
|
||||||
BoundKind::Again { args } => {
|
{
|
||||||
if !is_tail_position {
|
let rec = Rc::new(Self::transform(elements[0].clone(), false, allocator));
|
||||||
panic!("'again' is only allowed in tail position to avoid dead code.");
|
return Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::GetField {
|
||||||
|
rec,
|
||||||
|
field: *k,
|
||||||
|
},
|
||||||
|
ty: RuntimeMetadata {
|
||||||
|
ty: node.ty.original.ty.clone(),
|
||||||
|
is_tail: is_tail_position,
|
||||||
|
original: node_rc,
|
||||||
|
stack_size: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
BoundKind::Again {
|
|
||||||
|
NodeKind::Call {
|
||||||
|
callee: Rc::new(Self::transform(callee.clone(), false, allocator)),
|
||||||
args: Rc::new(Self::transform(args.clone(), false, allocator)),
|
args: Rc::new(Self::transform(args.clone(), false, allocator)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Pipe {
|
|
||||||
|
NodeKind::Again { args } => {
|
||||||
|
if !is_tail_position {
|
||||||
|
panic!("'again' is only allowed in tail position to avoid dead code.");
|
||||||
|
}
|
||||||
|
NodeKind::Again {
|
||||||
|
args: Rc::new(Self::transform(args.clone(), false, allocator)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Pipe {
|
||||||
inputs,
|
inputs,
|
||||||
lambda,
|
lambda,
|
||||||
out_type,
|
|
||||||
} => {
|
} => {
|
||||||
let mut t_inputs = Vec::with_capacity(inputs.len());
|
let mut t_inputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
t_inputs.push(Rc::new(Self::transform(input.clone(), false, allocator)));
|
t_inputs.push(Rc::new(Self::transform(input.clone(), false, allocator)));
|
||||||
}
|
}
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: t_inputs,
|
inputs: t_inputs,
|
||||||
lambda: Rc::new(Self::transform(lambda.clone(), false, allocator)),
|
lambda: Rc::new(Self::transform(lambda.clone(), false, allocator)),
|
||||||
out_type: out_type.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => BoundKind::If {
|
} => NodeKind::If {
|
||||||
cond: Rc::new(Self::transform(cond.clone(), false, allocator)),
|
cond: Rc::new(Self::transform(cond.clone(), false, allocator)),
|
||||||
then_br: Rc::new(Self::transform(then_br.clone(), is_tail_position, allocator)),
|
then_br: Rc::new(Self::transform(then_br.clone(), is_tail_position, allocator)),
|
||||||
else_br: else_br
|
else_br: else_br
|
||||||
@@ -100,9 +125,9 @@ impl Lowering {
|
|||||||
.map(|e| Rc::new(Self::transform(e.clone(), is_tail_position, allocator))),
|
.map(|e| Rc::new(Self::transform(e.clone(), is_tail_position, allocator))),
|
||||||
},
|
},
|
||||||
|
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
if exprs.is_empty() {
|
if exprs.is_empty() {
|
||||||
BoundKind::Block { exprs: vec![] }
|
NodeKind::Block { exprs: vec![] }
|
||||||
} else {
|
} else {
|
||||||
let last_idx = exprs.len() - 1;
|
let last_idx = exprs.len() - 1;
|
||||||
let mut new_exprs = Vec::with_capacity(exprs.len());
|
let mut new_exprs = Vec::with_capacity(exprs.len());
|
||||||
@@ -115,18 +140,18 @@ impl Lowering {
|
|||||||
allocator,
|
allocator,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs: new_exprs }
|
NodeKind::Block { exprs: new_exprs }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info: lambda_info,
|
||||||
} => {
|
} => {
|
||||||
// Upvalues refer to the PARENT scope's addresses.
|
// Upvalues refer to the PARENT scope's addresses.
|
||||||
let mapped_upvalues = upvalues
|
let mapped_upvalues = lambda_info
|
||||||
|
.upvalues
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| allocator.map_address(*a))
|
.map(|a| allocator.map_address(*a))
|
||||||
.collect();
|
.collect();
|
||||||
@@ -137,81 +162,108 @@ impl Lowering {
|
|||||||
let t_body = Rc::new(Self::transform(body.clone(), true, &mut lambda_allocator));
|
let t_body = Rc::new(Self::transform(body.clone(), true, &mut lambda_allocator));
|
||||||
lambda_stack_size = lambda_allocator.next_slot;
|
lambda_stack_size = lambda_allocator.next_slot;
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params: t_params,
|
params: t_params,
|
||||||
upvalues: mapped_upvalues,
|
|
||||||
body: t_body,
|
body: t_body,
|
||||||
positional_count: *positional_count,
|
info: LambdaBinding {
|
||||||
|
upvalues: mapped_upvalues,
|
||||||
|
positional_count: lambda_info.positional_count,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => BoundKind::Set {
|
NodeKind::Assign { target, value, info } => {
|
||||||
addr: allocator.map_address(*addr),
|
let new_info = if let Some(addr) = info.addr {
|
||||||
value: Rc::new(Self::transform(value.clone(), false, allocator)),
|
AssignBinding {
|
||||||
},
|
addr: Some(allocator.map_address(addr)),
|
||||||
BoundKind::Define {
|
}
|
||||||
name,
|
} else {
|
||||||
addr,
|
AssignBinding { addr: None }
|
||||||
kind,
|
};
|
||||||
value,
|
NodeKind::Assign {
|
||||||
captured_by,
|
target: Rc::new(Self::transform(target.clone(), false, allocator)),
|
||||||
} => BoundKind::Define {
|
value: Rc::new(Self::transform(value.clone(), false, allocator)),
|
||||||
name: name.clone(),
|
info: new_info,
|
||||||
addr: allocator.map_address(*addr),
|
|
||||||
kind: *kind,
|
|
||||||
value: Rc::new(Self::transform(value.clone(), false, allocator)),
|
|
||||||
captured_by: captured_by.clone(),
|
|
||||||
},
|
|
||||||
BoundKind::Destructure { pattern, value } => BoundKind::Destructure {
|
|
||||||
pattern: Rc::new(Self::transform(pattern.clone(), false, allocator)),
|
|
||||||
value: Rc::new(Self::transform(value.clone(), false, allocator)),
|
|
||||||
},
|
|
||||||
BoundKind::Record { layout, values } => {
|
|
||||||
let new_values = values
|
|
||||||
.iter()
|
|
||||||
.map(|v| Rc::new(Self::transform(v.clone(), false, allocator)))
|
|
||||||
.collect();
|
|
||||||
BoundKind::Record {
|
|
||||||
layout: layout.clone(),
|
|
||||||
values: new_values,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Def {
|
||||||
|
pattern,
|
||||||
|
value,
|
||||||
|
info,
|
||||||
|
} => NodeKind::Def {
|
||||||
|
pattern: Rc::new(Self::transform(pattern.clone(), false, allocator)),
|
||||||
|
value: Rc::new(Self::transform(value.clone(), false, allocator)),
|
||||||
|
info: info.clone(),
|
||||||
|
},
|
||||||
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
|
let new_binding = match binding {
|
||||||
|
IdentifierBinding::Reference(addr) => {
|
||||||
|
IdentifierBinding::Reference(allocator.map_address(*addr))
|
||||||
|
}
|
||||||
|
IdentifierBinding::Declaration { addr, kind } => {
|
||||||
|
IdentifierBinding::Declaration {
|
||||||
|
addr: allocator.map_address(*addr),
|
||||||
|
kind: *kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
binding: new_binding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Record { fields, layout } => {
|
||||||
|
let new_fields = fields
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
Rc::new(Self::transform(k.clone(), false, allocator)),
|
||||||
|
Rc::new(Self::transform(v.clone(), false, allocator)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
NodeKind::Record {
|
||||||
|
fields: new_fields,
|
||||||
|
layout: layout.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Tuple { elements } => {
|
||||||
let new_elements = elements
|
let new_elements = elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| Rc::new(Self::transform(e.clone(), false, allocator)))
|
.map(|e| Rc::new(Self::transform(e.clone(), false, allocator)))
|
||||||
.collect();
|
.collect();
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: new_elements,
|
elements: new_elements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Constant(v) => BoundKind::Constant(v.clone()),
|
NodeKind::Constant(v) => NodeKind::Constant(v.clone()),
|
||||||
BoundKind::Get { addr, name } => BoundKind::Get {
|
NodeKind::FieldAccessor(k) => NodeKind::FieldAccessor(*k),
|
||||||
addr: allocator.map_address(*addr),
|
NodeKind::GetField { rec, field } => NodeKind::GetField {
|
||||||
name: name.clone(),
|
|
||||||
},
|
|
||||||
BoundKind::FieldAccessor(k) => BoundKind::FieldAccessor(*k),
|
|
||||||
BoundKind::GetField { rec, field } => BoundKind::GetField {
|
|
||||||
rec: Rc::new(Self::transform(rec.clone(), false, allocator)),
|
rec: Rc::new(Self::transform(rec.clone(), false, allocator)),
|
||||||
field: *field,
|
field: *field,
|
||||||
},
|
},
|
||||||
BoundKind::Nop => BoundKind::Nop,
|
NodeKind::Nop => NodeKind::Nop,
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => BoundKind::Expansion {
|
} => NodeKind::Expansion {
|
||||||
original_call: original_call.clone(),
|
original_call: original_call.clone(),
|
||||||
bound_expanded: Rc::new(Self::transform(
|
expanded: Rc::new(Self::transform(
|
||||||
bound_expanded.clone(),
|
expanded.clone(),
|
||||||
is_tail_position,
|
is_tail_position,
|
||||||
allocator,
|
allocator,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
BoundKind::Extension(_) => BoundKind::Nop,
|
NodeKind::Extension(_) => NodeKind::Nop,
|
||||||
BoundKind::Error => BoundKind::Error,
|
NodeKind::Error => NodeKind::Error,
|
||||||
|
// Syntax-only variants should not appear in AnalyzedPhase
|
||||||
|
NodeKind::MacroDecl { .. }
|
||||||
|
| NodeKind::Template(_)
|
||||||
|
| NodeKind::Placeholder(_)
|
||||||
|
| NodeKind::Splice(_) => NodeKind::Nop,
|
||||||
};
|
};
|
||||||
|
|
||||||
let stack_size = if let BoundKind::Lambda { .. } = &new_kind {
|
let stack_size = if let NodeKind::Lambda { .. } = &new_kind {
|
||||||
lambda_stack_size
|
lambda_stack_size
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
|||||||
+140
-121
@@ -93,23 +93,23 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
match node.kind {
|
match node.kind {
|
||||||
SyntaxKind::MacroDecl { name, params, body } => {
|
SyntaxKind::MacroDecl { name, params, body } => {
|
||||||
let p_names = self.extract_param_names(¶ms)?;
|
let p_names = self.extract_param_names(¶ms)?;
|
||||||
self.registry.define(name.name, p_names, *body);
|
self.registry.define(name.name, p_names, (*body).clone());
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Nop,
|
kind: SyntaxKind::Nop,
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Call { callee, args } => {
|
SyntaxKind::Call { callee, args } => {
|
||||||
if let SyntaxKind::Identifier(ref sym) = callee.kind
|
if let SyntaxKind::Identifier { symbol: ref sym, .. } = callee.kind
|
||||||
&& let Some((params, body)) = self.registry.lookup(&sym.name)
|
&& let Some((params, body)) = self.registry.lookup(&sym.name)
|
||||||
{
|
{
|
||||||
let expanded_args = self.expand_recursive(*args)?;
|
let expanded_args = self.expand_recursive((*args).clone())?;
|
||||||
|
|
||||||
// Extract argument nodes from the expanded tuple
|
// Extract argument nodes from the expanded tuple
|
||||||
let arg_elements = if let SyntaxKind::Tuple { elements } = expanded_args.kind {
|
let arg_elements = if let SyntaxKind::Tuple { elements } = expanded_args.kind {
|
||||||
elements
|
elements.into_iter().map(|e| (*e).clone()).collect()
|
||||||
} else {
|
} else {
|
||||||
vec![expanded_args]
|
vec![expanded_args]
|
||||||
};
|
};
|
||||||
@@ -124,16 +124,16 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
return self.expand_recursive(expanded);
|
return self.expand_recursive(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
let expanded_callee = self.expand_recursive(*callee)?;
|
let expanded_callee = self.expand_recursive((*callee).clone())?;
|
||||||
let expanded_args = self.expand_recursive(*args)?;
|
let expanded_args = self.expand_recursive((*args).clone())?;
|
||||||
|
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Call {
|
kind: SyntaxKind::Call {
|
||||||
callee: Box::new(expanded_callee),
|
callee: Rc::new(expanded_callee),
|
||||||
args: Box::new(expanded_args),
|
args: Rc::new(expanded_args),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
self.registry.push();
|
self.registry.push();
|
||||||
let mut expanded_exprs = Vec::new();
|
let mut expanded_exprs = Vec::new();
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
expanded_exprs.push(self.expand_recursive(expr)?);
|
expanded_exprs.push(Rc::new(self.expand_recursive((*expr).clone())?));
|
||||||
}
|
}
|
||||||
self.registry.pop();
|
self.registry.pop();
|
||||||
|
|
||||||
@@ -150,39 +150,40 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
kind: SyntaxKind::Block {
|
kind: SyntaxKind::Block {
|
||||||
exprs: expanded_exprs,
|
exprs: expanded_exprs,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Pipe { inputs, lambda } => {
|
SyntaxKind::Pipe { inputs, lambda } => {
|
||||||
let mut expanded_inputs = Vec::with_capacity(inputs.len());
|
let mut expanded_inputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
expanded_inputs.push(self.expand_recursive(input)?);
|
expanded_inputs.push(Rc::new(self.expand_recursive((*input).clone())?));
|
||||||
}
|
}
|
||||||
let expanded_lambda = Box::new(self.expand_recursive(*lambda)?);
|
let expanded_lambda = Rc::new(self.expand_recursive((*lambda).clone())?);
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Pipe {
|
kind: SyntaxKind::Pipe {
|
||||||
inputs: expanded_inputs,
|
inputs: expanded_inputs,
|
||||||
lambda: expanded_lambda,
|
lambda: expanded_lambda,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Lambda { params, body } => {
|
SyntaxKind::Lambda { params, body, .. } => {
|
||||||
self.registry.push();
|
self.registry.push();
|
||||||
let expanded_params = self.expand_recursive(*params)?;
|
let expanded_params = self.expand_recursive((*params).clone())?;
|
||||||
let expanded_body = self.expand_recursive((*body).clone())?;
|
let expanded_body = self.expand_recursive((*body).clone())?;
|
||||||
self.registry.pop();
|
self.registry.pop();
|
||||||
|
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Lambda {
|
kind: SyntaxKind::Lambda {
|
||||||
params: Box::new(expanded_params),
|
params: Rc::new(expanded_params),
|
||||||
body: Rc::new(expanded_body),
|
body: Rc::new(expanded_body),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,98 +192,104 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => {
|
} => {
|
||||||
let cond = self.expand_recursive(*cond)?;
|
let cond = self.expand_recursive((*cond).clone())?;
|
||||||
let then_br = self.expand_recursive(*then_br)?;
|
let then_br = self.expand_recursive((*then_br).clone())?;
|
||||||
let else_br = if let Some(e) = else_br {
|
let else_br = if let Some(e) = else_br {
|
||||||
Some(Box::new(self.expand_recursive(*e)?))
|
Some(Rc::new(self.expand_recursive((*e).clone())?))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::If {
|
kind: SyntaxKind::If {
|
||||||
cond: Box::new(cond),
|
cond: Rc::new(cond),
|
||||||
then_br: Box::new(then_br),
|
then_br: Rc::new(then_br),
|
||||||
else_br,
|
else_br,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Def { target, value } => {
|
SyntaxKind::Def { pattern, value, .. } => {
|
||||||
let target = self.expand_recursive(*target)?;
|
let pattern = self.expand_recursive((*pattern).clone())?;
|
||||||
let value = self.expand_recursive(*value)?;
|
let value = self.expand_recursive((*value).clone())?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Def {
|
kind: SyntaxKind::Def {
|
||||||
target: Box::new(target),
|
pattern: Rc::new(pattern),
|
||||||
value: Box::new(value),
|
value: Rc::new(value),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Assign { target, value } => {
|
SyntaxKind::Assign { target, value, .. } => {
|
||||||
let target = self.expand_recursive(*target)?;
|
let target = self.expand_recursive((*target).clone())?;
|
||||||
let value = self.expand_recursive(*value)?;
|
let value = self.expand_recursive((*value).clone())?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Assign {
|
kind: SyntaxKind::Assign {
|
||||||
target: Box::new(target),
|
target: Rc::new(target),
|
||||||
value: Box::new(value),
|
value: Rc::new(value),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Tuple { elements } => {
|
SyntaxKind::Tuple { elements } => {
|
||||||
let mut expanded_elements = Vec::new();
|
let mut expanded_elements = Vec::new();
|
||||||
for e in elements {
|
for e in elements {
|
||||||
expanded_elements.push(self.expand_recursive(e)?);
|
expanded_elements.push(Rc::new(self.expand_recursive((*e).clone())?));
|
||||||
}
|
}
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Tuple {
|
kind: SyntaxKind::Tuple {
|
||||||
elements: expanded_elements,
|
elements: expanded_elements,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Record { fields } => {
|
SyntaxKind::Record { fields, .. } => {
|
||||||
let mut expanded_fields = Vec::new();
|
let mut expanded_fields = Vec::new();
|
||||||
for (k, v) in fields {
|
for (k, v) in fields {
|
||||||
expanded_fields.push((self.expand_recursive(k)?, self.expand_recursive(v)?));
|
expanded_fields.push((
|
||||||
|
Rc::new(self.expand_recursive((*k).clone())?),
|
||||||
|
Rc::new(self.expand_recursive((*v).clone())?),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Record {
|
kind: SyntaxKind::Record {
|
||||||
fields: expanded_fields,
|
fields: expanded_fields,
|
||||||
|
layout: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Expansion { call, expanded } => {
|
SyntaxKind::Expansion { original_call, expanded } => {
|
||||||
let expanded = self.expand_recursive(*expanded)?;
|
let expanded = self.expand_recursive((*expanded).clone())?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Expansion {
|
kind: SyntaxKind::Expansion {
|
||||||
call,
|
original_call,
|
||||||
expanded: Box::new(expanded),
|
expanded: Rc::new(expanded),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Again { args } => {
|
SyntaxKind::Again { args } => {
|
||||||
let expanded_args = self.expand_recursive(*args)?;
|
let expanded_args = self.expand_recursive((*args).clone())?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Again {
|
kind: SyntaxKind::Again {
|
||||||
args: Box::new(expanded_args),
|
args: Rc::new(expanded_args),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +325,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
bindings: &bindings,
|
bindings: &bindings,
|
||||||
expansion_id: identity.clone(),
|
expansion_id: identity.clone(),
|
||||||
};
|
};
|
||||||
self.expand_template(*inner, &mut state)?
|
self.expand_template((*inner).clone(), &mut state)?
|
||||||
} else {
|
} else {
|
||||||
// Static AST fragment: No substitution, no hygiene.
|
// Static AST fragment: No substitution, no hygiene.
|
||||||
body
|
body
|
||||||
@@ -327,35 +334,38 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
let original_call = SyntaxNode {
|
let original_call = SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Call {
|
kind: SyntaxKind::Call {
|
||||||
callee: Box::new(SyntaxNode {
|
callee: Rc::new(SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Identifier(Symbol::from(name)),
|
kind: SyntaxKind::Identifier {
|
||||||
|
symbol: Symbol::from(name),
|
||||||
|
binding: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}),
|
}),
|
||||||
args: Box::new(SyntaxNode {
|
args: Rc::new(SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Tuple {
|
kind: SyntaxKind::Tuple {
|
||||||
elements: bindings.into_values().collect(),
|
elements: bindings.into_values().map(Rc::new).collect(),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Expansion {
|
kind: SyntaxKind::Expansion {
|
||||||
call: Box::new(original_call),
|
original_call: Rc::new(original_call),
|
||||||
expanded: Box::new(expanded_body),
|
expanded: Rc::new(expanded_body),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_param_names(&self, node: &SyntaxNode) -> Result<Vec<Rc<str>>, String> {
|
fn extract_param_names(&self, node: &SyntaxNode) -> Result<Vec<Rc<str>>, String> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Identifier(sym) => Ok(vec![sym.name.clone()]),
|
SyntaxKind::Identifier { symbol: sym, .. } => Ok(vec![sym.name.clone()]),
|
||||||
SyntaxKind::Tuple { elements } => {
|
SyntaxKind::Tuple { elements } => {
|
||||||
let mut names = Vec::new();
|
let mut names = Vec::new();
|
||||||
for el in elements {
|
for el in elements {
|
||||||
@@ -373,19 +383,22 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
state: &mut ExpansionState,
|
state: &mut ExpansionState,
|
||||||
) -> Result<SyntaxNode, String> {
|
) -> Result<SyntaxNode, String> {
|
||||||
match node.kind {
|
match node.kind {
|
||||||
SyntaxKind::Identifier(mut sym) => {
|
SyntaxKind::Identifier { mut symbol, .. } => {
|
||||||
// Inside a template, all internal identifiers are colored.
|
// Inside a template, all internal identifiers are colored.
|
||||||
sym.context = Some(state.expansion_id.clone());
|
symbol.context = Some(state.expansion_id.clone());
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Identifier(sym),
|
kind: SyntaxKind::Identifier {
|
||||||
|
symbol,
|
||||||
|
binding: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Placeholder(inner) => {
|
SyntaxKind::Placeholder(inner) => {
|
||||||
// Break out of template for substitution/evaluation
|
// Break out of template for substitution/evaluation
|
||||||
if let SyntaxKind::Identifier(ref sym) = inner.kind
|
if let SyntaxKind::Identifier { symbol: ref sym, .. } = inner.kind
|
||||||
&& let Some(arg) = state.bindings.get(&sym.name)
|
&& let Some(arg) = state.bindings.get(&sym.name)
|
||||||
{
|
{
|
||||||
return Ok(arg.clone());
|
return Ok(arg.clone());
|
||||||
@@ -396,7 +409,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
|
|
||||||
SyntaxKind::Splice(inner) => {
|
SyntaxKind::Splice(inner) => {
|
||||||
// Splicing is also a form of substitution
|
// Splicing is also a form of substitution
|
||||||
if let SyntaxKind::Identifier(ref sym) = inner.kind
|
if let SyntaxKind::Identifier { symbol: ref sym, .. } = inner.kind
|
||||||
&& let Some(arg) = state.bindings.get(&sym.name)
|
&& let Some(arg) = state.bindings.get(&sym.name)
|
||||||
{
|
{
|
||||||
return Ok(arg.clone());
|
return Ok(arg.clone());
|
||||||
@@ -405,29 +418,31 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
Ok(self.value_to_node(val, node.identity))
|
Ok(self.value_to_node(val, node.identity))
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Def { target, value } => {
|
SyntaxKind::Def { pattern, value, .. } => {
|
||||||
let target = self.expand_template(*target, state)?;
|
let pattern = self.expand_template((*pattern).clone(), state)?;
|
||||||
let val = self.expand_template(*value, state)?;
|
let val = self.expand_template((*value).clone(), state)?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Def {
|
kind: SyntaxKind::Def {
|
||||||
target: Box::new(target),
|
pattern: Rc::new(pattern),
|
||||||
value: Box::new(val),
|
value: Rc::new(val),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Assign { target, value } => {
|
SyntaxKind::Assign { target, value, .. } => {
|
||||||
let target = self.expand_template(*target, state)?;
|
let target = self.expand_template((*target).clone(), state)?;
|
||||||
let value = self.expand_template(*value, state)?;
|
let value = self.expand_template((*value).clone(), state)?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Assign {
|
kind: SyntaxKind::Assign {
|
||||||
target: Box::new(target),
|
target: Rc::new(target),
|
||||||
value: Box::new(value),
|
value: Rc::new(value),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,7 +453,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
let val = self.evaluator.evaluate(inner, state.bindings)?;
|
let val = self.evaluator.evaluate(inner, state.bindings)?;
|
||||||
self.handle_splice_value(val, node.identity.clone(), &mut new_elements)?;
|
self.handle_splice_value(val, node.identity.clone(), &mut new_elements)?;
|
||||||
} else {
|
} else {
|
||||||
new_elements.push(self.expand_template(e, state)?);
|
new_elements.push(Rc::new(self.expand_template((*e).clone(), state)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
@@ -446,7 +461,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
kind: SyntaxKind::Tuple {
|
kind: SyntaxKind::Tuple {
|
||||||
elements: new_elements,
|
elements: new_elements,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,41 +472,44 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
let val = self.evaluator.evaluate(inner, state.bindings)?;
|
let val = self.evaluator.evaluate(inner, state.bindings)?;
|
||||||
self.handle_splice_value(val, node.identity.clone(), &mut new_exprs)?;
|
self.handle_splice_value(val, node.identity.clone(), &mut new_exprs)?;
|
||||||
} else {
|
} else {
|
||||||
new_exprs.push(self.expand_template(e, state)?);
|
new_exprs.push(Rc::new(self.expand_template((*e).clone(), state)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Block { exprs: new_exprs },
|
kind: SyntaxKind::Block { exprs: new_exprs },
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Record { fields } => {
|
SyntaxKind::Record { fields, .. } => {
|
||||||
let mut new_fields = Vec::new();
|
let mut new_fields = Vec::new();
|
||||||
for (k, v) in fields {
|
for (k, v) in fields {
|
||||||
new_fields.push((
|
new_fields.push((
|
||||||
self.expand_template(k, state)?,
|
Rc::new(self.expand_template((*k).clone(), state)?),
|
||||||
self.expand_template(v, state)?,
|
Rc::new(self.expand_template((*v).clone(), state)?),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Record { fields: new_fields },
|
kind: SyntaxKind::Record {
|
||||||
|
fields: new_fields,
|
||||||
|
layout: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Call { callee, args } => {
|
SyntaxKind::Call { callee, args } => {
|
||||||
let expanded_callee = self.expand_template(*callee, state)?;
|
let expanded_callee = self.expand_template((*callee).clone(), state)?;
|
||||||
let expanded_args = self.expand_template(*args, state)?;
|
let expanded_args = self.expand_template((*args).clone(), state)?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Call {
|
kind: SyntaxKind::Call {
|
||||||
callee: Box::new(expanded_callee),
|
callee: Rc::new(expanded_callee),
|
||||||
args: Box::new(expanded_args),
|
args: Rc::new(expanded_args),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,61 +518,62 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => {
|
} => {
|
||||||
let cond = self.expand_template(*cond, state)?;
|
let cond = self.expand_template((*cond).clone(), state)?;
|
||||||
let then_br = self.expand_template(*then_br, state)?;
|
let then_br = self.expand_template((*then_br).clone(), state)?;
|
||||||
let else_br = if let Some(e) = else_br {
|
let else_br = if let Some(e) = else_br {
|
||||||
Some(Box::new(self.expand_template(*e, state)?))
|
Some(Rc::new(self.expand_template((*e).clone(), state)?))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::If {
|
kind: SyntaxKind::If {
|
||||||
cond: Box::new(cond),
|
cond: Rc::new(cond),
|
||||||
then_br: Box::new(then_br),
|
then_br: Rc::new(then_br),
|
||||||
else_br,
|
else_br,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Pipe { inputs, lambda } => {
|
SyntaxKind::Pipe { inputs, lambda } => {
|
||||||
let mut expanded_inputs = Vec::with_capacity(inputs.len());
|
let mut expanded_inputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
expanded_inputs.push(self.expand_template(input, state)?);
|
expanded_inputs.push(Rc::new(self.expand_template((*input).clone(), state)?));
|
||||||
}
|
}
|
||||||
let expanded_lambda = Box::new(self.expand_template(*lambda, state)?);
|
let expanded_lambda = Rc::new(self.expand_template((*lambda).clone(), state)?);
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Pipe {
|
kind: SyntaxKind::Pipe {
|
||||||
inputs: expanded_inputs,
|
inputs: expanded_inputs,
|
||||||
lambda: expanded_lambda,
|
lambda: expanded_lambda,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Lambda { params, body } => {
|
SyntaxKind::Lambda { params, body, .. } => {
|
||||||
let expanded_params = self.expand_template(*params, state)?;
|
let expanded_params = self.expand_template((*params).clone(), state)?;
|
||||||
let body = self.expand_template((*body).clone(), state)?;
|
let body = self.expand_template((*body).clone(), state)?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Lambda {
|
kind: SyntaxKind::Lambda {
|
||||||
params: Box::new(expanded_params),
|
params: Rc::new(expanded_params),
|
||||||
body: Rc::new(body),
|
body: Rc::new(body),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxKind::Again { args } => {
|
SyntaxKind::Again { args } => {
|
||||||
let expanded_args = self.expand_template(*args, state)?;
|
let expanded_args = self.expand_template((*args).clone(), state)?;
|
||||||
Ok(SyntaxNode {
|
Ok(SyntaxNode {
|
||||||
identity: node.identity,
|
identity: node.identity,
|
||||||
kind: SyntaxKind::Again {
|
kind: SyntaxKind::Again {
|
||||||
args: Box::new(expanded_args),
|
args: Rc::new(expanded_args),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,7 +585,7 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
&self,
|
&self,
|
||||||
val: Value,
|
val: Value,
|
||||||
_identity: Identity,
|
_identity: Identity,
|
||||||
target: &mut Vec<SyntaxNode>,
|
target: &mut Vec<Rc<SyntaxNode>>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match val {
|
match val {
|
||||||
Value::Object(obj) => {
|
Value::Object(obj) => {
|
||||||
@@ -608,13 +627,13 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
|||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Constant(Value::Object(obj)),
|
kind: SyntaxKind::Constant(Value::Object(obj)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => SyntaxNode {
|
_ => SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Constant(val),
|
kind: SyntaxKind::Constant(val),
|
||||||
|
ty: (),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -635,7 +654,7 @@ mod tests {
|
|||||||
node: &SyntaxNode,
|
node: &SyntaxNode,
|
||||||
bindings: &HashMap<Rc<str>, SyntaxNode>,
|
bindings: &HashMap<Rc<str>, SyntaxNode>,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
if let SyntaxKind::Identifier(ref sym) = node.kind
|
if let SyntaxKind::Identifier { symbol: ref sym, .. } = node.kind
|
||||||
&& let Some(arg) = bindings.get(&sym.name)
|
&& let Some(arg) = bindings.get(&sym.name)
|
||||||
{
|
{
|
||||||
return Ok(Value::Object(Rc::new(arg.clone()) as Rc<dyn Object>));
|
return Ok(Value::Object(Rc::new(arg.clone()) as Rc<dyn Object>));
|
||||||
@@ -663,15 +682,15 @@ mod tests {
|
|||||||
if let SyntaxKind::Block { exprs } = &expanded.kind
|
if let SyntaxKind::Block { exprs } = &expanded.kind
|
||||||
&& let SyntaxKind::Expansion {
|
&& let SyntaxKind::Expansion {
|
||||||
expanded: result,
|
expanded: result,
|
||||||
call,
|
original_call,
|
||||||
} = &exprs[1].kind
|
} = &exprs[1].kind
|
||||||
{
|
{
|
||||||
if let SyntaxKind::Def { target, .. } = &result.kind {
|
if let SyntaxKind::Def { pattern, .. } = &result.kind {
|
||||||
if let SyntaxKind::Identifier(sym) = &target.kind {
|
if let SyntaxKind::Identifier { symbol: sym, .. } = &pattern.kind {
|
||||||
assert_eq!(sym.context, Some(call.identity.clone()));
|
assert_eq!(sym.context, Some(original_call.identity.clone()));
|
||||||
assert_eq!(sym.name.as_ref(), "y");
|
assert_eq!(sym.name.as_ref(), "y");
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected Identifier target, got {:?}", target.kind);
|
panic!("Expected Identifier target, got {:?}", pattern.kind);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected Def result, got {:?}", result.kind);
|
panic!("Expected Def result, got {:?}", result.kind);
|
||||||
@@ -694,7 +713,7 @@ mod tests {
|
|||||||
|
|
||||||
if let SyntaxKind::Block { exprs } = &expanded.kind
|
if let SyntaxKind::Block { exprs } = &expanded.kind
|
||||||
&& let SyntaxKind::Expansion {
|
&& let SyntaxKind::Expansion {
|
||||||
call: _,
|
original_call: _,
|
||||||
expanded: result,
|
expanded: result,
|
||||||
} = &exprs[1].kind
|
} = &exprs[1].kind
|
||||||
&& let SyntaxKind::If {
|
&& let SyntaxKind::If {
|
||||||
@@ -703,7 +722,7 @@ mod tests {
|
|||||||
else_br,
|
else_br,
|
||||||
} = &result.kind
|
} = &result.kind
|
||||||
{
|
{
|
||||||
if let SyntaxKind::Identifier(sym) = &cond.kind {
|
if let SyntaxKind::Identifier { symbol: sym, .. } = &cond.kind {
|
||||||
assert_eq!(sym.name.as_ref(), "false");
|
assert_eq!(sym.name.as_ref(), "false");
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected identifier 'false', got {:?}", cond.kind);
|
panic!("Expected identifier 'false', got {:?}", cond.kind);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{
|
use crate::ast::compiler::bound_nodes::{
|
||||||
Address, AnalyzedNode, BoundKind, GlobalAnalyzedRegistry, Node, UpvalueIdx,
|
Address, AnalyzedNode, AssignBinding, GlobalAnalyzedRegistry,
|
||||||
|
IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx,
|
||||||
};
|
};
|
||||||
use crate::ast::types::{Purity, Value};
|
use crate::ast::types::{Purity, Value};
|
||||||
use crate::ast::vm::Closure;
|
use crate::ast::vm::Closure;
|
||||||
@@ -106,8 +107,11 @@ impl Optimizer {
|
|||||||
let inliner = Inliner::new(&self.globals, &self.root_purity);
|
let inliner = Inliner::new(&self.globals, &self.root_purity);
|
||||||
|
|
||||||
let (new_kind, metrics) = match &node.kind {
|
let (new_kind, metrics) = match &node.kind {
|
||||||
BoundKind::Get { addr, name } => {
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
let addr = *addr;
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Reference(addr) => *addr,
|
||||||
|
IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||||
|
};
|
||||||
if !sub.assigned.contains(&addr) {
|
if !sub.assigned.contains(&addr) {
|
||||||
// 1. Try inlining from current value substitution map (locals/globals/upvalues)
|
// 1. Try inlining from current value substitution map (locals/globals/upvalues)
|
||||||
if let Some(val) = sub.get_value(&addr)
|
if let Some(val) = sub.get_value(&addr)
|
||||||
@@ -135,22 +139,33 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub.used.insert(addr);
|
sub.used.insert(addr);
|
||||||
|
let new_binding = match binding {
|
||||||
|
IdentifierBinding::Reference(_) => {
|
||||||
|
IdentifierBinding::Reference(sub.map_address(addr))
|
||||||
|
}
|
||||||
|
IdentifierBinding::Declaration { kind, .. } => {
|
||||||
|
IdentifierBinding::Declaration {
|
||||||
|
addr: sub.map_address(addr),
|
||||||
|
kind: *kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
(
|
(
|
||||||
BoundKind::Get {
|
NodeKind::Identifier {
|
||||||
addr: sub.map_address(addr),
|
symbol: symbol.clone(),
|
||||||
name: name.clone(),
|
binding: new_binding,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(*k), node.ty.clone()),
|
NodeKind::FieldAccessor(k) => (NodeKind::FieldAccessor(*k), node.ty.clone()),
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => {
|
NodeKind::GetField { rec, field } => {
|
||||||
let rec_opt = self.visit_node(rec.clone(), sub, path);
|
let rec_opt = self.visit_node(rec.clone(), sub, path);
|
||||||
|
|
||||||
// Constant folding for Field Access
|
// Constant folding for Field Access
|
||||||
if let BoundKind::Constant(Value::Record(layout, values)) = &rec_opt.kind
|
if let NodeKind::Constant(Value::Record(layout, values)) = &rec_opt.kind
|
||||||
&& let Some(idx) = layout.index_of(*field)
|
&& let Some(idx) = layout.index_of(*field)
|
||||||
{
|
{
|
||||||
return Rc::new(folder.make_constant_node(values[idx].clone(), node));
|
return Rc::new(folder.make_constant_node(values[idx].clone(), node));
|
||||||
@@ -161,7 +176,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::GetField {
|
NodeKind::GetField {
|
||||||
rec: rec_opt,
|
rec: rec_opt,
|
||||||
field: *field,
|
field: *field,
|
||||||
},
|
},
|
||||||
@@ -169,108 +184,120 @@ impl Optimizer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
|
let addr = info.addr;
|
||||||
let value_opt = self.visit_node(value.clone(), sub, path);
|
let value_opt = self.visit_node(value.clone(), sub, path);
|
||||||
if let BoundKind::Constant(val) = &value_opt.kind {
|
if let Some(addr) = addr {
|
||||||
sub.add_value(*addr, val.clone());
|
if let NodeKind::Constant(val) = &value_opt.kind {
|
||||||
} else {
|
sub.add_value(addr, val.clone());
|
||||||
sub.remove_value(addr);
|
} else {
|
||||||
}
|
sub.remove_value(&addr);
|
||||||
|
|
||||||
if Rc::ptr_eq(&value_opt, value) {
|
|
||||||
return node_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
BoundKind::Set {
|
|
||||||
addr: sub.map_address(*addr),
|
|
||||||
value: value_opt,
|
|
||||||
},
|
|
||||||
node.ty.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundKind::Define {
|
|
||||||
name,
|
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
|
||||||
captured_by,
|
|
||||||
} => {
|
|
||||||
let value_opt = self.visit_node(value.clone(), sub, path);
|
|
||||||
|
|
||||||
if let Address::Local(slot) = addr
|
|
||||||
&& !captured_by.is_empty()
|
|
||||||
{
|
|
||||||
sub.captured_slots.insert(*slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let BoundKind::Constant(val) = &value_opt.kind {
|
|
||||||
sub.add_value(*addr, val.clone());
|
|
||||||
} else {
|
|
||||||
sub.remove_value(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Address::Global(global_index) = addr
|
|
||||||
&& value_opt.ty.purity > Purity::Impure
|
|
||||||
&& let Some(purity_rc) = &self.root_purity
|
|
||||||
{
|
|
||||||
let mut pr = purity_rc.borrow_mut();
|
|
||||||
let idx = global_index.0 as usize;
|
|
||||||
if idx < pr.len() {
|
|
||||||
pr[idx] = value_opt.ty.purity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Rc::ptr_eq(&value_opt, value) {
|
// Remap target addresses without constant folding (targets are lvalues)
|
||||||
|
let target_opt = Self::remap_pattern(target, sub);
|
||||||
|
|
||||||
|
if Rc::ptr_eq(&value_opt, value) && Rc::ptr_eq(&target_opt, target) {
|
||||||
return node_rc;
|
return node_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let new_info = if let Some(addr) = addr {
|
||||||
|
AssignBinding {
|
||||||
|
addr: Some(sub.map_address(addr)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info.clone()
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Assign {
|
||||||
name: name.clone(),
|
target: target_opt,
|
||||||
addr: sub.map_address(*addr),
|
|
||||||
kind: *kind,
|
|
||||||
value: value_opt,
|
value: value_opt,
|
||||||
captured_by: captured_by.clone(),
|
info: new_info,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Def {
|
||||||
|
pattern,
|
||||||
|
value,
|
||||||
|
info,
|
||||||
|
} => {
|
||||||
|
let value_opt = self.visit_node(value.clone(), sub, path);
|
||||||
|
|
||||||
|
// Extract addr from the ORIGINAL pattern (before visiting)
|
||||||
|
let addr = Self::extract_def_addr(pattern);
|
||||||
|
|
||||||
|
if let Some(addr) = addr {
|
||||||
|
if let Address::Local(slot) = addr
|
||||||
|
&& !info.captured_by.is_empty()
|
||||||
|
{
|
||||||
|
sub.captured_slots.insert(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let NodeKind::Constant(val) = &value_opt.kind {
|
||||||
|
sub.add_value(addr, val.clone());
|
||||||
|
} else {
|
||||||
|
sub.remove_value(&addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Address::Global(global_index) = addr
|
||||||
|
&& value_opt.ty.purity > Purity::Impure
|
||||||
|
&& let Some(purity_rc) = &self.root_purity
|
||||||
|
{
|
||||||
|
let mut pr = purity_rc.borrow_mut();
|
||||||
|
let idx = global_index.0 as usize;
|
||||||
|
if idx < pr.len() {
|
||||||
|
pr[idx] = value_opt.ty.purity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap pattern addresses without constant folding (patterns are lvalues)
|
||||||
|
let pattern_opt = Self::remap_pattern(pattern, sub);
|
||||||
|
|
||||||
|
if Rc::ptr_eq(&value_opt, value) && Rc::ptr_eq(&pattern_opt, pattern) {
|
||||||
|
return node_rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
NodeKind::Def {
|
||||||
|
pattern: pattern_opt,
|
||||||
|
value: value_opt,
|
||||||
|
info: info.clone(),
|
||||||
|
},
|
||||||
|
node.ty.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Call { callee, args } => {
|
||||||
let callee_opt = self.visit_node(callee.clone(), sub, path);
|
let callee_opt = self.visit_node(callee.clone(), sub, path);
|
||||||
let args_opt = self.visit_node(args.clone(), sub, path);
|
let args_opt = self.visit_node(args.clone(), sub, path);
|
||||||
|
|
||||||
if self.enabled {
|
if self.enabled {
|
||||||
// Optimized Field Access Transformation
|
// Constant folding for Call { callee: FieldAccessor, args: Tuple[1] }
|
||||||
if let BoundKind::FieldAccessor(k) = &callee_opt.kind
|
// (field access on a constant record)
|
||||||
&& let BoundKind::Tuple { elements } = &args_opt.kind
|
if let NodeKind::FieldAccessor(k) = &callee_opt.kind
|
||||||
|
&& let NodeKind::Tuple { elements } = &args_opt.kind
|
||||||
&& elements.len() == 1
|
&& elements.len() == 1
|
||||||
|
&& let NodeKind::Constant(Value::Record(layout, values)) = &elements[0].kind
|
||||||
|
&& let Some(idx) = layout.index_of(*k)
|
||||||
{
|
{
|
||||||
let rec = elements[0].clone();
|
return Rc::new(folder.make_constant_node(values[idx].clone(), node));
|
||||||
let metrics = node.ty.clone();
|
|
||||||
return Rc::new(Node {
|
|
||||||
identity: node.identity.clone(),
|
|
||||||
kind: BoundKind::GetField {
|
|
||||||
rec,
|
|
||||||
field: *k,
|
|
||||||
},
|
|
||||||
ty: metrics,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut arg_nodes = Vec::new();
|
let mut arg_nodes = Vec::new();
|
||||||
self.flatten_tuple(args_opt.clone(), &mut arg_nodes);
|
self.flatten_tuple(args_opt.clone(), &mut arg_nodes);
|
||||||
|
|
||||||
if let BoundKind::Lambda {
|
if let NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
upvalues,
|
info: lambda_info,
|
||||||
positional_count,
|
|
||||||
} = &callee_opt.kind
|
} = &callee_opt.kind
|
||||||
&& upvalues.is_empty()
|
&& lambda_info.upvalues.is_empty()
|
||||||
&& positional_count.is_some()
|
&& lambda_info.positional_count.is_some()
|
||||||
&& path.inlining_depth < 5
|
&& path.inlining_depth < 5
|
||||||
&& !callee_opt.ty.is_recursive
|
&& !callee_opt.ty.is_recursive
|
||||||
&& path.enter_lambda(&callee_opt.identity)
|
&& path.enter_lambda(&callee_opt.identity)
|
||||||
@@ -285,8 +312,8 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Get {
|
if let NodeKind::Identifier {
|
||||||
addr: Address::Global(idx),
|
binding: IdentifierBinding::Reference(Address::Global(idx)),
|
||||||
..
|
..
|
||||||
} = &callee_opt.kind
|
} = &callee_opt.kind
|
||||||
&& let Some(registry_rc) = &self.lambda_registry
|
&& let Some(registry_rc) = &self.lambda_registry
|
||||||
@@ -295,14 +322,13 @@ impl Optimizer {
|
|||||||
{
|
{
|
||||||
let registry = registry_rc.borrow();
|
let registry = registry_rc.borrow();
|
||||||
if let Some(lambda_node) = registry.get(idx)
|
if let Some(lambda_node) = registry.get(idx)
|
||||||
&& let BoundKind::Lambda {
|
&& let NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
upvalues,
|
info: lambda_info,
|
||||||
positional_count,
|
|
||||||
} = &lambda_node.kind
|
} = &lambda_node.kind
|
||||||
&& upvalues.is_empty()
|
&& lambda_info.upvalues.is_empty()
|
||||||
&& positional_count.is_some()
|
&& lambda_info.positional_count.is_some()
|
||||||
&& !lambda_node.ty.is_recursive
|
&& !lambda_node.ty.is_recursive
|
||||||
{
|
{
|
||||||
path.inlining_stack.insert(*idx);
|
path.inlining_stack.insert(*idx);
|
||||||
@@ -317,7 +343,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Constant(Value::Object(ref obj)) = callee_opt.kind
|
if let NodeKind::Constant(Value::Object(ref obj)) = callee_opt.kind
|
||||||
&& path.inlining_depth < 5
|
&& path.inlining_depth < 5
|
||||||
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
||||||
&& (closure.upvalues.is_empty()
|
&& (closure.upvalues.is_empty()
|
||||||
@@ -334,7 +360,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path.inlining_depth += 1;
|
path.inlining_depth += 1;
|
||||||
if let BoundKind::Lambda { params, .. } = &closure.function_node.kind {
|
if let NodeKind::Lambda { params, .. } = &closure.function_node.kind {
|
||||||
let collapsed = self.try_inline(
|
let collapsed = self.try_inline(
|
||||||
params,
|
params,
|
||||||
&arg_nodes,
|
&arg_nodes,
|
||||||
@@ -365,7 +391,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Call {
|
NodeKind::Call {
|
||||||
callee: callee_opt,
|
callee: callee_opt,
|
||||||
args: args_opt,
|
args: args_opt,
|
||||||
},
|
},
|
||||||
@@ -373,27 +399,27 @@ impl Optimizer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Again { args } => {
|
NodeKind::Again { args } => {
|
||||||
let args_opt = self.visit_node(args.clone(), sub, path);
|
let args_opt = self.visit_node(args.clone(), sub, path);
|
||||||
if Rc::ptr_eq(&args_opt, args) {
|
if Rc::ptr_eq(&args_opt, args) {
|
||||||
return node_rc;
|
return node_rc;
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::Again {
|
NodeKind::Again {
|
||||||
args: args_opt,
|
args: args_opt,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => {
|
} => {
|
||||||
let cond_opt = self.visit_node(cond.clone(), sub, path);
|
let cond_opt = self.visit_node(cond.clone(), sub, path);
|
||||||
if self.enabled
|
if self.enabled
|
||||||
&& let BoundKind::Constant(ref val) = cond_opt.kind
|
&& let NodeKind::Constant(ref val) = cond_opt.kind
|
||||||
{
|
{
|
||||||
if val.is_truthy() {
|
if val.is_truthy() {
|
||||||
return self.visit_node(then_br.clone(), sub, path);
|
return self.visit_node(then_br.clone(), sub, path);
|
||||||
@@ -420,7 +446,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond: cond_opt,
|
cond: cond_opt,
|
||||||
then_br: then_br_opt,
|
then_br: then_br_opt,
|
||||||
else_br: else_br_opt,
|
else_br: else_br_opt,
|
||||||
@@ -429,10 +455,9 @@ impl Optimizer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs,
|
inputs,
|
||||||
lambda,
|
lambda,
|
||||||
out_type,
|
|
||||||
} => {
|
} => {
|
||||||
let mut o_inputs = Vec::with_capacity(inputs.len());
|
let mut o_inputs = Vec::with_capacity(inputs.len());
|
||||||
let mut inputs_changed = false;
|
let mut inputs_changed = false;
|
||||||
@@ -450,15 +475,14 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: o_inputs,
|
inputs: o_inputs,
|
||||||
lambda: o_lambda,
|
lambda: o_lambda,
|
||||||
out_type: out_type.clone(),
|
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let mut info = UsageInfo::default();
|
let mut info = UsageInfo::default();
|
||||||
if !exprs.is_empty() {
|
if !exprs.is_empty() {
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
@@ -476,24 +500,34 @@ impl Optimizer {
|
|||||||
let is_last = i == last_idx;
|
let is_last = i == last_idx;
|
||||||
if self.enabled && !is_last {
|
if self.enabled && !is_last {
|
||||||
let removable = match &e.kind {
|
let removable = match &e.kind {
|
||||||
BoundKind::Define { addr, value, .. } => {
|
NodeKind::Def { pattern, value, .. } => {
|
||||||
!info.is_used(addr)
|
let addr = Self::extract_def_addr(pattern);
|
||||||
&& (if let Address::Local(slot) = addr {
|
if let Some(addr) = addr {
|
||||||
!sub.captured_slots.contains(slot)
|
!info.is_used(&addr)
|
||||||
} else {
|
&& (if let Address::Local(slot) = addr {
|
||||||
true
|
!sub.captured_slots.contains(&slot)
|
||||||
})
|
} else {
|
||||||
&& (value.ty.purity >= Purity::SideEffectFree
|
true
|
||||||
|| matches!(value.kind, BoundKind::Lambda { .. }))
|
})
|
||||||
|
&& (value.ty.purity >= Purity::SideEffectFree
|
||||||
|
|| matches!(value.kind, NodeKind::Lambda { .. }))
|
||||||
|
} else {
|
||||||
|
// Destructuring def without single addr - not removable
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value, .. } => {
|
NodeKind::Assign { info: assign_info, value, .. } => {
|
||||||
!info.is_used(addr)
|
if let Some(addr) = assign_info.addr {
|
||||||
&& (if let Address::Local(slot) = addr {
|
!info.is_used(&addr)
|
||||||
!sub.captured_slots.contains(slot)
|
&& (if let Address::Local(slot) = addr {
|
||||||
} else {
|
!sub.captured_slots.contains(&slot)
|
||||||
true
|
} else {
|
||||||
})
|
true
|
||||||
&& value.ty.purity >= Purity::SideEffectFree
|
})
|
||||||
|
&& value.ty.purity >= Purity::SideEffectFree
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => e.ty.purity >= Purity::SideEffectFree,
|
_ => e.ty.purity >= Purity::SideEffectFree,
|
||||||
};
|
};
|
||||||
@@ -504,33 +538,33 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let unmapped_addr = if let BoundKind::Define { addr, .. } = &e.kind {
|
let unmapped_addr = if let NodeKind::Def { pattern, .. } = &e.kind {
|
||||||
Some(*addr)
|
Self::extract_def_addr(pattern)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt = self.visit_node(e.clone(), sub, path);
|
let opt = self.visit_node(e.clone(), sub, path);
|
||||||
|
|
||||||
if let BoundKind::Define { value, .. } = &opt.kind
|
if let NodeKind::Def { value, .. } = &opt.kind
|
||||||
&& let Some(orig_addr) = unmapped_addr
|
&& let Some(orig_addr) = unmapped_addr
|
||||||
&& !info.assigned.contains(&orig_addr)
|
&& !info.assigned.contains(&orig_addr)
|
||||||
{
|
{
|
||||||
let mut core_value = value.as_ref();
|
let mut core_value = value.as_ref();
|
||||||
while let BoundKind::Expansion { bound_expanded, .. } = &core_value.kind {
|
while let NodeKind::Expansion { expanded, .. } = &core_value.kind {
|
||||||
core_value = bound_expanded.as_ref();
|
core_value = expanded.as_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Constant(val) = &core_value.kind {
|
if let NodeKind::Constant(val) = &core_value.kind {
|
||||||
sub.add_value(orig_addr, val.clone());
|
sub.add_value(orig_addr, val.clone());
|
||||||
} else if let BoundKind::Lambda { upvalues, .. } = &core_value.kind
|
} else if let NodeKind::Lambda { info: lambda_info, .. } = &core_value.kind
|
||||||
&& upvalues.is_empty()
|
&& lambda_info.upvalues.is_empty()
|
||||||
{
|
{
|
||||||
sub.add_ast_substitution(orig_addr, core_value.clone());
|
sub.add_ast_substitution(orig_addr, core_value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.enabled && matches!(opt.kind, BoundKind::Nop) && !is_last {
|
if self.enabled && matches!(opt.kind, NodeKind::Nop) && !is_last {
|
||||||
block_changed = true;
|
block_changed = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -552,25 +586,24 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(BoundKind::Block { exprs: new_exprs }, node.ty.clone())
|
(NodeKind::Block { exprs: new_exprs }, node.ty.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info: lambda_info,
|
||||||
} => {
|
} => {
|
||||||
let mut info = UsageInfo::default();
|
let mut usage_info = UsageInfo::default();
|
||||||
info.collect(node);
|
usage_info.collect(node);
|
||||||
|
|
||||||
let mut new_upvalues = Vec::new();
|
let mut new_upvalues = Vec::new();
|
||||||
let mut mapping = Vec::new();
|
let mut mapping = Vec::new();
|
||||||
let mut next_inner_subs = sub.new_inner();
|
let mut next_inner_subs = sub.new_inner();
|
||||||
next_inner_subs.assigned = info.assigned;
|
next_inner_subs.assigned = usage_info.assigned;
|
||||||
let mut upvalues_changed = false;
|
let mut upvalues_changed = false;
|
||||||
|
|
||||||
for (old_idx, capture_addr) in upvalues.iter().enumerate() {
|
for (old_idx, capture_addr) in lambda_info.upvalues.iter().enumerate() {
|
||||||
let mut inlined_val = None;
|
let mut inlined_val = None;
|
||||||
let mut inlined_ast = None;
|
let mut inlined_ast = None;
|
||||||
if !sub.assigned.contains(capture_addr) {
|
if !sub.assigned.contains(capture_addr) {
|
||||||
@@ -608,7 +641,7 @@ impl Optimizer {
|
|||||||
let params_opt = self.visit_node(params.clone(), &mut next_inner_subs, path);
|
let params_opt = self.visit_node(params.clone(), &mut next_inner_subs, path);
|
||||||
|
|
||||||
let body_opt = self.visit_node(body.clone(), &mut next_inner_subs, path);
|
let body_opt = self.visit_node(body.clone(), &mut next_inner_subs, path);
|
||||||
let reindexed_body = if new_upvalues.len() != upvalues.len() {
|
let reindexed_body = if new_upvalues.len() != lambda_info.upvalues.len() {
|
||||||
sub.reindex_upvalues(body_opt, &mapping)
|
sub.reindex_upvalues(body_opt, &mapping)
|
||||||
} else {
|
} else {
|
||||||
body_opt
|
body_opt
|
||||||
@@ -619,40 +652,19 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params: params_opt,
|
params: params_opt,
|
||||||
upvalues: new_upvalues,
|
|
||||||
body: reindexed_body,
|
body: reindexed_body,
|
||||||
positional_count: *positional_count,
|
info: LambdaBinding {
|
||||||
|
upvalues: new_upvalues,
|
||||||
|
positional_count: lambda_info.positional_count,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Destructure { pattern, value } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let val_opt = self.visit_node(value.clone(), sub, path);
|
|
||||||
let pat_opt = self.visit_node(pattern.clone(), sub, path);
|
|
||||||
|
|
||||||
let mut info = UsageInfo::default();
|
|
||||||
info.collect_pattern(&pat_opt);
|
|
||||||
for addr in info.assigned {
|
|
||||||
sub.remove_value(&addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if Rc::ptr_eq(&val_opt, value) && Rc::ptr_eq(&pat_opt, pattern) {
|
|
||||||
return node_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
BoundKind::Destructure {
|
|
||||||
pattern: pat_opt,
|
|
||||||
value: val_opt,
|
|
||||||
},
|
|
||||||
node.ty.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => {
|
|
||||||
let mut new_elements = Vec::with_capacity(elements.len());
|
let mut new_elements = Vec::with_capacity(elements.len());
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for e in elements {
|
for e in elements {
|
||||||
@@ -665,23 +677,25 @@ impl Optimizer {
|
|||||||
if !changed {
|
if !changed {
|
||||||
return node_rc;
|
return node_rc;
|
||||||
}
|
}
|
||||||
(BoundKind::Tuple { elements: new_elements }, node.ty.clone())
|
(NodeKind::Tuple { elements: new_elements }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let mut mapped_values = Vec::with_capacity(values.len());
|
let mut mapped_fields = Vec::with_capacity(fields.len());
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for v in values {
|
for (k, v) in fields {
|
||||||
let opt = self.visit_node(v.clone(), sub, path);
|
let v_opt = self.visit_node(v.clone(), sub, path);
|
||||||
if !Rc::ptr_eq(&opt, v) {
|
if !Rc::ptr_eq(&v_opt, v) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
mapped_values.push(opt);
|
mapped_fields.push((k.clone(), v_opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.enabled
|
if self.enabled {
|
||||||
&& let Some(folded) = folder.try_fold_record(layout, &mapped_values, node)
|
let values: Vec<_> = mapped_fields.iter().map(|(_, v)| v.clone()).collect();
|
||||||
{
|
if let Some(folded) = folder.try_fold_record(layout, &values, node)
|
||||||
return Rc::new(folded);
|
{
|
||||||
|
return Rc::new(folded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !changed {
|
if !changed {
|
||||||
@@ -689,29 +703,29 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Record {
|
NodeKind::Record {
|
||||||
|
fields: mapped_fields,
|
||||||
layout: layout.clone(),
|
layout: layout.clone(),
|
||||||
values: mapped_values,
|
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => {
|
} => {
|
||||||
path.inlining_depth += 1;
|
path.inlining_depth += 1;
|
||||||
let expanded_opt = self.visit_node(bound_expanded.clone(), sub, path);
|
let expanded_opt = self.visit_node(expanded.clone(), sub, path);
|
||||||
path.inlining_depth -= 1;
|
path.inlining_depth -= 1;
|
||||||
|
|
||||||
if Rc::ptr_eq(&expanded_opt, bound_expanded) {
|
if Rc::ptr_eq(&expanded_opt, expanded) {
|
||||||
return node_rc;
|
return node_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call: original_call.clone(),
|
original_call: original_call.clone(),
|
||||||
bound_expanded: expanded_opt,
|
expanded: expanded_opt,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
@@ -726,14 +740,72 @@ impl Optimizer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts the address from a Def pattern node (when it's a simple Identifier with Declaration binding).
|
||||||
|
fn extract_def_addr(pattern: &AnalyzedNode) -> Option<Address<crate::ast::compiler::bound_nodes::VirtualId>> {
|
||||||
|
if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr, .. },
|
||||||
|
..
|
||||||
|
} = &pattern.kind
|
||||||
|
{
|
||||||
|
Some(*addr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remaps addresses in a pattern/target node without constant folding.
|
||||||
|
/// Used for Assign targets where identifiers are references to existing variables
|
||||||
|
/// that should not be replaced by their values.
|
||||||
|
fn remap_pattern(node_rc: &Rc<AnalyzedNode>, sub: &mut SubstitutionMap) -> Rc<AnalyzedNode> {
|
||||||
|
let node = &**node_rc;
|
||||||
|
let new_kind = match &node.kind {
|
||||||
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Reference(addr) => *addr,
|
||||||
|
IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||||
|
};
|
||||||
|
let new_binding = match binding {
|
||||||
|
IdentifierBinding::Reference(_) => {
|
||||||
|
IdentifierBinding::Reference(sub.map_address(addr))
|
||||||
|
}
|
||||||
|
IdentifierBinding::Declaration { kind, .. } => {
|
||||||
|
IdentifierBinding::Declaration {
|
||||||
|
addr: sub.map_address(addr),
|
||||||
|
kind: *kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
binding: new_binding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Tuple { elements } => {
|
||||||
|
let new_elements = elements
|
||||||
|
.iter()
|
||||||
|
.map(|e| Self::remap_pattern(e, sub))
|
||||||
|
.collect();
|
||||||
|
NodeKind::Tuple {
|
||||||
|
elements: new_elements,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return node_rc.clone(),
|
||||||
|
};
|
||||||
|
Rc::new(Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: new_kind,
|
||||||
|
ty: node.ty.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn flatten_tuple(&self, node: Rc<AnalyzedNode>, into: &mut Vec<Rc<AnalyzedNode>>) {
|
fn flatten_tuple(&self, node: Rc<AnalyzedNode>, into: &mut Vec<Rc<AnalyzedNode>>) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.flatten_tuple(el.clone(), into);
|
self.flatten_tuple(el.clone(), into);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Nop => {}
|
NodeKind::Nop => {}
|
||||||
_ => into.push(node),
|
_ => into.push(node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, Node, NodeMetrics};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, IdentifierBinding, Node, NodeKind, NodeMetrics,
|
||||||
|
};
|
||||||
use crate::ast::types::{Purity, RecordLayout, StaticType, Value};
|
use crate::ast::types::{Purity, RecordLayout, StaticType, Value};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -16,12 +18,12 @@ impl<'a> Folder<'a> {
|
|||||||
let ty = val.static_type();
|
let ty = val.static_type();
|
||||||
let typed_original = Rc::new(Node {
|
let typed_original = Rc::new(Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Constant(val.clone()),
|
kind: NodeKind::Constant(val.clone()),
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
});
|
});
|
||||||
Node {
|
Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Constant(val),
|
kind: NodeKind::Constant(val),
|
||||||
ty: NodeMetrics {
|
ty: NodeMetrics {
|
||||||
original: typed_original,
|
original: typed_original,
|
||||||
purity: Purity::Pure,
|
purity: Purity::Pure,
|
||||||
@@ -33,12 +35,12 @@ impl<'a> Folder<'a> {
|
|||||||
pub fn make_nop_node(&self, template: &AnalyzedNode) -> AnalyzedNode {
|
pub fn make_nop_node(&self, template: &AnalyzedNode) -> AnalyzedNode {
|
||||||
let typed_original = Rc::new(Node {
|
let typed_original = Rc::new(Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Nop,
|
kind: NodeKind::Nop,
|
||||||
ty: StaticType::Void,
|
ty: StaticType::Void,
|
||||||
});
|
});
|
||||||
Node {
|
Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Nop,
|
kind: NodeKind::Nop,
|
||||||
ty: NodeMetrics {
|
ty: NodeMetrics {
|
||||||
original: typed_original,
|
original: typed_original,
|
||||||
purity: Purity::Pure,
|
purity: Purity::Pure,
|
||||||
@@ -56,7 +58,7 @@ impl<'a> Folder<'a> {
|
|||||||
let mut constant_values = Vec::with_capacity(values.len());
|
let mut constant_values = Vec::with_capacity(values.len());
|
||||||
|
|
||||||
for v_node in values {
|
for v_node in values {
|
||||||
if let BoundKind::Constant(val) = &v_node.kind {
|
if let NodeKind::Constant(val) = &v_node.kind {
|
||||||
constant_values.push(val.clone());
|
constant_values.push(val.clone());
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@@ -78,18 +80,18 @@ impl<'a> Folder<'a> {
|
|||||||
|
|
||||||
let mut arg_values = Vec::with_capacity(arg_nodes.len());
|
let mut arg_values = Vec::with_capacity(arg_nodes.len());
|
||||||
for node in arg_nodes {
|
for node in arg_nodes {
|
||||||
if let BoundKind::Constant(val) = &node.kind {
|
if let NodeKind::Constant(val) = &node.kind {
|
||||||
arg_values.push(val.clone());
|
arg_values.push(val.clone());
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let func_val = match &callee.kind {
|
let func_val = match &callee.kind {
|
||||||
BoundKind::Get {
|
NodeKind::Identifier {
|
||||||
addr: Address::Global(idx),
|
binding: IdentifierBinding::Reference(Address::Global(idx)),
|
||||||
..
|
..
|
||||||
} => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(),
|
} => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(),
|
||||||
BoundKind::Constant(val) => val.clone(),
|
NodeKind::Constant(val) => val.clone(),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let result = match func_val {
|
let result = match func_val {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, IdentifierBinding, NodeKind, VirtualId,
|
||||||
|
};
|
||||||
use crate::ast::types::{Purity, Value};
|
use crate::ast::types::{Purity, Value};
|
||||||
use crate::ast::vm::Closure;
|
use crate::ast::vm::Closure;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -108,36 +110,82 @@ impl<'a> Inliner<'a> {
|
|||||||
body_usage: &UsageInfo,
|
body_usage: &UsageInfo,
|
||||||
) {
|
) {
|
||||||
match &pattern.kind {
|
match &pattern.kind {
|
||||||
BoundKind::Define { addr, .. } => {
|
NodeKind::Def { pattern: inner_pattern, .. } => {
|
||||||
if let Some(arg) = args.get(*offset)
|
// Extract addr from the pattern's Identifier binding
|
||||||
&& !body_usage.is_assigned(addr)
|
let addr = if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr, .. },
|
||||||
|
..
|
||||||
|
} = &inner_pattern.kind
|
||||||
{
|
{
|
||||||
let mut core_arg = arg.as_ref();
|
Some(*addr)
|
||||||
while let BoundKind::Expansion { bound_expanded, .. } = &core_arg.kind {
|
} else {
|
||||||
core_arg = bound_expanded.as_ref();
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(addr) = addr {
|
||||||
|
if let Some(arg) = args.get(*offset)
|
||||||
|
&& !body_usage.is_assigned(&addr)
|
||||||
|
{
|
||||||
|
let mut core_arg = arg.as_ref();
|
||||||
|
while let NodeKind::Expansion { expanded, .. } = &core_arg.kind {
|
||||||
|
core_arg = expanded.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let NodeKind::Constant(val) = &core_arg.kind {
|
||||||
|
sub.add_value(addr, val.clone());
|
||||||
|
} else if let NodeKind::Lambda { info: lambda_info, .. } = &core_arg.kind
|
||||||
|
&& lambda_info.upvalues.is_empty()
|
||||||
|
{
|
||||||
|
sub.add_ast_substitution(addr, core_arg.clone());
|
||||||
|
} else if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Reference(Address::Global(_)),
|
||||||
|
..
|
||||||
|
} = &core_arg.kind
|
||||||
|
{
|
||||||
|
sub.add_ast_substitution(addr, core_arg.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let BoundKind::Constant(val) = &core_arg.kind {
|
if let Address::Local(slot) = addr {
|
||||||
sub.add_value(*addr, val.clone());
|
sub.map_slot(slot);
|
||||||
} else if let BoundKind::Lambda { upvalues, .. } = &core_arg.kind
|
}
|
||||||
&& upvalues.is_empty()
|
}
|
||||||
|
*offset += 1;
|
||||||
|
}
|
||||||
|
NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr, .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let addr = *addr;
|
||||||
|
if let Some(arg) = args.get(*offset)
|
||||||
|
&& !body_usage.is_assigned(&addr)
|
||||||
|
{
|
||||||
|
let mut core_arg = arg.as_ref();
|
||||||
|
while let NodeKind::Expansion { expanded, .. } = &core_arg.kind {
|
||||||
|
core_arg = expanded.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let NodeKind::Constant(val) = &core_arg.kind {
|
||||||
|
sub.add_value(addr, val.clone());
|
||||||
|
} else if let NodeKind::Lambda { info: lambda_info, .. } = &core_arg.kind
|
||||||
|
&& lambda_info.upvalues.is_empty()
|
||||||
{
|
{
|
||||||
sub.add_ast_substitution(*addr, core_arg.clone());
|
sub.add_ast_substitution(addr, core_arg.clone());
|
||||||
} else if let BoundKind::Get {
|
} else if let NodeKind::Identifier {
|
||||||
addr: Address::Global(_),
|
binding: IdentifierBinding::Reference(Address::Global(_)),
|
||||||
..
|
..
|
||||||
} = &core_arg.kind
|
} = &core_arg.kind
|
||||||
{
|
{
|
||||||
sub.add_ast_substitution(*addr, core_arg.clone());
|
sub.add_ast_substitution(addr, core_arg.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Address::Local(slot) = addr {
|
if let Address::Local(slot) = addr {
|
||||||
sub.map_slot(*slot);
|
sub.map_slot(slot);
|
||||||
}
|
}
|
||||||
*offset += 1;
|
*offset += 1;
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.map_params_to_args(el, args, offset, sub, body_usage);
|
self.map_params_to_args(el, args, offset, sub, body_usage);
|
||||||
}
|
}
|
||||||
@@ -148,13 +196,22 @@ impl<'a> Inliner<'a> {
|
|||||||
|
|
||||||
pub fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<VirtualId>) {
|
pub fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<VirtualId>) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define {
|
NodeKind::Def { pattern, .. } => {
|
||||||
addr: Address::Local(slot),
|
if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr: Address::Local(slot), .. },
|
||||||
|
..
|
||||||
|
} = &pattern.kind
|
||||||
|
{
|
||||||
|
slots.insert(*slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr: Address::Local(slot), .. },
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
slots.insert(*slot);
|
slots.insert(*slot);
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.collect_parameter_slots_set(el, slots);
|
self.collect_parameter_slots_set(el, slots);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, Node, UpvalueIdx, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, AssignBinding, IdentifierBinding,
|
||||||
|
LambdaBinding, Node, NodeKind, UpvalueIdx, VirtualId,
|
||||||
|
};
|
||||||
use crate::ast::types::Value;
|
use crate::ast::types::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -90,34 +93,48 @@ impl SubstitutionMap {
|
|||||||
pub fn reindex_upvalues(&self, node_rc: Rc<AnalyzedNode>, mapping: &[Option<u32>]) -> Rc<AnalyzedNode> {
|
pub fn reindex_upvalues(&self, node_rc: Rc<AnalyzedNode>, mapping: &[Option<u32>]) -> Rc<AnalyzedNode> {
|
||||||
let node = &*node_rc;
|
let node = &*node_rc;
|
||||||
let (new_kind, metrics) = match &node.kind {
|
let (new_kind, metrics) = match &node.kind {
|
||||||
BoundKind::Get { addr, name } => (
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
BoundKind::Get {
|
let new_binding = match binding {
|
||||||
addr: self.reindex_addr(*addr, mapping),
|
IdentifierBinding::Reference(addr) => {
|
||||||
name: name.clone(),
|
IdentifierBinding::Reference(self.reindex_addr(*addr, mapping))
|
||||||
},
|
}
|
||||||
node.ty.clone(),
|
IdentifierBinding::Declaration { addr, kind } => {
|
||||||
),
|
IdentifierBinding::Declaration {
|
||||||
BoundKind::Lambda {
|
addr: self.reindex_addr(*addr, mapping),
|
||||||
params,
|
kind: *kind,
|
||||||
upvalues,
|
}
|
||||||
body,
|
}
|
||||||
positional_count,
|
};
|
||||||
} => {
|
|
||||||
let mut next_upvalues = Vec::new();
|
|
||||||
for addr in upvalues {
|
|
||||||
next_upvalues.push(self.reindex_addr(*addr, mapping));
|
|
||||||
}
|
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
NodeKind::Identifier {
|
||||||
params: params.clone(),
|
symbol: symbol.clone(),
|
||||||
upvalues: next_upvalues,
|
binding: new_binding,
|
||||||
body: body.clone(),
|
|
||||||
positional_count: *positional_count,
|
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::If {
|
NodeKind::Lambda {
|
||||||
|
params,
|
||||||
|
body,
|
||||||
|
info: lambda_info,
|
||||||
|
} => {
|
||||||
|
let mut next_upvalues = Vec::new();
|
||||||
|
for addr in &lambda_info.upvalues {
|
||||||
|
next_upvalues.push(self.reindex_addr(*addr, mapping));
|
||||||
|
}
|
||||||
|
(
|
||||||
|
NodeKind::Lambda {
|
||||||
|
params: params.clone(),
|
||||||
|
body: body.clone(),
|
||||||
|
info: LambdaBinding {
|
||||||
|
upvalues: next_upvalues,
|
||||||
|
positional_count: lambda_info.positional_count,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node.ty.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -126,7 +143,7 @@ impl SubstitutionMap {
|
|||||||
let then_br = self.reindex_upvalues(then_br.clone(), mapping);
|
let then_br = self.reindex_upvalues(then_br.clone(), mapping);
|
||||||
let else_br = else_br.as_ref().map(|e| self.reindex_upvalues(e.clone(), mapping));
|
let else_br = else_br.as_ref().map(|e| self.reindex_upvalues(e.clone(), mapping));
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -134,67 +151,77 @@ impl SubstitutionMap {
|
|||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let exprs = exprs
|
let exprs = exprs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| self.reindex_upvalues(e.clone(), mapping))
|
.map(|e| self.reindex_upvalues(e.clone(), mapping))
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Block { exprs }, node.ty.clone())
|
(NodeKind::Block { exprs }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
let callee = self.reindex_upvalues(callee.clone(), mapping);
|
let callee = self.reindex_upvalues(callee.clone(), mapping);
|
||||||
let args = self.reindex_upvalues(args.clone(), mapping);
|
let args = self.reindex_upvalues(args.clone(), mapping);
|
||||||
(BoundKind::Call { callee, args }, node.ty.clone())
|
(NodeKind::Call { callee, args }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by,
|
info,
|
||||||
} => {
|
} => {
|
||||||
|
let pattern = self.reindex_upvalues(pattern.clone(), mapping);
|
||||||
let value = self.reindex_upvalues(value.clone(), mapping);
|
let value = self.reindex_upvalues(value.clone(), mapping);
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name: name.clone(),
|
pattern,
|
||||||
addr: *addr,
|
|
||||||
kind: *kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by: captured_by.clone(),
|
info: info.clone(),
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign {
|
||||||
|
target,
|
||||||
|
value,
|
||||||
|
info: assign_info,
|
||||||
|
} => {
|
||||||
|
let target = self.reindex_upvalues(target.clone(), mapping);
|
||||||
let value = self.reindex_upvalues(value.clone(), mapping);
|
let value = self.reindex_upvalues(value.clone(), mapping);
|
||||||
|
let new_info = if let Some(addr) = assign_info.addr {
|
||||||
|
AssignBinding {
|
||||||
|
addr: Some(self.reindex_addr(addr, mapping)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assign_info.clone()
|
||||||
|
};
|
||||||
(
|
(
|
||||||
BoundKind::Set {
|
NodeKind::Assign {
|
||||||
addr: self.reindex_addr(*addr, mapping),
|
target,
|
||||||
value,
|
value,
|
||||||
|
info: new_info,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let elements = elements
|
let elements = elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| self.reindex_upvalues(e.clone(), mapping))
|
.map(|e| self.reindex_upvalues(e.clone(), mapping))
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Tuple { elements }, node.ty.clone())
|
(NodeKind::Tuple { elements }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let values = values
|
let fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| self.reindex_upvalues(v.clone(), mapping))
|
.map(|(k, v)| (k.clone(), self.reindex_upvalues(v.clone(), mapping)))
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Record { layout: layout.clone(), values }, node.ty.clone())
|
(NodeKind::Record { fields, layout: layout.clone() }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { original_call, bound_expanded } => {
|
NodeKind::Expansion { original_call, expanded } => {
|
||||||
let bound_expanded = self.reindex_upvalues(bound_expanded.clone(), mapping);
|
let expanded = self.reindex_upvalues(expanded.clone(), mapping);
|
||||||
(
|
(
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call: original_call.clone(),
|
original_call: original_call.clone(),
|
||||||
bound_expanded,
|
expanded,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, GlobalIdx, IdentifierBinding,
|
||||||
|
NodeKind, VirtualId,
|
||||||
|
};
|
||||||
use crate::ast::types::{Identity, Value};
|
use crate::ast::types::{Identity, Value};
|
||||||
use crate::ast::vm::Closure;
|
use crate::ast::vm::Closure;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -48,11 +51,11 @@ impl UsageInfo {
|
|||||||
|
|
||||||
pub fn collect(&mut self, node: &AnalyzedNode) {
|
pub fn collect(&mut self, node: &AnalyzedNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Destructure { pattern, value } => {
|
NodeKind::Def { pattern, value, .. } => {
|
||||||
self.collect_pattern(pattern);
|
self.collect_pattern(pattern);
|
||||||
self.collect(value);
|
self.collect(value);
|
||||||
}
|
}
|
||||||
BoundKind::Constant(v) => {
|
NodeKind::Constant(v) => {
|
||||||
if let Value::Object(obj) = v
|
if let Value::Object(obj) = v
|
||||||
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
||||||
{
|
{
|
||||||
@@ -61,21 +64,29 @@ impl UsageInfo {
|
|||||||
self.collect(&closure.function_node);
|
self.collect(&closure.function_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Get { addr, .. } => {
|
NodeKind::Identifier { binding, .. } => {
|
||||||
self.used.insert(*addr);
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Reference(addr) => *addr,
|
||||||
|
IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||||
|
};
|
||||||
|
self.used.insert(addr);
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info, .. } => {
|
||||||
self.assigned.insert(*addr);
|
if let Some(addr) = info.addr {
|
||||||
|
self.assigned.insert(addr);
|
||||||
|
} else {
|
||||||
|
// Destructuring assign: collect assigned addresses from target pattern
|
||||||
|
self.collect_assigned_from_target(target);
|
||||||
|
}
|
||||||
self.collect(value);
|
self.collect(value);
|
||||||
}
|
}
|
||||||
BoundKind::GetField { rec, .. } => {
|
NodeKind::GetField { rec, .. } => {
|
||||||
self.collect(rec);
|
self.collect(rec);
|
||||||
}
|
}
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
upvalues,
|
info: lambda_info,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.used_identities.insert(node.identity.clone());
|
self.used_identities.insert(node.identity.clone());
|
||||||
|
|
||||||
@@ -99,7 +110,7 @@ impl UsageInfo {
|
|||||||
// Map used upvalues to parent scope
|
// Map used upvalues to parent scope
|
||||||
for addr in &inner_info.used {
|
for addr in &inner_info.used {
|
||||||
if let Address::Upvalue(idx) = addr
|
if let Address::Upvalue(idx) = addr
|
||||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
&& let Some(parent_addr) = lambda_info.upvalues.get(idx.0 as usize)
|
||||||
{
|
{
|
||||||
self.used.insert(*parent_addr);
|
self.used.insert(*parent_addr);
|
||||||
}
|
}
|
||||||
@@ -107,18 +118,18 @@ impl UsageInfo {
|
|||||||
// Map assigned upvalues to parent scope
|
// Map assigned upvalues to parent scope
|
||||||
for addr in &inner_info.assigned {
|
for addr in &inner_info.assigned {
|
||||||
if let Address::Upvalue(idx) = addr
|
if let Address::Upvalue(idx) = addr
|
||||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
&& let Some(parent_addr) = lambda_info.upvalues.get(idx.0 as usize)
|
||||||
{
|
{
|
||||||
self.assigned.insert(*parent_addr);
|
self.assigned.insert(*parent_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -129,49 +140,57 @@ impl UsageInfo {
|
|||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
self.collect(callee);
|
self.collect(callee);
|
||||||
self.collect(args);
|
self.collect(args);
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for e in elements {
|
for e in elements {
|
||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Record { values, .. } => {
|
NodeKind::Record { fields, .. } => {
|
||||||
for v in values {
|
for (_, v) in fields {
|
||||||
self.collect(v);
|
self.collect(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Define { value, .. } => {
|
NodeKind::Expansion { expanded, .. } => {
|
||||||
self.collect(value);
|
self.collect(expanded);
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
NodeKind::Again { args } => {
|
||||||
self.collect(bound_expanded);
|
|
||||||
}
|
|
||||||
BoundKind::Again { args } => {
|
|
||||||
self.collect(args);
|
self.collect(args);
|
||||||
}
|
}
|
||||||
BoundKind::Pipe { inputs, lambda, .. } => {
|
NodeKind::Pipe { inputs, lambda, .. } => {
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
self.collect(input);
|
self.collect(input);
|
||||||
}
|
}
|
||||||
self.collect(lambda);
|
self.collect(lambda);
|
||||||
}
|
}
|
||||||
BoundKind::Nop
|
NodeKind::Nop
|
||||||
| BoundKind::FieldAccessor(_)
|
| NodeKind::FieldAccessor(_)
|
||||||
| BoundKind::Extension(_)
|
| NodeKind::Extension(_)
|
||||||
| BoundKind::Error => {}
|
| NodeKind::Error => {}
|
||||||
|
// Syntax-only variants that should not appear in AnalyzedPhase
|
||||||
|
NodeKind::MacroDecl { .. }
|
||||||
|
| NodeKind::Template(_)
|
||||||
|
| NodeKind::Placeholder(_)
|
||||||
|
| NodeKind::Splice(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define { .. } => {}
|
NodeKind::Identifier {
|
||||||
BoundKind::Set { addr, .. } => {
|
binding: IdentifierBinding::Declaration { .. },
|
||||||
self.assigned.insert(*addr);
|
..
|
||||||
|
} => {}
|
||||||
|
NodeKind::Def { .. } => {}
|
||||||
|
NodeKind::Assign { info, .. } => {
|
||||||
|
if let Some(addr) = info.addr {
|
||||||
|
self.assigned.insert(addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.collect_pattern(el);
|
self.collect_pattern(el);
|
||||||
}
|
}
|
||||||
@@ -179,4 +198,22 @@ impl UsageInfo {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collect_assigned_from_target(&mut self, node: &AnalyzedNode) {
|
||||||
|
match &node.kind {
|
||||||
|
NodeKind::Identifier { binding, .. } => {
|
||||||
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Reference(addr)
|
||||||
|
| IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||||
|
};
|
||||||
|
self.assigned.insert(addr);
|
||||||
|
}
|
||||||
|
NodeKind::Tuple { elements } => {
|
||||||
|
for el in elements {
|
||||||
|
self.collect_assigned_from_target(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, AnalyzedPhase, BoundKind, Node, NodeMetrics, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AnalyzedNode, AnalyzedPhase, IdentifierBinding, Node, NodeKind, NodeMetrics, VirtualId,
|
||||||
|
};
|
||||||
use crate::ast::types::{Purity, Signature, StaticType, Value};
|
use crate::ast::types::{Purity, Signature, StaticType, Value};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -50,13 +52,13 @@ impl Specializer {
|
|||||||
|
|
||||||
fn visit_node(&self, node: AnalyzedNode) -> AnalyzedNode {
|
fn visit_node(&self, node: AnalyzedNode) -> AnalyzedNode {
|
||||||
let (new_kind, metrics) = match node.kind {
|
let (new_kind, metrics) = match node.kind {
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
let (new_callee, new_args, _ret_ty) =
|
let (new_callee, new_args, _ret_ty) =
|
||||||
self.specialize_call_logic(callee, args, node.ty.original.ty.clone());
|
self.specialize_call_logic(callee, args, node.ty.original.ty.clone());
|
||||||
|
|
||||||
let new_metrics = node.ty.clone();
|
let new_metrics = node.ty.clone();
|
||||||
(
|
(
|
||||||
BoundKind::Call {
|
NodeKind::Call {
|
||||||
callee: Rc::new(new_callee),
|
callee: Rc::new(new_callee),
|
||||||
args: Rc::new(new_args),
|
args: Rc::new(new_args),
|
||||||
},
|
},
|
||||||
@@ -64,7 +66,7 @@ impl Specializer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -73,7 +75,7 @@ impl Specializer {
|
|||||||
let then_br = Rc::new(self.visit_node(then_br.as_ref().clone()));
|
let then_br = Rc::new(self.visit_node(then_br.as_ref().clone()));
|
||||||
let else_br = else_br.map(|e| Rc::new(self.visit_node(e.as_ref().clone())));
|
let else_br = else_br.map(|e| Rc::new(self.visit_node(e.as_ref().clone())));
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -81,68 +83,62 @@ impl Specializer {
|
|||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let exprs = exprs.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect();
|
let exprs = exprs.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect();
|
||||||
(BoundKind::Block { exprs }, node.ty.clone())
|
(NodeKind::Block { exprs }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => {
|
} => {
|
||||||
let params = Rc::new(self.visit_node(params.as_ref().clone()));
|
let params = Rc::new(self.visit_node(params.as_ref().clone()));
|
||||||
let body = Rc::new(self.visit_node(body.as_ref().clone()));
|
let body = Rc::new(self.visit_node(body.as_ref().clone()));
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by,
|
info,
|
||||||
} => {
|
} => {
|
||||||
let value = Rc::new(self.visit_node(value.as_ref().clone()));
|
let value = Rc::new(self.visit_node(value.as_ref().clone()));
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name: name.clone(),
|
pattern,
|
||||||
addr,
|
|
||||||
kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by: captured_by.clone(),
|
info,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
let value = Rc::new(self.visit_node(value.as_ref().clone()));
|
let value = Rc::new(self.visit_node(value.as_ref().clone()));
|
||||||
(BoundKind::Set { addr, value }, node.ty.clone())
|
(NodeKind::Assign { target, value, info }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let elements = elements.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect();
|
let elements = elements.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect();
|
||||||
(BoundKind::Tuple { elements }, node.ty.clone())
|
(NodeKind::Tuple { elements }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let values = values.into_iter().map(|v| Rc::new(self.visit_node(v.as_ref().clone()))).collect();
|
let fields = fields.into_iter().map(|(k, v)| (k, Rc::new(self.visit_node(v.as_ref().clone())))).collect();
|
||||||
(BoundKind::Record { layout, values }, node.ty.clone())
|
(NodeKind::Record { fields, layout }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => {
|
} => {
|
||||||
let bound_expanded = Rc::new(self.visit_node(bound_expanded.as_ref().clone()));
|
let expanded = Rc::new(self.visit_node(expanded.as_ref().clone()));
|
||||||
(
|
(
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
@@ -166,7 +162,11 @@ impl Specializer {
|
|||||||
let new_callee = self.visit_node(callee.as_ref().clone());
|
let new_callee = self.visit_node(callee.as_ref().clone());
|
||||||
let new_args = self.visit_node(args.as_ref().clone());
|
let new_args = self.visit_node(args.as_ref().clone());
|
||||||
|
|
||||||
let address = if let BoundKind::Get { addr, .. } = &new_callee.kind {
|
let address = if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Reference(addr),
|
||||||
|
..
|
||||||
|
} = &new_callee.kind
|
||||||
|
{
|
||||||
*addr
|
*addr
|
||||||
} else {
|
} else {
|
||||||
return (new_callee, new_args, original_ty);
|
return (new_callee, new_args, original_ty);
|
||||||
@@ -201,8 +201,8 @@ impl Specializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rtl_lookup) = &self.rtl_lookup
|
if let Some(rtl_lookup) = &self.rtl_lookup
|
||||||
&& let BoundKind::Get { name, .. } = &new_callee.kind
|
&& let NodeKind::Identifier { symbol, .. } = &new_callee.kind
|
||||||
&& let Some((val, ret_ty)) = rtl_lookup(&name.name, &arg_types)
|
&& let Some((val, ret_ty)) = rtl_lookup(&symbol.name, &arg_types)
|
||||||
{
|
{
|
||||||
self.cache
|
self.cache
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@@ -260,12 +260,12 @@ impl Specializer {
|
|||||||
) -> AnalyzedNode {
|
) -> AnalyzedNode {
|
||||||
let typed_original = Rc::new(Node {
|
let typed_original = Rc::new(Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Constant(val.clone()),
|
kind: NodeKind::Constant(val.clone()),
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
});
|
});
|
||||||
Node {
|
Node {
|
||||||
identity: template.identity.clone(),
|
identity: template.identity.clone(),
|
||||||
kind: BoundKind::Constant(val),
|
kind: NodeKind::Constant(val),
|
||||||
ty: NodeMetrics {
|
ty: NodeMetrics {
|
||||||
original: typed_original,
|
original: typed_original,
|
||||||
purity: Purity::Pure,
|
purity: Purity::Pure,
|
||||||
|
|||||||
+335
-185
@@ -1,4 +1,7 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundPhase, CompilerPhase, Node, TypedNode, VirtualId};
|
use crate::ast::compiler::bound_nodes::{
|
||||||
|
Address, AssignBinding, BoundLike, DefBinding, IdentifierBinding, LambdaBinding, Node,
|
||||||
|
NodeKind, TypedNode, TypedPhase, VirtualId,
|
||||||
|
};
|
||||||
use crate::ast::diagnostics::Diagnostics;
|
use crate::ast::diagnostics::Diagnostics;
|
||||||
use crate::ast::types::StaticType;
|
use crate::ast::types::StaticType;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -81,7 +84,7 @@ impl TypeChecker {
|
|||||||
|
|
||||||
pub fn check(
|
pub fn check(
|
||||||
&self,
|
&self,
|
||||||
node: &Node<BoundPhase>,
|
node: &Node<crate::ast::compiler::bound_nodes::BoundPhase>,
|
||||||
arg_types: &[StaticType],
|
arg_types: &[StaticType],
|
||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> TypedNode {
|
) -> TypedNode {
|
||||||
@@ -90,19 +93,21 @@ impl TypeChecker {
|
|||||||
|
|
||||||
/// Allows re-checking a node from any phase as if it were a bound node.
|
/// Allows re-checking a node from any phase as if it were a bound node.
|
||||||
/// This is useful for specialization where we re-type a TypedNode with more specific info.
|
/// This is useful for specialization where we re-type a TypedNode with more specific info.
|
||||||
pub fn check_node_as_bound<P: CompilerPhase<LocalAddress = VirtualId>>(
|
pub fn check_node_as_bound<P: BoundLike>(
|
||||||
&self,
|
&self,
|
||||||
node: &Node<P>,
|
node: &Node<P>,
|
||||||
arg_types: &[StaticType],
|
arg_types: &[StaticType],
|
||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> TypedNode {
|
) -> TypedNode {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => {
|
} => {
|
||||||
|
let upvalues = &info.upvalues;
|
||||||
|
let positional_count = info.positional_count;
|
||||||
|
|
||||||
let mut upvalue_types = Vec::with_capacity(upvalues.len());
|
let mut upvalue_types = Vec::with_capacity(upvalues.len());
|
||||||
for &_addr in upvalues {
|
for &_addr in upvalues {
|
||||||
upvalue_types.push(StaticType::Any);
|
upvalue_types.push(StaticType::Any);
|
||||||
@@ -136,11 +141,13 @@ impl TypeChecker {
|
|||||||
|
|
||||||
Node {
|
Node {
|
||||||
identity: node.identity.clone(),
|
identity: node.identity.clone(),
|
||||||
kind: BoundKind::Lambda {
|
kind: NodeKind::Lambda {
|
||||||
params: Rc::new(params_typed),
|
params: Rc::new(params_typed),
|
||||||
upvalues: upvalues.clone(),
|
|
||||||
body: Rc::new(body_typed),
|
body: Rc::new(body_typed),
|
||||||
positional_count: *positional_count,
|
info: LambdaBinding {
|
||||||
|
upvalues: upvalues.clone(),
|
||||||
|
positional_count,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ty: fn_ty,
|
ty: fn_ty,
|
||||||
}
|
}
|
||||||
@@ -152,113 +159,112 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_params<P: CompilerPhase<LocalAddress = VirtualId>>(
|
fn check_params<P: BoundLike>(
|
||||||
&self,
|
&self,
|
||||||
node: &Node<P>,
|
node: &Node<P>,
|
||||||
specialized_ty: &StaticType,
|
specialized_ty: &StaticType,
|
||||||
ctx: &mut TypeContext,
|
ctx: &mut TypeContext,
|
||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> TypedNode {
|
) -> TypedNode {
|
||||||
let (kind, ty) = match &node.kind {
|
let (kind, ty): (NodeKind<TypedPhase>, StaticType) = match &node.kind {
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
info,
|
||||||
kind: decl_kind,
|
|
||||||
captured_by,
|
|
||||||
..
|
..
|
||||||
|
} => {
|
||||||
|
if let NodeKind::Identifier {
|
||||||
|
symbol,
|
||||||
|
binding: IdentifierBinding::Declaration { addr, kind: decl_kind },
|
||||||
|
} = &pattern.kind
|
||||||
|
{
|
||||||
|
ctx.set_type(*addr, specialized_ty.clone());
|
||||||
|
(
|
||||||
|
NodeKind::Def {
|
||||||
|
pattern: Rc::new(Node {
|
||||||
|
identity: pattern.identity.clone(),
|
||||||
|
kind: NodeKind::Identifier {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
binding: IdentifierBinding::Declaration {
|
||||||
|
addr: *addr,
|
||||||
|
kind: *decl_kind,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ty: specialized_ty.clone(),
|
||||||
|
}),
|
||||||
|
value: Rc::new(Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Nop,
|
||||||
|
ty: specialized_ty.clone(),
|
||||||
|
}),
|
||||||
|
info: DefBinding {
|
||||||
|
captured_by: info.captured_by.clone(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
specialized_ty.clone(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Destructuring def in params — fall through to tuple handling
|
||||||
|
// if pattern is a Tuple, handle elements
|
||||||
|
if let NodeKind::Tuple { elements } = &pattern.kind {
|
||||||
|
return self.check_params_tuple(node, elements, specialized_ty, ctx, diag);
|
||||||
|
}
|
||||||
|
diag.push_error(
|
||||||
|
"Invalid pattern in parameter definition",
|
||||||
|
Some(node.identity.clone()),
|
||||||
|
);
|
||||||
|
(NodeKind::Error, StaticType::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeKind::Assign {
|
||||||
|
info,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
(
|
||||||
|
NodeKind::Assign {
|
||||||
|
target: Rc::new(Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Nop,
|
||||||
|
ty: specialized_ty.clone(),
|
||||||
|
}),
|
||||||
|
value: Rc::new(Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Nop,
|
||||||
|
ty: specialized_ty.clone(),
|
||||||
|
}),
|
||||||
|
info: AssignBinding {
|
||||||
|
addr: info.addr,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
specialized_ty.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol,
|
||||||
|
binding: IdentifierBinding::Declaration { addr, kind: decl_kind },
|
||||||
} => {
|
} => {
|
||||||
ctx.set_type(*addr, specialized_ty.clone());
|
ctx.set_type(*addr, specialized_ty.clone());
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Identifier {
|
||||||
name: name.clone(),
|
symbol: symbol.clone(),
|
||||||
addr: *addr,
|
binding: IdentifierBinding::Declaration {
|
||||||
kind: *decl_kind,
|
addr: *addr,
|
||||||
value: Rc::new(Node {
|
kind: *decl_kind,
|
||||||
identity: node.identity.clone(),
|
},
|
||||||
kind: BoundKind::Nop,
|
|
||||||
ty: specialized_ty.clone(),
|
|
||||||
}),
|
|
||||||
captured_by: captured_by.clone(),
|
|
||||||
},
|
},
|
||||||
specialized_ty.clone(),
|
specialized_ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Set {
|
NodeKind::Tuple { elements } => {
|
||||||
addr,
|
return self.check_params_tuple(node, elements, specialized_ty, ctx, diag);
|
||||||
value: _value,
|
|
||||||
} => {
|
|
||||||
(
|
|
||||||
BoundKind::Set {
|
|
||||||
addr: *addr,
|
|
||||||
value: Rc::new(Node {
|
|
||||||
identity: node.identity.clone(),
|
|
||||||
kind: BoundKind::Nop,
|
|
||||||
ty: specialized_ty.clone(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
specialized_ty.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Nop => (NodeKind::Nop, StaticType::Void),
|
||||||
match specialized_ty {
|
NodeKind::Error => (NodeKind::Error, StaticType::Error),
|
||||||
StaticType::Any
|
|
||||||
| StaticType::Tuple(_)
|
|
||||||
| StaticType::Vector(_, _)
|
|
||||||
| StaticType::Matrix(_, _)
|
|
||||||
| StaticType::List(_)
|
|
||||||
| StaticType::Record(_)
|
|
||||||
| StaticType::Error => {}
|
|
||||||
_ => {
|
|
||||||
diag.push_error(
|
|
||||||
format!(
|
|
||||||
"Cannot destructure type {} as a tuple/vector",
|
|
||||||
specialized_ty
|
|
||||||
),
|
|
||||||
Some(node.identity.clone()),
|
|
||||||
);
|
|
||||||
return Node {
|
|
||||||
identity: node.identity.clone(),
|
|
||||||
kind: BoundKind::Error,
|
|
||||||
ty: StaticType::Error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut typed_elements = Vec::new();
|
|
||||||
let mut elem_types = Vec::new();
|
|
||||||
|
|
||||||
for (i, el) in elements.iter().enumerate() {
|
|
||||||
let sub_ty = match specialized_ty {
|
|
||||||
StaticType::Tuple(t) => t.get(i).cloned().unwrap_or(StaticType::Any),
|
|
||||||
StaticType::Vector(inner, _) => (**inner).clone(),
|
|
||||||
StaticType::Matrix(inner, _) => (**inner).clone(),
|
|
||||||
StaticType::List(inner) => (**inner).clone(),
|
|
||||||
StaticType::Record(layout) => layout
|
|
||||||
.fields
|
|
||||||
.get(i)
|
|
||||||
.map(|(_, ty): &(crate::ast::types::Keyword, StaticType)| ty.clone())
|
|
||||||
.unwrap_or(StaticType::Any),
|
|
||||||
StaticType::Error => StaticType::Error,
|
|
||||||
_ => StaticType::Any,
|
|
||||||
};
|
|
||||||
let t = self.check_params(el.as_ref(), &sub_ty, ctx, diag);
|
|
||||||
elem_types.push(t.ty.clone());
|
|
||||||
typed_elements.push(Rc::new(t));
|
|
||||||
}
|
|
||||||
(
|
|
||||||
BoundKind::Tuple {
|
|
||||||
elements: typed_elements,
|
|
||||||
},
|
|
||||||
StaticType::Tuple(elem_types),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
BoundKind::Error => (BoundKind::Error, StaticType::Error),
|
|
||||||
_ => {
|
_ => {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
"Invalid node in parameter list",
|
"Invalid node in parameter list",
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
(BoundKind::Error, StaticType::Error)
|
(NodeKind::Error, StaticType::Error)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -269,59 +275,183 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_node<P: CompilerPhase<LocalAddress = VirtualId>>(
|
fn check_params_tuple<P: BoundLike>(
|
||||||
|
&self,
|
||||||
|
node: &Node<P>,
|
||||||
|
elements: &[Rc<Node<P>>],
|
||||||
|
specialized_ty: &StaticType,
|
||||||
|
ctx: &mut TypeContext,
|
||||||
|
diag: &mut Diagnostics,
|
||||||
|
) -> TypedNode {
|
||||||
|
match specialized_ty {
|
||||||
|
StaticType::Any
|
||||||
|
| StaticType::Tuple(_)
|
||||||
|
| StaticType::Vector(_, _)
|
||||||
|
| StaticType::Matrix(_, _)
|
||||||
|
| StaticType::List(_)
|
||||||
|
| StaticType::Record(_)
|
||||||
|
| StaticType::Error => {}
|
||||||
|
_ => {
|
||||||
|
diag.push_error(
|
||||||
|
format!(
|
||||||
|
"Cannot destructure type {} as a tuple/vector",
|
||||||
|
specialized_ty
|
||||||
|
),
|
||||||
|
Some(node.identity.clone()),
|
||||||
|
);
|
||||||
|
return Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Error,
|
||||||
|
ty: StaticType::Error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut typed_elements = Vec::new();
|
||||||
|
let mut elem_types = Vec::new();
|
||||||
|
|
||||||
|
for (i, el) in elements.iter().enumerate() {
|
||||||
|
let sub_ty = match specialized_ty {
|
||||||
|
StaticType::Tuple(t) => t.get(i).cloned().unwrap_or(StaticType::Any),
|
||||||
|
StaticType::Vector(inner, _) => (**inner).clone(),
|
||||||
|
StaticType::Matrix(inner, _) => (**inner).clone(),
|
||||||
|
StaticType::List(inner) => (**inner).clone(),
|
||||||
|
StaticType::Record(layout) => layout
|
||||||
|
.fields
|
||||||
|
.get(i)
|
||||||
|
.map(|(_, ty): &(crate::ast::types::Keyword, StaticType)| ty.clone())
|
||||||
|
.unwrap_or(StaticType::Any),
|
||||||
|
StaticType::Error => StaticType::Error,
|
||||||
|
_ => StaticType::Any,
|
||||||
|
};
|
||||||
|
let t = self.check_params(el.as_ref(), &sub_ty, ctx, diag);
|
||||||
|
elem_types.push(t.ty.clone());
|
||||||
|
typed_elements.push(Rc::new(t));
|
||||||
|
}
|
||||||
|
Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Tuple {
|
||||||
|
elements: typed_elements,
|
||||||
|
},
|
||||||
|
ty: StaticType::Tuple(elem_types),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_node<P: BoundLike>(
|
||||||
&self,
|
&self,
|
||||||
node: &Node<P>,
|
node: &Node<P>,
|
||||||
ctx: &mut TypeContext,
|
ctx: &mut TypeContext,
|
||||||
diag: &mut Diagnostics,
|
diag: &mut Diagnostics,
|
||||||
) -> TypedNode {
|
) -> TypedNode {
|
||||||
let (kind, ty) = match &node.kind {
|
let (kind, ty): (NodeKind<TypedPhase>, StaticType) = match &node.kind {
|
||||||
BoundKind::Nop => (BoundKind::Nop, StaticType::Void),
|
NodeKind::Nop => (NodeKind::Nop, StaticType::Void),
|
||||||
|
|
||||||
BoundKind::Constant(v) => {
|
NodeKind::Constant(v) => {
|
||||||
let ty = v.static_type();
|
let ty = v.static_type();
|
||||||
(BoundKind::Constant(v.clone()), ty)
|
(NodeKind::Constant(v.clone()), ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name,
|
pattern,
|
||||||
addr,
|
|
||||||
kind: decl_kind,
|
|
||||||
value,
|
value,
|
||||||
captured_by,
|
info,
|
||||||
} => {
|
} => {
|
||||||
let val_typed = self.check_node(value, ctx, diag);
|
let val_typed = self.check_node(value, ctx, diag);
|
||||||
let ty = val_typed.ty.clone();
|
let ty = val_typed.ty.clone();
|
||||||
ctx.set_type(*addr, ty.clone());
|
|
||||||
|
// Extract addr from pattern to register the type
|
||||||
|
if let NodeKind::Identifier {
|
||||||
|
binding: IdentifierBinding::Declaration { addr, .. },
|
||||||
|
..
|
||||||
|
} = &pattern.kind
|
||||||
|
{
|
||||||
|
ctx.set_type(*addr, ty.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For destructuring defs, check params on the pattern
|
||||||
|
if let NodeKind::Tuple { .. } = &pattern.kind {
|
||||||
|
let pat_typed = self.check_params(pattern.as_ref(), &val_typed.ty, ctx, diag);
|
||||||
|
let ty = val_typed.ty.clone();
|
||||||
|
return Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Def {
|
||||||
|
pattern: Rc::new(pat_typed),
|
||||||
|
value: Rc::new(val_typed),
|
||||||
|
info: DefBinding {
|
||||||
|
captured_by: info.captured_by.clone(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple def — reconstruct the pattern node with the new type
|
||||||
|
let new_pattern: TypedNode = Node {
|
||||||
|
identity: pattern.identity.clone(),
|
||||||
|
kind: match &pattern.kind {
|
||||||
|
NodeKind::Identifier { symbol, binding } => NodeKind::Identifier {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
binding: match binding {
|
||||||
|
IdentifierBinding::Declaration { addr, kind: decl_kind } => {
|
||||||
|
IdentifierBinding::Declaration {
|
||||||
|
addr: *addr,
|
||||||
|
kind: *decl_kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IdentifierBinding::Reference(addr) => {
|
||||||
|
IdentifierBinding::Reference(*addr)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => NodeKind::Error,
|
||||||
|
},
|
||||||
|
ty: ty.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
NodeKind::Def {
|
||||||
name: name.clone(),
|
pattern: Rc::new(new_pattern),
|
||||||
addr: *addr,
|
|
||||||
kind: *decl_kind,
|
|
||||||
value: Rc::new(val_typed),
|
value: Rc::new(val_typed),
|
||||||
captured_by: captured_by.clone(),
|
info: DefBinding {
|
||||||
|
captured_by: info.captured_by.clone(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ty,
|
ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Get { addr, name } => {
|
NodeKind::Identifier { symbol, binding } => {
|
||||||
let ty = ctx.get_type(*addr);
|
if let IdentifierBinding::Reference(addr) = binding {
|
||||||
(
|
let ty = ctx.get_type(*addr);
|
||||||
BoundKind::Get {
|
(
|
||||||
addr: *addr,
|
NodeKind::Identifier {
|
||||||
name: name.clone(),
|
symbol: symbol.clone(),
|
||||||
},
|
binding: IdentifierBinding::Reference(*addr),
|
||||||
ty,
|
},
|
||||||
)
|
ty,
|
||||||
|
)
|
||||||
|
} else if let IdentifierBinding::Declaration { addr, kind: decl_kind } = binding {
|
||||||
|
let ty = ctx.get_type(*addr);
|
||||||
|
(
|
||||||
|
NodeKind::Identifier {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
binding: IdentifierBinding::Declaration {
|
||||||
|
addr: *addr,
|
||||||
|
kind: *decl_kind,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ty,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(NodeKind::Error, StaticType::Error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::FieldAccessor(k) => {
|
NodeKind::FieldAccessor(k) => {
|
||||||
(BoundKind::FieldAccessor(*k), StaticType::FieldAccessor(*k))
|
(NodeKind::FieldAccessor(*k), StaticType::FieldAccessor(*k))
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => {
|
NodeKind::GetField { rec, field } => {
|
||||||
let rec_typed = self.check_node(rec, ctx, diag);
|
let rec_typed = self.check_node(rec, ctx, diag);
|
||||||
let field_ty = match &rec_typed.ty {
|
let field_ty = match &rec_typed.ty {
|
||||||
StaticType::Record(layout) => {
|
StaticType::Record(layout) => {
|
||||||
@@ -350,7 +480,7 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
BoundKind::GetField {
|
NodeKind::GetField {
|
||||||
rec: Rc::new(rec_typed),
|
rec: Rc::new(rec_typed),
|
||||||
field: *field,
|
field: *field,
|
||||||
},
|
},
|
||||||
@@ -358,34 +488,38 @@ impl TypeChecker {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
let val_typed = self.check_node(value, ctx, diag);
|
let val_typed = self.check_node(value, ctx, diag);
|
||||||
let ty = val_typed.ty.clone();
|
let ty = val_typed.ty.clone();
|
||||||
ctx.set_type(*addr, ty.clone());
|
if let Some(addr) = info.addr {
|
||||||
|
ctx.set_type(addr, ty.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For destructuring assigns (addr = None), preserve the target pattern
|
||||||
|
// so the VM can unpack values. For simple assigns, the target is unused.
|
||||||
|
let target_typed = if info.addr.is_none() {
|
||||||
|
Rc::new(self.check_node(target, ctx, diag))
|
||||||
|
} else {
|
||||||
|
Rc::new(Node {
|
||||||
|
identity: node.identity.clone(),
|
||||||
|
kind: NodeKind::Nop,
|
||||||
|
ty: ty.clone(),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Set {
|
NodeKind::Assign {
|
||||||
addr: *addr,
|
target: target_typed,
|
||||||
value: Rc::new(val_typed),
|
value: Rc::new(val_typed),
|
||||||
|
info: AssignBinding {
|
||||||
|
addr: info.addr,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ty,
|
ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Destructure { pattern, value } => {
|
NodeKind::If {
|
||||||
let val_typed = self.check_node(value, ctx, diag);
|
|
||||||
let pat_typed = self.check_params(pattern.as_ref(), &val_typed.ty, ctx, diag);
|
|
||||||
let ty = val_typed.ty.clone();
|
|
||||||
(
|
|
||||||
BoundKind::Destructure {
|
|
||||||
pattern: Rc::new(pat_typed),
|
|
||||||
value: Rc::new(val_typed),
|
|
||||||
},
|
|
||||||
ty,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundKind::If {
|
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -407,7 +541,7 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
NodeKind::If {
|
||||||
cond: Rc::new(cond_typed),
|
cond: Rc::new(cond_typed),
|
||||||
then_br: Rc::new(then_typed),
|
then_br: Rc::new(then_typed),
|
||||||
else_br: else_typed,
|
else_br: else_typed,
|
||||||
@@ -416,7 +550,7 @@ impl TypeChecker {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Pipe { inputs, lambda, .. } => {
|
NodeKind::Pipe { inputs, lambda } => {
|
||||||
let mut typed_inputs = Vec::with_capacity(inputs.len());
|
let mut typed_inputs = Vec::with_capacity(inputs.len());
|
||||||
let mut arg_types = Vec::with_capacity(inputs.len());
|
let mut arg_types = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
@@ -444,16 +578,15 @@ impl TypeChecker {
|
|||||||
StaticType::Any
|
StaticType::Any
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs: typed_inputs,
|
inputs: typed_inputs,
|
||||||
lambda: Rc::new(typed_lambda),
|
lambda: Rc::new(typed_lambda),
|
||||||
out_type: ret_ty.clone(),
|
|
||||||
},
|
},
|
||||||
StaticType::Stream(Box::new(ret_ty)),
|
StaticType::Stream(Box::new(ret_ty)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let mut typed_exprs = Vec::new();
|
let mut typed_exprs = Vec::new();
|
||||||
let mut last_ty = StaticType::Void;
|
let mut last_ty = StaticType::Void;
|
||||||
|
|
||||||
@@ -463,15 +596,17 @@ impl TypeChecker {
|
|||||||
typed_exprs.push(Rc::new(t));
|
typed_exprs.push(Rc::new(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
(BoundKind::Block { exprs: typed_exprs }, last_ty)
|
(NodeKind::Block { exprs: typed_exprs }, last_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => {
|
} => {
|
||||||
|
let upvalues = &info.upvalues;
|
||||||
|
let positional_count = info.positional_count;
|
||||||
|
|
||||||
let mut upvalue_types = Vec::with_capacity(upvalues.len());
|
let mut upvalue_types = Vec::with_capacity(upvalues.len());
|
||||||
for &addr in upvalues {
|
for &addr in upvalues {
|
||||||
upvalue_types.push(ctx.get_type(addr));
|
upvalue_types.push(ctx.get_type(addr));
|
||||||
@@ -498,20 +633,22 @@ impl TypeChecker {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params: Rc::new(params_typed),
|
params: Rc::new(params_typed),
|
||||||
upvalues: upvalues.clone(),
|
|
||||||
body: Rc::new(body_typed),
|
body: Rc::new(body_typed),
|
||||||
positional_count: *positional_count,
|
info: LambdaBinding {
|
||||||
|
upvalues: upvalues.clone(),
|
||||||
|
positional_count,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fn_ty,
|
fn_ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
let callee_typed = self.check_node(callee, ctx, diag);
|
let callee_typed = self.check_node(callee, ctx, diag);
|
||||||
|
|
||||||
let args_typed = if let BoundKind::Tuple { elements } = &args.kind {
|
let args_typed = if let NodeKind::Tuple { elements } = &args.kind {
|
||||||
let mut typed_elements = Vec::new();
|
let mut typed_elements = Vec::new();
|
||||||
let mut elem_types = Vec::new();
|
let mut elem_types = Vec::new();
|
||||||
for e in elements {
|
for e in elements {
|
||||||
@@ -521,7 +658,7 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
Node {
|
Node {
|
||||||
identity: args.identity.clone(),
|
identity: args.identity.clone(),
|
||||||
kind: BoundKind::Tuple {
|
kind: NodeKind::Tuple {
|
||||||
elements: typed_elements,
|
elements: typed_elements,
|
||||||
},
|
},
|
||||||
ty: StaticType::Tuple(elem_types),
|
ty: StaticType::Tuple(elem_types),
|
||||||
@@ -545,7 +682,7 @@ impl TypeChecker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Call {
|
NodeKind::Call {
|
||||||
callee: Rc::new(callee_typed),
|
callee: Rc::new(callee_typed),
|
||||||
args: Rc::new(args_typed),
|
args: Rc::new(args_typed),
|
||||||
},
|
},
|
||||||
@@ -553,8 +690,8 @@ impl TypeChecker {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Again { args } => {
|
NodeKind::Again { args } => {
|
||||||
let args_typed = if let BoundKind::Tuple { elements } = &args.kind {
|
let args_typed = if let NodeKind::Tuple { elements } = &args.kind {
|
||||||
let mut typed_elements = Vec::new();
|
let mut typed_elements = Vec::new();
|
||||||
let mut elem_types = Vec::new();
|
let mut elem_types = Vec::new();
|
||||||
for e in elements {
|
for e in elements {
|
||||||
@@ -564,7 +701,7 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
Node {
|
Node {
|
||||||
identity: args.identity.clone(),
|
identity: args.identity.clone(),
|
||||||
kind: BoundKind::Tuple {
|
kind: NodeKind::Tuple {
|
||||||
elements: typed_elements,
|
elements: typed_elements,
|
||||||
},
|
},
|
||||||
ty: StaticType::Tuple(elem_types),
|
ty: StaticType::Tuple(elem_types),
|
||||||
@@ -586,14 +723,14 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Again {
|
NodeKind::Again {
|
||||||
args: Rc::new(args_typed),
|
args: Rc::new(args_typed),
|
||||||
},
|
},
|
||||||
StaticType::Any,
|
StaticType::Any,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let mut typed_elements = Vec::new();
|
let mut typed_elements = Vec::new();
|
||||||
for e in elements {
|
for e in elements {
|
||||||
typed_elements.push(Rc::new(self.check_node(e, ctx, diag)));
|
typed_elements.push(Rc::new(self.check_node(e, ctx, diag)));
|
||||||
@@ -625,49 +762,50 @@ impl TypeChecker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
BoundKind::Tuple {
|
NodeKind::Tuple {
|
||||||
elements: typed_elements,
|
elements: typed_elements,
|
||||||
},
|
},
|
||||||
ty,
|
ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let mut typed_values = Vec::with_capacity(values.len());
|
let mut typed_fields = Vec::with_capacity(fields.len());
|
||||||
let mut fields_ty = Vec::with_capacity(values.len());
|
let mut fields_ty = Vec::with_capacity(fields.len());
|
||||||
|
|
||||||
for (i, v) in values.iter().enumerate() {
|
for (i, (key_node, val_node)) in fields.iter().enumerate() {
|
||||||
let vt = self.check_node(v, ctx, diag);
|
let kt = self.check_node(key_node, ctx, diag);
|
||||||
|
let vt = self.check_node(val_node, ctx, diag);
|
||||||
fields_ty.push((layout.fields[i].0, vt.ty.clone()));
|
fields_ty.push((layout.fields[i].0, vt.ty.clone()));
|
||||||
typed_values.push(Rc::new(vt));
|
typed_fields.push((Rc::new(kt), Rc::new(vt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_layout = crate::ast::types::RecordLayout::get_or_create(fields_ty);
|
let new_layout = crate::ast::types::RecordLayout::get_or_create(fields_ty);
|
||||||
(
|
(
|
||||||
BoundKind::Record {
|
NodeKind::Record {
|
||||||
|
fields: typed_fields,
|
||||||
layout: new_layout.clone(),
|
layout: new_layout.clone(),
|
||||||
values: typed_values,
|
|
||||||
},
|
},
|
||||||
StaticType::Record(new_layout),
|
StaticType::Record(new_layout),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call,
|
original_call,
|
||||||
bound_expanded,
|
expanded,
|
||||||
} => {
|
} => {
|
||||||
let expanded_typed = self.check_node(bound_expanded, ctx, diag);
|
let expanded_typed = self.check_node(expanded, ctx, diag);
|
||||||
let ty = expanded_typed.ty.clone();
|
let ty = expanded_typed.ty.clone();
|
||||||
(
|
(
|
||||||
BoundKind::Expansion {
|
NodeKind::Expansion {
|
||||||
original_call: original_call.clone(),
|
original_call: original_call.clone(),
|
||||||
bound_expanded: Rc::new(expanded_typed),
|
expanded: Rc::new(expanded_typed),
|
||||||
},
|
},
|
||||||
ty,
|
ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Extension(_ext) => {
|
NodeKind::Extension(_ext) => {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
format!(
|
format!(
|
||||||
"TypeChecking for extension '{}' not implemented",
|
"TypeChecking for extension '{}' not implemented",
|
||||||
@@ -675,9 +813,21 @@ impl TypeChecker {
|
|||||||
),
|
),
|
||||||
Some(node.identity.clone()),
|
Some(node.identity.clone()),
|
||||||
);
|
);
|
||||||
(BoundKind::Error, StaticType::Error)
|
(NodeKind::Error, StaticType::Error)
|
||||||
|
}
|
||||||
|
NodeKind::Error => (NodeKind::Error, StaticType::Error),
|
||||||
|
|
||||||
|
// Syntax-only variants should not appear in bound phases
|
||||||
|
NodeKind::MacroDecl { .. }
|
||||||
|
| NodeKind::Template(_)
|
||||||
|
| NodeKind::Placeholder(_)
|
||||||
|
| NodeKind::Splice(_) => {
|
||||||
|
diag.push_error(
|
||||||
|
"Unexpected syntax-only node in type checking",
|
||||||
|
Some(node.identity.clone()),
|
||||||
|
);
|
||||||
|
(NodeKind::Error, StaticType::Error)
|
||||||
}
|
}
|
||||||
BoundKind::Error => (BoundKind::Error, StaticType::Error),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Node {
|
Node {
|
||||||
@@ -752,8 +902,8 @@ mod tests {
|
|||||||
// (do (def x 10) x) -> The last 'x' must be Int
|
// (do (def x 10) x) -> The last 'x' must be Int
|
||||||
let typed = check_source("(do (def x 10) x)");
|
let typed = check_source("(do (def x 10) x)");
|
||||||
// Outer is Lambda, Body is Block
|
// Outer is Lambda, Body is Block
|
||||||
if let BoundKind::Lambda { body, .. } = &typed.kind {
|
if let NodeKind::Lambda { body, .. } = &typed.kind {
|
||||||
if let BoundKind::Block { exprs } = &body.kind {
|
if let NodeKind::Block { exprs } = &body.kind {
|
||||||
let last_expr = exprs.last().unwrap();
|
let last_expr = exprs.last().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_expr.ty,
|
last_expr.ty,
|
||||||
@@ -802,8 +952,8 @@ mod tests {
|
|||||||
fn test_inference_assignment_updates_type() {
|
fn test_inference_assignment_updates_type() {
|
||||||
// (do (def x 10) (assign x 20.5) x) -> x becomes Float after assignment
|
// (do (def x 10) (assign x 20.5) x) -> x becomes Float after assignment
|
||||||
let typed = check_source("(do (def x 10) (assign x 20.5) x)");
|
let typed = check_source("(do (def x 10) (assign x 20.5) x)");
|
||||||
if let BoundKind::Lambda { body, .. } = &typed.kind {
|
if let NodeKind::Lambda { body, .. } = &typed.kind {
|
||||||
if let BoundKind::Block { exprs } = &body.kind {
|
if let NodeKind::Block { exprs } = &body.kind {
|
||||||
let last_expr = exprs.last().unwrap();
|
let last_expr = exprs.last().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_expr.ty,
|
last_expr.ty,
|
||||||
|
|||||||
+18
-17
@@ -10,8 +10,8 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::ast::compiler::bound_nodes::{
|
use crate::ast::compiler::bound_nodes::{
|
||||||
Address, AnalyzedNode, BoundKind, ExecNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, GlobalIdx,
|
Address, AnalyzedNode, ExecNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, GlobalIdx,
|
||||||
Node, VirtualId,
|
LambdaBinding, Node, NodeKind, VirtualId,
|
||||||
};
|
};
|
||||||
use crate::ast::compiler::dumper::Dumper;
|
use crate::ast::compiler::dumper::Dumper;
|
||||||
use crate::ast::compiler::lambda_collector::LambdaCollector;
|
use crate::ast::compiler::lambda_collector::LambdaCollector;
|
||||||
@@ -117,7 +117,7 @@ impl MacroEvaluator for RuntimeMacroEvaluator {
|
|||||||
node: &SyntaxNode,
|
node: &SyntaxNode,
|
||||||
bindings: &HashMap<Rc<str>, SyntaxNode>,
|
bindings: &HashMap<Rc<str>, SyntaxNode>,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
if let SyntaxKind::Identifier(sym) = &node.kind
|
if let SyntaxKind::Identifier { symbol: sym, .. } = &node.kind
|
||||||
&& let Some(arg_node) = bindings.get(&sym.name)
|
&& let Some(arg_node) = bindings.get(&sym.name)
|
||||||
{
|
{
|
||||||
return Ok(Value::Object(Rc::new(arg_node.clone()) as Rc<dyn Object>));
|
return Ok(Value::Object(Rc::new(arg_node.clone()) as Rc<dyn Object>));
|
||||||
@@ -390,8 +390,8 @@ impl Environment {
|
|||||||
|
|
||||||
fn discover_globals(&self, node: &SyntaxNode) {
|
fn discover_globals(&self, node: &SyntaxNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Def { target, .. } => {
|
SyntaxKind::Def { pattern, .. } => {
|
||||||
if let SyntaxKind::Identifier(sym) = &target.kind {
|
if let SyntaxKind::Identifier { symbol: sym, .. } = &pattern.kind {
|
||||||
let mut root_scopes = self.root_scopes.borrow_mut();
|
let mut root_scopes = self.root_scopes.borrow_mut();
|
||||||
let last_idx = root_scopes.len() - 1;
|
let last_idx = root_scopes.len() - 1;
|
||||||
let current_scope = &mut root_scopes[last_idx];
|
let current_scope = &mut root_scopes[last_idx];
|
||||||
@@ -417,9 +417,9 @@ impl Environment {
|
|||||||
|
|
||||||
fn extract_names(node: &SyntaxNode) -> Vec<Rc<str>> {
|
fn extract_names(node: &SyntaxNode) -> Vec<Rc<str>> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
SyntaxKind::Identifier(sym) => vec![sym.name.clone()],
|
SyntaxKind::Identifier { symbol: sym, .. } => vec![sym.name.clone()],
|
||||||
SyntaxKind::Tuple { elements } => {
|
SyntaxKind::Tuple { elements } => {
|
||||||
elements.iter().flat_map(extract_names).collect()
|
elements.iter().flat_map(|e| extract_names(e)).collect()
|
||||||
}
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
@@ -476,20 +476,22 @@ impl Environment {
|
|||||||
LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut());
|
LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut());
|
||||||
|
|
||||||
let checker = TypeChecker::new(self.root_types.clone());
|
let checker = TypeChecker::new(self.root_types.clone());
|
||||||
let wrapped_ast = if let BoundKind::Lambda { .. } = bound_ast.kind {
|
let wrapped_ast = if let NodeKind::Lambda { .. } = bound_ast.kind {
|
||||||
bound_ast
|
bound_ast
|
||||||
} else {
|
} else {
|
||||||
Node {
|
Node {
|
||||||
identity: bound_ast.identity.clone(),
|
identity: bound_ast.identity.clone(),
|
||||||
kind: BoundKind::Lambda {
|
kind: NodeKind::Lambda {
|
||||||
params: std::rc::Rc::new(Node {
|
params: std::rc::Rc::new(Node {
|
||||||
identity: bound_ast.identity.clone(),
|
identity: bound_ast.identity.clone(),
|
||||||
kind: BoundKind::Tuple { elements: vec![] },
|
kind: NodeKind::Tuple { elements: vec![] },
|
||||||
ty: (),
|
ty: (),
|
||||||
}),
|
}),
|
||||||
upvalues: vec![],
|
|
||||||
body: std::rc::Rc::new(bound_ast),
|
body: std::rc::Rc::new(bound_ast),
|
||||||
positional_count: Some(0),
|
info: LambdaBinding {
|
||||||
|
upvalues: vec![],
|
||||||
|
positional_count: Some(0),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ty: (),
|
ty: (),
|
||||||
}
|
}
|
||||||
@@ -650,20 +652,19 @@ impl Environment {
|
|||||||
|
|
||||||
pub fn instantiate(&self, node: ExecNode) -> Rc<crate::ast::types::NativeFunction> {
|
pub fn instantiate(&self, node: ExecNode) -> Rc<crate::ast::types::NativeFunction> {
|
||||||
let root_values = self.root_values.clone();
|
let root_values = self.root_values.clone();
|
||||||
if let BoundKind::Lambda {
|
if let NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} = &node.kind
|
} = &node.kind
|
||||||
&& upvalues.is_empty()
|
&& info.upvalues.is_empty()
|
||||||
{
|
{
|
||||||
let closure = Rc::new(crate::ast::vm::Closure::new(
|
let closure = Rc::new(crate::ast::vm::Closure::new(
|
||||||
params.clone(),
|
params.clone(),
|
||||||
body.ty.original.clone(),
|
body.ty.original.clone(),
|
||||||
body.clone(),
|
body.clone(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
*positional_count,
|
info.positional_count,
|
||||||
node.ty.stack_size,
|
node.ty.stack_size,
|
||||||
));
|
));
|
||||||
let closure_obj: Rc<dyn crate::ast::types::Object> = closure;
|
let closure_obj: Rc<dyn crate::ast::types::Object> = closure;
|
||||||
|
|||||||
+8
-77
@@ -1,4 +1,5 @@
|
|||||||
use crate::ast::types::{Identity, Object, Value};
|
use crate::ast::compiler::bound_nodes::{Node, NodeKind, SyntaxPhase};
|
||||||
|
use crate::ast::types::{Identity, Object};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -30,14 +31,13 @@ impl From<&str> for Symbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A parser AST Node wrapper to preserve identity and metadata
|
/// Type alias: the parser AST is now `Node<SyntaxPhase>`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
pub type SyntaxNode = Node<SyntaxPhase>;
|
||||||
pub struct SyntaxNode {
|
|
||||||
pub identity: Identity,
|
|
||||||
pub kind: SyntaxKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Object for SyntaxNode {
|
/// Type alias: the parser AST kind is now `NodeKind<SyntaxPhase>`.
|
||||||
|
pub type SyntaxKind = NodeKind<SyntaxPhase>;
|
||||||
|
|
||||||
|
impl Object for Node<SyntaxPhase> {
|
||||||
fn type_name(&self) -> &'static str {
|
fn type_name(&self) -> &'static str {
|
||||||
"ast-node"
|
"ast-node"
|
||||||
}
|
}
|
||||||
@@ -58,75 +58,6 @@ impl Clone for Box<dyn CustomNode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum SyntaxKind {
|
|
||||||
Nop,
|
|
||||||
Constant(Value),
|
|
||||||
/// A general identifier (used for both references and declarations in the syntax AST).
|
|
||||||
Identifier(Symbol),
|
|
||||||
/// A first-class field accessor (e.g. .name)
|
|
||||||
FieldAccessor(crate::ast::types::Keyword),
|
|
||||||
If {
|
|
||||||
cond: Box<SyntaxNode>,
|
|
||||||
then_br: Box<SyntaxNode>,
|
|
||||||
else_br: Option<Box<SyntaxNode>>,
|
|
||||||
},
|
|
||||||
Def {
|
|
||||||
target: Box<SyntaxNode>,
|
|
||||||
value: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Assign {
|
|
||||||
target: Box<SyntaxNode>,
|
|
||||||
value: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Lambda {
|
|
||||||
params: Box<SyntaxNode>,
|
|
||||||
body: Rc<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Call {
|
|
||||||
callee: Box<SyntaxNode>,
|
|
||||||
args: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Again {
|
|
||||||
args: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Pipe {
|
|
||||||
inputs: Vec<SyntaxNode>,
|
|
||||||
lambda: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Block {
|
|
||||||
exprs: Vec<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Tuple {
|
|
||||||
elements: Vec<SyntaxNode>,
|
|
||||||
},
|
|
||||||
Record {
|
|
||||||
fields: Vec<(SyntaxNode, SyntaxNode)>,
|
|
||||||
},
|
|
||||||
/// A macro declaration that can be expanded at compile time.
|
|
||||||
MacroDecl {
|
|
||||||
name: Symbol,
|
|
||||||
params: Box<SyntaxNode>,
|
|
||||||
body: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
/// A template for AST nodes, allowing for substitutions. (Quasiquote)
|
|
||||||
Template(Box<SyntaxNode>),
|
|
||||||
/// A placeholder inside a template to be replaced by a node or value. (Unquote)
|
|
||||||
Placeholder(Box<SyntaxNode>),
|
|
||||||
/// A placeholder that flattens a sequence or merges a record into its surroundings. (Splice)
|
|
||||||
Splice(Box<SyntaxNode>),
|
|
||||||
/// Represents an expanded macro call, preserving the original call for debugging.
|
|
||||||
Expansion {
|
|
||||||
/// The original call from the source AST.
|
|
||||||
call: Box<SyntaxNode>,
|
|
||||||
/// The resulting AST after macro expansion.
|
|
||||||
expanded: Box<SyntaxNode>,
|
|
||||||
},
|
|
||||||
/// A diagnostic poison node, allowing compilation to continue after an error.
|
|
||||||
Error,
|
|
||||||
Extension(Box<dyn CustomNode>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Box<dyn CustomNode> {
|
impl PartialEq for Box<dyn CustomNode> {
|
||||||
fn eq(&self, _other: &Self) -> bool {
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
false
|
false
|
||||||
|
|||||||
+86
-64
@@ -64,16 +64,16 @@ impl<'a> Parser<'a> {
|
|||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Call {
|
kind: SyntaxKind::Call {
|
||||||
callee: Box::new(self.make_id_node("quote", identity.clone())),
|
callee: Rc::new(self.make_id_node("quote", identity.clone())),
|
||||||
args: Box::new(SyntaxNode {
|
args: Rc::new(SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Tuple {
|
kind: SyntaxKind::Tuple {
|
||||||
elements: vec![expr],
|
elements: vec![Rc::new(expr)],
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Backtick => {
|
TokenKind::Backtick => {
|
||||||
@@ -81,8 +81,8 @@ impl<'a> Parser<'a> {
|
|||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Template(Box::new(expr)),
|
kind: SyntaxKind::Template(Rc::new(expr)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Tilde => {
|
TokenKind::Tilde => {
|
||||||
@@ -92,15 +92,15 @@ impl<'a> Parser<'a> {
|
|||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Splice(Box::new(expr)),
|
kind: SyntaxKind::Splice(Rc::new(expr)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Placeholder(Box::new(expr)),
|
kind: SyntaxKind::Placeholder(Rc::new(expr)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,10 @@ impl<'a> Parser<'a> {
|
|||||||
s if s.starts_with('.') && s.len() > 1 => {
|
s if s.starts_with('.') && s.len() > 1 => {
|
||||||
SyntaxKind::FieldAccessor(Keyword::intern(&s[1..]))
|
SyntaxKind::FieldAccessor(Keyword::intern(&s[1..]))
|
||||||
}
|
}
|
||||||
_ => SyntaxKind::Identifier(id.into()),
|
_ => SyntaxKind::Identifier {
|
||||||
|
symbol: id.into(),
|
||||||
|
binding: (),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
TokenKind::EOF => SyntaxKind::Error, // Error already logged by advance
|
TokenKind::EOF => SyntaxKind::Error, // Error already logged by advance
|
||||||
_ => {
|
_ => {
|
||||||
@@ -155,6 +158,7 @@ impl<'a> Parser<'a> {
|
|||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind,
|
kind,
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,14 +175,14 @@ impl<'a> Parser<'a> {
|
|||||||
return SyntaxNode {
|
return SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Error,
|
kind: SyntaxKind::Error,
|
||||||
|
ty: (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = self.parse_expression();
|
let head = self.parse_expression();
|
||||||
|
|
||||||
let node = if let SyntaxKind::Identifier(ref sym) = head.kind {
|
let node = if let SyntaxKind::Identifier { ref symbol, .. } = head.kind {
|
||||||
match sym.name.as_ref() {
|
match symbol.name.as_ref() {
|
||||||
"if" => self.parse_if(identity),
|
"if" => self.parse_if(identity),
|
||||||
"fn" => self.parse_fn(identity),
|
"fn" => self.parse_fn(identity),
|
||||||
"pipe" => self.parse_pipe(identity),
|
"pipe" => self.parse_pipe(identity),
|
||||||
@@ -201,31 +205,31 @@ impl<'a> Parser<'a> {
|
|||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||||
elements.push(self.parse_expression());
|
elements.push(Rc::new(self.parse_expression()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let args_node = SyntaxNode {
|
let args_node = SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Tuple { elements },
|
kind: SyntaxKind::Tuple { elements },
|
||||||
|
ty: (),
|
||||||
};
|
};
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Again {
|
kind: SyntaxKind::Again {
|
||||||
args: Box::new(args_node),
|
args: Rc::new(args_node),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_if(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_if(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
let cond = Box::new(self.parse_expression());
|
let cond = Rc::new(self.parse_expression());
|
||||||
let then_br = Box::new(self.parse_expression());
|
let then_br = Rc::new(self.parse_expression());
|
||||||
let mut else_br = None;
|
let mut else_br = None;
|
||||||
|
|
||||||
if *self.peek() != TokenKind::RightParen {
|
if *self.peek() != TokenKind::RightParen {
|
||||||
else_br = Some(Box::new(self.parse_expression()));
|
else_br = Some(Rc::new(self.parse_expression()));
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
@@ -235,42 +239,50 @@ impl<'a> Parser<'a> {
|
|||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_def(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_def(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
let target = Box::new(self.parse_pattern());
|
let pattern = Rc::new(self.parse_pattern());
|
||||||
let value = Box::new(self.parse_expression());
|
let value = Rc::new(self.parse_expression());
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Def { target, value },
|
kind: SyntaxKind::Def {
|
||||||
|
pattern,
|
||||||
|
value,
|
||||||
|
info: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_assign(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_assign(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
// (assign target value)
|
// (assign target value)
|
||||||
let target = Box::new(self.parse_expression());
|
let target = Rc::new(self.parse_expression());
|
||||||
let value = Box::new(self.parse_expression());
|
let value = Rc::new(self.parse_expression());
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Assign { target, value },
|
kind: SyntaxKind::Assign {
|
||||||
|
target,
|
||||||
|
value,
|
||||||
|
info: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_do(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_do(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||||
exprs.push(self.parse_expression());
|
exprs.push(Rc::new(self.parse_expression()));
|
||||||
}
|
}
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Block { exprs },
|
kind: SyntaxKind::Block { exprs },
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,19 +290,19 @@ impl<'a> Parser<'a> {
|
|||||||
let inputs_node = self.parse_expression();
|
let inputs_node = self.parse_expression();
|
||||||
let inputs = match inputs_node.kind {
|
let inputs = match inputs_node.kind {
|
||||||
SyntaxKind::Tuple { elements } => elements,
|
SyntaxKind::Tuple { elements } => elements,
|
||||||
_ => vec![inputs_node],
|
_ => vec![Rc::new(inputs_node)],
|
||||||
};
|
};
|
||||||
let lambda = Box::new(self.parse_expression());
|
let lambda = Rc::new(self.parse_expression());
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Pipe { inputs, lambda },
|
kind: SyntaxKind::Pipe { inputs, lambda },
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_fn(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
let params = Box::new(self.parse_param_vector());
|
let params = Rc::new(self.parse_param_vector());
|
||||||
let body = self.parse_expression();
|
let body = self.parse_expression();
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
@@ -298,15 +310,16 @@ impl<'a> Parser<'a> {
|
|||||||
kind: SyntaxKind::Lambda {
|
kind: SyntaxKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body: Rc::new(body),
|
body: Rc::new(body),
|
||||||
|
info: (),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_macro_decl(&mut self, identity: Identity) -> SyntaxNode {
|
fn parse_macro_decl(&mut self, identity: Identity) -> SyntaxNode {
|
||||||
let name_node = self.parse_expression();
|
let name_node = self.parse_expression();
|
||||||
let name = match name_node.kind {
|
let name = match name_node.kind {
|
||||||
SyntaxKind::Identifier(sym) => sym,
|
SyntaxKind::Identifier { symbol, .. } => symbol,
|
||||||
_ => {
|
_ => {
|
||||||
self.diagnostics.push_error(
|
self.diagnostics.push_error(
|
||||||
"Expected identifier for macro name",
|
"Expected identifier for macro name",
|
||||||
@@ -315,16 +328,16 @@ impl<'a> Parser<'a> {
|
|||||||
Symbol::from("error")
|
Symbol::from("error")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let params = Box::new(self.parse_param_vector());
|
let params = Rc::new(self.parse_param_vector());
|
||||||
let body = self.parse_expression();
|
let body = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::MacroDecl {
|
kind: SyntaxKind::MacroDecl {
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
body: Box::new(body),
|
body: Rc::new(body),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +353,7 @@ impl<'a> Parser<'a> {
|
|||||||
return SyntaxNode {
|
return SyntaxNode {
|
||||||
identity: NodeIdentity::new(self.current_token.location),
|
identity: NodeIdentity::new(self.current_token.location),
|
||||||
kind: SyntaxKind::Error,
|
kind: SyntaxKind::Error,
|
||||||
|
ty: (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.parse_pattern()
|
self.parse_pattern()
|
||||||
@@ -357,8 +370,11 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(token.location),
|
identity: NodeIdentity::new(token.location),
|
||||||
kind: SyntaxKind::Identifier(sym),
|
kind: SyntaxKind::Identifier {
|
||||||
|
symbol: sym,
|
||||||
|
binding: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::LeftBracket => {
|
TokenKind::LeftBracket => {
|
||||||
@@ -367,14 +383,14 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||||
elements.push(self.parse_pattern());
|
elements.push(Rc::new(self.parse_pattern()));
|
||||||
}
|
}
|
||||||
self.expect(TokenKind::RightBracket);
|
self.expect(TokenKind::RightBracket);
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Tuple { elements },
|
kind: SyntaxKind::Tuple { elements },
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Tilde => {
|
TokenKind::Tilde => {
|
||||||
@@ -384,15 +400,15 @@ impl<'a> Parser<'a> {
|
|||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(token.location),
|
identity: NodeIdentity::new(token.location),
|
||||||
kind: SyntaxKind::Splice(Box::new(expr)),
|
kind: SyntaxKind::Splice(Rc::new(expr)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(token.location),
|
identity: NodeIdentity::new(token.location),
|
||||||
kind: SyntaxKind::Placeholder(Box::new(expr)),
|
kind: SyntaxKind::Placeholder(Rc::new(expr)),
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,7 +424,7 @@ impl<'a> Parser<'a> {
|
|||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(self.current_token.location),
|
identity: NodeIdentity::new(self.current_token.location),
|
||||||
kind: SyntaxKind::Error,
|
kind: SyntaxKind::Error,
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,23 +434,23 @@ impl<'a> Parser<'a> {
|
|||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||||
elements.push(self.parse_expression());
|
elements.push(Rc::new(self.parse_expression()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The arguments are wrapped in a Tuple node, reusing the call's identity/location.
|
// The arguments are wrapped in a Tuple node, reusing the call's identity/location.
|
||||||
let args_node = SyntaxNode {
|
let args_node = SyntaxNode {
|
||||||
identity: identity.clone(),
|
identity: identity.clone(),
|
||||||
kind: SyntaxKind::Tuple { elements },
|
kind: SyntaxKind::Tuple { elements },
|
||||||
|
ty: (),
|
||||||
};
|
};
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Call {
|
kind: SyntaxKind::Call {
|
||||||
callee: Box::new(callee),
|
callee: Rc::new(callee),
|
||||||
args: Box::new(args_node),
|
args: Rc::new(args_node),
|
||||||
},
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,7 +460,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||||
let expr = self.parse_expression();
|
let expr = self.parse_expression();
|
||||||
elements.push(expr);
|
elements.push(Rc::new(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(TokenKind::RightBracket);
|
self.expect(TokenKind::RightBracket);
|
||||||
@@ -452,7 +468,7 @@ impl<'a> Parser<'a> {
|
|||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(token.location),
|
identity: NodeIdentity::new(token.location),
|
||||||
kind: SyntaxKind::Tuple { elements },
|
kind: SyntaxKind::Tuple { elements },
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,14 +500,17 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
let val_node = self.parse_expression();
|
let val_node = self.parse_expression();
|
||||||
|
|
||||||
fields.push((key_node, val_node));
|
fields.push((Rc::new(key_node), Rc::new(val_node)));
|
||||||
}
|
}
|
||||||
self.expect(TokenKind::RightBrace);
|
self.expect(TokenKind::RightBrace);
|
||||||
|
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity: NodeIdentity::new(token.location),
|
identity: NodeIdentity::new(token.location),
|
||||||
kind: SyntaxKind::Record { fields },
|
kind: SyntaxKind::Record {
|
||||||
|
fields,
|
||||||
|
layout: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,8 +534,11 @@ impl<'a> Parser<'a> {
|
|||||||
fn make_id_node(&self, name: &str, identity: Identity) -> SyntaxNode {
|
fn make_id_node(&self, name: &str, identity: Identity) -> SyntaxNode {
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
identity,
|
identity,
|
||||||
kind: SyntaxKind::Identifier(Symbol::from(name)),
|
kind: SyntaxKind::Identifier {
|
||||||
|
symbol: Symbol::from(name),
|
||||||
|
binding: (),
|
||||||
|
},
|
||||||
|
ty: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+99
-86
@@ -1,4 +1,4 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, ExecNode, StackOffset};
|
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, ExecNode, IdentifierBinding, NodeKind, StackOffset};
|
||||||
use crate::ast::types::{Object, Value};
|
use crate::ast::types::{Object, Value};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -105,7 +105,7 @@ impl VMObserver for TracingObserver {
|
|||||||
self.indent = self.indent.saturating_sub(1);
|
self.indent = self.indent.saturating_sub(1);
|
||||||
let pad = self.pad();
|
let pad = self.pad();
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define { .. } | BoundKind::Set { .. } => {
|
NodeKind::Def { .. } | NodeKind::Assign { .. } => {
|
||||||
let s_pad = format!("{}| ", pad);
|
let s_pad = format!("{}| ", pad);
|
||||||
self.logs.push(format!("{}--- Scope Status ---", s_pad));
|
self.logs.push(format!("{}--- Scope Status ---", s_pad));
|
||||||
self.logs.push(format!(
|
self.logs.push(format!(
|
||||||
@@ -303,58 +303,76 @@ impl VM {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eval_core<O: VMObserver>(&mut self, obs: &mut O, node: &ExecNode) -> Result<Value, String> {
|
fn eval_core<O: VMObserver>(&mut self, obs: &mut O, node: &ExecNode) -> Result<Value, String> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Nop => Ok(Value::Void),
|
NodeKind::Nop => Ok(Value::Void),
|
||||||
BoundKind::Constant(v) => Ok(v.clone()),
|
NodeKind::Constant(v) => Ok(v.clone()),
|
||||||
BoundKind::Define {
|
NodeKind::Def { pattern, value, info } => {
|
||||||
addr,
|
|
||||||
value,
|
|
||||||
captured_by,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let val = self.eval_internal(obs, value)?;
|
let val = self.eval_internal(obs, value)?;
|
||||||
|
match &pattern.kind {
|
||||||
|
NodeKind::Identifier { binding, .. } => {
|
||||||
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Declaration { addr, .. } | IdentifierBinding::Reference(addr) => *addr,
|
||||||
|
};
|
||||||
|
|
||||||
let mut needs_cell_wrap = false;
|
let mut needs_cell_wrap = false;
|
||||||
if !captured_by.is_empty()
|
if !info.captured_by.is_empty()
|
||||||
&& let Address::Local(slot) = addr
|
&& let Address::Local(slot) = addr
|
||||||
{
|
{
|
||||||
let frame = self.frames.last().unwrap();
|
let frame = self.frames.last().unwrap();
|
||||||
let abs_index = frame.stack_base + (slot.0 as usize);
|
let abs_index = frame.stack_base + (slot.0 as usize);
|
||||||
|
|
||||||
// Robustness Fix: If the slot is already a Cell (due to forward capture
|
// Robustness Fix: If the slot is already a Cell (due to forward capture
|
||||||
// in a recursive scenario or complex pre-allocation), don't wrap it again.
|
// in a recursive scenario or complex pre-allocation), don't wrap it again.
|
||||||
// This prevents Cell(Cell(Value)) nesting which causes type errors.
|
// This prevents Cell(Cell(Value)) nesting which causes type errors.
|
||||||
if abs_index >= self.stack.len() || !matches!(self.stack[abs_index], Value::Cell(_)) {
|
if abs_index >= self.stack.len() || !matches!(self.stack[abs_index], Value::Cell(_)) {
|
||||||
needs_cell_wrap = true;
|
needs_cell_wrap = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let store_val = if needs_cell_wrap {
|
||||||
|
Value::Cell(Rc::new(RefCell::new(val.clone())))
|
||||||
|
} else {
|
||||||
|
val.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_value(addr, store_val)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Destructuring (was Destructure variant)
|
||||||
|
let mut offset = 0;
|
||||||
|
if let Some(vals) = val.as_slice() {
|
||||||
|
self.unpack(pattern.as_ref(), vals, &mut offset)?;
|
||||||
|
} else {
|
||||||
|
self.unpack(pattern.as_ref(), std::slice::from_ref(&val), &mut offset)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Def always evaluates to the unwrapped value for immediate use.
|
||||||
let store_val = if needs_cell_wrap {
|
|
||||||
Value::Cell(Rc::new(RefCell::new(val.clone())))
|
|
||||||
} else {
|
|
||||||
val.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.set_value(*addr, store_val)?;
|
|
||||||
// Define always evaluates to the unwrapped value for immediate use.
|
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
BoundKind::Destructure { pattern, value } => {
|
NodeKind::Assign { target, value, info } => {
|
||||||
let val = self.eval_internal(obs, value)?;
|
let val = self.eval_internal(obs, value)?;
|
||||||
let mut offset = 0;
|
if let Some(addr) = info.addr {
|
||||||
|
self.set_value(addr, val.clone())?;
|
||||||
// Destructuring works on tuples/vectors, or single values wrapped in a slice
|
|
||||||
if let Some(vals) = val.as_slice() {
|
|
||||||
self.unpack(pattern.as_ref(), vals, &mut offset)?;
|
|
||||||
} else {
|
} else {
|
||||||
self.unpack(pattern.as_ref(), std::slice::from_ref(&val), &mut offset)?;
|
// Destructuring assign
|
||||||
|
let mut offset = 0;
|
||||||
|
if let Some(vals) = val.as_slice() {
|
||||||
|
self.unpack(target.as_ref(), vals, &mut offset)?;
|
||||||
|
} else {
|
||||||
|
self.unpack(target.as_ref(), std::slice::from_ref(&val), &mut offset)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
BoundKind::Get { addr, .. } => self.get_value(*addr),
|
NodeKind::Identifier { binding, .. } => {
|
||||||
|
match binding {
|
||||||
|
IdentifierBinding::Reference(addr) | IdentifierBinding::Declaration { addr, .. } => self.get_value(*addr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BoundKind::FieldAccessor(k) => Ok(Value::FieldAccessor(*k)),
|
NodeKind::FieldAccessor(k) => Ok(Value::FieldAccessor(*k)),
|
||||||
|
|
||||||
BoundKind::GetField { rec, field } => {
|
NodeKind::GetField { rec, field } => {
|
||||||
let rec_val = self.eval_internal(obs, rec)?;
|
let rec_val = self.eval_internal(obs, rec)?;
|
||||||
|
|
||||||
match rec_val {
|
match rec_val {
|
||||||
@@ -395,12 +413,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundKind::Set { addr, value } => {
|
NodeKind::If {
|
||||||
let val = self.eval_internal(obs, value)?;
|
|
||||||
self.set_value(*addr, val.clone())?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
BoundKind::If {
|
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
@@ -414,10 +427,9 @@ impl VM {
|
|||||||
Ok(Value::Void)
|
Ok(Value::Void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Pipe {
|
NodeKind::Pipe {
|
||||||
inputs,
|
inputs,
|
||||||
lambda,
|
lambda,
|
||||||
out_type,
|
|
||||||
} => {
|
} => {
|
||||||
use crate::ast::rtl::streams::StreamNode;
|
use crate::ast::rtl::streams::StreamNode;
|
||||||
|
|
||||||
@@ -464,25 +476,24 @@ impl VM {
|
|||||||
|
|
||||||
// Delegate to the RTL Factory for specialized buffer instantiation
|
// Delegate to the RTL Factory for specialized buffer instantiation
|
||||||
let node =
|
let node =
|
||||||
crate::ast::rtl::streams::build_pipeline_node(obs_streams, executor, out_type);
|
crate::ast::rtl::streams::build_pipeline_node(obs_streams, executor, &node.ty.ty);
|
||||||
|
|
||||||
Ok(Value::Object(node))
|
Ok(Value::Object(node))
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
NodeKind::Block { exprs } => {
|
||||||
let mut last = Value::Void;
|
let mut last = Value::Void;
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
last = self.eval_internal(obs, e)?;
|
last = self.eval_internal(obs, e)?;
|
||||||
}
|
}
|
||||||
Ok(last)
|
Ok(last)
|
||||||
}
|
}
|
||||||
BoundKind::Lambda {
|
NodeKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
|
||||||
body,
|
body,
|
||||||
positional_count,
|
info,
|
||||||
} => {
|
} => {
|
||||||
let mut captured = Vec::with_capacity(upvalues.len());
|
let mut captured = Vec::with_capacity(info.upvalues.len());
|
||||||
for addr in upvalues {
|
for addr in &info.upvalues {
|
||||||
captured.push(self.capture_upvalue(*addr)?);
|
captured.push(self.capture_upvalue(*addr)?);
|
||||||
}
|
}
|
||||||
let stack_size = node.ty.stack_size;
|
let stack_size = node.ty.stack_size;
|
||||||
@@ -491,12 +502,12 @@ impl VM {
|
|||||||
body.ty.original.clone(),
|
body.ty.original.clone(),
|
||||||
body.clone(),
|
body.clone(),
|
||||||
captured,
|
captured,
|
||||||
*positional_count,
|
info.positional_count,
|
||||||
stack_size,
|
stack_size,
|
||||||
);
|
);
|
||||||
Ok(Value::Object(Rc::new(closure)))
|
Ok(Value::Object(Rc::new(closure)))
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
NodeKind::Call { callee, args } => {
|
||||||
let func_val = self.eval_internal(obs, callee)?;
|
let func_val = self.eval_internal(obs, callee)?;
|
||||||
|
|
||||||
let base = self.stack.len();
|
let base = self.stack.len();
|
||||||
@@ -654,7 +665,7 @@ impl VM {
|
|||||||
} else {
|
} else {
|
||||||
let args_for_unpack = self.stack[base..].to_vec();
|
let args_for_unpack = self.stack[base..].to_vec();
|
||||||
self.stack.truncate(base);
|
self.stack.truncate(base);
|
||||||
if let BoundKind::Tuple { elements } =
|
if let NodeKind::Tuple { elements } =
|
||||||
&closure.parameter_node.kind
|
&closure.parameter_node.kind
|
||||||
{
|
{
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
@@ -755,7 +766,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Again { args } => {
|
NodeKind::Again { args } => {
|
||||||
let base = self.stack.len();
|
let base = self.stack.len();
|
||||||
if let Err(e) = self.eval_args_to_stack(obs, args) {
|
if let Err(e) = self.eval_args_to_stack(obs, args) {
|
||||||
self.stack.truncate(base);
|
self.stack.truncate(base);
|
||||||
@@ -774,16 +785,16 @@ impl VM {
|
|||||||
Err("'again' called outside of a closure".to_string())
|
Err("'again' called outside of a closure".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let mut vals = Vec::with_capacity(elements.len());
|
let mut vals = Vec::with_capacity(elements.len());
|
||||||
for e in elements {
|
for e in elements {
|
||||||
vals.push(self.eval_internal(obs, e)?);
|
vals.push(self.eval_internal(obs, e)?);
|
||||||
}
|
}
|
||||||
Ok(Value::make_tuple(vals))
|
Ok(Value::make_tuple(vals))
|
||||||
}
|
}
|
||||||
BoundKind::Record { layout, values } => {
|
NodeKind::Record { fields, layout } => {
|
||||||
let mut evaluated_values = Vec::with_capacity(values.len());
|
let mut evaluated_values = Vec::with_capacity(fields.len());
|
||||||
for v in values {
|
for (_, v) in fields {
|
||||||
evaluated_values.push(self.eval_internal(obs, v)?);
|
evaluated_values.push(self.eval_internal(obs, v)?);
|
||||||
}
|
}
|
||||||
Ok(Value::Record(
|
Ok(Value::Record(
|
||||||
@@ -791,11 +802,11 @@ impl VM {
|
|||||||
std::rc::Rc::new(evaluated_values),
|
std::rc::Rc::new(evaluated_values),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
NodeKind::Expansion { expanded, .. } => {
|
||||||
let mut curr = bound_expanded;
|
let mut curr = expanded;
|
||||||
if !O::ACTIVE {
|
if !O::ACTIVE {
|
||||||
while let BoundKind::Expansion {
|
while let NodeKind::Expansion {
|
||||||
bound_expanded: next,
|
expanded: next,
|
||||||
..
|
..
|
||||||
} = &curr.kind
|
} = &curr.kind
|
||||||
{
|
{
|
||||||
@@ -804,11 +815,15 @@ impl VM {
|
|||||||
}
|
}
|
||||||
self.eval_internal(obs, curr)
|
self.eval_internal(obs, curr)
|
||||||
}
|
}
|
||||||
BoundKind::Extension(ext) => Err(format!(
|
NodeKind::Extension(ext) => Err(format!(
|
||||||
"Execution of extension '{}' not implemented yet",
|
"Execution of extension '{}' not implemented yet",
|
||||||
ext.display_name()
|
ext.display_name()
|
||||||
)),
|
)),
|
||||||
BoundKind::Error => Err("Cannot execute a poisoned AST node".to_string()),
|
NodeKind::Error => Err("Cannot execute a poisoned AST node".to_string()),
|
||||||
|
// Syntax-only variants that should never appear in runtime phase
|
||||||
|
NodeKind::MacroDecl { .. } | NodeKind::Template(_) | NodeKind::Placeholder(_) | NodeKind::Splice(_) => {
|
||||||
|
Err("Syntax-only node reached the VM".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,12 +833,12 @@ impl VM {
|
|||||||
args: &ExecNode,
|
args: &ExecNode,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match &args.kind {
|
match &args.kind {
|
||||||
BoundKind::Tuple { elements } => {
|
NodeKind::Tuple { elements } => {
|
||||||
for e in elements {
|
for e in elements {
|
||||||
let mut curr = e.as_ref();
|
let mut curr = e.as_ref();
|
||||||
if !O::ACTIVE {
|
if !O::ACTIVE {
|
||||||
while let BoundKind::Expansion {
|
while let NodeKind::Expansion {
|
||||||
bound_expanded: next,
|
expanded: next,
|
||||||
..
|
..
|
||||||
} = &curr.kind
|
} = &curr.kind
|
||||||
{
|
{
|
||||||
@@ -832,7 +847,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match &curr.kind {
|
match &curr.kind {
|
||||||
BoundKind::Constant(v) if !O::ACTIVE => self.stack.push(v.clone()),
|
NodeKind::Constant(v) if !O::ACTIVE => self.stack.push(v.clone()),
|
||||||
_ => {
|
_ => {
|
||||||
let val = self.eval_internal(obs, curr)?;
|
let val = self.eval_internal(obs, curr)?;
|
||||||
self.stack.push(val);
|
self.stack.push(val);
|
||||||
@@ -841,7 +856,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
BoundKind::Constant(v) => {
|
NodeKind::Constant(v) => {
|
||||||
if let Some(slice) = v.as_slice() {
|
if let Some(slice) = v.as_slice() {
|
||||||
self.stack.extend_from_slice(slice);
|
self.stack.extend_from_slice(slice);
|
||||||
} else {
|
} else {
|
||||||
@@ -849,11 +864,11 @@ impl VM {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
NodeKind::Expansion { expanded, .. } => {
|
||||||
let mut curr = bound_expanded;
|
let mut curr = expanded;
|
||||||
if !O::ACTIVE {
|
if !O::ACTIVE {
|
||||||
while let BoundKind::Expansion {
|
while let NodeKind::Expansion {
|
||||||
bound_expanded: next,
|
expanded: next,
|
||||||
..
|
..
|
||||||
} = &curr.kind
|
} = &curr.kind
|
||||||
{
|
{
|
||||||
@@ -1008,17 +1023,15 @@ impl VM {
|
|||||||
offset: &mut usize,
|
offset: &mut usize,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match &pattern.kind {
|
match &pattern.kind {
|
||||||
BoundKind::Define { addr, .. } => {
|
NodeKind::Identifier { binding, .. } => {
|
||||||
|
let addr = match binding {
|
||||||
|
IdentifierBinding::Declaration { addr, .. } | IdentifierBinding::Reference(addr) => *addr,
|
||||||
|
};
|
||||||
let val = values.get(*offset).cloned().unwrap_or(Value::Void);
|
let val = values.get(*offset).cloned().unwrap_or(Value::Void);
|
||||||
*offset += 1;
|
*offset += 1;
|
||||||
self.set_value(*addr, val)
|
self.set_value(addr, val)
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, .. } => {
|
NodeKind::Tuple { elements } => {
|
||||||
let val = values.get(*offset).cloned().unwrap_or(Value::Void);
|
|
||||||
*offset += 1;
|
|
||||||
self.set_value(*addr, val)
|
|
||||||
}
|
|
||||||
BoundKind::Tuple { elements } => {
|
|
||||||
if let Some(sub_values) = values.get(*offset).and_then(|v| v.as_slice()) {
|
if let Some(sub_values) = values.get(*offset).and_then(|v| v.as_slice()) {
|
||||||
*offset += 1;
|
*offset += 1;
|
||||||
let mut sub_offset = 0;
|
let mut sub_offset = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user