1mod ast;
7
8use ast::*;
9use omg_idl_grammar::{IdlParser, Rule};
10use pest::{
11 error::ErrorVariant,
12 iterators::{Pair, Pairs},
13 Parser, RuleType,
14};
15use std::{
16 fs::File,
17 io::{self, Read, Write},
18 path::{Path, PathBuf},
19};
20use thiserror::Error;
21
22#[derive(Debug, Error)]
23pub enum IdlError<R: RuleType> {
24 #[error("Failed to parse IDL files")]
25 ParserError(#[from] pest::error::Error<R>),
26 #[error("Could not find requested idl_file: {0:#?}")]
27 FileNotFound(PathBuf),
28 #[error("Failed to render generated code.")]
29 RenderError(#[from] minijinja::Error),
30 #[error("Failed to write generated code.")]
31 WriteError(#[from] io::Error),
32}
33
34pub trait IdlLoader {
36 fn load(&self, filename: &Path) -> Result<String, io::Error>;
37}
38
39#[derive(Debug, Default)]
41pub struct Configuration {
42 search_path: PathBuf,
43 idl_file: PathBuf,
44 verbose: bool,
45}
46
47impl Configuration {
48 pub fn new(search_path: &Path, idl_file: &Path, verbose: bool) -> Self {
49 Self {
50 search_path: search_path.to_path_buf(),
51 idl_file: idl_file.to_path_buf(),
52 verbose,
53 }
54 }
55}
56
57type Scope = Vec<String>;
59
60#[derive(Debug, Clone)]
62struct Context<'i> {
63 config: &'i Configuration,
64 root_module: IdlModule,
65}
66
67impl<'i> Context<'i> {
68 pub fn new(config: &'i Configuration) -> Context<'i> {
69 Context {
70 config,
71 root_module: IdlModule::new(None),
72 }
73 }
74
75 fn lookup_module(&mut self, scope: &Scope) -> &mut IdlModule {
78 let mut current_module = &mut self.root_module;
80
81 for name in scope {
82 let submodule = current_module
83 .modules
84 .entry(name.to_owned())
85 .or_insert(IdlModule::new(Some(name.to_owned())));
86 current_module = submodule;
87 }
88
89 current_module
90 }
91
92 fn add_type_dcl(&mut self, scope: &Scope, key: String, type_dcl: IdlTypeDcl) {
94 self.lookup_module(scope)
95 .types
96 .entry(key)
97 .or_insert(type_dcl);
98 }
99
100 fn add_const_dcl(&mut self, scope: &Scope, key: String, const_dcl: IdlConstDcl) {
102 self.lookup_module(scope)
103 .constants
104 .entry(key)
105 .or_insert(const_dcl);
106 }
107
108 pub fn read_type_spec(
110 &mut self,
111 scope: &Scope,
112 pair: Pair<Rule>,
113 ) -> Result<IdlTypeSpec, pest::error::Error<Rule>> {
114 let rule = pair.as_rule();
115 let pos = pair.as_span().start_pos();
116
117 if self.config.verbose {
118 print!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
119 }
120
121 let type_spec = match rule {
122 Rule::float => IdlTypeSpec::F32Type,
123 Rule::double => IdlTypeSpec::F64Type,
124 Rule::long_double => IdlTypeSpec::F128Type,
125 Rule::unsigned_short_int => IdlTypeSpec::U16Type,
126 Rule::unsigned_longlong_int => IdlTypeSpec::U64Type,
127 Rule::unsigned_long_int => IdlTypeSpec::U32Type,
128 Rule::signed_short_int => IdlTypeSpec::I16Type,
129 Rule::signed_longlong_int => IdlTypeSpec::I64Type,
130 Rule::signed_long_int => IdlTypeSpec::I32Type,
131 Rule::char_type => IdlTypeSpec::CharType,
132 Rule::wide_char_type => IdlTypeSpec::WideCharType,
133 Rule::boolean_type => IdlTypeSpec::BooleanType,
134 Rule::octet_type => IdlTypeSpec::OctetType,
135 Rule::string_type => match pair.into_inner().next() {
136 None => IdlTypeSpec::StringType(None),
137 Some(next_pair) => {
138 let pos_int_const = self.read_const_expr(scope, next_pair)?;
139 IdlTypeSpec::StringType(Some(Box::new(pos_int_const)))
140 }
141 },
142 Rule::wide_string_type => {
143 match pair.into_inner().next() {
144 None => IdlTypeSpec::WideStringType(None),
145 Some(next_pair) => {
146 let pos_int_const = self.read_const_expr(scope, next_pair)?;
147 IdlTypeSpec::WideStringType(Some(Box::new(pos_int_const)))
148 }
150 }
151 }
152 Rule::sequence_type => {
153 let pos = pair.as_span().start_pos();
154 let mut inner = pair.into_inner();
155 match (inner.next(), inner.next()) {
156 (Some(typ), None) => {
157 let typ_expr = self.read_type_spec(scope, typ)?;
158 Ok(IdlTypeSpec::SequenceType(Box::new(typ_expr)))
159 }
160 (Some(typ), Some(bound)) => {
161 let typ_expr = self.read_type_spec(scope, typ)?;
162 let _bound_expr = self.read_const_expr(scope, bound)?;
163 Ok(IdlTypeSpec::SequenceType(Box::new(typ_expr)))
164 }
165 _ => Err(pest::error::Error::new_from_pos(
166 ErrorVariant::CustomError {
167 message:
168 "Failed to discover required components to establish a sequence"
169 .to_string(),
170 },
171 pos,
172 )),
173 }?
174 }
175 Rule::scoped_name => {
177 let name = self.read_scoped_name(scope, pair)?;
178 IdlTypeSpec::ScopedName(name)
179 }
180 _ => match pair.into_inner().next() {
182 Some(pair) => self.read_type_spec(scope, pair),
183 _ => Err(pest::error::Error::new_from_pos(
184 ErrorVariant::CustomError {
185 message: "Failed find a deeper rule pair to follow".to_string(),
186 },
187 pos,
188 )),
189 }?,
190 };
191
192 Ok(type_spec)
193 }
194
195 pub fn read_struct_member_declarator(
199 &mut self,
200 scope: &Scope,
201 pair: Pair<Rule>,
202 type_spec: &IdlTypeSpec,
203 ) -> Result<IdlStructMember, pest::error::Error<Rule>> {
204 let pos = pair.as_span().start_pos();
205 match pair.into_inner().next() {
206 Some(decl) => {
207 let rule = decl.as_rule();
208 let pos = decl.as_span().start_pos();
209 if self.config.verbose {
210 print!(
211 "{:indent$}should be declarator {:?}",
212 "",
213 rule,
214 indent = 3 * scope.len()
215 );
216 }
217 let mut inner = decl.into_inner();
218 match rule {
219 Rule::simple_declarator => match inner.next() {
221 Some(pair) => Ok(IdlStructMember {
222 id: self.read_identifier(scope, pair)?,
223 type_spec: type_spec.clone(),
224 }),
225 _ => Err(pest::error::Error::new_from_pos(
226 ErrorVariant::CustomError {
227 message: "Pair did not contain a valid IDL simple declarator"
228 .to_string(),
229 },
230 pos,
231 )),
232 },
233 Rule::array_declarator => {
235 match inner.next() {
236 Some(pair) => {
237 let array_sizes: Result<Vec<_>, pest::error::Error<Rule>> = inner
238 .map(|pair| {
239 match pair.into_inner().next() {
240 Some(pair) => {
241 self.read_const_expr(scope, pair)
243 },
244 _ => {
245 Err(pest::error::Error::new_from_pos(
246 ErrorVariant::CustomError {
247 message: "Pair did not contain a valid 'const expression'".to_string(),
248 }, pos))
249 }
250 }
251 })
252 .collect();
253 let array_type_spec = IdlTypeSpec::ArrayType(
254 Box::new(type_spec.clone()),
255 array_sizes?,
256 );
257
258 Ok(IdlStructMember {
259 id: self.read_identifier(scope, pair)?,
260 type_spec: array_type_spec,
261 })
262 }
263 _ => Err(pest::error::Error::new_from_pos(
264 ErrorVariant::CustomError {
265 message: "Pair did not contain a valid IDL array declatator"
266 .to_string(),
267 },
268 pos,
269 )),
270 }
271 }
272 _ => Err(pest::error::Error::new_from_pos(
273 ErrorVariant::CustomError {
274 message: "Pair did not contain a valid IDL type rule".to_string(),
275 },
276 pos,
277 )),
278 }
279 }
280 _ => Err(pest::error::Error::new_from_pos(
281 ErrorVariant::CustomError {
282 message: "Pair did not contain a either other a simple or arraty declarator"
283 .to_string(),
284 },
285 pos,
286 )),
287 }
288 }
289
290 fn read_struct_member(
294 &mut self,
295 scope: &Scope,
296 pair: Pair<Rule>,
297 ) -> Result<Vec<IdlStructMember>, pest::error::Error<Rule>> {
298 let pos = pair.as_span().start_pos();
299
300 if self.config.verbose {
301 print!(
302 "{:indent$}{:?}",
303 "",
304 pair.as_rule(),
305 indent = 3 * scope.len()
306 );
307 }
308
309 let mut inner = pair.into_inner();
310 let type_spec = match inner.next() {
311 Some(pair) => self.read_type_spec(scope, pair),
312 _ => Err(pest::error::Error::new_from_pos(
313 ErrorVariant::CustomError {
314 message: "Pair did not contain a valid IDL type rule".to_string(),
315 },
316 pos,
317 )),
318 }?;
319
320 let declarators = match inner.next() {
322 Some(pair) => Ok(pair.into_inner()),
323 _ => Err(pest::error::Error::new_from_pos(
324 ErrorVariant::CustomError {
325 message: "Failed to aquire next declaration pair".to_string(),
326 },
327 pos,
328 )),
329 }?;
330
331 declarators
332 .map(|declarator| self.read_struct_member_declarator(scope, declarator, &type_spec))
333 .collect()
334 }
335
336 fn read_identifier(
338 &mut self,
339 scope: &Scope,
340 pair: Pair<Rule>,
341 ) -> Result<String, pest::error::Error<Rule>> {
342 let rule = pair.as_rule();
343 if self.config.verbose {
344 println!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
345 }
346 match rule {
347 Rule::identifier | Rule::enumerator => Ok(pair.as_str().to_owned()),
348 _ => Err(pest::error::Error::new_from_pos(
349 ErrorVariant::CustomError {
350 message: "Pair did not contain a valid scoped name rule".to_string(),
351 },
352 pair.as_span().start_pos(),
353 )),
354 }
355 }
356
357 fn read_scoped_name(
359 &mut self,
360 scope: &Scope,
361 pair: Pair<Rule>,
362 ) -> Result<IdlScopedName, pest::error::Error<Rule>> {
363 let is_absolute_name = pair.as_str().starts_with("::");
364 if self.config.verbose {
365 println!(
366 "{:indent$}>>> {:?} '{}' - abs? {is_absolute_name}",
367 "",
368 pair.as_rule(),
369 pair.as_str(),
370 indent = 3 * scope.len()
371 );
372 }
373
374 let inner = pair.into_inner();
376 let scoped_name: Result<Vec<String>, pest::error::Error<Rule>> = inner
377 .map(|pair| self.read_identifier(scope, pair))
378 .collect();
379
380 Ok(IdlScopedName(scoped_name?, is_absolute_name))
381 }
382
383 fn read_const_expr(
385 &mut self,
386 scope: &Scope,
387 pair: Pair<Rule>,
388 ) -> Result<IdlValueExpr, pest::error::Error<Rule>> {
389 let rule = pair.as_rule();
390 let pos = pair.as_span().start_pos();
391
392 if self.config.verbose {
393 println!(
394 "{:indent$}{:?} '{}'",
395 "",
396 rule,
397 pair.as_str(),
398 indent = 3 * scope.len()
399 );
400 }
401 let fp_collect_init = (None, None, None, None);
402
403 let fp_collect = |(i, f, e, s), node: Pair<Rule>| match node.as_rule() {
404 Rule::integral_part => (Some(node.as_str().to_owned()), f, e, s),
405 Rule::fractional_part => (i, Some(node.as_str().to_owned()), e, s),
406 Rule::exponent => (i, f, Some(node.as_str().to_owned()), s),
407 Rule::float_suffix => (i, f, e, Some(node.as_str().to_owned())),
408 _ => panic!(),
409 };
410
411 let mut binary_op_collect =
412 |pair: Option<Pair<'_, Rule>>, bin_op: BinaryOp, err_str: &str| match pair {
413 Some(pair) => {
414 let expr = self.read_const_expr(scope, pair)?;
415 Ok(IdlValueExpr::BinaryOp(bin_op, Box::new(expr)))
416 }
417 None => Err(pest::error::Error::new_from_pos(
418 ErrorVariant::CustomError {
419 message: format!("No associated values found with the parsed '{err_str}'"),
420 },
421 pos,
422 )),
423 };
424
425 let pair_as_str = pair.as_str();
426 let mut inner = pair.into_inner();
427 match rule {
428 Rule::const_expr => match (inner.next(), inner.next()) {
429 (Some(expr0), Some(expr1)) => {
430 let value_expr_0 = self.read_const_expr(scope, expr0)?;
431 let value_expr_1 = self.read_const_expr(scope, expr1)?;
432 Ok(IdlValueExpr::Expr(Box::new(value_expr_0), Box::new(value_expr_1)))
433 }
434 (Some(expr1), None) => self.read_const_expr(scope, expr1),
435 _ => Err(pest::error::Error::new_from_pos(
436 ErrorVariant::CustomError {
437 message: "Pair did not contain a valid const expression rule".to_string(),
438 }, pos)),
439 },
440 Rule::unary_expr => match (inner.next(), inner.next()) {
441 (Some(unary_op), Some(prim_expr)) => {
442 let pos = prim_expr.as_span().start_pos();
443 let expr = self.read_const_expr(scope, prim_expr)?;
444 match unary_op.as_str() {
445 "-" => Ok(IdlValueExpr::UnaryOp(UnaryOp::Neg, Box::new(expr))),
446 "+" => Ok(IdlValueExpr::UnaryOp(UnaryOp::Pos, Box::new(expr))),
447 "~" => Ok(IdlValueExpr::UnaryOp(UnaryOp::Inverse, Box::new(expr))),
448 _ => Err(pest::error::Error::new_from_pos(
449 ErrorVariant::CustomError {
450 message: format!("{unary_op} does not match acceptable values -|+|~"),
451 }, pos)),
452 }
453 }
454 (Some(prim_expr), None) => {
455 self.read_const_expr(scope, prim_expr)
456 },
457 _ => Err(pest::error::Error::new_from_pos(
458 ErrorVariant::CustomError {
459 message: "Rule does not match expected unary expression format".to_string(),
460 }, pos)),
461 },
462 Rule::primary_expr => match inner.next() {
463 Some(pair) if pair.as_rule() == Rule::scoped_name => {
465 let name = self.read_scoped_name(scope, pair)?;
466 Ok(IdlValueExpr::ScopedName(name))
467 }
468 Some(pair) if pair.as_rule() == Rule::literal => {
469 self.read_const_expr(scope, pair)
470 },
471 Some(pair) if pair.as_rule() == Rule::const_expr => {
472 let expr = self.read_const_expr(scope, pair)?;
473 Ok(IdlValueExpr::Brace(Box::new(expr)))
474 }
475 _ => Err(pest::error::Error::new_from_pos(
476 ErrorVariant::CustomError {
477 message: "Primary expression did not match 'scoped_name', 'literal', or 'const expression'".to_string(),
478 }, pos)),
479 },
480 Rule::and_expr => {
481 binary_op_collect(inner.next(), BinaryOp::And, "and expression")
482 }
483 Rule::or_expr => {
484 binary_op_collect(inner.next(), BinaryOp::Or, "or expression")
485 }
486 Rule::xor_expr => {
487 binary_op_collect(inner.next(), BinaryOp::Xor, "xor expression")
488 }
489 Rule::lshift_expr => {
490 binary_op_collect(inner.next(), BinaryOp::LShift, "left shift expression")
491 }
492 Rule::rshift_expr => {
493 binary_op_collect(inner.next(), BinaryOp::RShift, "right shift expression")
494 }
495 Rule::add_expr => {
496 binary_op_collect(inner.next(), BinaryOp::Add, "add expression")
497 }
498 Rule::sub_expr => {
499 binary_op_collect(inner.next(), BinaryOp::Sub, "sub expression")
500 }
501 Rule::mul_expr => {
502 binary_op_collect(inner.next(), BinaryOp::Mul, "multiply expression")
503 }
504 Rule::div_expr => {
505 binary_op_collect(inner.next(), BinaryOp::Div, "division expression")
506 }
507 Rule::mod_expr => {
508 binary_op_collect(inner.next(), BinaryOp::Mod, "modulo expression")
509 }
510 Rule::decimal_integer_literal => Ok(IdlValueExpr::DecLiteral(pair_as_str.to_owned())),
511 Rule::octal_integer_literal => Ok(IdlValueExpr::OctLiteral(pair_as_str.to_owned())),
512 Rule::hex_integer_literal => Ok(IdlValueExpr::HexLiteral(pair_as_str.to_owned())),
513 Rule::floating_pt_literal => {
514 let (i, f, e, s) = inner.fold(fp_collect_init, fp_collect);
515 Ok(IdlValueExpr::FloatLiteral(i, f, e, s))
516 }
517 Rule::boolean_literal => {
518 let true_str = "TRUE".to_string();
519 Ok(IdlValueExpr::BooleanLiteral(pair_as_str.to_uppercase() == true_str))
520 },
521 Rule::character_literal => Ok(IdlValueExpr::CharLiteral(pair_as_str.to_owned())),
522 Rule::wide_character_literal => {
523 Ok(IdlValueExpr::WideCharLiteral(pair_as_str.to_owned()))
524 }
525 Rule::string_literal => Ok(IdlValueExpr::StringLiteral(pair_as_str.to_owned())),
526 Rule::wide_string_literal => {
527 Ok(IdlValueExpr::WideStringLiteral(pair_as_str.to_owned()))
528 }
529 _ => {
530 match inner.next() {
531 Some(pair) => {
532 self.read_const_expr(scope, pair)
533 }
534 None => {
535 Err(pest::error::Error::new_from_pos(
536 ErrorVariant::CustomError {
537 message: "Failed to read 'const expression' in the catch all".to_string(),
538 }, pos))
539 }
540 }
541 },
542 }
543 }
544
545 fn read_switch_element_declarator(
549 &mut self,
550 scope: &Scope,
551 pair: Pair<Rule>,
552 type_spec: &IdlTypeSpec,
553 ) -> Result<IdlSwitchElement, pest::error::Error<Rule>> {
554 let pos = pair.as_span().start_pos();
555
556 match pair.into_inner().next() {
557 Some(decl) => {
558 let rule = decl.as_rule();
559 let pos = decl.as_span().start_pos();
560 if self.config.verbose {
561 println!(
562 "{:indent$}should be declarator {:?}",
563 "",
564 rule,
565 indent = 3 * scope.len()
566 );
567 }
568
569 let mut inner = decl.into_inner();
570 match rule {
571 Rule::simple_declarator => {
573 match inner.next() {
574 Some(pair) => {
575 Ok(IdlSwitchElement {
576 id: self.read_identifier(scope, pair)?,
577 type_spec: type_spec.clone(),
578 })
579 }
580 _ => {
581 Err(pest::error::Error::<Rule>::new_from_pos(
582 ErrorVariant::CustomError {
583 message: "Failed to discover simple declarator for switch element".to_string(),
584 }, pos))
585 },
586 }
587 }
588 Rule::array_declarator => {
590 match inner.next() {
591 Some(pair) => {
592 let id = self.read_identifier(scope, pair)?;
593 let array_sizes: Result<Vec<_>, pest::error::Error<Rule>> = inner
594 .map(|pair| {
595 let pos = pair.as_span().start_pos();
596 match pair.into_inner().next() {
597 Some(pair) => {
598 self.read_const_expr(scope, pair)
600 }
601 _ => Err(pest::error::Error::new_from_pos(
602 ErrorVariant::CustomError {
603 message: "Failed to discover const_expr under the fixed_array_size for switch element declarator".to_string(),
604 }, pos)),
605 }
606 })
607 .collect();
608 let array_type_spec =
609 IdlTypeSpec::ArrayType(Box::new(type_spec.clone()), array_sizes?);
610
611 Ok(IdlSwitchElement {
612 id,
613 type_spec: array_type_spec,
614 })
615 }
616 _ => Err(pest::error::Error::new_from_pos(
617 ErrorVariant::CustomError {
618 message: "Failed to parse array declarator for switch element declarator".to_string(),
619 }, pos)),
620 }
621 },
622 _ => Err(pest::error::Error::new_from_pos(
623 ErrorVariant::CustomError {
624 message: "Failed to discover either simple or array declarator for switch element declarator".to_string(),
625 }, pos)),
626
627 }
628 }
629 _ => Err(pest::error::Error::new_from_pos(
630 ErrorVariant::CustomError {
631 message: "Failed to parse switch element declarator".to_string(),
632 },
633 pos,
634 )),
635 }
636 }
637
638 fn read_switch_element_spec(
640 &mut self,
641 scope: &Scope,
642 pair: Pair<Rule>,
643 ) -> Result<IdlSwitchElement, pest::error::Error<Rule>> {
644 let rule = pair.as_rule();
645 let pos = pair.as_span().start_pos();
646 if self.config.verbose {
647 println!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
648 }
649 let mut inner = pair.into_inner();
650 match inner.next() {
651 Some(pair) => {
652 let type_spec = self.read_type_spec(scope, pair)?;
653 match inner.next() {
654 Some(pair) => self.read_switch_element_declarator(scope, pair, &type_spec),
655 _ => Err(pest::error::Error::new_from_pos(
656 ErrorVariant::CustomError {
657 message: "Failed to read declarator from the switch element spec"
658 .to_string(),
659 },
660 pos,
661 )),
662 }
663 }
664 _ => Err(pest::error::Error::new_from_pos(
665 ErrorVariant::CustomError {
666 message: "Failed to read type spec from the switch element spec".to_string(),
667 },
668 pos,
669 )),
670 }
671 }
672
673 fn read_switch_type_spec(
675 &mut self,
676 scope: &Scope,
677 pair: Pair<Rule>,
678 ) -> Result<IdlTypeSpec, pest::error::Error<Rule>> {
679 let rule = pair.as_rule();
680 let pos = pair.as_span().start_pos();
681 if self.config.verbose {
682 println!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
683 }
684 match pair.into_inner().next() {
685 Some(pair) => self.read_type_spec(scope, pair),
686 _ => Err(pest::error::Error::new_from_pos(
687 ErrorVariant::CustomError {
688 message: "Failed to read associated type for switch type".to_string(),
689 },
690 pos,
691 )),
692 }
693 }
694
695 fn read_switch_body(
697 &mut self,
698 scope: &Scope,
699 pair: Pair<Rule>,
700 ) -> Result<Vec<IdlSwitchCase>, pest::error::Error<Rule>> {
701 let rule = pair.as_rule();
702 if self.config.verbose {
703 println!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
704 }
705
706 pair.into_inner()
707 .map(|pair| self.read_switch_case(scope, pair))
708 .collect()
709 }
710
711 fn read_switch_label(
713 &mut self,
714 scope: &Scope,
715 pair: Pair<Rule>,
716 ) -> Result<IdlSwitchLabel, pest::error::Error<Rule>> {
717 if self.config.verbose {
718 println!(
719 "{:indent$}{:?}",
720 "",
721 pair.as_rule(),
722 indent = 3 * scope.len()
723 );
724 }
725
726 match pair.into_inner().next() {
727 Some(pair) => {
728 let expr = self.read_const_expr(scope, pair)?;
729 Ok(IdlSwitchLabel::Label(expr))
730 }
731 _ => Ok(IdlSwitchLabel::Default),
732 }
733 }
734
735 fn read_switch_case(
737 &mut self,
738 scope: &Scope,
739 pair: Pair<Rule>,
740 ) -> Result<IdlSwitchCase, pest::error::Error<Rule>> {
741 if self.config.verbose {
742 println!(
743 "{:indent$}{:?}",
744 "",
745 pair.as_rule(),
746 indent = 3 * scope.len()
747 );
748 }
749
750 let inner = pair.into_inner();
751 let case_labels: Result<Vec<IdlSwitchLabel>, pest::error::Error<Rule>> = inner
752 .clone()
753 .filter(|p| p.as_rule() == Rule::case_label)
754 .map(|p| self.read_switch_label(scope, p))
755 .collect();
756
757 let elem_spec = inner
759 .filter(|p| p.as_rule() == Rule::element_spec)
760 .map(|p| self.read_switch_element_spec(scope, p))
761 .last()
762 .unwrap();
763
764 Ok(IdlSwitchCase {
765 labels: case_labels?,
766 elem_spec: elem_spec?,
767 })
768 }
769
770 fn process_declarator(
774 &mut self,
775 scope: &Scope,
776 pair: Pair<Rule>,
777 type_spec: &IdlTypeSpec,
778 ) -> Result<(), pest::error::Error<Rule>> {
779 let pos = pair.as_span().start_pos();
780 match pair.into_inner().next() {
781 Some(decl) => {
782 let rule = decl.as_rule();
783 let pos = decl.as_span().start_pos();
784 if self.config.verbose {
785 println!("{:indent$}{:?}", "", rule, indent = 3 * scope.len());
786 }
787 let mut inner = decl.clone().into_inner();
788
789 match rule {
790 Rule::simple_declarator => {
791 match inner.next() {
792 Some(pair) => {
793 let id = self.read_identifier(scope, pair)?;
794 let type_dcl = IdlTypeDcl(IdlTypeDclKind::TypeDcl(id.clone(), type_spec.clone()));
795 self.add_type_dcl(scope, id, type_dcl);
796 Ok(())
797 },
798 _ => {
799 Err(pest::error::Error::new_from_pos(
800 ErrorVariant::CustomError {
801 message: "Pair did not contain a valid identifer for the simple declarator".to_string(),
802 }, pos))
803 }
804 }
805 },
806 Rule::array_declarator => {
808 match inner.next() {
809 Some(pair) => {
810 let id = self.read_identifier(scope, pair)?;
811 let key = id.clone();
812
813 let array_sizes: Result<Vec<_>, pest::error::Error<Rule>> = inner
814 .map(|pair| {
815 match pair.into_inner().next() {
816 Some(pair) => {
817 self.read_const_expr(scope, pair)
819 },
820 _ => {
821 Err(pest::error::Error::new_from_pos(
822 ErrorVariant::CustomError {
823 message: "Failed to read the const expr under the Rule::fixed_array_size".to_string(),
824 }, pos))
825 }
826 }
827 })
828 .collect();
829 let array_type_spec =
830 IdlTypeSpec::ArrayType(Box::new(type_spec.clone()), array_sizes?);
831 let type_dcl = IdlTypeDcl(IdlTypeDclKind::TypeDcl(id, array_type_spec));
832 self.add_type_dcl(scope, key, type_dcl);
833 Ok(())
834 },
835 _ => {
836 Err(pest::error::Error::new_from_pos(
837 ErrorVariant::CustomError {
838 message: "Pair did not contain a valid identifer for the simple declarator".to_string(),
839 }, pos))
840 }
841 }
842 },
843 _ => {
844 Err(pest::error::Error::new_from_pos(
845 ErrorVariant::CustomError {
846 message: "Pair did not contain a valid simple or array declarator".to_string(),
847 }, pos))
848 }
849 }
850 }
851 _ => Err(pest::error::Error::new_from_pos(
853 ErrorVariant::CustomError {
854 message: "No associated values found with the parsed array|simple declarator"
855 .to_string(),
856 },
857 pos,
858 )),
859 }
860 }
861
862 fn process<L: IdlLoader>(
864 &mut self,
865 scope: &mut Scope,
866 loader: &mut dyn IdlLoader,
867 pair: Pair<Rule>,
868 ) -> Result<(), IdlError<Rule>> {
869 let mut iter = pair.clone().into_inner();
870 if self.config.verbose {
871 println!(
872 "{:indent$}{:?}",
873 "",
874 pair.as_rule(),
875 indent = 3 * scope.len()
876 );
877 }
878 match pair.as_rule() {
879 Rule::module_dcl => {
881 let id = iter.next().unwrap().as_str();
882
883 scope.push(id.to_owned());
884
885 let _ = self.lookup_module(scope);
886
887 for p in iter {
888 let _ = self.process::<L>(scope, loader, p);
889 }
890
891 let _ = scope.pop();
892
893 Ok(())
894 }
895 Rule::struct_def => {
897 let id = iter.next().unwrap().as_str().to_owned();
898 let key = id.clone();
899 let m1: Result<Vec<Vec<IdlStructMember>>, _> = iter
900 .map(|p| {
901 self.read_struct_member(scope, p)
903 })
904 .collect();
905
906 let m2 = m1?;
907 let members = m2.into_iter().flatten().collect::<Vec<_>>();
908
909 let typedcl = IdlTypeDcl(IdlTypeDclKind::StructDcl(id, members));
910 self.add_type_dcl(scope, key, typedcl);
911 Ok(())
912 }
913 Rule::union_def => {
915 let id = self.read_identifier(scope, iter.next().unwrap())?;
916 let key = id.to_owned();
917 let switch_type_spec = self.read_switch_type_spec(scope, iter.next().unwrap())?;
918 let switch_body = self.read_switch_body(scope, iter.next().unwrap())?;
919 let union_def =
920 IdlTypeDcl(IdlTypeDclKind::UnionDcl(id, switch_type_spec, switch_body));
921
922 self.add_type_dcl(scope, key, union_def);
923 Ok(())
924 }
925 Rule::type_declarator => {
927 let type_spec = self.read_type_spec(scope, iter.next().unwrap())?;
928
929 let any_declarators_pair = &iter.next().unwrap();
930
931 for p in any_declarators_pair.clone().into_inner() {
932 let _ = self.process_declarator(scope, p, &type_spec);
933 }
934 Ok(())
935 }
936 Rule::enum_dcl => {
939 let id = iter.next().unwrap().as_str().to_owned();
940 let key = id.clone();
941 let enums: Result<Vec<_>, pest::error::Error<Rule>> =
942 iter.map(|p| self.read_identifier(scope, p)).collect();
943
944 let typedcl = IdlTypeDcl(IdlTypeDclKind::EnumDcl(id, enums?));
945 self.add_type_dcl(scope, key, typedcl);
946 Ok(())
947 }
948 Rule::const_dcl => {
950 let type_spec = self.read_type_spec(scope, iter.next().unwrap())?;
951 let id = self.read_identifier(scope, iter.next().unwrap())?;
952 let key = id.clone();
953 let const_expr = self.read_const_expr(scope, iter.next().unwrap())?;
954 let const_dcl = IdlConstDcl {
955 id,
956 typedcl: type_spec,
957 value: const_expr,
958 };
959 self.add_const_dcl(scope, key, const_dcl);
960 Ok(())
961 }
962 Rule::include_directive => {
964 if let Some(ref p) = pair.clone().into_inner().nth(0) {
965 let fname = PathBuf::from(p.as_str());
966 let data = loader
967 .load(&fname)
968 .map_err(|_| IdlError::FileNotFound(fname))?;
969
970 let idl: Pairs<Rule> = IdlParser::parse(Rule::specification, &data)?;
971 for p in idl {
972 self.process::<L>(scope, loader, p)?;
973 }
974 }
975 Ok(())
976 }
977 _ => {
979 for p in iter {
980 let _ = self.process::<L>(scope, loader, p);
981 }
982 Ok(())
983 }
984 }
985 }
986
987 }
990
991fn generate_with_loader<W: Write, L: IdlLoader>(
998 out: &mut W,
999 loader: &mut L,
1000 config: &Configuration,
1001) -> Result<(), IdlError<Rule>> {
1002 let mut ctx = Context::new(config);
1003
1004 let idl_file = config.idl_file.clone();
1005 let idl_file_data = loader
1006 .load(&idl_file)
1007 .map_err(|_| IdlError::FileNotFound(idl_file))?;
1008
1009 let mut scope = Scope::new();
1010 let idl: Pairs<Rule> = IdlParser::parse(Rule::specification, &idl_file_data)?;
1011
1012 for p in idl {
1013 let _ = ctx.process::<L>(&mut scope, loader, p);
1014 }
1015
1016 let mut env = minijinja::Environment::new();
1017 minijinja_embed::load_templates!(&mut env);
1018 let root_module_text = ctx.root_module.render(&env, 0)?;
1019
1020 Ok(write!(out, "{root_module_text}")?)
1021}
1022
1023#[derive(Debug, Clone, Default)]
1025struct Loader {
1026 search_path: PathBuf,
1027}
1028
1029impl Loader {
1030 pub fn new(search_path: &Path) -> Self {
1031 Self {
1032 search_path: search_path.to_path_buf(),
1033 }
1034 }
1035}
1036
1037impl IdlLoader for Loader {
1038 fn load(&self, filename: &Path) -> Result<String, io::Error> {
1040 let fullname = self.search_path.join(filename);
1041 let mut file = File::open(fullname)?;
1042 let mut data = String::new();
1043
1044 file.read_to_string(&mut data)?;
1045
1046 Ok(data)
1047 }
1048}
1049
1050pub fn generate_with_search_path<W: Write>(
1056 out: &mut W,
1057 config: &Configuration,
1058) -> Result<(), IdlError<Rule>> {
1059 let mut loader = Loader::new(&config.search_path);
1060 let mut env = minijinja::Environment::new();
1061 minijinja_embed::load_templates!(&mut env);
1062 generate_with_loader(out, &mut loader, config)
1063}