From 9dfe8a30214bd78ee152a086580d486a720d97a4 Mon Sep 17 00:00:00 2001 From: melody! <24357776+melody-notpond@users.noreply.github.com> Date: Mon, 20 May 2024 19:13:43 +0000 Subject: [PATCH] idk --- src/ast.rs | 14 +++ src/lib.rs | 1 + src/seperation.rs | 197 +++++++++++++++++++++++++++++++++ src/typecheck.rs | 105 ++++++++++++------ tests/amy/seperation/basic.amy | 6 + 5 files changed, 288 insertions(+), 35 deletions(-) create mode 100644 src/seperation.rs create mode 100644 tests/amy/seperation/basic.amy diff --git a/src/ast.rs b/src/ast.rs index a4a3a42..28890f7 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -16,6 +16,20 @@ impl Type { _ => self } } + + pub fn generates_pointer(&self) -> bool { + let Type::Func(_, r) = self + else { + return false; + }; + + let Type::Name(s) = r.func_of_app() + else { + return false; + }; + + s == "Pointer" + } } impl Display for Type { diff --git a/src/lib.rs b/src/lib.rs index 20a2bd3..99f44b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod ast; pub mod lexer; pub mod parse; +pub mod seperation; pub mod typecheck; diff --git a/src/seperation.rs b/src/seperation.rs new file mode 100644 index 0000000..81cfb8a --- /dev/null +++ b/src/seperation.rs @@ -0,0 +1,197 @@ +use std::{fmt::Display, collections::HashMap}; + +#[derive(Debug, Clone)] +enum MapValue { + Unknown, + Pointer(usize), + // Struct(Vec>), +} + +impl Display for MapValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MapValue::Unknown => write!(f, "-"), + MapValue::Pointer(p) => write!(f, "p_{p}"), + // MapValue::Struct(vs) => { + // write!(f, "(")?; + + // if let Some(v) = vs.first() { + // match v { + // Some(p) => write!(f, "p_{p}")?, + // None => write!(f, "_")?, + // } + // } + + // for v in vs[1..].iter() { + // match v { + // Some(p) => write!(f, ", p_{p}")?, + // None => write!(f, ", _")?, + // } + // } + + // write!(f, ")") + // } + } + } +} + +#[derive(Debug, Clone)] +enum HeapPred { + Empty, + Map(usize, MapValue), + Star(Vec), +} + +impl Display for HeapPred { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HeapPred::Empty => write!(f, "emp"), + HeapPred::Map(p, v) => write!(f, "p_{p} |-> {v}"), + HeapPred::Star(s) => { + if let Some(p) = s.first() { + write!(f, "({p}")?; + } + + for p in s[1..].iter() { + write!(f, " * {p}")?; + } + + write!(f, ")") + } + } + } +} + +impl HeapPred { + fn add_predicate(&mut self, pred: HeapPred) { + match (self, pred) { + (_, HeapPred::Empty) => (), + (s @ HeapPred::Empty, pred) => *s = pred, + + (HeapPred::Star(ps), HeapPred::Star(ps_add)) => ps.extend(ps_add), + (HeapPred::Star(ps), pred) => ps.push(pred), + (s, pred @ HeapPred::Star(_)) => { + let mut temp = pred; + std::mem::swap(s, &mut temp); + let HeapPred::Star(ps) = s + else { + unreachable!(); + }; + ps.push(temp); + } + + (s, pred) => { + let mut temp = HeapPred::Star(vec![pred]); + std::mem::swap(s, &mut temp); + let HeapPred::Star(ps) = s + else { + unreachable!(); + }; + ps.insert(0, temp); + } + } + } + + fn remove_map(&mut self, ptr: usize) -> bool { + match self { + HeapPred::Star(ps) => { + let mut i = None; + for (j, p) in ps.iter_mut().enumerate() { + match p { + &mut HeapPred::Map(p_, _) => { + if ptr == p_ { + i = Some(j); + break; + } + } + + p => { + if p.remove_map(ptr) { + return true; + } + } + } + } + + if let Some(i) = i { + ps.remove(i); + true + } else { + false + } + } + + &mut HeapPred::Map(p, _) if p == ptr => { + *self = HeapPred::Empty; + true + } + + _ => false, + } + } + + fn unifiable(&self, other: &HeapPred) -> bool { + match (self, other) { + (HeapPred::Empty, HeapPred::Empty) => true, + + // TODO + _ => false, + } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Pointer(usize); + +#[derive(Debug, Clone)] +pub struct Store { + var_map: HashMap, + pred: HeapPred, + next_ptr: usize, +} + +impl Default for Store { + fn default() -> Self { + Self { + var_map: HashMap::default(), + pred: HeapPred::Empty, + next_ptr: 1, + } + } +} + +impl Display for Store { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}, sigma |= {}", self.var_map, self.pred) + } +} + +impl Store { + pub fn alloc(&mut self) -> Pointer { + let ptr = self.next_ptr; + self.pred.add_predicate(HeapPred::Map(ptr, MapValue::Unknown)); + self.next_ptr += 1; + Pointer(ptr) + } + + pub fn dealloc(&mut self, ptr: Pointer) -> bool { + self.pred.remove_map(ptr.0) + } + + pub fn set_var(&mut self, var: &str, p: Pointer) -> Option { + self.var_map.insert(var.to_owned(), p.0).map(Pointer) + } + + pub fn get_var(&self, var: &str) -> Option { + self.var_map.get(var).cloned().map(Pointer) + } + + pub fn remove_var(&mut self, var: &str) -> Option { + self.var_map.remove(var).map(Pointer) + } + + // TEMP: we prolly don't need this once we actually have types + pub fn is_empty(&self) -> bool { + self.pred.unifiable(&HeapPred::Empty) + } +} diff --git a/src/typecheck.rs b/src/typecheck.rs index 75d2e0d..5a8a6d4 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -1,10 +1,9 @@ use std::collections::{HashMap, hash_map::Entry}; -use crate::ast::*; +use crate::{ast::*, seperation::{Pointer, Store}}; #[derive(Debug)] struct TypeData { - va_params: bool, params: Vec, variants: Vec, } @@ -18,37 +17,71 @@ pub struct TypeError { pub message: String, } -pub fn typecheck(ast: &[TopLevel]) -> Result<(), TypeError> { - // set up scopes +fn initial_values() -> (HashMap, HashMap) { let mut globals = HashMap::new(); - let mut defined_types = HashMap::new(); - let mut type_vars = Vec::new(); - defined_types.insert("Tuple".to_owned(), TypeData { - va_params: true, - params: Vec::new(), - variants: Vec::new(), + globals.insert("!".to_owned(), GlobalData { + type_: Type::Func( + vec![Type::App(Box::new(Type::Name("Pointer".to_owned())), vec![Type::Generic("T".to_owned())])], + Box::new(Type::Generic("T".to_owned()))), + variant_of: None, }); + globals.insert(":=".to_owned(), GlobalData { + type_: Type::Func( + vec![ + Type::App(Box::new(Type::Name("Pointer".to_owned())), vec![Type::Generic("T".to_owned())]), + Type::Generic("T".to_owned()), + ], + Box::new(Type::Name("Unit".to_owned()))), + variant_of: None, + }); + globals.insert("alloc".to_owned(), GlobalData { + type_: Type::Func( + vec![Type::Generic("T".to_owned())], + Box::new(Type::App(Box::new(Type::Name("Pointer".to_owned())), vec![Type::Generic("T".to_owned())]))), + variant_of: None, + }); + globals.insert("dealloc".to_owned(), GlobalData { + type_: Type::Func( + vec![Type::App(Box::new(Type::Name("Pointer".to_owned())), vec![Type::Generic("T".to_owned())])], + Box::new(Type::Name("Unit".to_owned()))), + variant_of: None, + }); + globals.insert("Unit".to_owned(), GlobalData { + type_: Type::Func( + vec![], + Box::new(Type::Name("Unit".to_owned()))), + variant_of: Some("Unit".to_owned()), + }); + + let mut defined_types = HashMap::new(); defined_types.insert("Int".to_owned(), TypeData { - va_params: false, params: Vec::new(), variants: Vec::new(), }); defined_types.insert("Unit".to_owned(), TypeData { - va_params: false, params: Vec::new(), - variants: Vec::new(), + variants: vec![Variant { + name: "Unit".to_owned(), + fields: Vec::new(), + }], }); defined_types.insert("String".to_owned(), TypeData { - va_params: false, params: Vec::new(), variants: Vec::new(), }); defined_types.insert("Pointer".to_owned(), TypeData { - va_params: false, params: vec!["T".to_string()], variants: Vec::new(), }); + (globals, defined_types) +} + +pub fn typecheck(ast: &[TopLevel]) -> Result<(), TypeError> { + // set up scopes + let (mut globals, mut defined_types) = initial_values(); + let mut type_vars = Vec::new(); + // get all globals (functions and type definitions) for top in ast { match top { @@ -85,7 +118,6 @@ pub fn typecheck(ast: &[TopLevel]) -> Result<(), TypeError> { } let data = TypeData { - va_params: false, params: generics.clone(), variants: variants.clone(), }; @@ -127,8 +159,9 @@ pub fn typecheck(ast: &[TopLevel]) -> Result<(), TypeError> { } let mut has_ret = false; + let mut store = Store::default(); for stat in stats { - has_ret |= typecheck_stat(&mut type_vars, &defined_types, &globals, &mut scopes, stat, &ret, false)?; + has_ret |= typecheck_stat(&mut type_vars, &defined_types, &globals, &mut scopes, stat, &ret, false, &mut store)?; } match ret { @@ -159,12 +192,13 @@ fn typecheck_stat( stat: &Statement, expected_ret: &Type, in_loop: bool, + store: &mut Store, ) -> Result { match stat { Statement::FuncCall { func, args } => { let mut a = Vec::new(); for arg in args { - a.push(typecheck_expr(type_vars, globals, scopes, arg)?); + a.push(typecheck_expr(type_vars, globals, scopes, arg, store)?); } let f = lookup(type_vars, globals, scopes, func)?; @@ -174,13 +208,13 @@ fn typecheck_stat( } Statement::Let { name, value } => { - let ty = typecheck_expr(type_vars, globals, scopes, value)?; + let ty = typecheck_expr(type_vars, globals, scopes, value, store)?; scopes.last_mut().unwrap().insert(name.clone(), ty); Ok(false) } Statement::Set { name, value } => { - let ty = typecheck_expr(type_vars, globals, scopes, value)?; + let ty = typecheck_expr(type_vars, globals, scopes, value, store)?; let local = &lookup_local(type_vars, scopes, name)?; unify(type_vars, local, &ty)?; Ok(false) @@ -189,7 +223,7 @@ fn typecheck_stat( Statement::Loop { body } => { scopes.push(HashMap::new()); for stat in body { - typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, true)?; + typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, true, store)?; } scopes.pop(); @@ -208,7 +242,7 @@ fn typecheck_stat( Statement::Return(v) => { let ty = match v { - Some(v) => typecheck_expr(type_vars, globals, scopes, &v)?, + Some(v) => typecheck_expr(type_vars, globals, scopes, &v, store)?, None => Type::Name("Unit".to_owned()), }; unify(type_vars, &ty, expected_ret)?; @@ -216,7 +250,7 @@ fn typecheck_stat( } Statement::If { cond, then, elsy } => { - let ty = typecheck_expr(type_vars, globals, scopes, cond)?; + let ty = typecheck_expr(type_vars, globals, scopes, cond, store)?; match ty.func_of_app() { Type::Name(n) => { let Some(data) = defined_types.get(n) @@ -238,14 +272,14 @@ fn typecheck_stat( scopes.push(HashMap::new()); let mut then_ret = false; for stat in then.iter() { - then_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop)?; + then_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop, store)?; } scopes.pop(); scopes.push(HashMap::new()); let mut else_ret = false; for stat in elsy.iter() { - else_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop)?; + else_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop, store)?; } scopes.pop(); @@ -259,7 +293,7 @@ fn typecheck_stat( } Statement::Match { value, branches } => { - let t = typecheck_expr(type_vars, globals, scopes, value)?; + let t = typecheck_expr(type_vars, globals, scopes, value, store)?; let mut ret = !branches.is_empty(); for (pat, stats) in branches { @@ -270,7 +304,7 @@ fn typecheck_stat( let mut branch_ret = false; for stat in stats { - branch_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop)?; + branch_ret |= typecheck_stat(type_vars, defined_types, globals, scopes, stat, expected_ret, in_loop, store)?; } ret &= branch_ret; @@ -394,17 +428,22 @@ fn typecheck_expr( globals: &HashMap, scopes: &mut Vec>, expr: &Expr, + store: &mut Store, ) -> Result { match expr { Expr::Integer(_) => Ok(Type::Name("Int".to_string())), Expr::String(_) => Ok(Type::Name("String".to_string())), - Expr::Symbol(s) => lookup(type_vars, globals, scopes, s), + Expr::Symbol(s) => { + let t = lookup(type_vars, globals, scopes, s)?; + let _p = store.get_var(s); + Ok(t) + } Expr::FuncCall { func, args } => { - let f = typecheck_expr(type_vars, globals, scopes, &func)?; + let f = typecheck_expr(type_vars, globals, scopes, &func, store)?; let mut a = Vec::new(); for a_orig in args { - a.push(typecheck_expr(type_vars, globals, scopes, a_orig)?) + a.push(typecheck_expr(type_vars, globals, scopes, a_orig, store)?) } valid_call(type_vars, &f, &a).cloned() @@ -521,11 +560,7 @@ fn verify_type(t: &Type, defined_types: &HashMap) -> Result<() }); }; - if data.va_params { - Ok(None) - } else { - Ok(Some(data.params.len())) - } + Ok(Some(data.params.len())) } Type::Func(args, ret) => { diff --git a/tests/amy/seperation/basic.amy b/tests/amy/seperation/basic.amy new file mode 100644 index 0000000..b3e6dc3 --- /dev/null +++ b/tests/amy/seperation/basic.amy @@ -0,0 +1,6 @@ +def main() do + let p = alloc(0) + let _ = p := 1 + let _ = p := p! + dealloc(p) +end