diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-15 11:27:52 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-15 11:27:52 +0300 |
commit | 0ca4c3f103acd9d1ea78bbc42b9b70161a94308d (patch) | |
tree | 7e8144434656f44e2e1f66175bb80ec6364a6ce5 | |
parent | 322f541d6922422e5a4aa29f50c6534517ee85be (diff) | |
download | myslip-0ca4c3f103acd9d1ea78bbc42b9b70161a94308d.tar.gz myslip-0ca4c3f103acd9d1ea78bbc42b9b70161a94308d.zip |
feat: fixed point dynamics
-rw-r--r-- | TUTORIAL.md | 2 | ||||
-rw-r--r-- | src/sexp/step.rs | 62 | ||||
-rw-r--r-- | src/sexp/util.rs | 41 | ||||
-rw-r--r-- | src/type/check.rs | 2 |
4 files changed, 81 insertions, 26 deletions
diff --git a/TUTORIAL.md b/TUTORIAL.md index 8e5165d..d7bf266 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -199,7 +199,7 @@ For basic lists, the `case`-operator can be used. It's syntax is: ```myslip (case [condition] - ([pattern 1] [value 1]) + ([pattern 1] [value 1]) ([pattern 2] [value 2]) ...) ``` diff --git a/src/sexp/step.rs b/src/sexp/step.rs index 5b60fec..84553e1 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -1,6 +1,5 @@ use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; -use crate::r#type::{Type::*, util::*}; impl SExp { @@ -346,6 +345,31 @@ impl SExp { None => panic!("unreachable as per match guard arm"), }, + // Custom anonymous functions + SCons(op, l) if (*op).is_fun() => { + + // Get function parts + let ls = op.parts(); + let argnames = ls.get(1).unwrap() + .clone().parts(); + let mut argnamevec = vec![]; + for name in argnames.clone() { + argnamevec.push(match name { + Atom(Var(s)) => Ok(s), + _ => Err("invalid entry in argument list (should be unreachable after type checker)".to_string()), + }?); + } + let mut body = ls.get(4).unwrap().clone(); + + // Get argument parts + let suppliedargs = l.parts(); + for (name, value) in argnamevec.into_iter().zip(suppliedargs) { + body = body.subst(&name, &value); + } + + Ok(body) + }, + // case expressions SCons(op, l) if scons(op.clone(), l.clone()).check_case().is_some() => { let (scrutinee, patarms) = scons(op, l).check_case().unwrap(); @@ -394,29 +418,19 @@ impl SExp { }, - // Custom anonymous functions - SCons(op, l) if (*op).is_fun() => { - - // Get function parts - let ls = op.parts(); - let argnames = ls.get(1).unwrap() - .clone().parts(); - let mut argnamevec = vec![]; - for name in argnames.clone() { - argnamevec.push(match name { - Atom(Var(s)) => Ok(s), - _ => Err("invalid entry in argument list (should be unreachable after type checker)".to_string()), - }?); - } - let mut body = ls.get(4).unwrap().clone(); - - // Get argument parts - let suppliedargs = l.parts(); - for (name, value) in argnamevec.into_iter().zip(suppliedargs) { - body = body.subst(&name, &value); - } - - Ok(body) + // Fixed point recursion + SCons(op, l) if *op == Atom(Fix) => { + let ls = match (*l).clone() { + SCons(a, n) if *n == Atom(Nil) => a.clone(), + _ => todo!() + }.parts(); + let argls = ls[1].clone(); + let argname = match argls { + Atom(Var(name)) => name, + _ => todo!() + }; + let body = ls[4].clone(); + Ok(body.subst(&argname, &scons(op, l))) }, diff --git a/src/sexp/util.rs b/src/sexp/util.rs index aa7ae18..db400e9 100644 --- a/src/sexp/util.rs +++ b/src/sexp/util.rs @@ -87,6 +87,47 @@ impl SExp { } } + pub fn get_vars_bound_by_pattern(&self) -> Vec<String> { + match self { + Atom(Var(s)) => vec![s.clone()], + Atom(RestPat(s)) => vec![s.clone()], + SCons(a, b) => + (*a).get_vars_bound_by_pattern() + .into_iter() + .chain((*b).get_vars_bound_by_pattern()) + .collect(), + _ => vec![], + } + } + + pub fn get_case_scrut_pats_and_arms(self) -> + Option<(SExp, Vec<(SExp, SExp)>)> { + let (scrutinee, patarms) = self.check_case()?; + + let scrutinee = match scrutinee { + SCons(q, v) if *q == Atom(Quote) || *q == Atom(Vector) => *v, + t => t, + }; + + let mut res = vec![]; + for patarm in patarms { + let (pat, arm) = match patarm { + SCons(pat, arm) => Some((*pat, *arm)), + _ => { + println!("warn: invalid structure in case arms,"); + println!(" should be unreachable after type checking"); + None + }, + }?; + let arm = match arm { + SCons(x, n) if *n == Atom(Nil) => *x, + t => t, + }; + res.push((pat, arm)); + } + Some((scrutinee, res)) + } + pub fn check_case(self) -> Option<(SExp, Vec<SExp>)> { match &(self.parts())[..] { [casekw, scrutinee, cases @ ..] if casekw.clone() == Atom(Case) => diff --git a/src/type/check.rs b/src/type/check.rs index d118871..170feec 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -483,7 +483,7 @@ impl Type { #[cfg(test)] mod tests { - use super::{*, TypeError}; + use super::*; #[test] fn test_failing_infer_generics() { |