use crate::*; use crate::syntax::block::Item; use crate::syntax::block::constructors::*; use crate::gen::schema::*; use convert_case::{Case, Casing}; use lazy_static::lazy_static; use preserves::value::Map; use preserves::value::NestedValue; use preserves::value::Value; use super::CompilerConfig; use super::names; use super::types; pub struct ModuleContext<'m> { pub config: &'m CompilerConfig, pub literals: Map<_Any, String>, pub typedefs: Vec, pub functiondefs: Vec, } pub struct FunctionContext<'a, 'm> { pub m: &'a mut ModuleContext<'m>, pub temp_counter: usize, pub captures: Vec, } pub struct Capture { pub field_name: String, pub ty: types::TField, pub source_expr: String, } lazy_static! { static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap(); } impl<'m> ModuleContext<'m> { pub fn new(config: &'m CompilerConfig) -> Self { ModuleContext { config: config, literals: Map::new(), typedefs: Vec::new(), functiondefs: Vec::new(), } } pub fn define_literal(&mut self, v: &_Any) -> String { let prefix = format!("LIT_{}", self.literals.len()); let next_id = match v.value() { Value::Boolean(b) => prefix + "_" + &b.to_string(), Value::Symbol(s) => if ID_RE.is_match(&s) { prefix + "_" + s } else { prefix }, Value::String(s) => if ID_RE.is_match(&s) { prefix + "_" + s } else { prefix }, Value::SignedInteger(n) => prefix + "_" + &n.to_string(), _ => prefix }; let next_id = next_id.to_case(Case::UpperSnake); "&*".to_owned() + self.literals.entry(v.clone()).or_insert(next_id) } pub fn define_type(&mut self, i: Item) { self.typedefs.push(i) } pub fn define_function Item>(&mut self, f: F) { let i = f(FunctionContext::new(self)); self.functiondefs.push(i) } pub fn render_ref(&self, r: &Ref) -> Item { match self.config.module_aliases.get(&r.module.0) { None => if r.module.0.is_empty() { item(r.name.to_owned()) } else { let mut items = Vec::new(); items.push(item(self.config.fully_qualified_module_prefix.to_owned())); for p in &r.module.0 { items.push(item(names::render_modname(p))) } items.push(item(r.name.to_owned())); item(name(items)) } Some(s) => item(name![s.to_owned(), r.name.to_owned()]) } } } impl<'a, 'm> FunctionContext<'a, 'm> { pub fn new(m: &'a mut ModuleContext<'m>) -> Self { FunctionContext { m: m, temp_counter: 0, captures: Vec::new(), } } pub fn capture(&mut self, field_name: String, ty: types::TField, source_expr: String) { self.captures.push(Capture { field_name: field_name, ty: ty, source_expr: source_expr, }) } pub fn lookup_capture(&self, field_name: &str) -> &Capture { for c in &self.captures { if c.field_name == field_name { return c; } } panic!("No capture for field {:?} available", field_name) } pub fn gentempname(&mut self) -> String { let i = self.temp_counter; self.temp_counter += 1; format!("_tmp{}", i) } pub fn branch R>(&mut self, f: F) -> R { let saved_temp_counter = self.temp_counter; let saved_capture_count = self.captures.len(); let result = f(self); self.temp_counter = saved_temp_counter; self.captures.truncate(saved_capture_count); result } }