WIP to think about tail calls etc
This commit is contained in:
parent
201d7d2594
commit
d4d4756002
@ -5,14 +5,16 @@ use crate::parser;
|
||||
|
||||
pub struct LexicalContext<'a> {
|
||||
parent: Option<&'a LexicalContext<'a>>,
|
||||
local: HashSet<String>
|
||||
local: HashSet<String>,
|
||||
is_tail: bool,
|
||||
}
|
||||
|
||||
impl <'a> LexicalContext<'a> {
|
||||
pub fn toplevel() -> Self {
|
||||
LexicalContext {
|
||||
parent: None,
|
||||
local: HashSet::new()
|
||||
local: HashSet::new(),
|
||||
is_tail: false,
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
@ -20,6 +22,7 @@ impl <'a> LexicalContext<'a> {
|
||||
LexicalContext {
|
||||
parent: Some(parent),
|
||||
local: HashSet::new(),
|
||||
is_tail: false,
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
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(())
|
||||
}
|
||||
@ -66,6 +94,42 @@ pub fn emit_expr(w: &mut dyn Write, expr: &parser::Expr, ctx: &mut LexicalContex
|
||||
parser::Expr::Atom(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!(),
|
||||
}
|
||||
Ok(())
|
||||
|
@ -49,9 +49,11 @@ pub fn eval(ast: &parser::Stmt, env: &mut Env) {
|
||||
match res {
|
||||
Atom::Bool(true) => {
|
||||
matched = true;
|
||||
for stmt in block {
|
||||
eval(stmt, env);
|
||||
}
|
||||
if let parser::Expr::Block(block) = block {
|
||||
for stmt in block {
|
||||
eval(stmt, env);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
Atom::Bool(false) => continue,
|
||||
|
@ -43,7 +43,7 @@ impl fmt::Display for Atom {
|
||||
#[derive(Debug,PartialEq,Clone)]
|
||||
pub struct GuardedBlock {
|
||||
pub guard: Expr,
|
||||
pub block: Vec<Stmt>,
|
||||
pub block: Expr,
|
||||
}
|
||||
|
||||
peg::parser! {
|
||||
@ -93,14 +93,14 @@ peg::parser! {
|
||||
= "{" _ stop() indent() __* a:assignment()+ dedent() __* "}" _ { Expr::Object(a) }
|
||||
|
||||
rule _if() -> GuardedBlock
|
||||
= "if" _ g:expr() b:indented_block() {
|
||||
= "if" _ g:expr() b:block() {
|
||||
GuardedBlock {
|
||||
guard: g,
|
||||
block: b,
|
||||
}
|
||||
}
|
||||
rule elif() -> GuardedBlock
|
||||
= "elif" _ g:expr() b:indented_block() {
|
||||
= "elif" _ g:expr() b:block() {
|
||||
GuardedBlock {
|
||||
guard: g,
|
||||
block: b
|
||||
@ -333,11 +333,11 @@ else
|
||||
vec![
|
||||
GuardedBlock {
|
||||
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 {
|
||||
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![]))])),
|
||||
|
Loading…
Reference in New Issue
Block a user