From 403b79190cb15cd4ef86c5e4d2bb6abc01c1de21 Mon Sep 17 00:00:00 2001 From: Eugene Rossokha Date: Mon, 18 Dec 2023 23:52:39 +0200 Subject: [PATCH] Implement if, for, while and try js codegen --- backend/src/codegen.rs | 224 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 220 insertions(+), 4 deletions(-) diff --git a/backend/src/codegen.rs b/backend/src/codegen.rs index 9b51e79..f4948a8 100644 --- a/backend/src/codegen.rs +++ b/backend/src/codegen.rs @@ -23,11 +23,27 @@ pub enum Statement { }, Return(Expression), Expression(Expression), - For, - If, - While, + For { + init: Option, + condition: Option, + update: Option, + body: Vec, + }, + If { + condition: Expression, + then_: Vec, + else_: Option>, + }, + While { + condition: Expression, + body: Vec, + }, Throw(Expression), - Try, + Try { + body: Vec, + catch_: Option<(String, Vec)>, + finally: Option>, + }, } impl Emit for Statement { @@ -63,6 +79,107 @@ impl Emit for Statement { write!(w, "throw ").map_err(EmitError::WriterError)?; e.emit(w) } + Statement::Try { + body, + catch_, + finally, + } => { + write!(w, "try {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in body.iter().enumerate() { + st.emit(w)?; + if i + 1 != body.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError)?; + if let Some((name, catch_body)) = catch_ { + write!(w, " catch ({}) {}", name, "{").map_err(EmitError::WriterError)?; + for (i, st) in catch_body.iter().enumerate() { + st.emit(w)?; + if i + 1 != catch_body.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError)?; + } + if let Some(finally) = finally { + write!(w, " finally {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in finally.iter().enumerate() { + st.emit(w)?; + if i + 1 != finally.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError)?; + } + Ok(()) + } + Statement::If { + condition, + then_, + else_, + } => { + write!(w, "if (").map_err(EmitError::WriterError)?; + condition.emit(w)?; + write!(w, ") {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in then_.iter().enumerate() { + st.emit(w)?; + if i + 1 != then_.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError)?; + if let Some(else_) = else_ { + write!(w, " else {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in else_.iter().enumerate() { + st.emit(w)?; + if i + 1 != else_.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError)?; + } + Ok(()) + } + Statement::For { + init, + condition, + update, + body, + } => { + write!(w, "for (").map_err(EmitError::WriterError)?; + if let Some(init) = init { + init.emit(w)?; + } + write!(w, "; ").map_err(EmitError::WriterError)?; + if let Some(condition) = condition { + condition.emit(w)?; + } + write!(w, "; ").map_err(EmitError::WriterError)?; + if let Some(update) = update { + update.emit(w)?; + } + write!(w, ") {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in body.iter().enumerate() { + st.emit(w)?; + if i + 1 != body.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError) + } + Statement::While { condition, body } => { + write!(w, "while (").map_err(EmitError::WriterError)?; + condition.emit(w)?; + write!(w, ") {}", "{").map_err(EmitError::WriterError)?; + for (i, st) in body.iter().enumerate() { + st.emit(w)?; + if i + 1 != body.len() { + write!(w, "; ").map_err(EmitError::WriterError)?; + } + } + write!(w, "{}", "}").map_err(EmitError::WriterError) + } _ => todo!("Tehe"), } } @@ -421,3 +538,102 @@ fn throw_emit() { throw.emit(&mut res).unwrap(); assert_eq!(res, "throw null") } + +#[test] +fn empty_try_emit() { + let try_ = Statement::Try { + body: Vec::new(), + catch_: None, + finally: None, + }; + let mut res = String::new(); + try_.emit(&mut res).unwrap(); + assert_eq!(res, "try {}") +} + +#[test] +fn try_emit() { + let try_ = Statement::Try { + body: vec![Statement::Expression(Expression::Null)], + catch_: Some(( + "e".to_owned(), + vec![Statement::Expression(Expression::Undefined)], + )), + finally: Some(vec![Statement::Expression(Expression::Null)]), + }; + let mut res = String::new(); + try_.emit(&mut res).unwrap(); + assert_eq!(res, "try {null} catch (e) {undefined} finally {null}") +} + +#[test] +fn empty_for_emit() { + let for_ = Statement::For { + init: None, + condition: None, + update: None, + body: Vec::new(), + }; + let mut res = String::new(); + for_.emit(&mut res).unwrap(); + assert_eq!(res, "for (; ; ) {}") +} + +#[test] +fn for_emit() { + let for_ = Statement::For { + init: Some(Expression::Null), + condition: Some(Expression::Bool(true)), + update: Some(Expression::Null), + body: vec![Statement::Expression(Expression::Null)], + }; + let mut res = String::new(); + for_.emit(&mut res).unwrap(); + assert_eq!(res, "for (null; true; null) {null}") +} + +#[test] +fn empty_while_emit() { + let while_ = Statement::While { + condition: Expression::Bool(true), + body: Vec::new(), + }; + let mut res = String::new(); + while_.emit(&mut res).unwrap(); + assert_eq!(res, "while (true) {}") +} + +#[test] +fn while_emit() { + let while_ = Statement::While { + condition: Expression::Bool(true), + body: vec![Statement::Expression(Expression::Null)], + }; + let mut res = String::new(); + while_.emit(&mut res).unwrap(); + assert_eq!(res, "while (true) {null}") +} + +#[test] +fn empty_if_emit() { + let if_ = Statement::If { + condition: Expression::Bool(true), + then_: Vec::new(), + else_: None, + }; + let mut res = String::new(); + if_.emit(&mut res).unwrap(); + assert_eq!(res, "if (true) {}") +} + +#[test] +fn if_emit() { + let if_ = Statement::If { + condition: Expression::Bool(true), + then_: vec![Statement::Expression(Expression::Null)], + else_: Some(vec![Statement::Expression(Expression::Undefined)]), + }; + let mut res = String::new(); + if_.emit(&mut res).unwrap(); + assert_eq!(res, "if (true) {null} else {undefined}") +}