use std::sync::Arc;
use super::{
Array, ArrayFill, Assign, Block, Call, CallClosure, Expression, For, ForN, Grab,
Id, If, Item, Link, Mat4, Object, Swizzle, TryExpr, Vec4,
};
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
use super::{ForIn, Go};
use crate::Variable;
pub fn number(expr: &Expression, name: &Arc<String>, val: f64) -> Expression {
use super::Expression as E;
match *expr {
E::Link(ref link_expr) => {
let mut new_items: Vec<Expression> = vec![];
for item in &link_expr.items {
new_items.push(number(item, name, val));
}
E::Link(Box::new(Link {
items: new_items,
source_range: link_expr.source_range,
}))
}
E::Item(ref item) => {
if &item.name == name {
E::Variable(Box::new((item.source_range, Variable::f64(val))))
} else {
let mut new_ids: Vec<Id> = vec![];
for id in &item.ids {
if let Id::Expression(ref expr) = *id {
new_ids.push(Id::Expression(number(expr, name, val)));
} else {
new_ids.push(id.clone());
}
}
E::Item(Box::new(Item {
name: item.name.clone(),
current: item.current,
stack_id: item.stack_id.clone(),
static_stack_id: item.static_stack_id.clone(),
try_flag: item.try_flag,
ids: new_ids,
try_ids: item.try_ids.clone(),
source_range: item.source_range,
}))
}
}
E::Block(ref block) => E::Block(Box::new(number_block(block, name, val))),
E::Assign(ref assign_expr) => E::Assign(Box::new(Assign {
op: assign_expr.op,
left: number(&assign_expr.left, name, val),
right: number(&assign_expr.right, name, val),
source_range: assign_expr.source_range,
})),
E::Object(ref obj_expr) => {
let mut new_key_values: Vec<(Arc<String>, Expression)> = vec![];
for key_value in &obj_expr.key_values {
new_key_values.push((key_value.0.clone(), number(&key_value.1, name, val)));
}
E::Object(Box::new(Object {
key_values: new_key_values,
source_range: obj_expr.source_range,
}))
}
E::Call(ref call_expr) => E::Call(Box::new(number_call(call_expr, name, val))),
E::CallVoid(_) => unimplemented!("`CallVoid` is transformed from `Call` later"),
E::CallReturn(_) => unimplemented!("`CallVoid` is transformed from `Call` later"),
E::CallLazy(_) => unimplemented!("`CallLazy` is transformed from `Call` later"),
E::CallLoaded(_) => unimplemented!("`CallLoaded` is transform from `Call` later"),
E::CallBinOp(_) => unimplemented!("`CallBinOp` is transformed from `Call` later"),
E::CallUnOp(_) => unimplemented!("`CallUnOp` is transformed from `Call` later"),
E::Array(ref array_expr) => {
let mut new_items: Vec<Expression> = vec![];
for item in &array_expr.items {
new_items.push(number(item, name, val));
}
E::Array(Box::new(Array {
items: new_items,
source_range: array_expr.source_range,
}))
}
E::ArrayFill(ref array_fill_expr) => E::ArrayFill(Box::new(ArrayFill {
fill: number(&array_fill_expr.fill, name, val),
n: number(&array_fill_expr.n, name, val),
source_range: array_fill_expr.source_range,
})),
E::Return(ref ret_expr) => E::Return(Box::new(number(ret_expr, name, val))),
E::ReturnVoid(_) => expr.clone(),
E::Break(_) => expr.clone(),
E::Continue(_) => expr.clone(),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::Go(ref go) => E::Go(Box::new(Go {
call: number_call(&go.call, name, val),
source_range: go.source_range,
})),
#[cfg(not(all(not(target_family = "wasm"), feature = "threading")))]
E::Go(ref go) => match **go {},
E::Vec4(ref vec4_expr) => {
let mut new_args: Vec<Expression> = vec![];
for arg in &vec4_expr.args {
new_args.push(number(arg, name, val));
}
E::Vec4(Box::new(Vec4 {
args: new_args,
source_range: vec4_expr.source_range,
}))
}
E::Mat4(ref mat4_expr) => {
let mut new_args: Vec<Expression> = vec![];
for arg in &mat4_expr.args {
new_args.push(number(arg, name, val));
}
E::Mat4(Box::new(Mat4 {
args: new_args,
source_range: mat4_expr.source_range,
}))
}
E::For(ref for_expr) => {
let mut init: Option<Expression> = None;
if let Expression::Assign(ref assign_expr) = for_expr.init {
if let Expression::Item(ref item) = assign_expr.left {
if &item.name == name {
init = Some(Expression::Assign(Box::new(Assign {
op: assign_expr.op,
left: assign_expr.left.clone(),
right: number(&assign_expr.right, name, val),
source_range: assign_expr.source_range,
})));
}
}
}
if let Some(init) = init {
E::For(Box::new(For {
label: for_expr.label.clone(),
init,
cond: for_expr.cond.clone(),
step: for_expr.step.clone(),
block: for_expr.block.clone(),
source_range: for_expr.source_range,
}))
} else {
E::For(Box::new(For {
label: for_expr.label.clone(),
init: number(&for_expr.init, name, val),
cond: number(&for_expr.cond, name, val),
step: number(&for_expr.step, name, val),
block: number_block(&for_expr.block, name, val),
source_range: for_expr.source_range,
}))
}
}
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::ForIn(ref for_in_expr) => E::ForIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(not(all(not(target_family = "wasm"), feature = "threading")))]
E::ForIn(ref for_in_expr) |
E::SumIn(ref for_in_expr) |
E::ProdIn(ref for_in_expr) |
E::MinIn(ref for_in_expr) |
E::MaxIn(ref for_in_expr) |
E::SiftIn(ref for_in_expr) |
E::AnyIn(ref for_in_expr) |
E::AllIn(ref for_in_expr) |
E::LinkIn(ref for_in_expr) => match **for_in_expr {},
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::SumIn(ref for_in_expr) => E::SumIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::ProdIn(ref for_in_expr) => E::ProdIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::MinIn(ref for_in_expr) => E::MinIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::MaxIn(ref for_in_expr) => E::MaxIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::AnyIn(ref for_in_expr) => E::AnyIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::AllIn(ref for_in_expr) => E::AllIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::SiftIn(ref for_in_expr) => E::SiftIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
E::LinkIn(ref for_in_expr) => E::LinkIn(Box::new(ForIn {
label: for_in_expr.label.clone(),
name: for_in_expr.name.clone(),
iter: number(&for_in_expr.iter, name, val),
block: number_block(&for_in_expr.block, name, val),
source_range: for_in_expr.source_range,
})),
E::ForN(ref for_n_expr) => E::ForN(Box::new(number_for_n(for_n_expr, name, val))),
E::Sum(ref for_n_expr) => E::Sum(Box::new(number_for_n(for_n_expr, name, val))),
E::SumVec4(ref for_n_expr) => E::SumVec4(Box::new(number_for_n(for_n_expr, name, val))),
E::Prod(ref for_n_expr) => E::Prod(Box::new(number_for_n(for_n_expr, name, val))),
E::ProdVec4(ref for_n_expr) => E::ProdVec4(Box::new(number_for_n(for_n_expr, name, val))),
E::Min(ref for_n_expr) => E::Min(Box::new(number_for_n(for_n_expr, name, val))),
E::Max(ref for_n_expr) => E::Max(Box::new(number_for_n(for_n_expr, name, val))),
E::Sift(ref for_n_expr) => E::Sift(Box::new(number_for_n(for_n_expr, name, val))),
E::Any(ref for_n_expr) => E::Any(Box::new(number_for_n(for_n_expr, name, val))),
E::All(ref for_n_expr) => E::All(Box::new(number_for_n(for_n_expr, name, val))),
E::LinkFor(ref for_n_expr) => E::LinkFor(Box::new(number_for_n(for_n_expr, name, val))),
E::If(ref if_expr) => {
let mut new_else_if_conds: Vec<Expression> = vec![];
for else_if_cond in &if_expr.else_if_conds {
new_else_if_conds.push(number(else_if_cond, name, val));
}
let mut new_else_if_blocks: Vec<Block> = vec![];
for else_if_block in &if_expr.else_if_blocks {
new_else_if_blocks.push(number_block(else_if_block, name, val));
}
E::If(Box::new(If {
cond: number(&if_expr.cond, name, val),
true_block: number_block(&if_expr.true_block, name, val),
else_if_conds: new_else_if_conds,
else_if_blocks: new_else_if_blocks,
else_block: if_expr
.else_block
.as_ref()
.map(|else_block| number_block(else_block, name, val)),
source_range: if_expr.source_range,
}))
}
E::Variable(_) => expr.clone(),
E::Try(ref expr) => E::Try(Box::new(number(expr, name, val))),
E::Swizzle(ref swizzle_expr) => E::Swizzle(Box::new(Swizzle {
sw0: swizzle_expr.sw0,
sw1: swizzle_expr.sw1,
sw2: swizzle_expr.sw2,
sw3: swizzle_expr.sw3,
expr: number(&swizzle_expr.expr, name, val),
source_range: swizzle_expr.source_range,
})),
E::Closure(_) => expr.clone(),
E::CallClosure(ref call_expr) => {
E::CallClosure(Box::new(number_call_closure(call_expr, name, val)))
}
E::Grab(ref grab_expr) => E::Grab(Box::new(Grab {
level: grab_expr.level,
expr: number(&grab_expr.expr, name, val),
source_range: grab_expr.source_range,
})),
E::TryExpr(ref try_expr) => E::TryExpr(Box::new(TryExpr {
expr: number(&try_expr.expr, name, val),
source_range: try_expr.source_range,
})),
E::In(_) => expr.clone(),
}
}
fn number_call(call_expr: &Call, name: &Arc<String>, val: f64) -> Call {
let mut new_args: Vec<Expression> = vec![];
for arg in &call_expr.args {
new_args.push(number(arg, name, val));
}
Call {
args: new_args,
f_index: call_expr.f_index,
custom_source: None,
info: call_expr.info.clone(),
}
}
fn number_call_closure(call_expr: &CallClosure, name: &Arc<String>, val: f64) -> CallClosure {
let mut new_args: Vec<Expression> = vec![];
for arg in &call_expr.args {
new_args.push(number(arg, name, val));
}
CallClosure {
item: call_expr.item.clone(),
args: new_args,
source_range: call_expr.source_range,
}
}
fn number_block(block: &Block, name: &Arc<String>, val: f64) -> Block {
let mut new_expressions: Vec<Expression> = vec![];
let mut just_clone = false;
for expr in &block.expressions {
if just_clone {
new_expressions.push(expr.clone());
} else {
if let Expression::Assign(ref assign_expr) = *expr {
if let Expression::Item(ref item) = assign_expr.left {
if &item.name == name {
new_expressions.push(Expression::Assign(Box::new(Assign {
op: assign_expr.op,
left: assign_expr.left.clone(),
right: number(&assign_expr.right, name, val),
source_range: assign_expr.source_range,
})));
just_clone = true;
continue;
}
}
}
new_expressions.push(number(expr, name, val));
}
}
Block {
expressions: new_expressions,
source_range: block.source_range,
}
}
fn number_for_n(for_n_expr: &ForN, name: &Arc<String>, val: f64) -> ForN {
if &for_n_expr.name == name {
for_n_expr.clone()
} else {
ForN {
label: for_n_expr.label.clone(),
name: for_n_expr.name.clone(),
start: for_n_expr
.start
.as_ref()
.map(|start| number(start, name, val)),
end: number(&for_n_expr.end, name, val),
block: number_block(&for_n_expr.block, name, val),
source_range: for_n_expr.source_range,
}
}
}