donet_core/parser/
mod.rs

1/*
2    This file is part of Donet.
3
4    Copyright © 2024-2025 Max Rodriguez
5
6    Donet is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Affero General Public License,
8    as published by the Free Software Foundation, either version 3
9    of the License, or (at your option) any later version.
10
11    Donet is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14    GNU Affero General Public License for more details.
15
16    You should have received a copy of the GNU Affero General Public
17    License along with Donet. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20//! Module of libdonet that contains the [`Context Free Grammar`] definition
21//! of the DC file language, the process of generating the DC file
22//! [`Abstract Syntax Tree`], and the process of converting the AST into the
23//! final DC file class hierarchy structure that is used by the Donet daemon
24//! at runtime to be able to interpret network messages that follow the
25//! network contract defined in the DC file(s).
26//!
27//! [`Context Free Grammar`]: https://en.wikipedia.org/wiki/Context-free_grammar
28//! [`Abstract Syntax Tree`]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
29
30pub(crate) mod ast;
31pub mod error;
32mod generation;
33pub(crate) mod lexer;
34pub(crate) mod parser;
35pub(crate) mod pipeline;
36mod semantics;
37
38use crate::dcfile::DCFile;
39use anyhow::Result;
40use error::DCReadError;
41use pipeline::PipelineData;
42
43/// Tuple that represents an input file for the DC parser.
44/// The first item is the filename, the second item is the file content.
45pub(crate) type InputFile = (String, String);
46
47/// Runs the entire DC parser pipeline. The input is an array of strings
48/// that represent the input DC files in UTF-8, and the output is the final
49/// DC element tree data structure to be used by Donet.
50pub(crate) fn dcparse_pipeline(inputs: Vec<InputFile>) -> Result<DCFile, DCReadError> {
51    // Create new pipeline data struct
52    let mut pipeline_data: PipelineData<'_> = PipelineData::default();
53
54    // Create codespan files for each DC file
55    for input in &inputs {
56        let _: usize = pipeline_data.files.add(&input.0, &input.1);
57    }
58
59    // Create an abstract syntax tree per DC file
60    for input in &inputs {
61        let lexer: lexer::Lexer<'_> = lexer::Lexer::new(&input.1);
62
63        let ast: ast::Root = match parser::parse(lexer) {
64            // See issue #19 for why LALR parser cannot return custom errors.
65            Err(err) => {
66                if let Some(parser_err) = err.clone().0 {
67                    // Extract parser error details
68                    let span: lexer::Span = parser_err.1;
69                    let token: lexer::DCToken = parser_err.0;
70                    let msg: String = err.1.to_owned();
71
72                    let diag: error::Diagnostic = error::Diagnostic::error(
73                        span,
74                        &mut pipeline_data,
75                        error::PipelineError::Parser(error::ParseError::Error(token, msg)),
76                    );
77
78                    pipeline_data
79                        .emit_diagnostic(diag.into())
80                        .expect("Failed to emit diagnostic.");
81                }
82
83                return Err(DCReadError::Syntax);
84            }
85            Ok(ast) => ast,
86        };
87
88        pipeline_data.syntax_trees.push(ast);
89        pipeline_data.next_file();
90    }
91
92    // Process all abstract syntax trees in semantic analyzer.
93    // Will output diagnostics if any semantic issues are found.
94    semantics::semantic_analyzer(&mut pipeline_data)?;
95
96    // Final stage of the DC parser pipeline.
97    // Generates the final immutable DC element tree data structure.
98    Ok(generation::dc_tree_generation(&mut pipeline_data))
99}