mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
159 lines
5.8 KiB
Rust
159 lines
5.8 KiB
Rust
use crate::ast;
|
|
|
|
pub fn fold_script(script: &mut ast::Script) {
|
|
for func in &mut script.functions {
|
|
fold_expr(&mut func.body);
|
|
}
|
|
}
|
|
|
|
fn fold_mem_location(mem_location: &mut ast::MemoryLocation) {
|
|
fold_expr(&mut mem_location.left);
|
|
fold_expr(&mut mem_location.right);
|
|
}
|
|
|
|
fn fold_expr(expr: &mut ast::Expression) {
|
|
use ast::BinOp::*;
|
|
match expr.expr {
|
|
ast::Expr::Block { ref mut statements, ref mut final_expression} => {
|
|
for stmt in statements {
|
|
fold_expr(stmt);
|
|
}
|
|
if let Some(ref mut expr) = final_expression {
|
|
fold_expr(expr);
|
|
}
|
|
}
|
|
ast::Expr::Let { ref mut value, .. } => {
|
|
if let Some(ref mut expr) = value {
|
|
fold_expr(expr);
|
|
}
|
|
}
|
|
ast::Expr::Poke {
|
|
ref mut mem_location,
|
|
ref mut value,
|
|
..
|
|
} => {
|
|
fold_mem_location(mem_location);
|
|
fold_expr(value);
|
|
}
|
|
ast::Expr::Peek(ref mut mem_location) => fold_mem_location(mem_location),
|
|
ast::Expr::UnaryOp { op, ref mut value } => {
|
|
fold_expr(value);
|
|
let result = match (op, &value.expr) {
|
|
(ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => Some(ast::Expr::I32Const(-*value)),
|
|
_ => None
|
|
};
|
|
if let Some(result) = result {
|
|
expr.expr = result;
|
|
}
|
|
}
|
|
ast::Expr::BinOp {
|
|
ref mut left,
|
|
op,
|
|
ref mut right,
|
|
..
|
|
} => {
|
|
fold_expr(left);
|
|
fold_expr(right);
|
|
match (&left.expr, &right.expr) {
|
|
(&ast::Expr::I32Const(left), &ast::Expr::I32Const(right)) => {
|
|
let result = match op {
|
|
Add => left.wrapping_add(right),
|
|
Sub => left.wrapping_sub(right),
|
|
Mul => left.wrapping_mul(right),
|
|
Div => {
|
|
if let Some(result) = left.checked_div(right) {
|
|
result
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
Rem => {
|
|
if let Some(result) = left.checked_rem(right) {
|
|
result
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
And => left & right,
|
|
Or => left | right,
|
|
Xor => left ^ right,
|
|
Eq => (left == right) as i32,
|
|
Ne => (left != right) as i32,
|
|
Lt => (left < right) as i32,
|
|
Le => (left <= right) as i32,
|
|
Gt => (left > right) as i32,
|
|
Ge => (left >= right) as i32,
|
|
Lsl => left << right,
|
|
Lsr => ((left as u32) >> right) as i32,
|
|
Asr => left >> right
|
|
};
|
|
expr.expr = ast::Expr::I32Const(result);
|
|
}
|
|
(&ast::Expr::F32Const(left), &ast::Expr::F32Const(right)) => {
|
|
use ast::Expr::*;
|
|
expr.expr = match op {
|
|
Add => F32Const(left + right),
|
|
Sub => F32Const(left - right),
|
|
Mul => F32Const(left * right),
|
|
Div => F32Const(left / right),
|
|
Rem | And | Or | Xor | Lsl | Lsr | Asr => return,
|
|
Eq => I32Const((left == right) as i32),
|
|
Ne => I32Const((left != right) as i32),
|
|
Lt => I32Const((left < right) as i32),
|
|
Le => I32Const((left <= right) as i32),
|
|
Gt => I32Const((left > right) as i32),
|
|
Ge => I32Const((left >= right) as i32),
|
|
};
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
ast::Expr::I32Const(_) | ast::Expr::F32Const(_) | ast::Expr::Variable { .. } => (),
|
|
ast::Expr::Assign { ref mut value, .. } => fold_expr(value),
|
|
ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value),
|
|
ast::Expr::Loop { ref mut block, .. } => fold_expr(block),
|
|
ast::Expr::Branch(_) => (),
|
|
ast::Expr::BranchIf {
|
|
ref mut condition, ..
|
|
} => fold_expr(condition),
|
|
ast::Expr::Cast { ref mut value, .. } => fold_expr(value),
|
|
ast::Expr::FuncCall {
|
|
ref name,
|
|
ref mut params,
|
|
..
|
|
} => {
|
|
for param in params.iter_mut() {
|
|
fold_expr(param);
|
|
}
|
|
use ast::Expr::*;
|
|
let params: Vec<_> = params.iter().map(|e| &e.expr).collect();
|
|
expr.expr = match (name.as_str(), params.as_slice()) {
|
|
("sqrt", [F32Const(v)]) if *v >= 0.0 => F32Const(v.sqrt()),
|
|
_ => return,
|
|
};
|
|
}
|
|
ast::Expr::Select {
|
|
ref mut condition,
|
|
ref mut if_true,
|
|
ref mut if_false,
|
|
..
|
|
} => {
|
|
fold_expr(condition);
|
|
fold_expr(if_true);
|
|
fold_expr(if_false);
|
|
}
|
|
ast::Expr::If {
|
|
ref mut condition, ref mut if_true, ref mut if_false
|
|
} => {
|
|
fold_expr(condition);
|
|
fold_expr(if_true);
|
|
if let Some(ref mut if_false) = if_false {
|
|
fold_expr(if_false);
|
|
}
|
|
}
|
|
ast::Expr::Return { value: Some(ref mut value) } => fold_expr(value),
|
|
ast::Expr::Return { value: None } => (),
|
|
ast::Expr::Error => unreachable!()
|
|
}
|
|
}
|