Beginnings of EMCAScript code generator

This commit is contained in:
Dane Johnson 2024-11-12 07:19:43 -06:00
parent dea529b42b
commit 0fddcbd645
2 changed files with 84 additions and 1 deletions

72
rust/src/emitter.rs Normal file
View File

@ -0,0 +1,72 @@
use std::io::Write;
use std::collections::HashSet;
use crate::parser;
pub struct LexicalContext<'a> {
parent: Option<&'a LexicalContext<'a>>,
local: HashSet<String>
}
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<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, ";")?;
}
_ => 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(())
}

View File

@ -1,5 +1,6 @@
mod parser;
mod evaluator;
mod emitter;
use clap::Parser;
@ -15,17 +16,23 @@ struct Cli {
file: Option<PathBuf>,
#[clap(short, long, help="Only parse, do not evaluate")]
parse_only: bool,
#[clap(short, long, help="Cross-compile to ECMAScript")]
ecmascript: bool,
}
fn repl(cli: &Cli) {
let mut global = evaluator::Env::global();
let mut toplevel = emitter::LexicalContext::toplevel();
let mut out = io::stdout();
loop {
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
let tree = parser::parse_stmt(&line);
if cli.parse_only {
println!("{:#?}", tree);
} else {
} else if cli.ecmascript {
emitter::emit(&mut out, &tree, &mut toplevel).ok();
} else {
evaluator::eval(&tree, &mut global);
}
}
@ -38,6 +45,10 @@ fn script(cli: &Cli) {
let tree = parser::parse(&prgm);
if cli.parse_only {
println!("{:#?}", tree);
} else if cli.ecmascript {
let mut out = io::stdout();
let mut toplevel = emitter::LexicalContext::toplevel();
emitter::emit_all(&mut out, &tree, &mut toplevel).ok();
} else {
todo!();
}