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

306 lines
9.5 KiB
Rust

use crate::*;
use crate::syntax::block::Item;
use crate::syntax::block::escape_string;
use crate::syntax::block::constructors::*;
use crate::gen::schema::*;
use convert_case::{Case, Casing};
use lazy_static::lazy_static;
use preserves::value::IOValue;
use preserves::value::Map;
use preserves::value::NestedValue;
use preserves::value::Value;
use super::CompilerConfig;
use super::names;
use super::types;
pub struct BundleContext<'b> {
pub config: &'b CompilerConfig,
pub types: Map<Ref, types::TDefinition>,
pub literals: Map<IOValue, String>,
}
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum ModuleContextMode {
TargetModule,
TargetToplevel,
TargetGeneric,
}
pub struct ModuleContext<'m, 'b> {
pub bundle: &'m mut BundleContext<'b>,
pub module_path: ModulePath,
pub schema: &'m Schema,
pub typedefs: Vec<Item>,
pub functiondefs: Vec<Item>,
pub mode: ModuleContextMode,
}
pub struct FunctionContext<'a, 'm, 'b> {
pub error_context: String,
pub m: &'a mut ModuleContext<'m, 'b>,
pub temp_counter: usize,
pub captures: Vec<Capture>,
pub capture_mode: CaptureMode,
}
pub struct Capture {
pub field_name: String,
pub ty: types::TField,
pub source_expr: String,
}
pub enum CaptureMode {
Definite,
Indefinite(Vec<Item>),
}
lazy_static! {
static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
}
impl<'b> BundleContext<'b> {
pub fn new(
config: &'b CompilerConfig,
) -> Self {
BundleContext {
config,
types: config.build_type_cache(),
literals: Map::new(),
}
}
pub fn type_for_name(&self, r: &Ref) -> &types::TDefinition {
self.types.get(r).unwrap_or_else(|| panic!("{:?} not found", r))
}
pub fn define_literal(&mut self, v: &IOValue) -> 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);
format!("&_ctxt.{}", self.literals.entry(v.clone()).or_insert(next_id))
}
pub fn generate_module<F: FnOnce(&mut ModuleContext)>(
&mut self,
path: &Vec<String>,
schema: &Schema,
mode: ModuleContextMode,
items: &mut Map<ModuleContextMode, Vec<Item>>,
f: F,
) {
let mut m = ModuleContext::new(self, &ModulePath(path.clone()), schema, mode);
f(&mut m);
items.entry(mode).or_default().extend(m.extract());
}
}
impl<'m, 'b> ModuleContext<'m, 'b> {
pub fn new(
bundle: &'m mut BundleContext<'b>,
module_path: &ModulePath,
schema: &'m Schema,
mode: ModuleContextMode,
) -> Self {
ModuleContext {
bundle,
module_path: module_path.to_owned(),
schema,
typedefs: Vec::new(),
functiondefs: Vec::new(),
mode,
}
}
pub fn reset_mode(&mut self) {
self.mode = ModuleContextMode::TargetToplevel;
}
pub fn define_literal(&mut self, v: &IOValue) -> String {
self.bundle.define_literal(v)
}
pub fn define_type(&mut self, i: Item) {
self.typedefs.push(i)
}
pub fn define_function<F: FnOnce(FunctionContext) -> Item>(&mut self, error_context: &str, f: F) {
let i = f(FunctionContext::new(self, error_context));
self.functiondefs.push(i)
}
pub fn render_ref(&self, r: &Ref, with_generic_args: bool) -> Item {
let base = match self.bundle.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.bundle.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()])
};
if with_generic_args && self.type_for_name(r).has_embedded(self) {
item(seq![base, anglebrackets!["_Any"]])
} else {
base
}
}
pub fn any_type(&self) -> &'static str {
"_Any"
}
pub fn qualify(&self, r: &Ref) -> Ref {
if r.module.0.is_empty() {
Ref { module: self.module_path.clone(), name: r.name.clone() }
} else {
r.clone()
}
}
pub fn type_for_name(&self, r: &Ref) -> &types::TDefinition {
self.bundle.type_for_name(&self.qualify(r))
}
pub fn literals_generic_decls(&self) -> Item {
item(anglebrackets!["_Any: preserves::value::NestedValue"])
}
pub fn literals_generic_decls_with_defaults(&self) -> Item {
item(anglebrackets![
seq!["_Any: preserves::value::NestedValue = ",
if self.schema.embedded_type == EmbeddedTypeName::False {
"preserves::value::IOValue"
} else {
"_Any"
}]])
}
pub fn literals_generic_arg(&self) -> Item {
item("<_Any>")
}
pub fn literals_type(&self) -> Item {
item(seq!["&", self.literals_base_type(), self.literals_generic_arg()])
}
pub fn literals_base_type(&self) -> Item {
item(format!("{}::Literals", self.bundle.config.fully_qualified_module_prefix))
}
pub fn extract(&mut self) -> Vec<Item> {
let mut items = std::mem::take(&mut self.typedefs);
items.extend(std::mem::take(&mut self.functiondefs));
items
}
}
impl<'a, 'm, 'b> FunctionContext<'a, 'm, 'b> {
pub fn new(m: &'a mut ModuleContext<'m, 'b>, error_context: &str) -> Self {
FunctionContext {
error_context: error_context.to_owned(),
m: m,
temp_counter: 0,
captures: Vec::new(),
capture_mode: CaptureMode::Definite,
}
}
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: match self.capture_mode {
CaptureMode::Definite =>
source_expr,
CaptureMode::Indefinite(_) =>
format!("{}.ok_or_else(|| {:?})?", source_expr, self.conformance_err_code()),
}
})
}
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 declare_compound(&self, body: &mut Vec<Item>, name: &str, init_expr: Item) {
body.push(item(seq!["let mut ", name.to_owned(), " = ", init_expr, ";"]));
}
pub fn define_atom(&mut self, body: &mut Vec<Item>, name: &str, val_expr: Item) {
body.push(match &mut self.capture_mode {
CaptureMode::Definite => item(seq!["let ", name.to_owned(), " = ", val_expr, ";"]),
CaptureMode::Indefinite(items) => {
items.push(item(seq!["let mut ", name.to_owned(), " = None;"]));
item(seq![name.to_owned(), " = Some(", val_expr, ");"])
}
})
}
pub fn with_definite_mode<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
let saved_mode = std::mem::replace(&mut self.capture_mode, CaptureMode::Definite);
let result = f(self);
match std::mem::replace(&mut self.capture_mode, saved_mode) {
CaptureMode::Definite => (),
CaptureMode::Indefinite(_) => panic!("corrupt capture_mode"),
}
result
}
pub fn with_indefinite_mode<F: FnOnce(&mut Self) -> ()>(&mut self, f: F) -> Vec<Item> {
let saved_mode = std::mem::replace(&mut self.capture_mode, CaptureMode::Indefinite(Vec::new()));
f(self);
match std::mem::replace(&mut self.capture_mode, saved_mode) {
CaptureMode::Definite => panic!("corrupt capture_mode"),
CaptureMode::Indefinite(declarations) => declarations,
}
}
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
}
pub fn err_code(&self) -> Item {
return item(seq!["Err", parens![self.conformance_err_code()]]);
}
pub fn fully_qualified_error_context(&self) -> String {
self.m.module_path.0.join(".") + "." + &self.error_context
}
pub fn conformance_err_code(&self) -> Item {
return item(seq!["_support::ParseError::conformance_error", parens![
escape_string(&self.fully_qualified_error_context())]]);
}
}