Some HIR
```python x = """Lambda, If, Set, Define, Cond, Case, And, Or, When, Unless, Begin,""" x = x.replace(" ", "").replace(",", "").replace("\r", "") x = x.splitlines() print("// ===== Begin Special Forms =====") for i in x: i = i.lower() print(f"fn sf_{i}<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {{") print("todo!()") print("}") print("// ===== End Special Forms =====") ```trunk
parent
c98550907d
commit
0b82031e1b
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
(+ 1 2 (/ 3 4))
|
||||||
|
|
||||||
|
(if (= 2 "hello world")
|
||||||
|
(display f x)
|
||||||
|
1)
|
14
hello.scm
14
hello.scm
|
@ -9,3 +9,17 @@
|
||||||
(set! f f_)))
|
(set! f f_)))
|
||||||
|
|
||||||
(f)
|
(f)
|
||||||
|
|
||||||
|
|
||||||
|
(fffo
|
||||||
|
(ddssd))
|
||||||
|
|
||||||
|
(define (fx)
|
||||||
|
(+ x x))
|
||||||
|
|
||||||
|
(defin)
|
||||||
|
|
||||||
|
(def)
|
||||||
|
|
||||||
|
(define (f x)
|
||||||
|
(+ 2 3 4 x))
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
use crate::{Ast, Error};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum Hir<'s> {
|
||||||
|
Call(Box<Hir<'s>>, Vec<Hir<'s>>),
|
||||||
|
If(Box<(Hir<'s>, Hir<'s>, Hir<'s>)>),
|
||||||
|
Define(&'s str, Box<Hir<'s>>),
|
||||||
|
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<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lowerer {
|
||||||
|
pub(crate) fn ast<'s>(&mut self, a: &Ast<'s>) -> Option<Hir<'s>> {
|
||||||
|
match a {
|
||||||
|
Ast::Tree(tree) => self.tree(tree),
|
||||||
|
Ast::Leaf(leaf) => self.leaf(leaf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf<'a>(&mut self, leaf: &'a str) -> Option<Hir<'a>> {
|
||||||
|
// 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<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
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<SpecialForm> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_if<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_define<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn define_val<'a>(&mut self, name: &'a str, rest: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
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<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_case<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_and<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_or<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_when<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_unless<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn sf_begin<'a>(&mut self, tree: &[Ast<'a>]) -> Option<Hir<'a>> {
|
||||||
|
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<T>(self) -> Option<Vec<T>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
Option<Vec<T>>: FromIterator<Self::Item>,
|
||||||
|
{
|
||||||
|
// 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<T: Iterator> IterExt for T {}
|
14
src/main.rs
14
src/main.rs
|
@ -1,7 +1,11 @@
|
||||||
|
mod hir;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
|
use anyhow::bail;
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
|
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, logos::Logos)]
|
#[derive(Debug, PartialEq, logos::Logos)]
|
||||||
enum Kind {
|
enum Kind {
|
||||||
#[token("(")]
|
#[token("(")]
|
||||||
|
@ -33,7 +37,15 @@ fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let src = fs::read_to_string(&arg)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use logos::Logos;
|
||||||
|
|
||||||
use crate::{Ast, Kind};
|
use crate::{Ast, Kind};
|
||||||
|
|
||||||
type Error = String;
|
use crate::Error;
|
||||||
|
|
||||||
struct Parser<'s> {
|
struct Parser<'s> {
|
||||||
lex: Peekable<Lexer<'s>>,
|
lex: Peekable<Lexer<'s>>,
|
||||||
|
|
Loading…
Reference in New Issue