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
//! 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.
mod syntactic_sugar;
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, RtLolaError};
#[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 }
}
/// Creates a new parser configuration for the given specification using the name as file name.
pub fn for_named_spec(name: String, spec: String) -> Self {
ParserConfig {
path: Some(PathBuf::from(name)),
spec,
}
}
/// Invokes the parser on the specification given in the configuration.
pub fn parse(&self) -> Result<RtLolaAst, RtLolaError> {
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, RtLolaError> {
parse::RtLolaParser::parse(cfg)
}
impl<'a> From<&'a ParserConfig> for Handler<'a> {
fn from(cfg: &'a ParserConfig) -> Self {
match &cfg.path {
Some(path) => Handler::new(path, cfg.spec()),
None => Handler::without_file(cfg.spec()),
}
}
}