deelang/src/emitter.rs

137 lines
3.2 KiB
Rust
Raw Normal View History

use std::io::Write;
use std::collections::HashSet;
use crate::parser;
pub struct LexicalContext<'a> {
parent: Option<&'a LexicalContext<'a>>,
2024-11-13 09:50:44 -06:00
local: HashSet<String>,
is_tail: bool,
}
impl <'a> LexicalContext<'a> {
pub fn toplevel() -> Self {
LexicalContext {
parent: None,
2024-11-13 09:50:44 -06:00
local: HashSet::new(),
is_tail: false,
}
}
#[allow(dead_code)]
fn new(parent: &'a LexicalContext<'a>) -> Self {
LexicalContext {
parent: Some(parent),
local: HashSet::new(),
2024-11-13 09:50:44 -06:00
is_tail: false,
}
}
fn contains(&self, s: &str) -> bool {
self.local.contains(s) || self.parent.map_or(false, |c| c.contains(s))
}
fn insert(&mut self, s: String) -> bool {
self.local.insert(s)
}
}
pub fn emit_all(w: &mut dyn Write, ast: &Vec<parser::Stmt>, ctx: &mut LexicalContext) -> std::io::Result<()> {
for stmt in ast {
emit(w, stmt, ctx)?;
}
Ok(())
}
pub fn emit(w: &mut dyn Write, stmt: &parser::Stmt, ctx: &mut LexicalContext) -> std::io::Result<()> {
match &stmt {
parser::Stmt::ReplPrint(expr) => {
write!(w, "console.log((")?;
emit_expr(w, expr, ctx)?;
writeln!(w, "));")?;
}
parser::Stmt::Assignment(id, expr) => {
if !ctx.contains(id) {
ctx.insert(id.clone());
write!(w, "let ")?;
}
write!(w, "{} = ", id)?;
emit_expr(w, expr, ctx)?;
writeln!(w, ";")?;
}
2024-11-13 09:50:44 -06:00
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(())
}
pub fn emit_expr(w: &mut dyn Write, expr: &parser::Expr, ctx: &mut LexicalContext) -> std::io::Result<()> {
match &expr {
parser::Expr::Id(id) => {
write!(w, "{}", id)?;
}
parser::Expr::Atom(atom) => {
write!(w, "{}", atom)?;
}
2024-11-13 09:50:44 -06:00
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(())
}