use std::io::Write; use std::collections::HashSet; use crate::parser; pub struct LexicalContext<'a> { parent: Option<&'a LexicalContext<'a>>, local: HashSet } impl <'a> LexicalContext<'a> { pub fn toplevel() -> Self { LexicalContext { parent: None, local: HashSet::new() } } #[allow(dead_code)] fn new(parent: &'a LexicalContext<'a>) -> Self { LexicalContext { parent: Some(parent), local: HashSet::new(), } } 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, 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, ";")?; } _ => todo!(), } 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)?; } _ => todo!(), } Ok(()) }