Implement if, for, while and try js codegen

This commit is contained in:
Eugene Rossokha
2023-12-18 23:52:39 +02:00
parent 58e668285c
commit 403b79190c
+220 -4
View File
@@ -23,11 +23,27 @@ pub enum Statement {
},
Return(Expression),
Expression(Expression),
For,
If,
While,
For {
init: Option<Expression>,
condition: Option<Expression>,
update: Option<Expression>,
body: Vec<Statement>,
},
If {
condition: Expression,
then_: Vec<Statement>,
else_: Option<Vec<Statement>>,
},
While {
condition: Expression,
body: Vec<Statement>,
},
Throw(Expression),
Try,
Try {
body: Vec<Statement>,
catch_: Option<(String, Vec<Statement>)>,
finally: Option<Vec<Statement>>,
},
}
impl<W: Write> Emit<W> for Statement {
@@ -63,6 +79,107 @@ impl<W: Write> Emit<W> 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}")
}