1use crate::lang::GeneratorError;
2use crate::model;
3
4use model::Named;
5
6use std::collections::HashMap;
7use num_bigint::{BigUint, BigInt, Sign};
8use num_traits::One;
9use std::io::Write;
10use std::marker::PhantomData;
11
12#[derive(Copy, Clone, Debug)]
13pub enum VersionedTypeKind {
14 Struct,
15 Enum,
16}
17
18#[derive(Clone, Debug)]
19pub enum LangType<'model> {
20 Versioned(VersionedTypeKind, &'model model::QualifiedName, BigUint, Vec<LangType<'model>>, LangVerTypeFields<'model>),
21 Extern(&'model model::QualifiedName, Vec<LangType<'model>>, LangExternTypeLiterals<'model>),
22 TypeParameter(String),
23 Converter(Box<LangType<'model>>, Box<LangType<'model>>),
24 Codec(Box<LangType<'model>>),
25}
26
27pub struct LangField<'model> {
28 pub name: &'model String,
29 pub field_type: LangType<'model>,
30}
31
32impl <'model> Clone for LangField<'model> {
33 fn clone(&self) -> Self {
34 LangField {
35 name: self.name,
36 field_type: self.field_type.clone(),
37 }
38 }
39}
40
41pub enum LangLiteral<'model> {
42 Integer(model::ExternLiteralIntBound, Option<BigInt>, model::ExternLiteralIntBound, Option<BigInt>),
43 String,
44 Sequence(LangType<'model>),
45 Case(String, Vec<LangType<'model>>),
46 Record(Vec<LangField<'model>>),
47}
48
49pub struct LangVerTypeFields<'model> {
50 model: &'model model::Verilization,
51 type_args: HashMap<String, LangType<'model>>,
52 type_def: Named<'model, model::VersionedTypeDefinitionData>,
53 ver_type: model::TypeVersionInfo<'model>,
54}
55
56impl <'model> Clone for LangVerTypeFields<'model> {
57 fn clone(&self) -> Self {
58 LangVerTypeFields {
59 model: self.model,
60 type_args: self.type_args.clone(),
61 type_def: self.type_def,
62 ver_type: self.ver_type.clone(),
63 }
64 }
65}
66
67impl <'model> std::fmt::Debug for LangVerTypeFields<'model> {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
69 f.debug_struct("LangVerTypeFields").finish()
70 }
71}
72
73impl <'model> LangVerTypeFields<'model> {
74 pub fn build(&self) -> Result<Vec<LangField<'model>>, GeneratorError> {
75 let scope = self.type_def.scope();
76 let mut fields = Vec::new();
77
78 for (name, field) in self.ver_type.ver_type.fields() {
79 let t = build_type_impl(self.model, &self.ver_type.version, &field.field_type, &scope, &self.type_args)?;
80
81 fields.push(LangField {
82 name: &name,
83 field_type: t,
84 });
85 }
86
87 Ok(fields)
88 }
89}
90
91pub struct LangExternTypeLiterals<'model> {
92 model: &'model model::Verilization,
93 type_args: HashMap<String, LangType<'model>>,
94 type_def: Named<'model, model::ExternTypeDefinitionData>,
95}
96
97impl <'model> Clone for LangExternTypeLiterals<'model> {
98 fn clone(&self) -> Self {
99 LangExternTypeLiterals {
100 model: self.model,
101 type_args: self.type_args.clone(),
102 type_def: self.type_def,
103 }
104 }
105}
106
107impl <'model> std::fmt::Debug for LangExternTypeLiterals<'model> {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
109 f.debug_struct("LangExternTypeLiterals").finish()
110 }
111}
112
113impl <'model> LangExternTypeLiterals<'model> {
114 pub fn build(self) -> Result<Vec<LangLiteral<'model>>, GeneratorError> {
115 let scope = self.type_def.scope();
116 let mut fields = Vec::new();
117
118 for literal in self.type_def.literals() {
119 let lang_literal = match literal {
120 model::ExternLiteralSpecifier::Integer(lower_type, lower, upper_type, upper) => LangLiteral::Integer(*lower_type, lower.clone(), *upper_type, upper.clone()),
121 model::ExternLiteralSpecifier::String => LangLiteral::String,
122 model::ExternLiteralSpecifier::Sequence(t) => LangLiteral::Sequence(build_type_impl(self.model, &BigUint::one(), t, &scope, &self.type_args)?),
123 model::ExternLiteralSpecifier::Case(name, params) =>
124 LangLiteral::Case(name.clone(), params.iter().map(|param| build_type_impl(self.model, &BigUint::one(), param, &scope, &self.type_args)).collect::<Result<Vec<_>, _>>()?),
125 model::ExternLiteralSpecifier::Record(fields) => {
126 let mut lang_fields = Vec::new();
127
128 for (name, field) in fields {
129 let t = build_type_impl(self.model, &BigUint::one(), &field.field_type, &scope, &self.type_args)?;
130
131 lang_fields.push(LangField {
132 name: &name,
133 field_type: t,
134 });
135 }
136
137 LangLiteral::Record(lang_fields)
138 }
139 };
140
141 fields.push(lang_literal);
142 }
143
144 Ok(fields)
145 }
146}
147
148
149#[derive(Debug)]
150pub enum Operation {
151 FromPreviousVersion(BigUint),
152 FinalTypeConverter,
153 TypeCodec,
154 FromInteger,
155 FromString,
156 FromSequence,
157 FromCase(String),
158 FromRecord(Vec<String>),
159}
160
161#[derive(Debug)]
162pub enum OperationTarget<'model> {
163 VersionedType(&'model model::QualifiedName, BigUint),
164 ExternType(&'model model::QualifiedName)
165}
166
167#[derive(Debug)]
168pub enum LangExpr<'model> {
169 Identifier(String),
170 IntegerLiteral(BigInt),
171 StringLiteral(String),
172 InvokeConverter {
173 converter: Box<LangExpr<'model>>,
174 value: Box<LangExpr<'model>>,
175 },
176 IdentityConverter(LangType<'model>),
177 ReadDiscriminator,
178 WriteDiscriminator(BigUint),
179 CodecRead {
180 codec: Box<LangExpr<'model>>,
181 },
182 CodecWrite {
183 codec: Box<LangExpr<'model>>,
184 value: Box<LangExpr<'model>>,
185 },
186 InvokeOperation(Operation, OperationTarget<'model>, Vec<LangType<'model>>, Vec<LangExpr<'model>>),
187 InvokeUserConverter {
188 name: &'model model::QualifiedName,
189 prev_ver: BigUint,
190 version: BigUint,
191 type_args: Vec<LangType<'model>>,
192 args: Vec<LangExpr<'model>>,
193 },
194 ConstantValue(&'model model::QualifiedName, BigUint),
195 CreateStruct(&'model model::QualifiedName, BigUint, Vec<LangType<'model>>, Vec<(&'model String, LangExpr<'model>)>),
196 CreateEnum(&'model model::QualifiedName, BigUint, Vec<LangType<'model>>, &'model String, Box<LangExpr<'model>>),
197 StructField(&'model model::QualifiedName, BigUint, &'model String, Box<LangExpr<'model>>),
198}
199
200pub struct OperationInfo<'model> {
201 pub operation: Operation,
202 pub version: BigUint,
203 pub type_params: Vec<String>,
204 pub params: Vec<(String, LangType<'model>)>,
205 pub result: LangType<'model>,
206 pub implementation: LangExprStmt<'model>,
207}
208
209pub struct MatchCase<'model> {
210 pub binding_name: String,
211 pub case_name: String,
212 pub body: LangStmt<'model>,
213}
214
215pub enum LangExprStmt<'model> {
216 Expr(LangExpr<'model>),
217 CreateCodec {
218 t: LangType<'model>,
219 read: Box<LangStmt<'model>>,
220 write: Box<LangStmt<'model>>,
221 },
222 CreateConverter {
223 from_type: LangType<'model>,
224 to_type: LangType<'model>,
225 body: Box<LangStmt<'model>>,
226 },
227}
228
229pub enum LangStmt<'model> {
230 Expr(Vec<LangExpr<'model>>, Option<LangExpr<'model>>),
231 MatchEnum {
232 value: LangExpr<'model>,
233 value_type: LangType<'model>,
234 cases: Vec<MatchCase<'model>>,
235 },
236 MatchDiscriminator {
237 value: LangExpr<'model>,
238 cases: Vec<(BigUint, LangStmt<'model>)>,
239 },
240}
241
242impl <'model> LangStmt<'model> {
243 pub fn has_value(&self) -> bool {
244 match self {
245 LangStmt::Expr(_, None) => false,
246 LangStmt::Expr(_, Some(_)) => true,
247 LangStmt::MatchEnum { cases, .. } => cases.iter().any(|MatchCase { body, .. }| body.has_value()),
248 LangStmt::MatchDiscriminator { cases, .. } => cases.iter().any(|(_, body)| body.has_value()),
249 }
250 }
251}
252
253pub enum ConvertParam<'model> {
254 ConverterObject,
255 Expression(LangExpr<'model>),
256}
257
258fn requires_conversion<'model, G: Generator<'model>>(gen: &G, t: &model::Type, prev_ver: &BigUint) -> bool {
259 match gen.scope().lookup(t.name.clone()) {
260 model::ScopeLookup::NamedType(name) => match gen.model().get_type(&name) {
261 Some(model::NamedTypeDefinition::StructType(type_def)) | Some(model::NamedTypeDefinition::EnumType(type_def)) => {
262 !type_def.is_final() ||
263 (match type_def.last_explicit_version() {
264 Some(last_ver) => last_ver > prev_ver,
265 None => true
266 }) ||
267 t.args.iter().any(|arg| requires_conversion(gen, arg, prev_ver))
268 },
269
270 Some(model::NamedTypeDefinition::ExternType(_)) => false,
271
272 None => true, },
274 model::ScopeLookup::TypeParameter(_) => true,
275 }
276}
277
278pub trait GeneratorNameMapping {
279 fn convert_prev_type_param(param: &str) -> String;
280 fn convert_current_type_param(param: &str) -> String;
281 fn convert_conv_param_name(param: &str) -> String;
282 fn convert_prev_param_name() -> &'static str;
283
284 fn codec_write_value_name() -> &'static str;
285 fn codec_codec_param_name(param: &str) -> String;
286
287 fn constant_version_name(version: &BigUint) -> String;
288}
289
290
291fn build_type_impl<'model>(model: &'model model::Verilization, version: &BigUint, t: &model::Type, scope: &model::Scope<'model>, type_args: &HashMap<String, LangType<'model>>) -> Result<LangType<'model>, GeneratorError> {
292 let lang_args = t.args.iter()
293 .map(|arg| build_type_impl(model, version, arg, scope, type_args))
294 .collect::<Result<Vec<_>, _>>()?;
295
296 Ok(match scope.lookup(t.name.clone()) {
297 model::ScopeLookup::NamedType(name) => match model.get_type(&name).ok_or_else(|| GeneratorError::CouldNotFind(name.clone()))? {
298 model::NamedTypeDefinition::StructType(type_def) => {
299 let lang_args_map = type_def.type_params().clone().into_iter()
300 .zip(lang_args.clone().into_iter())
301 .collect::<HashMap<_, _>>();
302
303 let ver_type = type_def.versioned(version).ok_or_else(|| GeneratorError::CouldNotFindVersion(name, version.clone()))?;
304 let type_ver = ver_type.version.clone();
305
306 let fields = LangVerTypeFields {
307 model: model,
308 type_args: lang_args_map,
309 type_def: type_def,
310 ver_type: ver_type,
311 };
312
313 LangType::Versioned(VersionedTypeKind::Struct, type_def.name(), type_ver, lang_args, fields)
314 },
315
316 model::NamedTypeDefinition::EnumType(type_def) => {
317 let lang_args_map = type_def.type_params().clone().into_iter()
318 .zip(lang_args.clone().into_iter())
319 .collect::<HashMap<_, _>>();
320
321 let ver_type = type_def.versioned(version).ok_or_else(|| GeneratorError::CouldNotFindVersion(name, version.clone()))?;
322 let type_ver = ver_type.version.clone();
323
324 let fields = LangVerTypeFields {
325 model: model,
326 type_args: lang_args_map,
327 type_def: type_def,
328 ver_type: ver_type,
329 };
330
331 LangType::Versioned(VersionedTypeKind::Enum, type_def.name(), type_ver, lang_args, fields)
332 },
333
334 model::NamedTypeDefinition::ExternType(type_def) => {
335 let lang_args_map = type_def.type_params().clone().into_iter()
336 .zip(lang_args.clone().into_iter())
337 .collect::<HashMap<_, _>>();
338
339 let literals = LangExternTypeLiterals {
340 model: model,
341 type_args: lang_args_map,
342 type_def: type_def,
343 };
344
345 LangType::Extern(type_def.name(), lang_args, literals)
346 },
347 },
348 model::ScopeLookup::TypeParameter(name) => type_args.get(&name).ok_or_else(|| GeneratorError::CouldNotResolveTypeParameter(name))?.clone(),
349 })
350}
351
352fn constant_invoke_operation<'model>(op: Operation, values: Vec<LangExpr<'model>>, t: LangType<'model>) -> Result<LangExpr<'model>, GeneratorError> {
353 let (target, type_args) = match t {
354 LangType::Versioned(_, name, version, type_args, _) => (OperationTarget::VersionedType(name, version), type_args),
355 LangType::Extern(name, type_args, _) => (OperationTarget::ExternType(name), type_args),
356 LangType::TypeParameter(_) | LangType::Codec(_) | LangType::Converter(_, _) => return Err(GeneratorError::InvalidTypeForConstant),
357 };
358
359 Ok(LangExpr::InvokeOperation(op, target, type_args, values))
360}
361
362pub trait Generator<'model> : Sized {
363 type Lang: GeneratorNameMapping;
364
365 fn model(&self) -> &'model model::Verilization;
366 fn scope(&self) -> &model::Scope<'model>;
367
368
369 fn build_type<'gen>(&'gen self, version: &BigUint, t: &model::Type) -> Result<LangType<'model>, GeneratorError> {
370 let type_args = self.scope().type_params().into_iter().map(|param| (param.clone(), LangType::TypeParameter(param))).collect::<HashMap<_, _>>();
371
372 build_type_impl(self.model(), version, t, self.scope(), &type_args)
373 }
374
375 fn build_codec(&self, t: LangType<'model>) -> Result<LangExpr<'model>, GeneratorError> {
376 Ok(match t {
377 LangType::Versioned(_, name, version, args, _) => {
378 let codec_args = args.iter().map(|arg| self.build_codec(arg.clone())).collect::<Result<Vec<_>, _>>()?;
379
380 LangExpr::InvokeOperation(
381 Operation::TypeCodec,
382 OperationTarget::VersionedType(name, version),
383 args,
384 codec_args,
385 )
386 },
387
388 LangType::Extern(name, args, _) => {
389 let codec_args = args.iter().map(|arg| self.build_codec(arg.clone())).collect::<Result<Vec<_>, _>>()?;
390
391 LangExpr::InvokeOperation(
392 Operation::TypeCodec,
393 OperationTarget::ExternType(name),
394 args,
395 codec_args,
396 )
397 },
398
399 LangType::TypeParameter(name) => LangExpr::Identifier(Self::Lang::codec_codec_param_name(&name)),
400
401 LangType::Codec(_) | LangType::Converter(_, _) => return Err(GeneratorError::InvalidTypeForCodec),
402 })
403 }
404
405 fn build_conversion(&self, prev_ver: &BigUint, version: &BigUint, t: &model::Type, param: ConvertParam<'model>) -> Result<LangExpr<'model>, GeneratorError> {
406 if !requires_conversion(self, t, prev_ver) {
407 return Ok(match param {
408 ConvertParam::ConverterObject => LangExpr::IdentityConverter(self.build_type(version, t)?),
409 ConvertParam::Expression(expr) => expr,
410 })
411 }
412
413 let converter = match self.scope().lookup(t.name.clone()) {
414 model::ScopeLookup::NamedType(name) => {
415
416 let mut op_type_args = Vec::new();
417 let mut op_args = Vec::new();
418
419 for arg in &t.args {
420 op_type_args.push(self.build_type(prev_ver, arg)?);
421 op_type_args.push(self.build_type(version, arg)?);
422 op_args.push(self.build_conversion(prev_ver, version, arg, ConvertParam::ConverterObject)?);
423 }
424
425
426 let named_type_def = self.model().get_type(&name).ok_or_else(|| GeneratorError::CouldNotFind(name.clone()))?;
427 let operation;
428 let target;
429 match named_type_def {
430 model::NamedTypeDefinition::StructType(type_def) | model::NamedTypeDefinition::EnumType(type_def) => {
431 let ver_type = type_def.versioned(version).ok_or_else(|| GeneratorError::CouldNotFindVersion(name.clone(), version.clone()))?;
432
433 operation =
434 if ver_type.version < *version {
435 Operation::FinalTypeConverter
436 }
437 else {
438 Operation::FromPreviousVersion(prev_ver.clone())
439 };
440
441 target = OperationTarget::VersionedType(named_type_def.name(), ver_type.version.clone());
442 },
443
444 model::NamedTypeDefinition::ExternType(_) => {
445 operation = Operation::FinalTypeConverter;
446 target = OperationTarget::ExternType(named_type_def.name());
447 },
448 };
449
450 LangExpr::InvokeOperation(
451 operation,
452 target,
453 op_type_args,
454 op_args
455 )
456 },
457 model::ScopeLookup::TypeParameter(name) => LangExpr::Identifier(Self::Lang::convert_conv_param_name(&name)),
458 };
459
460
461 Ok(match param {
462 ConvertParam::ConverterObject => converter,
463 ConvertParam::Expression(expr) => LangExpr::InvokeConverter {
464 converter: Box::new(converter),
465 value: Box::new(expr),
466 },
467 })
468 }
469
470 fn build_value(&self, version: &BigUint, t: LangType<'model>, value: model::ConstantValue) -> Result<LangExpr<'model>, GeneratorError> {
471 Ok(match value {
472 model::ConstantValue::Integer(n) => constant_invoke_operation(Operation::FromInteger, vec!(LangExpr::IntegerLiteral(n.clone())), t)?,
473 model::ConstantValue::String(s) => constant_invoke_operation(Operation::FromString, vec!(LangExpr::StringLiteral(s.clone())), t)?,
474 model::ConstantValue::Sequence(seq) => match t {
475 LangType::Extern(type_name, type_args, literals) => {
476 let literals = literals.build()?;
477
478 let element_type = literals
479 .into_iter()
480 .find_map(|literal| match literal {
481 LangLiteral::Sequence(element_type) => Some(element_type),
482 _ => None,
483 })
484 .ok_or_else(|| GeneratorError::TypeCannotBeSequence(type_name.clone()))?;
485
486 let args = seq.into_iter()
487 .map(|elem| self.build_value(version, element_type.clone(), elem))
488 .collect::<Result<Vec<_>, _>>()?;
489
490 LangExpr::InvokeOperation(
491 Operation::FromSequence,
492 OperationTarget::ExternType(type_name),
493 type_args,
494 args,
495 )
496 },
497 LangType::Versioned(_, type_name, ..) => return Err(GeneratorError::TypeCannotBeSequence(type_name.clone())),
498 LangType::TypeParameter(_) | LangType::Codec(_) | LangType::Converter(_, _) => return Err(GeneratorError::InvalidTypeForConstant),
499 },
500
501 model::ConstantValue::Case(case_name, mut args) => match t {
502 LangType::Versioned(VersionedTypeKind::Enum, type_name, type_version, type_args, fields) if args.len() == 1 => {
503 let field = fields.build()?.into_iter().find(|field| *field.name == case_name).ok_or_else(|| GeneratorError::TypeDoesNotHaveCase(type_name.clone(), Some(type_version.clone()), case_name.clone()))?;
504
505 let arg = self.build_value(version, field.field_type, args.remove(0))?;
506 LangExpr::CreateEnum(type_name, type_version, type_args, field.name, Box::new(arg))
507 },
508 LangType::Versioned(VersionedTypeKind::Enum, type_name, ..) => return Err(GeneratorError::IncorrectCaseArity(type_name.clone(), case_name.clone())),
509
510 LangType::Extern(type_name, type_args, literals) => {
511 let case_params = literals.build()?
512 .into_iter()
513 .find_map(|literal| match literal {
514 LangLiteral::Case(name, case_params) if name == *case_name => Some(case_params),
515 _ => None,
516 })
517 .ok_or_else(|| GeneratorError::TypeDoesNotHaveCase(type_name.clone(), None, case_name.clone()))?;
518
519 let args = args.into_iter().zip(case_params.into_iter())
520 .map(|(arg, param)| self.build_value(version, param, arg))
521 .collect::<Result<Vec<_>, _>>()?;
522
523 LangExpr::InvokeOperation(
524 Operation::FromCase(case_name.clone()),
525 OperationTarget::ExternType(type_name),
526 type_args,
527 args,
528 )
529 },
530
531 LangType::Versioned(VersionedTypeKind::Struct, ..) => return Err(GeneratorError::RecordLiteralNotForStruct),
532 LangType::TypeParameter(_) | LangType::Codec(_) | LangType::Converter(_, _) => return Err(GeneratorError::InvalidTypeForConstant),
533 },
534
535 model::ConstantValue::Record(record) => match t {
536 LangType::Versioned(VersionedTypeKind::Struct, type_name, type_version, type_args, fields) => {
537 let mut lang_args = Vec::new();
538 let mut field_values = record.into_field_values();
539
540 for field in fields.build()? {
541 let value = field_values.remove(field.name).ok_or_else(|| GeneratorError::CouldNotFindRecordField(type_name.clone(), Some(type_version.clone()), field.name.clone()))?;
542 let value = self.build_value(version, field.field_type, value)?;
543 lang_args.push((field.name, value));
544 }
545
546 LangExpr::CreateStruct(type_name, type_version, type_args, lang_args)
547 },
548
549 LangType::Extern(type_name, type_args, literals) => {
550 let record_fields = literals.build()?
551 .into_iter()
552 .find_map(|literal| match literal {
553 LangLiteral::Record(fields) => Some(fields),
554 _ => None,
555 })
556 .ok_or_else(|| GeneratorError::ExternTypeDoesNotHaveRecordLiteral(type_name.clone()))?;
557
558 let mut field_values = record.into_field_values();
559 let mut field_names = Vec::new();
560 let mut args = Vec::new();
561
562 for field in record_fields {
563 let value = field_values.remove(field.name).ok_or_else(|| GeneratorError::CouldNotFindRecordField(type_name.clone(), None, field.name.clone()))?;
564 let value = self.build_value(version, field.field_type, value)?;
565 field_names.push(field.name.clone());
566 args.push(value);
567 }
568
569 LangExpr::InvokeOperation(
570 Operation::FromRecord(field_names),
571 OperationTarget::ExternType(type_name),
572 type_args,
573 args,
574 )
575 },
576
577 LangType::Versioned(VersionedTypeKind::Enum, ..) => return Err(GeneratorError::InvalidTypeForConstant),
578 LangType::TypeParameter(_) => return Err(GeneratorError::InvalidTypeForConstant),
579 LangType::Codec(_) | LangType::Converter(_, _) => return Err(GeneratorError::InvalidTypeForConstant),
580 },
581 model::ConstantValue::Constant(name) => {
582 match self.scope().lookup(name) {
583 model::ScopeLookup::NamedType(name) => {
584 let constant = self.model().get_constant(&name).ok_or_else(|| GeneratorError::CouldNotFind(name))?;
585
586 LangExpr::ConstantValue(constant.name(), version.clone())
587 },
588 model::ScopeLookup::TypeParameter(name) => return Err(GeneratorError::CouldNotFind(model::QualifiedName { package: model::PackageName::new(), name: name, }))
589 }
590
591 },
592 })
593 }
594
595}
596
597#[derive(Default)]
598pub struct GenConstant {}
599
600#[derive(Default)]
601pub struct GenType<GenTypeKind> {
602 type_gen: PhantomData<GenTypeKind>,
603}
604
605pub trait ConstGenerator<'model> : Generator<'model> {
606 fn constant(&self) -> Named<'model, model::Constant>;
607
608 fn write_header(&mut self) -> Result<(), GeneratorError>;
609 fn write_constant(&mut self, version_name: String, t: LangType<'model>, value: LangExpr<'model>) -> Result<(), GeneratorError>;
610 fn write_footer(&mut self) -> Result<(), GeneratorError>;
611
612
613 fn generate(&mut self) -> Result<(), GeneratorError> {
614 self.write_header()?;
615
616 for ver in self.constant().versions() {
617 let version_name = Self::Lang::constant_version_name(&ver.version);
618 let t = self.build_type(&ver.version, self.constant().value_type())?;
619 let value =
620 if let Some(value) = ver.value {
621 self.build_value(&ver.version, t.clone(), value.clone())?
622 }
623 else {
624 let prev_ver: BigInt = BigInt::from_biguint(Sign::Plus, ver.version.clone()) - 1;
625 let prev_ver = prev_ver.to_biguint().unwrap();
626 self.build_value_from_prev(&prev_ver, &ver.version, self.constant().value_type())?
627 };
628
629 self.write_constant(version_name, t, value)?;
630 }
631
632 self.write_footer()
633 }
634
635 fn build_value_from_prev(&self, prev_ver: &BigUint, version: &BigUint, t: &model::Type) -> Result<LangExpr<'model>, GeneratorError> {
636 self.build_conversion(prev_ver, version, t, ConvertParam::Expression(LangExpr::ConstantValue(self.constant().name(), prev_ver.clone())))
637 }
638
639
640
641}
642
643pub trait VersionedTypeGenerator<'model> : Generator<'model> {
644 fn type_def(&self) -> Named<'model, model::VersionedTypeDefinitionData>;
645
646 fn write_header(&mut self) -> Result<(), GeneratorError>;
647 fn write_version_header(&mut self, t: LangType<'model>) -> Result<(), GeneratorError>;
648 fn write_operation(&mut self, operation: OperationInfo<'model>) -> Result<(), GeneratorError>;
649 fn write_version_footer(&mut self) -> Result<(), GeneratorError>;
650 fn write_footer(&mut self) -> Result<(), GeneratorError>;
651
652
653 fn generate(&mut self) -> Result<(), GeneratorError> {
654 self.write_header()?;
655
656 let mut first_version = true;
657
658 for ver_type in self.type_def().versions() {
659 let version = &ver_type.version;
660
661 let prev_ver: BigInt = BigInt::from_biguint(Sign::Plus, version.clone()) - 1;
662 let prev_ver = prev_ver.to_biguint().unwrap();
663
664 let type_params_as_args = self.type_def().type_params().iter()
665 .map(|param| model::Type { name: model::QualifiedName::from_parts(&[], ¶m), args: vec!() })
666 .collect::<Vec<_>>();
667
668 let t = self.build_type(version, &model::Type { name: self.type_def().name().clone(), args: type_params_as_args.clone() })?;
669 let type_kind = match &t {
670 LangType::Versioned(kind, ..) => *kind,
671 _ => return Err(GeneratorError::CouldNotGenerateType),
672 };
673 self.write_version_header(t)?;
674
675 if self.type_def().is_final() && !self.type_def().type_params().is_empty() && self.type_def().last_explicit_version() == Some(&ver_type.version) {
677 self.write_operation(build_converter_operation_common(self, Operation::FinalTypeConverter, type_kind, &ver_type, version)?)?;
678 }
679
680 if !first_version { self.write_operation(build_converter_operation_common(self, Operation::FromPreviousVersion(prev_ver.clone()), type_kind, &ver_type, &prev_ver)?)?;
683 }
684
685 {
687 let mut codec_params = Vec::new();
688
689 for param in self.type_def().type_params() {
690 let param_type = LangType::TypeParameter(param.clone());
691
692 codec_params.push((Self::Lang::codec_codec_param_name(param), LangType::Codec(Box::new(param_type.clone()))));
693 }
694
695 let obj_type = self.build_type(version, &model::Type { name: self.type_def().name().clone(), args: type_params_as_args })?;
696
697 let codec_type = LangType::Codec(Box::new(obj_type.clone()));
698
699 let op = OperationInfo {
700 operation: Operation::TypeCodec,
701 version: version.clone(),
702 type_params: self.type_def().type_params().clone(),
703 params: codec_params,
704 result: codec_type,
705 implementation: LangExprStmt::CreateCodec {
706 t: obj_type.clone(),
707 read: Box::new(codec_read_implementation(self, obj_type.clone())?),
708 write: Box::new(codec_write_implementation(self, obj_type)?),
709 },
710 };
711
712 self.write_operation(op)?;
713 }
714
715
716 self.write_version_footer()?;
717 first_version = false;
718 }
719
720 self.write_footer()
721 }
722}
723
724fn build_converter_operation_common<'model, Gen>(gen: &Gen, op: Operation, type_kind: VersionedTypeKind, ver_type: &model::TypeVersionInfo<'model>, prev_ver: &BigUint) -> Result<OperationInfo<'model>, GeneratorError> where
725 Gen : VersionedTypeGenerator<'model>
726{
727 let version = &ver_type.version;
728
729 let mut type_params_as_args = Vec::new();
730 let mut type_params = Vec::new();
731 let mut type_args = Vec::new();
732 let mut params = Vec::new();
733 let mut result_type_args = Vec::new();
734 let mut prev_type_args = HashMap::new();
735 let mut result_type_args_map = HashMap::new();
736 let mut impl_call_args = Vec::new();
737
738 for param in gen.type_def().type_params() {
739 type_params_as_args.push(model::Type { name: model::QualifiedName::from_parts(&[], ¶m), args: vec!() });
740 let t1 = Gen::Lang::convert_prev_type_param(¶m);
741 let t2 = Gen::Lang::convert_current_type_param(¶m);
742 type_params.push(t1.clone());
743 type_params.push(t2.clone());
744 let t1_arg = LangType::TypeParameter(t1.clone());
745 let t2_arg = LangType::TypeParameter(t2.clone());
746 type_args.push(t1_arg.clone());
747 type_args.push(t2_arg.clone());
748 result_type_args.push(t2_arg.clone());
749 prev_type_args.insert(param.clone(), t1_arg);
750 result_type_args_map.insert(param.clone(), t2_arg);
751
752 let conv_type = LangType::Converter(
753 Box::new(LangType::TypeParameter(t1)),
754 Box::new(LangType::TypeParameter(t2)),
755 );
756
757 let conv_param = Gen::Lang::convert_conv_param_name(param);
758 params.push((conv_param.clone(), conv_type));
759 impl_call_args.push(LangExpr::Identifier(conv_param));
760 }
761
762 let prev_type = build_type_impl(gen.model(), prev_ver, &model::Type { name: gen.type_def().name().clone(), args: type_params_as_args.clone() }, gen.scope(), &prev_type_args)?;
763 let result_type = build_type_impl(gen.model(), version, &model::Type { name: gen.type_def().name().clone(), args: type_params_as_args.clone() }, gen.scope(), &result_type_args_map)?;
764
765 let converter_type = LangType::Converter(Box::new(prev_type.clone()), Box::new(result_type.clone()));
766
767 let implementation = if ver_type.explicit_version && ver_type.version != *prev_ver {
768 LangExprStmt::Expr(LangExpr::InvokeUserConverter {
769 name: gen.type_def().name(),
770 prev_ver: prev_ver.clone(),
771 version: version.clone(),
772 type_args: type_args,
773 args: impl_call_args,
774 })
775 }
776 else {
777 let body = match type_kind {
778 VersionedTypeKind::Struct => {
779 let mut fields = Vec::new();
780
781 for (field_name, field) in ver_type.ver_type.fields() {
782 let obj_value = LangExpr::Identifier(Gen::Lang::convert_prev_param_name().to_string());
783
784 let value_expr = LangExpr::StructField(gen.type_def().name(), ver_type.version.clone(), field_name, Box::new(obj_value));
785 let conv_value = gen.build_conversion(prev_ver, &ver_type.version, &field.field_type, ConvertParam::Expression(value_expr))?;
786
787 fields.push((field_name, conv_value));
788 }
789
790 LangStmt::Expr(vec!(),
791 Some(LangExpr::CreateStruct(gen.type_def().name(), ver_type.version.clone(), result_type_args, fields))
792 )
793 },
794 VersionedTypeKind::Enum => {
795 let mut cases = Vec::new();
796
797
798 for (field_name, field) in ver_type.ver_type.fields() {
799
800 let value_expr = LangExpr::Identifier(field_name.clone());
801 let conv_value = gen.build_conversion(prev_ver, &ver_type.version, &field.field_type, ConvertParam::Expression(value_expr))?;
802 let enum_value = LangExpr::CreateEnum(gen.type_def().name(), ver_type.version.clone(), result_type_args.clone(), field_name, Box::new(conv_value));
803
804 cases.push(MatchCase {
805 binding_name: field_name.clone(),
806 case_name: field_name.clone(),
807 body: LangStmt::Expr(vec!(), Some(enum_value)),
808 });
809 }
810
811 LangStmt::MatchEnum {
812 value: LangExpr::Identifier(Gen::Lang::convert_prev_param_name().to_string()),
813 value_type: build_type_impl(gen.model(), prev_ver, &model::Type { name: gen.type_def().name().clone(), args: type_params_as_args.clone() }, gen.scope(), &prev_type_args)?,
814 cases: cases,
815 }
816 },
817 };
818
819 LangExprStmt::CreateConverter {
820 from_type: prev_type,
821 to_type: result_type,
822 body: Box::new(body),
823 }
824 };
825
826 Ok(OperationInfo {
827 operation: op,
828 version: version.clone(),
829 type_params: type_params,
830 params: params,
831 result: converter_type,
832 implementation: implementation,
833 })
834}
835
836
837fn codec_read_implementation<'model, Gen>(gen: &Gen, t: LangType<'model>) -> Result<LangStmt<'model>, GeneratorError> where
838 Gen : VersionedTypeGenerator<'model>
839{
840 Ok(match t {
841 LangType::Versioned(VersionedTypeKind::Struct, _, version, type_args, fields) => {
842 let mut field_values = Vec::new();
843
844 for field in fields.build()? {
845 let field_codec = gen.build_codec(field.field_type)?;
846 field_values.push((field.name, LangExpr::CodecRead { codec: Box::new(field_codec) }));
847 }
848
849 LangStmt::Expr(vec!(),
850 Some(LangExpr::CreateStruct(gen.type_def().name(), version, type_args, field_values))
851 )
852 },
853
854 LangType::Versioned(VersionedTypeKind::Enum, _, version, type_args, fields) => {
855 let mut cases = Vec::new();
856
857 for (index, field) in fields.build()?.into_iter().enumerate() {
858 let codec = gen.build_codec(field.field_type)?;
859
860 let body = LangStmt::Expr(vec!(),
861 Some(LangExpr::CreateEnum(
862 gen.type_def().name(),
863 version.clone(),
864 type_args.clone(),
865 field.name,
866 Box::new(LangExpr::CodecRead {
867 codec: Box::new(codec),
868 })
869 ))
870 );
871
872 cases.push((BigUint::from(index), body));
873 }
874
875 LangStmt::MatchDiscriminator {
876 value: LangExpr::ReadDiscriminator,
877 cases: cases,
878 }
879 },
880
881 _ => return Err(GeneratorError::InvalidTypeForCodec),
882 })
883}
884
885fn codec_write_implementation<'model, Gen>(gen: &Gen, t: LangType<'model>) -> Result<LangStmt<'model>, GeneratorError> where
886 Gen : VersionedTypeGenerator<'model>
887{
888 Ok(match t.clone() {
889 LangType::Versioned(VersionedTypeKind::Struct, _, version, _, fields) => {
890 let mut field_values = Vec::new();
891
892 for field in fields.build()? {
893 let obj_value = LangExpr::Identifier(Gen::Lang::codec_write_value_name().to_string());
894 let field_codec = gen.build_codec(field.field_type)?;
895 let value_expr = LangExpr::StructField(gen.type_def().name(), version.clone(), field.name, Box::new(obj_value));
896
897 field_values.push(LangExpr::CodecWrite {
898 codec: Box::new(field_codec),
899 value: Box::new(value_expr),
900 });
901 }
902
903 LangStmt::Expr(field_values, None)
904 },
905
906 LangType::Versioned(VersionedTypeKind::Enum, _, _, _, fields) => {
907 let mut cases = Vec::new();
908
909 for (index, field) in fields.build()?.into_iter().enumerate() {
910 let value_expr = LangExpr::Identifier(field.name.clone());
911 let codec = gen.build_codec(field.field_type)?;
912
913
914 cases.push(MatchCase {
915 binding_name: field.name.clone(),
916 case_name: field.name.clone(),
917 body: LangStmt::Expr(vec!(
918 LangExpr::WriteDiscriminator(BigUint::from(index)),
919 LangExpr::CodecWrite {
920 codec: Box::new(codec),
921 value: Box::new(value_expr),
922 },
923 ), None),
924 });
925 }
926
927 LangStmt::MatchEnum {
928 value: LangExpr::Identifier(Gen::Lang::codec_write_value_name().to_string()),
929 value_type: t,
930 cases: cases,
931 }
932 },
933
934 _ => return Err(GeneratorError::InvalidTypeForCodec),
935 })
936}
937
938
939pub trait GeneratorWithFile {
940 type GeneratorFile : Write;
941 fn file(&mut self) -> &mut Self::GeneratorFile;
942}
943
944pub trait Indentation : GeneratorWithFile {
945 fn indentation_size(&mut self) -> &mut u32;
946
947 fn write_indent(&mut self) -> Result<(), GeneratorError> {
948 for _ in 0..*self.indentation_size() {
949 write!(self.file(), "\t")?;
950 }
951 Ok(())
952 }
953
954 fn indent_increase(&mut self) {
955 *self.indentation_size() += 1;
956 }
957
958 fn indent_decrease(&mut self) {
959 *self.indentation_size() -= 1;
960 }
961}