preserves/implementations/rust/preserves-schema/src/compiler/context.rs

114 lines
3.2 KiB
Rust

use crate::*;
use crate::syntax::block::Item;
use crate::syntax::block::constructors::*;
use crate::gen::schema::*;
use preserves::value::Map;
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<Item>,
pub functiondefs: Vec<Item>,
}
pub struct FunctionContext<'a, 'm> {
pub m: &'a mut ModuleContext<'m>,
pub temp_counter: usize,
pub captures: Vec<Capture>,
}
pub struct Capture {
pub field_name: String,
pub ty: types::TField,
pub source_expr: String,
}
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 next_id = format!("LIT{}", self.literals.len());
"&*".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<F: FnOnce(FunctionContext) -> 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, F: FnOnce(&mut Self) -> 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
}
}