1#[doc = include_str!("../README.md")]
2pub(crate) mod common;
3mod error;
4mod generator;
5mod input;
6pub mod intermediate;
7mod lexer;
8#[cfg(test)]
9mod tests;
10mod validator;
11
12#[cfg(feature = "cli")]
13pub mod cli;
14
15use std::{
16 cell::RefCell,
17 collections::BTreeMap,
18 fs::{self, read_to_string},
19 path::PathBuf,
20 rc::Rc,
21 vec,
22};
23
24use error::CompilerError;
25use generator::Backend;
26use intermediate::ToplevelDefinition;
27use lexer::{asn_spec, error::LexerError};
28use prelude::{GeneratorError, GeneratorErrorType};
29use validator::Validator;
30
31pub mod prelude {
32 pub use super::{
35 error::CompilerError, CompileResult, Compiler, CompilerMissingParams, CompilerOutputSet,
36 CompilerReady, CompilerSourcesSet,
37 };
38 pub use crate::generator::{
39 error::*,
40 rasn::{Config as RasnConfig, Rasn as RasnBackend},
41 typescript::{Config as TsConfig, Typescript as TypescriptBackend},
42 Backend, GeneratedModule,
43 };
44
45 pub use crate::intermediate::{
46 ExtensibilityEnvironment, TaggingEnvironment, ToplevelDefinition,
47 };
48
49 pub use crate::lexer::error::{LexerError, LexerErrorType, ReportData};
50 pub use crate::validator::error::{LinkerError, LinkerErrorType};
51
52 pub mod ir {
53 pub use crate::intermediate::{
54 constraints::*,
55 encoding_rules::{per_visible::*, *},
56 error::*,
57 information_object::*,
58 parameterization::*,
59 types::*,
60 *,
61 };
62 }
63}
64
65#[cfg(target_family = "wasm")]
66use wasm_bindgen::prelude::*;
67
68#[cfg(target_family = "wasm")]
69#[wasm_bindgen(inspectable, getter_with_clone)]
70pub struct Generated {
71 pub rust: String,
72 pub warnings: String,
73}
74
75#[cfg(target_family = "wasm")]
76#[wasm_bindgen]
77pub fn compile_to_typescript(asn1: &str) -> Result<Generated, JsValue> {
78 Compiler::<crate::prelude::TypescriptBackend, _>::new()
79 .add_asn_literal(asn1)
80 .compile_to_string()
81 .map(|result| Generated {
82 rust: result.generated,
83 warnings: result
84 .warnings
85 .into_iter()
86 .fold(String::new(), |mut acc, w| {
87 acc += &w.to_string();
88 acc += "\n";
89 acc
90 }),
91 })
92 .map_err(|e| JsValue::from(e.to_string()))
93}
94
95#[cfg(target_family = "wasm")]
96#[wasm_bindgen]
97pub fn compile_to_rust(
98 asn1: &str,
99 config: crate::prelude::RasnConfig,
100) -> Result<Generated, JsValue> {
101 Compiler::<crate::prelude::RasnBackend, _>::new_with_config(config)
102 .add_asn_literal(asn1)
103 .compile_to_string()
104 .map(|result| Generated {
105 rust: result.generated,
106 warnings: result
107 .warnings
108 .into_iter()
109 .fold(String::new(), |mut acc, w| {
110 acc += &w.to_string();
111 acc += "\n";
112 acc
113 }),
114 })
115 .map_err(|e| JsValue::from(e.to_string()))
116}
117
118pub struct Compiler<B: Backend, S: CompilerState> {
120 state: S,
121 backend: B,
122}
123
124pub struct CompilerMissingParams;
126
127impl Default for CompilerMissingParams {
128 fn default() -> Self {
129 Self
130 }
131}
132
133pub struct CompilerReady {
135 sources: Vec<AsnSource>,
136 output_path: PathBuf,
137}
138
139pub struct CompilerOutputSet {
141 output_path: PathBuf,
142}
143
144pub struct CompilerSourcesSet {
146 sources: Vec<AsnSource>,
147}
148
149pub trait CompilerState {}
151impl CompilerState for CompilerReady {}
152impl CompilerState for CompilerOutputSet {}
153impl CompilerState for CompilerSourcesSet {}
154impl CompilerState for CompilerMissingParams {}
155
156#[derive(Debug)]
157pub struct CompileResult {
158 pub generated: String,
159 pub warnings: Vec<CompilerError>,
160}
161
162impl CompileResult {
163 fn fmt<B: Backend>(mut self) -> Self {
164 self.generated = B::format_bindings(&self.generated).unwrap_or(self.generated);
165 self
166 }
167}
168
169#[derive(Debug, PartialEq)]
170enum AsnSource {
171 Path(PathBuf),
172 Literal(String),
173}
174
175impl<B: Backend> Default for Compiler<B, CompilerMissingParams> {
176 fn default() -> Self {
177 Self::new()
178 }
179}
180
181impl<B: Backend, S: CompilerState> Compiler<B, S> {
182 pub fn with_backend<B2: Backend>(self, backend: B2) -> Compiler<B2, S> {
183 Compiler {
184 state: self.state,
185 backend,
186 }
187 }
188}
189
190impl<B: Backend> Compiler<B, CompilerMissingParams> {
191 pub fn new() -> Compiler<B, CompilerMissingParams> {
193 Compiler {
194 state: CompilerMissingParams,
195 backend: B::default(),
196 }
197 }
198
199 pub fn new_with_config(config: B::Config) -> Compiler<B, CompilerMissingParams> {
201 Compiler {
202 state: CompilerMissingParams,
203 backend: B::from_config(config),
204 }
205 }
206}
207
208impl<B: Backend> Compiler<B, CompilerMissingParams> {
209 pub fn add_asn_by_path(
212 self,
213 path_to_source: impl Into<PathBuf>,
214 ) -> Compiler<B, CompilerSourcesSet> {
215 Compiler {
216 state: CompilerSourcesSet {
217 sources: vec![AsnSource::Path(path_to_source.into())],
218 },
219 backend: self.backend,
220 }
221 }
222
223 pub fn add_asn_sources_by_path(
226 self,
227 paths_to_sources: impl Iterator<Item = impl Into<PathBuf>>,
228 ) -> Compiler<B, CompilerSourcesSet> {
229 Compiler {
230 state: CompilerSourcesSet {
231 sources: paths_to_sources
232 .map(|p| AsnSource::Path(p.into()))
233 .collect(),
234 },
235 backend: self.backend,
236 }
237 }
238
239 pub fn add_asn_literal(self, literal: impl Into<String>) -> Compiler<B, CompilerSourcesSet> {
249 Compiler {
250 state: CompilerSourcesSet {
251 sources: vec![AsnSource::Literal(literal.into())],
252 },
253 backend: self.backend,
254 }
255 }
256
257 pub fn set_output_path(
261 self,
262 output_path: impl Into<PathBuf>,
263 ) -> Compiler<B, CompilerOutputSet> {
264 let mut path: PathBuf = output_path.into();
265 if path.is_dir() {
266 path.set_file_name("rasn_generated.rs");
267 }
268 Compiler {
269 state: CompilerOutputSet { output_path: path },
270 backend: self.backend,
271 }
272 }
273}
274
275impl<B: Backend> Compiler<B, CompilerOutputSet> {
276 pub fn add_asn_by_path(self, path_to_source: impl Into<PathBuf>) -> Compiler<B, CompilerReady> {
279 Compiler {
280 state: CompilerReady {
281 sources: vec![AsnSource::Path(path_to_source.into())],
282 output_path: self.state.output_path,
283 },
284 backend: self.backend,
285 }
286 }
287
288 pub fn add_asn_sources_by_path(
291 self,
292 paths_to_sources: impl Iterator<Item = impl Into<PathBuf>>,
293 ) -> Compiler<B, CompilerReady> {
294 Compiler {
295 state: CompilerReady {
296 sources: paths_to_sources
297 .map(|p| AsnSource::Path(p.into()))
298 .collect(),
299 output_path: self.state.output_path,
300 },
301 backend: self.backend,
302 }
303 }
304
305 pub fn add_asn_literal(self, literal: impl Into<String>) -> Compiler<B, CompilerReady> {
315 Compiler {
316 state: CompilerReady {
317 sources: vec![AsnSource::Literal(literal.into())],
318 output_path: self.state.output_path,
319 },
320 backend: self.backend,
321 }
322 }
323}
324
325impl<B: Backend> Compiler<B, CompilerSourcesSet> {
326 pub fn add_asn_by_path(
329 self,
330 path_to_source: impl Into<PathBuf>,
331 ) -> Compiler<B, CompilerSourcesSet> {
332 let mut sources: Vec<AsnSource> = self.state.sources;
333 sources.push(AsnSource::Path(path_to_source.into()));
334 Compiler {
335 state: CompilerSourcesSet { sources },
336 backend: self.backend,
337 }
338 }
339
340 pub fn add_asn_sources_by_path(
343 self,
344 paths_to_sources: impl Iterator<Item = impl Into<PathBuf>>,
345 ) -> Compiler<B, CompilerSourcesSet> {
346 let mut sources: Vec<AsnSource> = self.state.sources;
347 sources.extend(paths_to_sources.map(|p| AsnSource::Path(p.into())));
348 Compiler {
349 state: CompilerSourcesSet { sources },
350 backend: self.backend,
351 }
352 }
353
354 pub fn add_asn_literal(self, literal: impl Into<String>) -> Compiler<B, CompilerSourcesSet> {
364 let mut sources: Vec<AsnSource> = self.state.sources;
365 sources.push(AsnSource::Literal(literal.into()));
366 Compiler {
367 state: CompilerSourcesSet { sources },
368 backend: self.backend,
369 }
370 }
371
372 pub fn set_output_path(self, output_path: impl Into<PathBuf>) -> Compiler<B, CompilerReady> {
377 Compiler {
378 state: CompilerReady {
379 sources: self.state.sources,
380 output_path: output_path.into(),
381 },
382 backend: self.backend,
383 }
384 }
385
386 pub fn compile_to_string(mut self) -> Result<CompileResult, CompilerError> {
391 self.internal_compile().map(CompileResult::fmt::<B>)
392 }
393
394 fn internal_compile(&mut self) -> Result<CompileResult, CompilerError> {
395 let mut generated_modules = vec![];
396 let mut warnings = Vec::<CompilerError>::new();
397 let mut modules: Vec<ToplevelDefinition> = vec![];
398 for src in &self.state.sources {
399 let stringified_src = match src {
400 AsnSource::Path(p) => read_to_string(p).map_err(LexerError::from)?,
401 AsnSource::Literal(l) => l.clone(),
402 };
403 modules.append(
404 &mut asn_spec(&stringified_src)?
405 .into_iter()
406 .flat_map(|(header, tlds)| {
407 let header_ref = Rc::new(RefCell::new(header));
408 tlds.into_iter().enumerate().map(move |(index, mut tld)| {
409 tld.apply_tagging_environment(&header_ref.borrow().tagging_environment);
410 tld.set_index(header_ref.clone(), index);
411 tld
412 })
413 })
414 .collect(),
415 );
416 }
417 let (valid_items, mut validator_errors) = Validator::new(modules).validate()?;
418 let modules = valid_items.into_iter().fold(
419 BTreeMap::<String, Vec<ToplevelDefinition>>::new(),
420 |mut modules, tld| {
421 let key = tld
422 .get_index()
423 .map_or(<_>::default(), |(module, _)| module.borrow().name.clone());
424 match modules.entry(key) {
425 std::collections::btree_map::Entry::Vacant(v) => {
426 v.insert(vec![tld]);
427 }
428 std::collections::btree_map::Entry::Occupied(ref mut e) => {
429 e.get_mut().push(tld)
430 }
431 }
432 modules
433 },
434 );
435 for (_, module) in modules {
436 let mut generated_module = self.backend.generate_module(module)?;
437 if let Some(m) = generated_module.generated {
438 generated_modules.push(m);
439 }
440 warnings.append(&mut generated_module.warnings);
441 }
442 warnings.append(&mut validator_errors);
443
444 Ok(CompileResult {
445 generated: generated_modules.join("\n"),
446 warnings,
447 })
448 }
449}
450
451impl<B: Backend> Compiler<B, CompilerReady> {
452 pub fn add_asn_by_path(self, path_to_source: impl Into<PathBuf>) -> Compiler<B, CompilerReady> {
455 let mut sources: Vec<AsnSource> = self.state.sources;
456 sources.push(AsnSource::Path(path_to_source.into()));
457 Compiler {
458 state: CompilerReady {
459 output_path: self.state.output_path,
460 sources,
461 },
462 backend: self.backend,
463 }
464 }
465
466 pub fn add_asn_sources_by_path(
469 self,
470 paths_to_sources: impl Iterator<Item = impl Into<PathBuf>>,
471 ) -> Compiler<B, CompilerReady> {
472 let mut sources: Vec<AsnSource> = self.state.sources;
473 sources.extend(paths_to_sources.map(|p| AsnSource::Path(p.into())));
474 Compiler {
475 state: CompilerReady {
476 sources,
477 output_path: self.state.output_path,
478 },
479 backend: self.backend,
480 }
481 }
482
483 pub fn add_asn_literal(self, literal: impl Into<String>) -> Compiler<B, CompilerReady> {
493 let mut sources: Vec<AsnSource> = self.state.sources;
494 sources.push(AsnSource::Literal(literal.into()));
495 Compiler {
496 state: CompilerReady {
497 output_path: self.state.output_path,
498 sources,
499 },
500 backend: self.backend,
501 }
502 }
503
504 pub fn compile_to_string(self) -> Result<CompileResult, CompilerError> {
509 Compiler {
510 state: CompilerSourcesSet {
511 sources: self.state.sources,
512 },
513 backend: self.backend,
514 }
515 .compile_to_string()
516 }
517
518 pub fn compile(self) -> Result<Vec<CompilerError>, CompilerError> {
523 let result = Compiler {
524 state: CompilerSourcesSet {
525 sources: self.state.sources,
526 },
527 backend: self.backend,
528 }
529 .internal_compile()?
530 .fmt::<B>();
531 fs::write(
532 self.state
533 .output_path
534 .is_dir()
535 .then(|| {
536 self.state
537 .output_path
538 .join(format!("generated{}", B::FILE_EXTENSION))
539 })
540 .unwrap_or(self.state.output_path),
541 result.generated,
542 )
543 .map_err(|e| GeneratorError {
544 top_level_declaration: None,
545 details: e.to_string(),
546 kind: GeneratorErrorType::IO,
547 })?;
548
549 Ok(result.warnings)
550 }
551}