preserves_schema/compiler/
context.rs1use crate::gen::schema::*;
2use crate::syntax::block::constructors::*;
3use crate::syntax::block::escape_string;
4use crate::syntax::block::Item;
5use crate::*;
6
7use convert_case::{Case, Casing};
8
9use lazy_static::lazy_static;
10
11use preserves::value::IOValue;
12use preserves::value::Map;
13use preserves::value::NestedValue;
14use preserves::value::Value;
15
16use super::names;
17use super::types;
18use super::types::Purpose;
19use super::CompilerConfig;
20
21pub struct BundleContext<'b> {
22 pub config: &'b CompilerConfig,
23 pub types: Map<Ref, types::TDefinition>,
24 pub literals: Map<IOValue, String>,
25}
26
27#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
28pub enum ModuleContextMode {
29 TargetModule,
30 TargetToplevel,
31 TargetGeneric,
32}
33
34pub struct ModuleContext<'m, 'b> {
35 pub bundle: &'m mut BundleContext<'b>,
36 pub module_path: ModulePath,
37 pub schema: &'m Schema,
38 pub typedefs: Vec<Item>,
39 pub functiondefs: Vec<Item>,
40 pub mode: ModuleContextMode,
41}
42
43pub struct FunctionContext<'a, 'm, 'b> {
44 pub error_context: String,
45 pub m: &'a mut ModuleContext<'m, 'b>,
46 pub temp_counter: usize,
47 pub captures: Vec<Capture>,
48 pub capture_mode: CaptureMode,
49}
50
51pub struct Capture {
52 pub field_name: String,
53 pub ty: types::TField,
54 pub source_expr: String,
55}
56
57pub enum CaptureMode {
58 Definite,
59 Indefinite(Vec<Item>),
60}
61
62pub enum RefRenderStyle {
63 Bare,
64 Qualified,
65}
66
67lazy_static! {
68 static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
69}
70
71impl<'b> BundleContext<'b> {
72 pub fn new(config: &'b CompilerConfig) -> Self {
73 BundleContext {
74 config,
75 types: config.build_type_cache(),
76 literals: Map::new(),
77 }
78 }
79
80 pub fn any_type(&self) -> &'static str {
81 "_Value"
82 }
83
84 pub fn lookup_definition(&self, r: &Ref) -> Option<(&Definition, Purpose)> {
85 self.config
86 .bundle
87 .get(&r.module.0)
88 .and_then(|s| s.0.definitions.0.get(&r.name).map(|d| (d, s.1)))
89 }
90
91 pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> {
92 if r.module.0.is_empty() {
93 panic!(
94 "BundleContext::type_for_name with module-relative ref {:?}",
95 r
96 );
97 }
98 let result = self.types.get(r);
99 if result.is_none() && !self.config.external_modules.contains_key(&r.module.0) {
100 panic!("Attempted to lookup unknown type {:?}", r)
101 }
102 result
103 }
104
105 pub fn define_literal(&mut self, v: &IOValue) -> String {
106 let prefix = format!("LIT_{}", self.literals.len());
107 let next_id = match v.value() {
108 Value::Boolean(b) => prefix + "_" + &b.to_string(),
109 Value::Symbol(s) => {
110 if ID_RE.is_match(&s) {
111 prefix + "_" + s
112 } else {
113 prefix
114 }
115 }
116 Value::String(s) => {
117 if ID_RE.is_match(&s) {
118 prefix + "_" + s
119 } else {
120 prefix
121 }
122 }
123 Value::SignedInteger(n) => prefix + "_" + &n.to_string(),
124 _ => prefix,
125 };
126 let next_id = next_id.to_case(Case::UpperSnake);
127 format!(
128 "&<_L as Into<&'a {}>>::into(_ctxt).{}",
129 self.language_type(),
130 self.literals.entry(v.clone()).or_insert(next_id)
131 )
132 }
133
134 pub fn generate_module<F: FnOnce(&mut ModuleContext)>(
135 &mut self,
136 path: &Vec<String>,
137 schema: &Schema,
138 mode: ModuleContextMode,
139 items: &mut Map<ModuleContextMode, Vec<Item>>,
140 f: F,
141 ) {
142 let mut m = ModuleContext::new(self, &ModulePath(path.clone()), schema, mode);
143 f(&mut m);
144 items.entry(mode).or_default().extend(m.extract());
145 }
146
147 pub fn language_struct_name(&self) -> &'static str {
148 "Language"
149 }
150
151 pub fn language_type_base(&self) -> String {
152 format!(
153 "{}::{}",
154 self.config.fully_qualified_module_prefix.clone(),
155 self.language_struct_name()
156 )
157 }
158
159 pub fn language_type(&self) -> String {
160 format!("{}<{}>", self.language_type_base(), self.any_type())
161 }
162}
163
164impl<'m, 'b> ModuleContext<'m, 'b> {
165 pub fn new(
166 bundle: &'m mut BundleContext<'b>,
167 module_path: &ModulePath,
168 schema: &'m Schema,
169 mode: ModuleContextMode,
170 ) -> Self {
171 ModuleContext {
172 bundle,
173 module_path: module_path.to_owned(),
174 schema,
175 typedefs: Vec::new(),
176 functiondefs: Vec::new(),
177 mode,
178 }
179 }
180
181 pub fn any_type(&self) -> &'static str {
182 self.bundle.any_type()
183 }
184
185 pub fn reset_mode(&mut self) {
186 self.mode = ModuleContextMode::TargetToplevel;
187 }
188
189 pub fn define_literal(&mut self, v: &IOValue) -> String {
190 self.bundle.define_literal(v)
191 }
192
193 pub fn define_type(&mut self, i: Item) {
194 self.typedefs.push(i)
195 }
196
197 pub fn define_function<F: FnOnce(FunctionContext) -> Item>(
198 &mut self,
199 error_context: &str,
200 f: F,
201 ) {
202 let i = f(FunctionContext::new(self, error_context));
203 self.functiondefs.push(i)
204 }
205
206 pub fn render_ref(&self, r: &Ref, style: RefRenderStyle) -> Item {
207 let base = match self.bundle.config.external_modules.get(&r.module.0) {
208 None => {
209 if r.module.0.is_empty() {
210 item(names::render_constructor(&r.name))
211 } else {
212 let mut items = Vec::new();
213 items.push(item(
214 self.bundle.config.fully_qualified_module_prefix.to_owned(),
215 ));
216 for p in &r.module.0 {
217 items.push(item(names::render_modname(p)))
218 }
219 items.push(item(names::render_constructor(&r.name)));
220 item(name(items))
221 }
222 }
223 Some(xm) => item(name![
224 xm.rust_namespace.clone(),
225 names::render_constructor(&r.name)
226 ]),
227 };
228 let q = self.ref_has_embedded(r);
229 match style {
230 RefRenderStyle::Bare => base,
231 RefRenderStyle::Qualified => {
232 if q {
233 item(seq![base, anglebrackets![self.any_type()]])
234 } else {
235 base
236 }
237 }
238 }
239 }
240
241 pub fn ref_has_embedded(&self, r: &Ref) -> bool {
242 let r = r.qualify(&self.module_path);
243 self.bundle
244 .type_for_name(&r)
245 .map(|ty| ty.has_embedded(self.bundle))
246 .unwrap_or(false)
247 }
249
250 pub fn parse_unparse_generic_decls(&self, ty: &types::TDefinition) -> Item {
251 let mut lts = ty.language_types(self.bundle);
252 lts.insert(self.bundle.language_type());
253 item(anglebrackets![
254 "'a",
255 seq![
256 "_L: Copy",
257 seq(lts
258 .into_iter()
259 .map(|t| item(seq![" + Into<&'a ", t, ">"]))
260 .collect())
261 ],
262 seq![self.any_type(), ": preserves::value::NestedValue + 'a"]
263 ])
264 }
265
266 pub fn extract(&mut self) -> Vec<Item> {
267 let mut items = std::mem::take(&mut self.typedefs);
268 items.extend(std::mem::take(&mut self.functiondefs));
269 items
270 }
271}
272
273impl<'a, 'm, 'b> FunctionContext<'a, 'm, 'b> {
274 pub fn new(m: &'a mut ModuleContext<'m, 'b>, error_context: &str) -> Self {
275 FunctionContext {
276 error_context: error_context.to_owned(),
277 m,
278 temp_counter: 0,
279 captures: Vec::new(),
280 capture_mode: CaptureMode::Definite,
281 }
282 }
283
284 pub fn capture(&mut self, field_name: String, ty: types::TField, source_expr: String) {
285 self.captures.push(Capture {
286 field_name,
287 ty,
288 source_expr: match self.capture_mode {
289 CaptureMode::Definite => source_expr,
290 CaptureMode::Indefinite(_) => format!(
291 "{}.ok_or_else(|| {:?})?",
292 source_expr,
293 self.conformance_err_code()
294 ),
295 },
296 })
297 }
298
299 pub fn lookup_capture(&self, field_name: &str) -> &Capture {
300 for c in &self.captures {
301 if c.field_name == field_name {
302 return c;
303 }
304 }
305 panic!("No capture for field {:?} available", field_name)
306 }
307
308 pub fn gentempname(&mut self) -> String {
309 let i = self.temp_counter;
310 self.temp_counter += 1;
311 format!("_tmp{}", i)
312 }
313
314 pub fn declare_compound(&self, body: &mut Vec<Item>, name: &str, init_expr: Item) {
315 body.push(item(seq![
316 "let mut ",
317 name.to_owned(),
318 " = ",
319 init_expr,
320 ";"
321 ]));
322 }
323
324 pub fn define_atom(&mut self, body: &mut Vec<Item>, name: &str, val_expr: Item) {
325 body.push(match &mut self.capture_mode {
326 CaptureMode::Definite => item(seq!["let ", name.to_owned(), " = ", val_expr, ";"]),
327 CaptureMode::Indefinite(items) => {
328 items.push(item(seq!["let mut ", name.to_owned(), " = None;"]));
329 item(seq![name.to_owned(), " = Some(", val_expr, ");"])
330 }
331 })
332 }
333
334 pub fn with_definite_mode<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
335 let saved_mode = std::mem::replace(&mut self.capture_mode, CaptureMode::Definite);
336 let result = f(self);
337 match std::mem::replace(&mut self.capture_mode, saved_mode) {
338 CaptureMode::Definite => (),
339 CaptureMode::Indefinite(_) => panic!("corrupt capture_mode"),
340 }
341 result
342 }
343
344 pub fn with_indefinite_mode<F: FnOnce(&mut Self) -> ()>(&mut self, f: F) -> Vec<Item> {
345 let saved_mode =
346 std::mem::replace(&mut self.capture_mode, CaptureMode::Indefinite(Vec::new()));
347 f(self);
348 match std::mem::replace(&mut self.capture_mode, saved_mode) {
349 CaptureMode::Definite => panic!("corrupt capture_mode"),
350 CaptureMode::Indefinite(declarations) => declarations,
351 }
352 }
353
354 pub fn branch<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
355 let saved_temp_counter = self.temp_counter;
356 let saved_capture_count = self.captures.len();
357 let result = f(self);
358 self.temp_counter = saved_temp_counter;
359 self.captures.truncate(saved_capture_count);
360 result
361 }
362
363 pub fn err_code(&self) -> Item {
364 return item(seq!["Err", parens![self.conformance_err_code()]]);
365 }
366
367 pub fn fully_qualified_error_context(&self) -> String {
368 self.m.module_path.0.join(".") + "." + &self.error_context
369 }
370
371 pub fn conformance_err_code(&self) -> Item {
372 return item(seq![
373 "_support::ParseError::conformance_error",
374 parens![escape_string(&self.fully_qualified_error_context())]
375 ]);
376 }
377}