WIP to think about tail calls etc

This commit is contained in:
Dane Johnson 2024-11-13 09:50:44 -06:00
parent 201d7d2594
commit d4d4756002
3 changed files with 77 additions and 11 deletions

View File

@ -5,14 +5,16 @@ use crate::parser;
pub struct LexicalContext<'a> { pub struct LexicalContext<'a> {
parent: Option<&'a LexicalContext<'a>>, parent: Option<&'a LexicalContext<'a>>,
local: HashSet<String> local: HashSet<String>,
is_tail: bool,
} }
impl <'a> LexicalContext<'a> { impl <'a> LexicalContext<'a> {
pub fn toplevel() -> Self { pub fn toplevel() -> Self {
LexicalContext { LexicalContext {
parent: None, parent: None,
local: HashSet::new() local: HashSet::new(),
is_tail: false,
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -20,6 +22,7 @@ impl <'a> LexicalContext<'a> {
LexicalContext { LexicalContext {
parent: Some(parent), parent: Some(parent),
local: HashSet::new(), local: HashSet::new(),
is_tail: false,
} }
} }
fn contains(&self, s: &str) -> bool { fn contains(&self, s: &str) -> bool {
@ -53,7 +56,32 @@ pub fn emit(w: &mut dyn Write, stmt: &parser::Stmt, ctx: &mut LexicalContext) ->
emit_expr(w, expr, ctx)?; emit_expr(w, expr, ctx)?;
writeln!(w, ";")?; writeln!(w, ";")?;
} }
_ => todo!(), parser::Stmt::Funcall(call) => {
emit_expr(w, call, ctx)?;
writeln!(w, ";")?;
}
parser::Stmt::Conditional(if_blocks, else_block) => {
let mut first_block = true;
for if_block in if_blocks {
if first_block {
write!(w, "if (")?;
} else {
write!(w, " else if(")?;
}
first_block = false;
emit_expr(w, &if_block.guard, ctx)?;
writeln!(w, ") {{")?;
let mut block_ctx = LexicalContext::new(ctx);
emit_expr(w, &if_block.block, &mut block_ctx)?;
writeln!(w, "}}")?;
}
if let Some(block) = else_block {
writeln!(w, "else {{")?;
let mut block_ctx = LexicalContext::new(ctx);
emit_expr(w, block, &mut block_ctx)?;
writeln!(w, "}}")?;
}
}
} }
Ok(()) Ok(())
} }
@ -66,6 +94,42 @@ pub fn emit_expr(w: &mut dyn Write, expr: &parser::Expr, ctx: &mut LexicalContex
parser::Expr::Atom(atom) => { parser::Expr::Atom(atom) => {
write!(w, "{}", atom)?; write!(w, "{}", atom)?;
} }
parser::Expr::Funcall(id, args) => {
write!(w, "{}", id)?;
if args.is_empty() {
write!(w, "()")?;
}
for arg in args {
write!(w, "(")?;
emit_expr(w, arg, ctx)?;
write!(w, ")")?;
}
}
parser::Expr::Funcdef(arg, body) => {
if let Some(arg) = arg {
writeln!(w, "function ({}){{", arg)?;
} else {
writeln!(w, "function (){{")?;
}
let mut fun_ctx = LexicalContext::new(ctx);
fun_ctx.is_tail = true;
emit_expr(w, body.as_ref(), &mut fun_ctx)?;
write!(w, "}}")?;
}
parser::Expr::Block(stmts) => {
let mut peek_iter = stmts.iter().peekable();
while let Some(stmt) = peek_iter.next() {
if peek_iter.peek().is_none() {
write!(w, "return ")?;
}
emit(w, stmt, ctx)?;
}
}
parser::Expr::Plus(e1, e2) => {
emit_expr(w, e1.as_ref(), ctx)?;
write!(w, " + ")?;
emit_expr(w, e2.as_ref(), ctx)?;
}
_ => todo!(), _ => todo!(),
} }
Ok(()) Ok(())

View File

@ -49,9 +49,11 @@ pub fn eval(ast: &parser::Stmt, env: &mut Env) {
match res { match res {
Atom::Bool(true) => { Atom::Bool(true) => {
matched = true; matched = true;
if let parser::Expr::Block(block) = block {
for stmt in block { for stmt in block {
eval(stmt, env); eval(stmt, env);
} }
}
break; break;
} }
Atom::Bool(false) => continue, Atom::Bool(false) => continue,

View File

@ -43,7 +43,7 @@ impl fmt::Display for Atom {
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub struct GuardedBlock { pub struct GuardedBlock {
pub guard: Expr, pub guard: Expr,
pub block: Vec<Stmt>, pub block: Expr,
} }
peg::parser! { peg::parser! {
@ -93,14 +93,14 @@ peg::parser! {
= "{" _ stop() indent() __* a:assignment()+ dedent() __* "}" _ { Expr::Object(a) } = "{" _ stop() indent() __* a:assignment()+ dedent() __* "}" _ { Expr::Object(a) }
rule _if() -> GuardedBlock rule _if() -> GuardedBlock
= "if" _ g:expr() b:indented_block() { = "if" _ g:expr() b:block() {
GuardedBlock { GuardedBlock {
guard: g, guard: g,
block: b, block: b,
} }
} }
rule elif() -> GuardedBlock rule elif() -> GuardedBlock
= "elif" _ g:expr() b:indented_block() { = "elif" _ g:expr() b:block() {
GuardedBlock { GuardedBlock {
guard: g, guard: g,
block: b block: b
@ -333,11 +333,11 @@ else
vec![ vec![
GuardedBlock { GuardedBlock {
guard: Expr::Id("foo".to_string()), guard: Expr::Id("foo".to_string()),
block: vec![Stmt::Funcall(Expr::Funcall("bar".to_string(), vec![]))] block: Expr::Block(vec![Stmt::Funcall(Expr::Funcall("bar".to_string(), vec![]))])
}, },
GuardedBlock { GuardedBlock {
guard: Expr::Id("baz".to_string()), guard: Expr::Id("baz".to_string()),
block: vec![Stmt::Funcall(Expr::Funcall("foobar".to_string(), vec![]))] block: Expr::Block(vec![Stmt::Funcall(Expr::Funcall("foobar".to_string(), vec![]))])
}, },
], ],
Some(Expr::Block(vec![Stmt::Funcall(Expr::Funcall("quux".to_string(), vec![]))])), Some(Expr::Block(vec![Stmt::Funcall(Expr::Funcall("quux".to_string(), vec![]))])),