Refactor: Implement block scoping and statement separation
This commit introduces fundamental changes to Myc's language structure to enhance type safety and scoping clarity. Key changes include: - Introducing local scopes for `do` blocks. - Separating statements (`def`, `assign`) from expressions, where statements now have no return value and are only allowed within blocks. - A block now consists of multiple statements followed by a single final expression. - Stricter validation rules are enforced, such as disallowing redefinition of local symbols in the same scope while allowing shadowing of outer symbols. - Compiler errors are generated for statements used in expression contexts. The implementation involved modifications to the AST, parser, binder (scope-stack), and various compiler passes, along with VM runtime optimizations.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot, UpvalueIdx};
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot, UpvalueIdx, UpvalueSource};
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::types::Value;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -88,6 +88,21 @@ impl SubstitutionMap {
|
||||
}
|
||||
}
|
||||
|
||||
fn reindex_source(&self, source: UpvalueSource, mapping: &[Option<u32>]) -> UpvalueSource {
|
||||
match source {
|
||||
UpvalueSource::Upvalue(idx) => {
|
||||
if let Some(res) = mapping.get(idx.0 as usize)
|
||||
&& let Some(new_idx) = res
|
||||
{
|
||||
UpvalueSource::Upvalue(UpvalueIdx(*new_idx))
|
||||
} else {
|
||||
source
|
||||
}
|
||||
}
|
||||
_ => source
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reindex_upvalues(&self, node_rc: Rc<AnalyzedNode>, mapping: &[Option<u32>]) -> Rc<AnalyzedNode> {
|
||||
let node = &*node_rc;
|
||||
let (new_kind, metrics) = match &node.kind {
|
||||
@@ -105,8 +120,8 @@ impl SubstitutionMap {
|
||||
positional_count,
|
||||
} => {
|
||||
let mut next_upvalues = Vec::new();
|
||||
for addr in upvalues {
|
||||
next_upvalues.push(self.reindex_addr(*addr, mapping));
|
||||
for source in upvalues {
|
||||
next_upvalues.push(self.reindex_source(*source, mapping));
|
||||
}
|
||||
(
|
||||
BoundKind::Lambda {
|
||||
@@ -135,12 +150,13 @@ impl SubstitutionMap {
|
||||
node.ty.clone(),
|
||||
)
|
||||
}
|
||||
BoundKind::Block { exprs } => {
|
||||
let exprs = exprs
|
||||
BoundKind::Block { statements, result } => {
|
||||
let t_statements = statements
|
||||
.iter()
|
||||
.map(|e| self.reindex_upvalues(e.clone(), mapping))
|
||||
.map(|s| self.reindex_upvalues(s.clone(), mapping))
|
||||
.collect();
|
||||
(BoundKind::Block { exprs }, node.ty.clone())
|
||||
let t_result = self.reindex_upvalues(result.clone(), mapping);
|
||||
(BoundKind::Block { statements: t_statements, result: t_result }, node.ty.clone())
|
||||
}
|
||||
BoundKind::Call { callee, args } => {
|
||||
let callee = self.reindex_upvalues(callee.clone(), mapping);
|
||||
@@ -152,6 +168,7 @@ impl SubstitutionMap {
|
||||
addr,
|
||||
kind,
|
||||
value,
|
||||
identity,
|
||||
captured_by,
|
||||
} => {
|
||||
let value = self.reindex_upvalues(value.clone(), mapping);
|
||||
@@ -161,6 +178,7 @@ impl SubstitutionMap {
|
||||
addr: *addr,
|
||||
kind: *kind,
|
||||
value,
|
||||
identity: identity.clone(),
|
||||
captured_by: captured_by.clone(),
|
||||
},
|
||||
node.ty.clone(),
|
||||
|
||||
Reference in New Issue
Block a user