use prelude::*;
use compiler::Compiler;
use vm::{Vm, Round};
use quote::{Tokens, Ident};
use std::mem;
struct Syn {
tokens: Tokens,
stored: usize,
inputs: Vec<Ident>
}
impl Syn {
pub fn new() -> Syn {
Syn {
tokens: Tokens::new(),
stored: 0,
inputs: Vec::new()
}
}
}
impl Vm for Syn {
type Var = Tokens;
type Storage = Ident;
fn make_int(&mut self, i: i64) -> Self::Var {
let i: i16 = i.cast().unwrap();
quote! { Real::int(#i) }
}
fn make_const(&mut self, x: f64) -> Self::Var {
quote! { #x }
}
fn make_source(&mut self, name: &str) -> Self::Var {
let name = Ident::from(name);
self.inputs.push(name.clone());
quote! { #name }
}
fn make_sum(&mut self, parts: Vec<Self::Var>) -> Self::Var {
let first = &parts[0];
let others = &parts[1..];
quote! { #first #(.add(#others) )* }
}
fn make_product(&mut self, parts: Vec<Self::Var>) -> Self::Var {
let first = &parts[0];
let others = &parts[1..];
quote! { #first #( .mul( #others ) )* }
}
fn store(&mut self, var: &mut Self::Var, _uses: usize) -> Self::Storage {
let name = format!("storage_{}", self.stored).into();
self.stored += 1;
let var = mem::replace(var, self.load(&name));
self.tokens.append(quote! { let #name = #var; });
name
}
fn load(&mut self, name: &Self::Storage) -> Self::Var {
quote! { #name }
}
fn round(&mut self, x: Self::Var, mode: Round) -> Self::Var {
match mode {
Round::Up => quote! { #x.ceil() },
Round::Down => quote! { #x.floor() }
}
}
fn div(&mut self, a: Self::Var, b: Self::Var) -> Self::Var {
quote! { #a / #b }
}
fn inv(&mut self, a: Self::Var) -> Self::Var {
quote! { #a.inv() }
}
fn step_at(&mut self, at: Self::Var, x: Self::Var) -> Self::Var {
quote! {
#x.ge(#at).select(f32x8::splat(1.0), f32::splat(0.0))
}
}
}
pub fn syn(node: NodeRc) -> Tokens {
let mut syn = Syn::new();
let inner = Compiler::run(&mut syn, &node).unwrap();
let store = syn.tokens;
let params = syn.inputs.iter().map(|i| quote! { #i: T });
let args = &syn.inputs;
quote! {
{
extern crate math_traits;
use math_traits::Real;
#[allow(unused_imports)]
fn f<T: Real>(#(#params),*) -> T {
use std::ops::*;
#store
#inner
}
f(#args)
}
}
}