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_)))
|
||||
|
||||
(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;
|
||||
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use logos::Logos;
|
|||
|
||||
use crate::{Ast, Kind};
|
||||
|
||||
type Error = String;
|
||||
use crate::Error;
|
||||
|
||||
struct Parser<'s> {
|
||||
lex: Peekable<Lexer<'s>>,
|
||||
|
|
Loading…
Reference in New Issue