1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! A parser for RTLola specifications //! //! This crate offers functionality to transform a textual representation of an RTLola specification into an abstract syntax tree. The Ast is not the most convenient data structure for //! modifying or analyzing a specification; there are other options available, outlined below. //! //! # Specification Representations //! * [RtLolaAst]: The Ast represents the abstract syntax of the specification. It is obtained by first parsing the specification into a homogenous tree //! and then remove concrete syntax fragments irrelevant for the logics of the specification. Apart from that, the Ast does not provide much functionality. //! The only checks performed when creating the Ast concern the correct syntax. See also: [RtLolaAst], and [parse()]. //! * [RtLolaHir](https://docs.rs/rtlola_hir/struct.RtLolaHir.html): The Hir represents a high-level intermediate representation optimized for analyzability. It contains more convenient methods than the Ast, enables different //! analysis steps and provides their reports. The Hir traverses several modes representing the level to which it was analyzed and refined. //! Its base mode is `RtLolaHir<BaseMode>` and its fully analyzed version is `RtLolaHir<CompleteMode>`. See also: [rtlola_hir](https://docs.rs/rtlola_hir). //! * [RtLolaMir](https://docs.rs/rtlola_frontend/struct.RtLolaMir.html): The Mir represents a mid-level intermediate representation optimized for external use such as interpretation and compilation. It contains several interconnections //! enabling easy accesses and additional annotation such as memory bounds for each stream. See also: [rtlola_hir](https://docs.rs/rtlola_hir). //! As a rule of thumb, if you want to analyze and/or enrich a specification, use the [RtLolaHir](https://docs.rs/rtlola_hir/struct.RtLolaHir.html). If you only need a convenient representation of the specification for some devious //! activity such as compiling it into something else, the [RtLolaMir](https://docs.rs/rtlola_frontend/struct.RtLolaMir.html) is the way to go. //! //! # Modules //! * [ast] Contains anything related to the [RtLolaAst]. #![forbid(unused_must_use)] // disallow discarding errors #![warn( missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, unused_qualifications )] //! This module provides the functionality needed to parse an RTLola specification into a [RtLolaAst]. mod parse; // Shall not be exposed; use parse function instead. use std::fs::File; use std::io::{self, Read}; use std::path::PathBuf; // Public exports pub mod ast; pub use ast::RtLolaAst; use rtlola_reporting::Handler; #[derive(Debug, Clone)] /// The configuration of the parser. pub struct ParserConfig { /// The path to the specification file that should be parsed path: Option<PathBuf>, /// The specification given as a string spec: String, } impl ParserConfig { /// Reads the specification from the given path and creates a new parser configuration for it. pub fn from_path(path_to_spec: PathBuf) -> io::Result<Self> { let mut file = File::open(&path_to_spec)?; let mut spec = String::new(); file.read_to_string(&mut spec)?; drop(file); Ok(ParserConfig { path: Some(path_to_spec), spec, }) } /// Creates a new parser configuration for the given specification. pub fn for_string(spec: String) -> Self { ParserConfig { path: None, spec } } /// Invokes the parser on the specification given in the configuration. pub fn parse(self) -> Result<RtLolaAst, String> { parse(self) } /// Returns the path of the specification. pub fn path(&self) -> &Option<PathBuf> { &self.path } /// Returns the specification of the configuration. pub fn spec(&self) -> &str { &self.spec } } /// Invokes the parser with the given configuration. pub fn parse(cfg: ParserConfig) -> Result<RtLolaAst, String> { let handler = if let Some(path) = &cfg.path { rtlola_reporting::Handler::new(path.clone(), cfg.spec.clone()) } else { rtlola_reporting::Handler::without_file(cfg.spec.clone()) }; let spec = match crate::parse::RtLolaParser::parse(&handler, cfg) { Ok(spec) => spec, Err(e) => { return Err(format!("error: invalid syntax:\n{}", e)); }, }; Ok(spec) } /// Invokes the parser with the given configuration and uses the provided [Handler] for error reporting. pub fn parse_with_handler(cfg: ParserConfig, handler: &Handler) -> Result<RtLolaAst, String> { let spec = match crate::parse::RtLolaParser::parse(&handler, cfg) { Ok(spec) => spec, Err(e) => { return Err(format!("error: invalid syntax:\n{}", e)); }, }; Ok(spec) }