diff --git a/SCHEMES.md b/SCHEMES.md new file mode 100644 index 0000000..4e98d7f --- /dev/null +++ b/SCHEMES.md @@ -0,0 +1,62 @@ +## Chez + +- `chezscheme` +- `M-x run-chez` +- + ```lisp + > (expand '(define (f x) (cond (a b) (c d) (else e)))) + (begin + (set! f + (lambda (#{x kbvpqn6dj3c6k95f21kwqmji8-1}) + (if a b (if c d e)))) + (#2%void)) + ``` + +## Chicken + +- `csi` +- + ```lisp + #2> (import expand-full) ; May need to be `chicken-installed` first + ; loading /var/lib//chicken/11/expand-full.import.so ... + ; loading /var/lib//chicken/11/expand-full.so ... + ; loading /var/lib//chicken/11/srfi-1.so ... + #3> (ppexpand* '(define (f x) (cond (a b) (c d) (else e)))) + (##core#begin + (##core#ensure-toplevel-definition f) + (##core#set! + f + (##core#lambda + (x) + (##core#if + a + (##core#begin b) + (##core#if c (##core#begin d) (##core#begin e)))))) + ``` + +## Racket + +`racket + + +## Chibi + +- `chibi-scheme` +- `M-x run-chibi` +- + ```lisp + > (import (chibi ast)) + > (macroexpand '(define (f x) (cond (a b) (c d) (else g)))) + (set! f (lambda (x) (if a b (if c d g)))) + ``` + +## Gambit + +## Gauche + +## Guile + +## MIT-scheme + +## Racket + diff --git a/basic.scm b/basic.scm new file mode 100644 index 0000000..57e32a1 --- /dev/null +++ b/basic.scm @@ -0,0 +1,5 @@ +(+ 1 2 (/ 3 4)) + +(if (= 2 "hello world") + (display f x) + 1) \ No newline at end of file diff --git a/hello.scm b/hello.scm index 11d8dd0..da5368f 100644 --- a/hello.scm +++ b/hello.scm @@ -9,3 +9,17 @@ (set! f f_))) (f) + + +(fffo + (ddssd)) + +(define (fx) + (+ x x)) + +(defin) + +(def) + +(define (f x) + (+ 2 3 4 x)) diff --git a/src/hir.rs b/src/hir.rs new file mode 100644 index 0000000..18d2681 --- /dev/null +++ b/src/hir.rs @@ -0,0 +1,231 @@ +use crate::{Ast, Error}; + +#[derive(Debug)] +pub(crate) enum Hir<'s> { + Call(Box>, Vec>), + If(Box<(Hir<'s>, Hir<'s>, Hir<'s>)>), + Define(&'s str, Box>), + Ident(&'s str), + Lit(Lit<'s>), +} + +#[derive(Debug)] +pub(crate) enum Lit<'s> { + Str(&'s str), + Num(f64), +} + +#[derive(Debug, Default)] +pub(crate) struct Lowerer { + errors: Vec, +} + +impl Lowerer { + pub(crate) fn ast<'s>(&mut self, a: &Ast<'s>) -> Option> { + match a { + Ast::Tree(tree) => self.tree(tree), + Ast::Leaf(leaf) => self.leaf(leaf), + } + } + + fn leaf<'a>(&mut self, leaf: &'a str) -> Option> { + // TODO + let fst = leaf.chars().next().unwrap(); + + if fst == '"' { + return self.str(leaf); + } else if fst.is_digit(10) { + return self.num(leaf); + } + + Some(Hir::Ident(leaf)) + } + + fn str<'a>(&mut self, leaf: &'a str) -> Option> { + assert_eq!(leaf.chars().next().unwrap(), '"'); + assert_eq!(leaf.chars().last().unwrap(), '"'); + + Some(Hir::Lit(Lit::Str(&leaf[1..leaf.len() - 1]))) + } + + fn num<'a>(&mut self, leaf: &str) -> Option> { + match leaf.parse() { + Ok(n) => Some(Hir::Lit(Lit::Num(n))), + Err(_) => { + self.errors.push(format!("Invalid float `{}`", leaf)); + None + } + } + } + + fn tree<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + let first = tree.first().unwrap(); + if let Some(sf) = Self::get_special_form(first) { + self.special_form(sf, &tree[1..]) + } else { + self.call(tree) + } + } + + fn get_special_form(a: &Ast<'_>) -> Option { + use SpecialForm::*; + + let leaf = match a { + Ast::Leaf(l) => *l, + Ast::Tree(_) => return None, + }; + + Some(match leaf { + "define" => Define, + "lambda" => Lambda, + "cond" => Cond, + "begin" => Begin, + "when" => When, + "unless" => Unless, + "set" => Set, + _ => return None, + }) + } + + fn special_form<'a>(&mut self, sf: SpecialForm, tree: &[Ast<'a>]) -> Option> { + match sf { + SpecialForm::Lambda => self.sf_lambda(tree), + SpecialForm::If => self.sf_if(tree), + SpecialForm::Set => self.sf_set(tree), + SpecialForm::Define => self.sf_define(tree), + SpecialForm::Cond => self.sf_cond(tree), + SpecialForm::Case => self.sf_case(tree), + SpecialForm::And => self.sf_and(tree), + SpecialForm::Or => self.sf_or(tree), + SpecialForm::When => self.sf_when(tree), + SpecialForm::Unless => self.sf_unless(tree), + SpecialForm::Begin => self.sf_begin(tree), + } + } + + fn call<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + let func = tree.first().unwrap(); + let args = &tree[1..]; + + let func = self.ast(func)?; + let args = args.iter().map(|arg| self.ast(arg)).collect_opt()?; + + Some(Hir::Call(Box::new(func), args)) + } + + // ===== Begin Special Forms ===== + // ===== Begin Special Forms ===== + fn sf_lambda<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_if<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + let [test, when, unless] = self.n_args(tree, "if")?; + let test = self.ast(test)?; + let when = self.ast(when)?; + let unless = self.ast(unless)?; + Some(Hir::If(Box::new((test, when, unless)))) + } + fn sf_set<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_define<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + let what = &tree[0]; + let rest = &tree[1..]; + match what { + Ast::Tree(nameargs) => self.define_func(nameargs, rest), + Ast::Leaf(name) => self.define_val(name, rest), + } + } + + fn define_func<'a>(&mut self, nameargs: &[Ast<'a>], rest: &[Ast<'a>]) -> Option> { + todo!() + } + + fn define_val<'a>(&mut self, name: &'a str, rest: &[Ast<'a>]) -> Option> { + let [val] = self.n_args(rest, "define(value)")?; + let val = self.ast(val)?; + + Some(Hir::Define(name, Box::new(val))) + } + + fn sf_cond<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_case<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_and<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_or<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_when<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_unless<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + fn sf_begin<'a>(&mut self, tree: &[Ast<'a>]) -> Option> { + todo!() + } + // ===== End Special Forms ===== + + fn n_args<'a, 'b, const N: usize>( + &mut self, + tree: &'b [Ast<'a>], + name: &str, + ) -> Option<&'b [Ast<'a>; N]> { + match tree.try_into() { + Ok(arr) => Some(arr), + Err(_) => { + self.errors + .push(format!("{} need {} args, but got {}", name, N, tree.len())); + None + } + } + } +} + +enum SpecialForm { + Lambda, + If, + // TODO: Define vs set. + Set, + Define, + + Cond, + Case, + And, + Or, + When, + Unless, + + // Let, + // LetStar, + // Letrec, + // LetrecStar, + // LetValues, + // LetStarValues, + Begin, + // Do, + // Only needed if we do the lazy lib + // Delay, + // DelayForce, + // Force, + // Guard, +} + +trait IterExt: Iterator { + fn collect_opt(self) -> Option> + where + Self: Sized, + Option>: FromIterator, + { + // TODO: Customize this to not early return, so we get errors from + // later parts even if we know theirs already an error. + self.collect() + } +} + +impl IterExt for T {} diff --git a/src/main.rs b/src/main.rs index 9b78de7..7c0b21e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,11 @@ +mod hir; mod parser; +use anyhow::bail; use fs_err as fs; +type Error = String; + #[derive(Debug, PartialEq, logos::Logos)] enum Kind { #[token("(")] @@ -33,7 +37,15 @@ fn main() -> anyhow::Result<()> { let src = fs::read_to_string(&arg)?; - dbg!(parser::parse(&src)); + let (trees, errs) = dbg!(parser::parse(&src)); + + if !errs.is_empty() { + bail!("Got some parse errors"); + } + + for tree in trees { + dbg!(hir::Lowerer::default().ast(&tree)); + } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 7fae83d..20a1070 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4,7 +4,7 @@ use logos::Logos; use crate::{Ast, Kind}; -type Error = String; +use crate::Error; struct Parser<'s> { lex: Peekable>,