Beginnings of EMCAScript code generator
This commit is contained in:
parent
dea529b42b
commit
0fddcbd645
72
rust/src/emitter.rs
Normal file
72
rust/src/emitter.rs
Normal 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(())
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
mod parser;
|
mod parser;
|
||||||
mod evaluator;
|
mod evaluator;
|
||||||
|
mod emitter;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
@ -15,16 +16,22 @@ struct Cli {
|
|||||||
file: Option<PathBuf>,
|
file: Option<PathBuf>,
|
||||||
#[clap(short, long, help="Only parse, do not evaluate")]
|
#[clap(short, long, help="Only parse, do not evaluate")]
|
||||||
parse_only: bool,
|
parse_only: bool,
|
||||||
|
#[clap(short, long, help="Cross-compile to ECMAScript")]
|
||||||
|
ecmascript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repl(cli: &Cli) {
|
fn repl(cli: &Cli) {
|
||||||
let mut global = evaluator::Env::global();
|
let mut global = evaluator::Env::global();
|
||||||
|
let mut toplevel = emitter::LexicalContext::toplevel();
|
||||||
|
let mut out = io::stdout();
|
||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
io::stdin().read_line(&mut line).unwrap();
|
io::stdin().read_line(&mut line).unwrap();
|
||||||
let tree = parser::parse_stmt(&line);
|
let tree = parser::parse_stmt(&line);
|
||||||
if cli.parse_only {
|
if cli.parse_only {
|
||||||
println!("{:#?}", tree);
|
println!("{:#?}", tree);
|
||||||
|
} else if cli.ecmascript {
|
||||||
|
emitter::emit(&mut out, &tree, &mut toplevel).ok();
|
||||||
} else {
|
} else {
|
||||||
evaluator::eval(&tree, &mut global);
|
evaluator::eval(&tree, &mut global);
|
||||||
}
|
}
|
||||||
@ -38,6 +45,10 @@ fn script(cli: &Cli) {
|
|||||||
let tree = parser::parse(&prgm);
|
let tree = parser::parse(&prgm);
|
||||||
if cli.parse_only {
|
if cli.parse_only {
|
||||||
println!("{:#?}", tree);
|
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 {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user