Compare commits
No commits in common. "b959e11e51f6d337dfefb618f46e69f56f37df26" and "22e2a454019d2a46b8fd2c1cd01da3a1aaf131ba" have entirely different histories.
b959e11e51
...
22e2a45401
14 changed files with 70 additions and 682 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
fn simple() -> int do
|
|
||||||
42
|
|
||||||
end
|
|
||||||
13
src/ast.rs
13
src/ast.rs
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::typechecker::Type;
|
use crate::typechecker::Type;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub struct BindingId(pub usize);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypeAnnot {
|
pub enum TypeAnnot {
|
||||||
Var(String),
|
Var(String),
|
||||||
|
|
@ -309,7 +306,7 @@ pub enum TypedASTNodeKind {
|
||||||
pub struct TypedFunction {
|
pub struct TypedFunction {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub parameters: Vec<Parameter>,
|
pub parameters: Vec<Parameter>,
|
||||||
pub args: Vec<(BindingId, String, Option<TypeAnnot>)>,
|
pub args: Vec<(String, Option<TypeAnnot>)>,
|
||||||
pub return_type: Option<TypeAnnot>,
|
pub return_type: Option<TypeAnnot>,
|
||||||
pub body: TypedExpr,
|
pub body: TypedExpr,
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
|
|
@ -398,8 +395,8 @@ pub enum TypedExprKind {
|
||||||
Dot(Box<TypedExpr>, String),
|
Dot(Box<TypedExpr>, String),
|
||||||
EarlyReturn(Option<Box<TypedExpr>>),
|
EarlyReturn(Option<Box<TypedExpr>>),
|
||||||
OptionalChain(Option<Box<TypedExpr>>, String),
|
OptionalChain(Option<Box<TypedExpr>>, String),
|
||||||
Lambda(Vec<(BindingId, String, Option<TypeAnnot>)>, Box<TypedExpr>),
|
Lambda(Vec<(String, Option<TypeAnnot>)>, Box<TypedExpr>),
|
||||||
Let(BindingId, String, BindingKind, Option<TypeAnnot>, Box<TypedExpr>),
|
Let(String, BindingKind, Option<TypeAnnot>, Box<TypedExpr>),
|
||||||
Assign(Box<TypedExpr>, Box<TypedExpr>),
|
Assign(Box<TypedExpr>, Box<TypedExpr>),
|
||||||
Cast(Box<TypedExpr>, TypeAnnot),
|
Cast(Box<TypedExpr>, TypeAnnot),
|
||||||
If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>),
|
If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>),
|
||||||
|
|
@ -408,7 +405,7 @@ pub enum TypedExprKind {
|
||||||
Do(Vec<TypedExpr>),
|
Do(Vec<TypedExpr>),
|
||||||
BinOp(Box<TypedExpr>, BinOp, Box<TypedExpr>),
|
BinOp(Box<TypedExpr>, BinOp, Box<TypedExpr>),
|
||||||
UnOp(UnOp, Box<TypedExpr>),
|
UnOp(UnOp, Box<TypedExpr>),
|
||||||
For(BindingId, String, Box<TypedExpr>, Box<TypedExpr>),
|
For(String, Box<TypedExpr>, Box<TypedExpr>),
|
||||||
Range(Box<TypedExpr>, Box<TypedExpr>),
|
Range(Box<TypedExpr>, Box<TypedExpr>),
|
||||||
Return(Option<Box<TypedExpr>>),
|
Return(Option<Box<TypedExpr>>),
|
||||||
Break,
|
Break,
|
||||||
|
|
@ -425,7 +422,7 @@ pub struct TypedPattern {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypedPatternKind {
|
pub enum TypedPatternKind {
|
||||||
Wildcard,
|
Wildcard,
|
||||||
Variable(BindingId, String),
|
Variable(String),
|
||||||
Literal(String),
|
Literal(String),
|
||||||
Tuple(Vec<TypedPattern>),
|
Tuple(Vec<TypedPattern>),
|
||||||
Struct(String, Vec<(String, TypedPattern)>),
|
Struct(String, Vec<(String, TypedPattern)>),
|
||||||
|
|
|
||||||
|
|
@ -1,382 +0,0 @@
|
||||||
use crate::ast::*;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
/// LambdaLowerer converts lambda expressions into generated functions
|
|
||||||
/// that are hoisted to the top level of the program.
|
|
||||||
pub struct LambdaLowerer {
|
|
||||||
lambda_counter: Rc<RefCell<usize>>,
|
|
||||||
generated_functions: Rc<RefCell<Vec<ASTNode>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LambdaLowerer {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
LambdaLowerer {
|
|
||||||
lambda_counter: Rc::new(RefCell::new(0)),
|
|
||||||
generated_functions: Rc::new(RefCell::new(Vec::new())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn collect_free_vars(&self, expr: &Expr, lambda_params: &[String]) -> std::collections::HashSet<String> {
|
|
||||||
let mut free_vars = std::collections::HashSet::new();
|
|
||||||
let mut local_scope = std::collections::HashSet::new();
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, &mut free_vars, &mut local_scope);
|
|
||||||
free_vars
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_free_vars_expr(&self, expr: &Expr, lambda_params: &[String], free_vars: &mut std::collections::HashSet<String>, local_scope: &mut std::collections::HashSet<String>) {
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Variable(name) => {
|
|
||||||
if !lambda_params.contains(name) && !local_scope.contains(name) {
|
|
||||||
free_vars.insert(name.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Lambda(args, body) => {
|
|
||||||
let param_names: Vec<String> = args.iter().map(|(name, _)| name.clone()).collect();
|
|
||||||
// For nested lambdas, we don't enter a new scope here since we're just collecting free vars
|
|
||||||
self.collect_free_vars_expr(body, ¶m_names, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Let(name, _, _, body) => {
|
|
||||||
// Collect from body before adding the binding
|
|
||||||
self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope);
|
|
||||||
// Add to local scope
|
|
||||||
local_scope.insert(name.clone());
|
|
||||||
}
|
|
||||||
ExprKind::Call(func, args) => {
|
|
||||||
self.collect_free_vars_expr(func, lambda_params, free_vars, local_scope);
|
|
||||||
for arg in args {
|
|
||||||
self.collect_free_vars_expr(arg, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Handle other expression types that contain subexpressions
|
|
||||||
ExprKind::If(cond, then_expr, else_expr) => {
|
|
||||||
self.collect_free_vars_expr(cond, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(then_expr, lambda_params, free_vars, local_scope);
|
|
||||||
if let Some(else_expr) = else_expr {
|
|
||||||
self.collect_free_vars_expr(else_expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Match(scrutinee, arms) => {
|
|
||||||
self.collect_free_vars_expr(scrutinee, lambda_params, free_vars, local_scope);
|
|
||||||
for (_, expr) in arms {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::While(cond, body) => {
|
|
||||||
self.collect_free_vars_expr(cond, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::For(_, iter, body) => {
|
|
||||||
self.collect_free_vars_expr(iter, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Do(exprs) => {
|
|
||||||
for expr in exprs {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::BinOp(left, _, right) => {
|
|
||||||
self.collect_free_vars_expr(left, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(right, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::UnOp(_, operand) => {
|
|
||||||
self.collect_free_vars_expr(operand, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Assign(target, value) => {
|
|
||||||
self.collect_free_vars_expr(target, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(value, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Cast(operand, _) => {
|
|
||||||
self.collect_free_vars_expr(operand, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Index(obj, index) => {
|
|
||||||
self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(index, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::Dot(obj, _) => {
|
|
||||||
self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
ExprKind::EarlyReturn(expr) => {
|
|
||||||
if let Some(expr) = expr {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::OptionalChain(obj, _) => {
|
|
||||||
if let Some(obj) = obj {
|
|
||||||
self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Return(expr) => {
|
|
||||||
if let Some(expr) = expr {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Array(exprs) => {
|
|
||||||
for expr in exprs {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Tuple(exprs) => {
|
|
||||||
for expr in exprs {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::StructLit(_, fields) => {
|
|
||||||
for (_, expr) in fields {
|
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::EnumLit(_, _, args) => {
|
|
||||||
for arg in args {
|
|
||||||
self.collect_free_vars_expr(arg, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Range(start, end) => {
|
|
||||||
self.collect_free_vars_expr(start, lambda_params, free_vars, local_scope);
|
|
||||||
self.collect_free_vars_expr(end, lambda_params, free_vars, local_scope);
|
|
||||||
}
|
|
||||||
// Terminal expressions don't contain variables
|
|
||||||
ExprKind::Int(_) | ExprKind::Float(_) | ExprKind::Bool(_) | ExprKind::String(_) | ExprKind::Break | ExprKind::Continue => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lower all lambdas in a program by hoisting them to functions
|
|
||||||
pub fn lower_program(&self, nodes: &[ASTNode]) -> Result<Vec<ASTNode>, String> {
|
|
||||||
let mut lowered_nodes = Vec::new();
|
|
||||||
|
|
||||||
// Process each top-level node
|
|
||||||
for node in nodes {
|
|
||||||
let lowered = self.lower_node(node)?;
|
|
||||||
lowered_nodes.push(lowered);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all generated lambda functions to the end
|
|
||||||
let generated = self.generated_functions.borrow();
|
|
||||||
lowered_nodes.extend(generated.iter().cloned());
|
|
||||||
|
|
||||||
Ok(lowered_nodes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_node(&self, node: &ASTNode) -> Result<ASTNode, String> {
|
|
||||||
let new_kind = match &node.kind {
|
|
||||||
ASTNodeKind::Function(func) => {
|
|
||||||
let lowered_body = self.lower_expr(&func.body)?;
|
|
||||||
ASTNodeKind::Function(Function {
|
|
||||||
name: func.name.clone(),
|
|
||||||
parameters: func.parameters.clone(),
|
|
||||||
args: func.args.clone(),
|
|
||||||
return_type: func.return_type.clone(),
|
|
||||||
body: lowered_body,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
other => other.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ASTNode {
|
|
||||||
kind: new_kind,
|
|
||||||
span: node.span.clone(),
|
|
||||||
attributes: node.attributes.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_expr(&self, expr: &Expr) -> Result<Expr, String> {
|
|
||||||
let new_kind = match &expr.kind {
|
|
||||||
ExprKind::Lambda(args, body) => {
|
|
||||||
// Collect free variables (captured variables)
|
|
||||||
let lambda_params: Vec<String> = args.iter().map(|(name, _)| name.clone()).collect();
|
|
||||||
let free_vars = self.collect_free_vars(body, &lambda_params);
|
|
||||||
|
|
||||||
if free_vars.is_empty() {
|
|
||||||
// No captures - hoist to function like the original implementation
|
|
||||||
let lambda_id = {
|
|
||||||
let mut counter = self.lambda_counter.borrow_mut();
|
|
||||||
*counter += 1;
|
|
||||||
*counter
|
|
||||||
};
|
|
||||||
let lambda_name = format!("__suic_gen_lambda_{}", lambda_id);
|
|
||||||
|
|
||||||
// Lower the lambda body recursively
|
|
||||||
let lowered_body = self.lower_expr(body)?;
|
|
||||||
|
|
||||||
// Create a new function for this lambda
|
|
||||||
let lambda_func = ASTNode {
|
|
||||||
kind: ASTNodeKind::Function(Function {
|
|
||||||
name: lambda_name.clone(),
|
|
||||||
parameters: Vec::new(), // No type parameters for now
|
|
||||||
args: args.clone(),
|
|
||||||
return_type: None, // Let typechecker infer return type
|
|
||||||
body: lowered_body,
|
|
||||||
}),
|
|
||||||
span: expr.span.clone(),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store the generated function
|
|
||||||
self.generated_functions
|
|
||||||
.borrow_mut()
|
|
||||||
.push(lambda_func);
|
|
||||||
|
|
||||||
// Replace the lambda with a reference to the generated function
|
|
||||||
ExprKind::Variable(lambda_name)
|
|
||||||
} else {
|
|
||||||
// Has captures - keep as lambda, but recursively lower the body
|
|
||||||
let lowered_body = self.lower_expr(body)?;
|
|
||||||
ExprKind::Lambda(args.clone(), Box::new(lowered_body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Call(func, args) => {
|
|
||||||
let lowered_func = self.lower_expr(func)?;
|
|
||||||
let lowered_args = args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| self.lower_expr(arg))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
ExprKind::Call(Box::new(lowered_func), lowered_args)
|
|
||||||
}
|
|
||||||
ExprKind::Let(name, kind, type_annot, body) => {
|
|
||||||
let lowered_body = self.lower_expr(body)?;
|
|
||||||
ExprKind::Let(
|
|
||||||
name.clone(),
|
|
||||||
kind.clone(),
|
|
||||||
type_annot.clone(),
|
|
||||||
Box::new(lowered_body),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExprKind::If(cond, then_expr, else_expr) => {
|
|
||||||
let lowered_cond = self.lower_expr(cond)?;
|
|
||||||
let lowered_then = self.lower_expr(then_expr)?;
|
|
||||||
let lowered_else = else_expr
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.transpose()?;
|
|
||||||
ExprKind::If(
|
|
||||||
Box::new(lowered_cond),
|
|
||||||
Box::new(lowered_then),
|
|
||||||
lowered_else.map(Box::new),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExprKind::Match(scrutinee, arms) => {
|
|
||||||
let lowered_scrutinee = self.lower_expr(scrutinee)?;
|
|
||||||
let mut lowered_arms = Vec::new();
|
|
||||||
for (pattern, expr) in arms {
|
|
||||||
let lowered_expr = self.lower_expr(expr)?;
|
|
||||||
lowered_arms.push((pattern.clone(), lowered_expr));
|
|
||||||
}
|
|
||||||
ExprKind::Match(Box::new(lowered_scrutinee), lowered_arms)
|
|
||||||
}
|
|
||||||
ExprKind::While(cond, body) => {
|
|
||||||
let lowered_cond = self.lower_expr(cond)?;
|
|
||||||
let lowered_body = self.lower_expr(body)?;
|
|
||||||
ExprKind::While(Box::new(lowered_cond), Box::new(lowered_body))
|
|
||||||
}
|
|
||||||
ExprKind::For(var, iter, body) => {
|
|
||||||
let lowered_iter = self.lower_expr(iter)?;
|
|
||||||
let lowered_body = self.lower_expr(body)?;
|
|
||||||
ExprKind::For(var.clone(), Box::new(lowered_iter), Box::new(lowered_body))
|
|
||||||
}
|
|
||||||
ExprKind::Do(exprs) => {
|
|
||||||
let lowered_exprs = exprs
|
|
||||||
.iter()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
ExprKind::Do(lowered_exprs)
|
|
||||||
}
|
|
||||||
ExprKind::BinOp(left, op, right) => {
|
|
||||||
let lowered_left = self.lower_expr(left)?;
|
|
||||||
let lowered_right = self.lower_expr(right)?;
|
|
||||||
ExprKind::BinOp(Box::new(lowered_left), op.clone(), Box::new(lowered_right))
|
|
||||||
}
|
|
||||||
ExprKind::UnOp(op, operand) => {
|
|
||||||
let lowered_operand = self.lower_expr(operand)?;
|
|
||||||
ExprKind::UnOp(op.clone(), Box::new(lowered_operand))
|
|
||||||
}
|
|
||||||
ExprKind::Assign(target, value) => {
|
|
||||||
let lowered_target = self.lower_expr(target)?;
|
|
||||||
let lowered_value = self.lower_expr(value)?;
|
|
||||||
ExprKind::Assign(Box::new(lowered_target), Box::new(lowered_value))
|
|
||||||
}
|
|
||||||
ExprKind::Cast(operand, type_annot) => {
|
|
||||||
let lowered_operand = self.lower_expr(operand)?;
|
|
||||||
ExprKind::Cast(Box::new(lowered_operand), type_annot.clone())
|
|
||||||
}
|
|
||||||
ExprKind::Index(obj, index) => {
|
|
||||||
let lowered_obj = self.lower_expr(obj)?;
|
|
||||||
let lowered_index = self.lower_expr(index)?;
|
|
||||||
ExprKind::Index(Box::new(lowered_obj), Box::new(lowered_index))
|
|
||||||
}
|
|
||||||
ExprKind::Dot(obj, field) => {
|
|
||||||
let lowered_obj = self.lower_expr(obj)?;
|
|
||||||
ExprKind::Dot(Box::new(lowered_obj), field.clone())
|
|
||||||
}
|
|
||||||
ExprKind::EarlyReturn(expr) => {
|
|
||||||
let lowered_expr = expr
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.transpose()?;
|
|
||||||
ExprKind::EarlyReturn(lowered_expr.map(Box::new))
|
|
||||||
}
|
|
||||||
ExprKind::OptionalChain(obj, field) => {
|
|
||||||
let lowered_obj = obj.as_ref().map(|e| self.lower_expr(e)).transpose()?;
|
|
||||||
ExprKind::OptionalChain(lowered_obj.map(Box::new), field.clone())
|
|
||||||
}
|
|
||||||
ExprKind::Return(expr) => {
|
|
||||||
let lowered_expr = expr
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.transpose()?;
|
|
||||||
ExprKind::Return(lowered_expr.map(Box::new))
|
|
||||||
}
|
|
||||||
ExprKind::Array(exprs) => {
|
|
||||||
let lowered_exprs = exprs
|
|
||||||
.iter()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
ExprKind::Array(lowered_exprs)
|
|
||||||
}
|
|
||||||
ExprKind::Tuple(exprs) => {
|
|
||||||
let lowered_exprs = exprs
|
|
||||||
.iter()
|
|
||||||
.map(|e| self.lower_expr(e))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
ExprKind::Tuple(lowered_exprs)
|
|
||||||
}
|
|
||||||
ExprKind::StructLit(name, fields) => {
|
|
||||||
let mut lowered_fields = Vec::new();
|
|
||||||
for (field_name, field_expr) in fields {
|
|
||||||
let lowered_expr = self.lower_expr(field_expr)?;
|
|
||||||
lowered_fields.push((field_name.clone(), lowered_expr));
|
|
||||||
}
|
|
||||||
ExprKind::StructLit(name.clone(), lowered_fields)
|
|
||||||
}
|
|
||||||
ExprKind::EnumLit(enum_name, variant, args) => {
|
|
||||||
let lowered_args = args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| self.lower_expr(arg))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
ExprKind::EnumLit(enum_name.clone(), variant.clone(), lowered_args)
|
|
||||||
}
|
|
||||||
ExprKind::Range(start, end) => {
|
|
||||||
let lowered_start = self.lower_expr(start)?;
|
|
||||||
let lowered_end = self.lower_expr(end)?;
|
|
||||||
ExprKind::Range(Box::new(lowered_start), Box::new(lowered_end))
|
|
||||||
}
|
|
||||||
// Terminal expressions that don't contain other expressions
|
|
||||||
ExprKind::Int(_)
|
|
||||||
| ExprKind::Float(_)
|
|
||||||
| ExprKind::Bool(_)
|
|
||||||
| ExprKind::String(_)
|
|
||||||
| ExprKind::Variable(_)
|
|
||||||
| ExprKind::Break
|
|
||||||
| ExprKind::Continue => expr.kind.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Expr {
|
|
||||||
kind: new_kind,
|
|
||||||
span: expr.span.clone(),
|
|
||||||
attributes: expr.attributes.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,5 @@ pub const EXTENSION: &str = ".sui";
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod lambda_lower;
|
|
||||||
pub mod typechecker;
|
pub mod typechecker;
|
||||||
pub mod monomorphize;
|
pub mod monomorphize;
|
||||||
|
|
|
||||||
11
src/main.rs
11
src/main.rs
|
|
@ -1,7 +1,7 @@
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use suicmez::{
|
use suicmez::{
|
||||||
lexer::Token, parser::Parser, lambda_lower::LambdaLowerer, typechecker::TypeChecker,
|
lexer::Token, parser::Parser, typechecker::TypeChecker,
|
||||||
monomorphize::{Monomorphizer, check_no_typevars},
|
monomorphize::{Monomorphizer, check_no_typevars},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -73,16 +73,9 @@ fn run_file(filename: &str) -> Result<(), String> {
|
||||||
|
|
||||||
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
||||||
|
|
||||||
// Lower lambdas to generated functions
|
|
||||||
let lowerer = LambdaLowerer::new();
|
|
||||||
let lowered_nodes = lowerer.lower_program(&ast_nodes)
|
|
||||||
.map_err(|e| format!("Lambda lowering error: {}", e))?;
|
|
||||||
|
|
||||||
println!("Lambda lowering passed! {} nodes after lowering.", lowered_nodes.len());
|
|
||||||
|
|
||||||
// Typecheck the AST
|
// Typecheck the AST
|
||||||
let mut typechecker = TypeChecker::new();
|
let mut typechecker = TypeChecker::new();
|
||||||
let typed_nodes = typechecker.typecheck_program(&lowered_nodes).map_err(|e| {
|
let typed_nodes = typechecker.typecheck_program(&ast_nodes).map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Type error at {}:{}: {:?}",
|
"Type error at {}:{}: {:?}",
|
||||||
e.span.file, e.span.start, e.kind
|
e.span.file, e.span.start, e.kind
|
||||||
|
|
|
||||||
|
|
@ -439,11 +439,10 @@ impl Monomorphizer {
|
||||||
TypedExprKind::Lambda(params.clone(), Box::new(new_body))
|
TypedExprKind::Lambda(params.clone(), Box::new(new_body))
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedExprKind::Let(id, name, binding_kind, ty_annot, expr) => {
|
TypedExprKind::Let(name, binding_kind, ty_annot, expr) => {
|
||||||
let (new_expr, expr_needs) = self.monomorphize_expr(expr)?;
|
let (new_expr, expr_needs) = self.monomorphize_expr(expr)?;
|
||||||
needs.extend(expr_needs);
|
needs.extend(expr_needs);
|
||||||
TypedExprKind::Let(
|
TypedExprKind::Let(
|
||||||
*id,
|
|
||||||
name.clone(),
|
name.clone(),
|
||||||
binding_kind.clone(),
|
binding_kind.clone(),
|
||||||
ty_annot.clone(),
|
ty_annot.clone(),
|
||||||
|
|
@ -528,12 +527,12 @@ impl Monomorphizer {
|
||||||
TypedExprKind::UnOp(op.clone(), Box::new(new_operand))
|
TypedExprKind::UnOp(op.clone(), Box::new(new_operand))
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedExprKind::For(id, var, iter_expr, body) => {
|
TypedExprKind::For(var, iter_expr, body) => {
|
||||||
let (new_iter, iter_needs) = self.monomorphize_expr(iter_expr)?;
|
let (new_iter, iter_needs) = self.monomorphize_expr(iter_expr)?;
|
||||||
let (new_body, body_needs) = self.monomorphize_expr(body)?;
|
let (new_body, body_needs) = self.monomorphize_expr(body)?;
|
||||||
needs.extend(iter_needs);
|
needs.extend(iter_needs);
|
||||||
needs.extend(body_needs);
|
needs.extend(body_needs);
|
||||||
TypedExprKind::For(*id, var.clone(), Box::new(new_iter), Box::new(new_body))
|
TypedExprKind::For(var.clone(), Box::new(new_iter), Box::new(new_body))
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedExprKind::Range(start, end) => {
|
TypedExprKind::Range(start, end) => {
|
||||||
|
|
@ -683,7 +682,7 @@ impl Monomorphizer {
|
||||||
let mut new_args = Vec::new();
|
let mut new_args = Vec::new();
|
||||||
let mut needs = Vec::new();
|
let mut needs = Vec::new();
|
||||||
|
|
||||||
for (arg_id, arg_name, arg_ty_opt) in &generic_func.args {
|
for (arg_name, arg_ty_opt) in &generic_func.args {
|
||||||
let new_arg_ty = if let Some(arg_ty) = arg_ty_opt {
|
let new_arg_ty = if let Some(arg_ty) = arg_ty_opt {
|
||||||
let ty = self.substitute_in_type_annot(arg_ty, &subst_map)?;
|
let ty = self.substitute_in_type_annot(arg_ty, &subst_map)?;
|
||||||
self.collect_needs_from_type(&ty, &mut needs);
|
self.collect_needs_from_type(&ty, &mut needs);
|
||||||
|
|
@ -691,7 +690,7 @@ impl Monomorphizer {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
new_args.push((*arg_id, arg_name.clone(), new_arg_ty));
|
new_args.push((arg_name.clone(), new_arg_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialize return type
|
// Specialize return type
|
||||||
|
|
@ -987,7 +986,7 @@ fn check_function_for_typevars(func: &TypedFunction) -> Result<(), Monomorphizat
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, _, ty_opt) in &func.args {
|
for (_, ty_opt) in &func.args {
|
||||||
if let Some(ty) = ty_opt {
|
if let Some(ty) = ty_opt {
|
||||||
if has_typevars_in_type_annot(ty) {
|
if has_typevars_in_type_annot(ty) {
|
||||||
return Err(MonomorphizationError::new(
|
return Err(MonomorphizationError::new(
|
||||||
|
|
@ -1057,7 +1056,7 @@ fn check_enum_for_typevars(e: &TypedEnum) -> Result<(), MonomorphizationError> {
|
||||||
fn check_expr_for_typevars(expr: &TypedExpr) -> Result<(), MonomorphizationError> {
|
fn check_expr_for_typevars(expr: &TypedExpr) -> Result<(), MonomorphizationError> {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
TypedExprKind::Lambda(params, body) => {
|
TypedExprKind::Lambda(params, body) => {
|
||||||
for (_, _, ty_opt) in params {
|
for (_, ty_opt) in params {
|
||||||
if let Some(ty) = ty_opt {
|
if let Some(ty) = ty_opt {
|
||||||
if has_typevars_in_type_annot(ty) {
|
if has_typevars_in_type_annot(ty) {
|
||||||
return Err(MonomorphizationError::new(
|
return Err(MonomorphizationError::new(
|
||||||
|
|
@ -1069,7 +1068,7 @@ fn check_expr_for_typevars(expr: &TypedExpr) -> Result<(), MonomorphizationError
|
||||||
}
|
}
|
||||||
check_expr_for_typevars(body)?;
|
check_expr_for_typevars(body)?;
|
||||||
}
|
}
|
||||||
TypedExprKind::Let(_, _, _, ty_opt, expr) => {
|
TypedExprKind::Let(_, _, ty_opt, expr) => {
|
||||||
if let Some(ty) = ty_opt {
|
if let Some(ty) = ty_opt {
|
||||||
if has_typevars_in_type_annot(ty) {
|
if has_typevars_in_type_annot(ty) {
|
||||||
return Err(MonomorphizationError::new(
|
return Err(MonomorphizationError::new(
|
||||||
|
|
@ -1161,7 +1160,7 @@ fn check_expr_for_typevars(expr: &TypedExpr) -> Result<(), MonomorphizationError
|
||||||
TypedExprKind::UnOp(_, operand) => {
|
TypedExprKind::UnOp(_, operand) => {
|
||||||
check_expr_for_typevars(operand)?;
|
check_expr_for_typevars(operand)?;
|
||||||
}
|
}
|
||||||
TypedExprKind::For(_, _, iter, body) => {
|
TypedExprKind::For(_, iter, body) => {
|
||||||
check_expr_for_typevars(iter)?;
|
check_expr_for_typevars(iter)?;
|
||||||
check_expr_for_typevars(body)?;
|
check_expr_for_typevars(body)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,25 +84,14 @@ pub enum TypeErrorKind {
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct VarInfo {
|
|
||||||
ty: Type,
|
|
||||||
kind: BindingKind,
|
|
||||||
name: String,
|
|
||||||
usage: usize,
|
|
||||||
span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TypeEnv {
|
struct TypeEnv {
|
||||||
vars: HashMap<crate::ast::BindingId, VarInfo>,
|
vars: HashMap<String, (Type, BindingKind)>,
|
||||||
name_to_id: HashMap<String, crate::ast::BindingId>,
|
|
||||||
types: HashMap<String, TypeInfo>,
|
types: HashMap<String, TypeInfo>,
|
||||||
functions: HashMap<String, FunctionType>,
|
functions: HashMap<String, FunctionType>,
|
||||||
traits: HashMap<String, TraitInfo>,
|
traits: HashMap<String, TraitInfo>,
|
||||||
impls: Vec<ImplInfo>,
|
impls: Vec<ImplInfo>,
|
||||||
type_vars: HashMap<String, Type>,
|
type_vars: HashMap<String, Type>,
|
||||||
scopes: Vec<Vec<crate::ast::BindingId>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -141,100 +130,31 @@ impl TypeEnv {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
TypeEnv {
|
TypeEnv {
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
name_to_id: HashMap::new(),
|
|
||||||
types: HashMap::new(),
|
types: HashMap::new(),
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
traits: HashMap::new(),
|
traits: HashMap::new(),
|
||||||
impls: Vec::new(),
|
impls: Vec::new(),
|
||||||
type_vars: HashMap::new(),
|
type_vars: HashMap::new(),
|
||||||
scopes: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_scope(&mut self) {
|
fn enter_scope(&self) -> Self {
|
||||||
self.scopes.push(Vec::new());
|
TypeEnv {
|
||||||
}
|
vars: self.vars.clone(),
|
||||||
|
types: self.types.clone(),
|
||||||
fn exit_scope(&mut self) -> Result<(), TypeError> {
|
functions: self.functions.clone(),
|
||||||
if let Some(scope) = self.scopes.pop() {
|
traits: self.traits.clone(),
|
||||||
for &id in &scope {
|
impls: self.impls.clone(),
|
||||||
if let Some(var_info) = self.vars.get(&id) {
|
type_vars: self.type_vars.clone(),
|
||||||
match var_info.kind {
|
|
||||||
BindingKind::Linear => {
|
|
||||||
if var_info.usage != 1 {
|
|
||||||
return Err(TypeError {
|
|
||||||
kind: TypeErrorKind::LinearityError(format!(
|
|
||||||
"Linear variable '{}' used {} times, must be exactly 1",
|
|
||||||
var_info.name, var_info.usage
|
|
||||||
)),
|
|
||||||
span: var_info.span.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BindingKind::Affine => {
|
|
||||||
if var_info.usage > 1 {
|
|
||||||
return Err(TypeError {
|
|
||||||
kind: TypeErrorKind::LinearityError(format!(
|
|
||||||
"Affine variable '{}' used {} times, must be at most 1",
|
|
||||||
var_info.name, var_info.usage
|
|
||||||
)),
|
|
||||||
span: var_info.span.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let name = var_info.name.clone();
|
|
||||||
self.vars.remove(&id);
|
|
||||||
self.name_to_id.remove(&name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_var(
|
|
||||||
&mut self,
|
|
||||||
id: crate::ast::BindingId,
|
|
||||||
name: String,
|
|
||||||
ty: Type,
|
|
||||||
kind: BindingKind,
|
|
||||||
span: Span,
|
|
||||||
) {
|
|
||||||
let var_info = VarInfo {
|
|
||||||
ty,
|
|
||||||
kind,
|
|
||||||
name: name.clone(),
|
|
||||||
usage: 0,
|
|
||||||
span,
|
|
||||||
};
|
|
||||||
self.vars.insert(id, var_info);
|
|
||||||
if let Some(current) = self.scopes.last_mut() {
|
|
||||||
current.push(id);
|
|
||||||
}
|
|
||||||
self.name_to_id.insert(name, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_var(&self, id: &crate::ast::BindingId) -> Option<&VarInfo> {
|
|
||||||
self.vars.get(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_var_by_name(&self, name: &str) -> Option<(crate::ast::BindingId, &VarInfo)> {
|
|
||||||
if let Some(id) = self.name_to_id.get(name) {
|
|
||||||
if let Some(var_info) = self.vars.get(id) {
|
|
||||||
Some((*id, var_info))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_usage(&mut self, id: &crate::ast::BindingId) {
|
fn add_var(&mut self, name: String, ty: Type, kind: BindingKind) {
|
||||||
if let Some(var_info) = self.vars.get_mut(id) {
|
self.vars.insert(name, (ty, kind));
|
||||||
var_info.usage += 1;
|
}
|
||||||
}
|
|
||||||
|
fn get_var(&self, name: &str) -> Option<&(Type, BindingKind)> {
|
||||||
|
self.vars.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_type(&mut self, name: String, info: TypeInfo) {
|
fn add_type(&mut self, name: String, info: TypeInfo) {
|
||||||
|
|
@ -256,23 +176,15 @@ impl TypeEnv {
|
||||||
|
|
||||||
pub struct TypeChecker {
|
pub struct TypeChecker {
|
||||||
env: TypeEnv,
|
env: TypeEnv,
|
||||||
binding_id_counter: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeChecker {
|
impl TypeChecker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TypeChecker {
|
TypeChecker {
|
||||||
env: TypeEnv::new(),
|
env: TypeEnv::new(),
|
||||||
binding_id_counter: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_binding_id(&mut self) -> crate::ast::BindingId {
|
|
||||||
let id = crate::ast::BindingId(self.binding_id_counter);
|
|
||||||
self.binding_id_counter += 1;
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn typecheck_program(&mut self, nodes: &[ASTNode]) -> Result<Vec<TypedASTNode>, TypeError> {
|
pub fn typecheck_program(&mut self, nodes: &[ASTNode]) -> Result<Vec<TypedASTNode>, TypeError> {
|
||||||
// First pass: collect all type definitions, function signatures, etc.
|
// First pass: collect all type definitions, function signatures, etc.
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
|
|
@ -280,12 +192,10 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second pass: typecheck everything
|
// Second pass: typecheck everything
|
||||||
self.env.enter_scope();
|
|
||||||
let mut typed_nodes = Vec::new();
|
let mut typed_nodes = Vec::new();
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
typed_nodes.push(self.typecheck_node(node)?);
|
typed_nodes.push(self.typecheck_node(node)?);
|
||||||
}
|
}
|
||||||
self.env.exit_scope()?;
|
|
||||||
|
|
||||||
Ok(typed_nodes)
|
Ok(typed_nodes)
|
||||||
}
|
}
|
||||||
|
|
@ -330,13 +240,7 @@ impl TypeChecker {
|
||||||
.return_type
|
.return_type
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| self.type_annot_to_type(t))
|
.map(|t| self.type_annot_to_type(t))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or(Type::Unit);
|
||||||
if f.name.starts_with("__suic_gen_lambda_") {
|
|
||||||
Type::Unknown
|
|
||||||
} else {
|
|
||||||
Type::Unit
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let func_type = FunctionType {
|
let func_type = FunctionType {
|
||||||
type_params: f.parameters.iter().map(|p| p.name.clone()).collect(),
|
type_params: f.parameters.iter().map(|p| p.name.clone()).collect(),
|
||||||
|
|
@ -421,15 +325,11 @@ impl TypeChecker {
|
||||||
kind: TypedASTNodeKind::Struct(TypedStruct {
|
kind: TypedASTNodeKind::Struct(TypedStruct {
|
||||||
name: s.name.clone(),
|
name: s.name.clone(),
|
||||||
parameters: s.parameters.clone(),
|
parameters: s.parameters.clone(),
|
||||||
fields: s
|
fields: s.fields.iter().map(|f| TypedField {
|
||||||
.fields
|
name: f.name.clone(),
|
||||||
.iter()
|
field_type: f.field_type.clone(),
|
||||||
.map(|f| TypedField {
|
span: f.span.clone(),
|
||||||
name: f.name.clone(),
|
}).collect(),
|
||||||
field_type: f.field_type.clone(),
|
|
||||||
span: f.span.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}),
|
}),
|
||||||
span: node.span.clone(),
|
span: node.span.clone(),
|
||||||
attributes: node.attributes.clone(),
|
attributes: node.attributes.clone(),
|
||||||
|
|
@ -442,15 +342,11 @@ impl TypeChecker {
|
||||||
kind: TypedASTNodeKind::Enum(TypedEnum {
|
kind: TypedASTNodeKind::Enum(TypedEnum {
|
||||||
name: e.name.clone(),
|
name: e.name.clone(),
|
||||||
parameters: e.parameters.clone(),
|
parameters: e.parameters.clone(),
|
||||||
variants: e
|
variants: e.variants.iter().map(|v| TypedVariant {
|
||||||
.variants
|
name: v.name.clone(),
|
||||||
.iter()
|
fields: v.fields.clone(),
|
||||||
.map(|v| TypedVariant {
|
span: v.span.clone(),
|
||||||
name: v.name.clone(),
|
}).collect(),
|
||||||
fields: v.fields.clone(),
|
|
||||||
span: v.span.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}),
|
}),
|
||||||
span: node.span.clone(),
|
span: node.span.clone(),
|
||||||
attributes: node.attributes.clone(),
|
attributes: node.attributes.clone(),
|
||||||
|
|
@ -528,8 +424,11 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck_function(&mut self, func: &Function) -> Result<TypedFunction, TypeError> {
|
fn typecheck_function(&mut self, func: &Function) -> Result<TypedFunction, TypeError> {
|
||||||
|
// Save the original environment
|
||||||
|
let original_env = self.env.clone();
|
||||||
|
|
||||||
// Enter new scope for function
|
// Enter new scope for function
|
||||||
self.env.enter_scope();
|
self.env = self.env.enter_scope();
|
||||||
|
|
||||||
// Add type parameters to environment
|
// Add type parameters to environment
|
||||||
for param in &func.parameters {
|
for param in &func.parameters {
|
||||||
|
|
@ -540,41 +439,28 @@ impl TypeChecker {
|
||||||
|
|
||||||
// Add function parameters to environment
|
// Add function parameters to environment
|
||||||
let mut param_types = Vec::new();
|
let mut param_types = Vec::new();
|
||||||
let mut typed_args = Vec::new();
|
|
||||||
for (arg_name, arg_type_annot) in &func.args {
|
for (arg_name, arg_type_annot) in &func.args {
|
||||||
let arg_id = self.next_binding_id();
|
|
||||||
let arg_type = arg_type_annot
|
let arg_type = arg_type_annot
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| self.type_annot_to_type(t))
|
.map(|t| self.type_annot_to_type(t))
|
||||||
.unwrap_or(Type::Unknown);
|
.unwrap_or(Type::Unknown);
|
||||||
param_types.push(arg_type.clone());
|
param_types.push(arg_type.clone());
|
||||||
self.env.add_var(
|
self.env
|
||||||
arg_id,
|
.add_var(arg_name.clone(), arg_type, BindingKind::Default);
|
||||||
arg_name.clone(),
|
|
||||||
arg_type,
|
|
||||||
BindingKind::Default,
|
|
||||||
func.body.span.clone(),
|
|
||||||
);
|
|
||||||
typed_args.push((arg_id, arg_name.clone(), arg_type_annot.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typecheck function body
|
// Typecheck function body
|
||||||
let typed_body = self.typecheck_expr(&func.body)?;
|
let typed_body = self.typecheck_expr(&func.body)?;
|
||||||
|
|
||||||
// Exit scope, checking usages
|
// Restore the original environment
|
||||||
self.env.exit_scope()?;
|
self.env = original_env;
|
||||||
|
|
||||||
// Check return type
|
// Check return type
|
||||||
let expected_return =
|
let expected_return = func
|
||||||
if func.name.starts_with("__suic_gen_lambda_") && func.return_type.is_none() {
|
.return_type
|
||||||
// For generated lambda functions, infer return type from body
|
.as_ref()
|
||||||
typed_body.ty.clone()
|
.map(|t| self.type_annot_to_type(t))
|
||||||
} else {
|
.unwrap_or(Type::Unit);
|
||||||
func.return_type
|
|
||||||
.as_ref()
|
|
||||||
.map(|t| self.type_annot_to_type(t))
|
|
||||||
.unwrap_or(Type::Unit)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self.types_compatible(&typed_body.ty, &expected_return) {
|
if !self.types_compatible(&typed_body.ty, &expected_return) {
|
||||||
return Err(TypeError {
|
return Err(TypeError {
|
||||||
|
|
@ -588,7 +474,7 @@ impl TypeChecker {
|
||||||
Ok(TypedFunction {
|
Ok(TypedFunction {
|
||||||
name: func.name.clone(),
|
name: func.name.clone(),
|
||||||
parameters: func.parameters.clone(),
|
parameters: func.parameters.clone(),
|
||||||
args: typed_args,
|
args: func.args.clone(),
|
||||||
return_type: func.return_type.clone(),
|
return_type: func.return_type.clone(),
|
||||||
body: typed_body,
|
body: typed_body,
|
||||||
ty: func_type,
|
ty: func_type,
|
||||||
|
|
@ -604,10 +490,8 @@ impl TypeChecker {
|
||||||
|
|
||||||
ExprKind::Variable(name) => {
|
ExprKind::Variable(name) => {
|
||||||
// First check if it's a variable
|
// First check if it's a variable
|
||||||
if let Some((id, var_info)) = self.env.get_var_by_name(name) {
|
if let Some((t, _)) = self.env.get_var(name) {
|
||||||
let ty = var_info.ty.clone();
|
(TypedExprKind::Variable(name.clone()), t.clone())
|
||||||
self.env.increment_usage(&id);
|
|
||||||
(TypedExprKind::Variable(name.clone()), ty)
|
|
||||||
} else if let Some(func_type) = self.env.get_function(name) {
|
} else if let Some(func_type) = self.env.get_function(name) {
|
||||||
// If not a variable, check if it's a function
|
// If not a variable, check if it's a function
|
||||||
let func_type_clone = func_type.clone();
|
let func_type_clone = func_type.clone();
|
||||||
|
|
@ -805,18 +689,11 @@ impl TypeChecker {
|
||||||
typed_value.ty.clone()
|
typed_value.ty.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let var_id = self.next_binding_id();
|
self.env
|
||||||
self.env.add_var(
|
.add_var(name.clone(), var_type.clone(), binding_kind.clone());
|
||||||
var_id,
|
|
||||||
name.clone(),
|
|
||||||
var_type.clone(),
|
|
||||||
binding_kind.clone(),
|
|
||||||
expr.span.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
TypedExprKind::Let(
|
TypedExprKind::Let(
|
||||||
var_id,
|
|
||||||
name.clone(),
|
name.clone(),
|
||||||
binding_kind.clone(),
|
binding_kind.clone(),
|
||||||
type_annot.clone(),
|
type_annot.clone(),
|
||||||
|
|
@ -899,25 +776,13 @@ impl TypeChecker {
|
||||||
_ => Type::Unknown,
|
_ => Type::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.env.enter_scope();
|
self.env = self.env.enter_scope();
|
||||||
let var_id = self.next_binding_id();
|
self.env
|
||||||
self.env.add_var(
|
.add_var(var.clone(), element_type, BindingKind::Default);
|
||||||
var_id,
|
|
||||||
var.clone(),
|
|
||||||
element_type,
|
|
||||||
BindingKind::Default,
|
|
||||||
expr.span.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let typed_body = self.typecheck_expr(body)?;
|
let typed_body = self.typecheck_expr(body)?;
|
||||||
self.env.exit_scope()?;
|
|
||||||
(
|
(
|
||||||
TypedExprKind::For(
|
TypedExprKind::For(var.clone(), Box::new(typed_iterable), Box::new(typed_body)),
|
||||||
var_id,
|
|
||||||
var.clone(),
|
|
||||||
Box::new(typed_iterable),
|
|
||||||
Box::new(typed_body),
|
|
||||||
),
|
|
||||||
Type::Unit,
|
Type::Unit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1142,10 +1007,8 @@ impl TypeChecker {
|
||||||
let mut result_type = Type::Unknown;
|
let mut result_type = Type::Unknown;
|
||||||
|
|
||||||
for (i, (pattern, body)) in arms.iter().enumerate() {
|
for (i, (pattern, body)) in arms.iter().enumerate() {
|
||||||
self.env.enter_scope();
|
|
||||||
let typed_pattern = self.typecheck_pattern(pattern, &typed_scrutinee.ty)?;
|
let typed_pattern = self.typecheck_pattern(pattern, &typed_scrutinee.ty)?;
|
||||||
let typed_body = self.typecheck_expr(body)?;
|
let typed_body = self.typecheck_expr(body)?;
|
||||||
self.env.exit_scope()?;
|
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
result_type = typed_body.ty.clone();
|
result_type = typed_body.ty.clone();
|
||||||
|
|
@ -1166,62 +1029,29 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Lambda(params, body) => {
|
ExprKind::Lambda(params, body) => {
|
||||||
// Enter scope for lambda parameters
|
self.env = self.env.enter_scope();
|
||||||
self.env.enter_scope();
|
|
||||||
let mut param_types = Vec::new();
|
let mut param_types = Vec::new();
|
||||||
let mut typed_params = Vec::new();
|
|
||||||
for (param_name, param_type_annot) in params {
|
for (param_name, param_type_annot) in params {
|
||||||
let param_id = self.next_binding_id();
|
|
||||||
let param_type = param_type_annot
|
let param_type = param_type_annot
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| self.type_annot_to_type(t))
|
.map(|t| self.type_annot_to_type(t))
|
||||||
.unwrap_or(Type::Unknown);
|
.unwrap_or(Type::Unknown);
|
||||||
param_types.push(param_type.clone());
|
param_types.push(param_type.clone());
|
||||||
self.env.add_var(
|
self.env
|
||||||
param_id,
|
.add_var(param_name.clone(), param_type, BindingKind::Default);
|
||||||
param_name.clone(),
|
|
||||||
param_type,
|
|
||||||
BindingKind::Default,
|
|
||||||
expr.span.clone(),
|
|
||||||
);
|
|
||||||
typed_params.push((param_id, param_name.clone(), param_type_annot.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let typed_body = self.typecheck_expr(body)?;
|
let typed_body = self.typecheck_expr(body)?;
|
||||||
let func_type = Type::Function(param_types, Box::new(typed_body.ty.clone()));
|
let func_type = Type::Function(param_types, Box::new(typed_body.ty.clone()));
|
||||||
|
|
||||||
// Exit scope, checking usages
|
|
||||||
self.env.exit_scope()?;
|
|
||||||
|
|
||||||
(
|
(
|
||||||
TypedExprKind::Lambda(typed_params, Box::new(typed_body)),
|
TypedExprKind::Lambda(params.clone(), Box::new(typed_body)),
|
||||||
func_type,
|
func_type,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Assign(lhs, rhs) => {
|
ExprKind::Assign(lhs, rhs) => {
|
||||||
// Check if lhs is a mutable variable
|
|
||||||
if let ExprKind::Variable(name) = &lhs.kind {
|
|
||||||
if let Some((_, var_info)) = self.env.get_var_by_name(name) {
|
|
||||||
if var_info.kind != BindingKind::Mutable {
|
|
||||||
return Err(TypeError {
|
|
||||||
kind: TypeErrorKind::MutableityError(format!(
|
|
||||||
"Cannot assign to immutable variable '{}'",
|
|
||||||
name
|
|
||||||
)),
|
|
||||||
span: lhs.span.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(TypeError {
|
|
||||||
kind: TypeErrorKind::MutableityError(
|
|
||||||
"Invalid left-hand side of assignment".to_string(),
|
|
||||||
),
|
|
||||||
span: lhs.span.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let typed_lhs = self.typecheck_expr(lhs)?;
|
let typed_lhs = self.typecheck_expr(lhs)?;
|
||||||
let typed_rhs = self.typecheck_expr(rhs)?;
|
let typed_rhs = self.typecheck_expr(rhs)?;
|
||||||
|
|
||||||
|
|
@ -1340,16 +1170,10 @@ impl TypeChecker {
|
||||||
PatternKind::Wildcard => (TypedPatternKind::Wildcard, scrutinee_type.clone()),
|
PatternKind::Wildcard => (TypedPatternKind::Wildcard, scrutinee_type.clone()),
|
||||||
|
|
||||||
PatternKind::Variable(name) => {
|
PatternKind::Variable(name) => {
|
||||||
let var_id = self.next_binding_id();
|
self.env
|
||||||
self.env.add_var(
|
.add_var(name.clone(), scrutinee_type.clone(), BindingKind::Default);
|
||||||
var_id,
|
|
||||||
name.clone(),
|
|
||||||
scrutinee_type.clone(),
|
|
||||||
BindingKind::Default,
|
|
||||||
pattern.span.clone(),
|
|
||||||
);
|
|
||||||
(
|
(
|
||||||
TypedPatternKind::Variable(var_id, name.clone()),
|
TypedPatternKind::Variable(name.clone()),
|
||||||
scrutinee_type.clone(),
|
scrutinee_type.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
fn test_affine() -> int do
|
|
||||||
let uniq x = 5
|
|
||||||
x + 1
|
|
||||||
x + 2
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
fn test_binding_id() -> int do
|
|
||||||
let x = 5
|
|
||||||
let x = x + 1 # shadowing
|
|
||||||
x
|
|
||||||
end
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
fn test_linear() -> int do
|
|
||||||
let once y = 10
|
|
||||||
5
|
|
||||||
end
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
fn test_linear_ok() -> int do
|
|
||||||
let once z = 10
|
|
||||||
z + 5
|
|
||||||
end
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fn test_scoping() -> int do
|
|
||||||
let x = 5
|
|
||||||
let f = lambda (y) y + 1 # simple lambda
|
|
||||||
f = lambda (z) z+1
|
|
||||||
let x = 10 # shadow x
|
|
||||||
f(3) # should work
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
fn test_shadow() -> int do
|
|
||||||
let x = 5
|
|
||||||
let x = 10
|
|
||||||
x
|
|
||||||
end
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
# OCaml my Caml, our fearful trip is `done`
|
|
||||||
|
|
||||||
fn main(_) do
|
|
||||||
let mylamba = lambda (x) x+1;
|
|
||||||
mylamba(5)
|
|
||||||
let id = lambda (y) y;
|
|
||||||
id("hi")
|
|
||||||
id(1)
|
|
||||||
end
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue