donet_core/parser/
pipeline.rs1use super::ast;
24use super::error::Diagnostic as DCDiagnostic;
25use super::error::SemanticError;
26use super::lexer::Span;
27use crate::globals;
28use anyhow::{anyhow, Result};
29use codespan_reporting::diagnostic::Diagnostic;
30use codespan_reporting::diagnostic::Severity;
31use codespan_reporting::files::{self, SimpleFiles};
32use codespan_reporting::term;
33use multimap::MultiMap;
34use term::termcolor::{ColorChoice, StandardStream};
35
36#[derive(Debug, Default, Clone, PartialEq, Eq)]
39pub(crate) enum PipelineStage {
40 #[default]
41 Parser, SemanticAnalyzer,
43 Generation,
44}
45
46impl PipelineStage {
47 pub(crate) fn next(&self) -> Self {
48 match self {
49 PipelineStage::Parser => PipelineStage::SemanticAnalyzer,
50 PipelineStage::SemanticAnalyzer => PipelineStage::Generation,
51 PipelineStage::Generation => panic!("No next stage in pipeline."),
52 }
53 }
54}
55
56#[derive(PartialEq)]
57pub enum TopLevelSymbol {
58 TypeDef,
59 KeywordDef,
60 Struct,
61 DClass,
62}
63
64pub type SymbolMap = MultiMap<String, TopLevelSymbol>;
68
69#[derive(Default)]
72pub struct DCData {
73 symbol_map: SymbolMap,
74 next_dclass_id: globals::DClassId,
75 next_field_id: globals::FieldId,
76}
77
78impl DCData {
79 pub fn register_symbol(&mut self, identifier: String, symbol_type: TopLevelSymbol) {
81 self.symbol_map.insert(identifier, symbol_type);
82 }
83
84 pub fn symbol_exists(&self, identifier: &String, symbol_type: TopLevelSymbol) -> bool {
87 self.symbol_map
88 .iter()
89 .find(|&x| x == (&identifier, &symbol_type))
90 .is_some()
91 }
92
93 pub fn get_next_dclass_id(
99 &mut self,
100 pipeline: &mut PipelineData,
101 dclass: ast::DClass, ) -> Result<globals::DClassId> {
103 let next_id: globals::DClassId = self.next_dclass_id;
104
105 if next_id == globals::DClassId::MAX {
106 let diag: DCDiagnostic =
108 DCDiagnostic::error(dclass.span, pipeline, SemanticError::DClassOverflow);
109
110 pipeline
111 .emit_diagnostic(diag.into())
112 .expect("Failed to emit diagnostic.");
113
114 return Err(anyhow!("Ran out of 16-bit DClass IDs!"));
115 }
116
117 self.next_dclass_id += 1; Ok(next_id)
119 }
120
121 pub fn get_next_field_id(
127 &mut self,
128 pipeline: &mut PipelineData,
129 field_span: Span,
130 ) -> Result<globals::FieldId> {
131 let next_id: globals::FieldId = self.next_field_id;
132
133 if next_id == globals::DClassId::MAX {
134 let diag: DCDiagnostic = DCDiagnostic::error(field_span, pipeline, SemanticError::DClassOverflow);
136
137 pipeline
138 .emit_diagnostic(diag.into())
139 .expect("Failed to emit diagnostic.");
140
141 return Err(anyhow!("Ran out of 16-bit Field IDs!"));
142 }
143
144 self.next_field_id += 1; Ok(next_id)
146 }
147}
148
149pub(crate) struct PipelineData<'a> {
154 stage: PipelineStage,
155 _writer: StandardStream,
156 _config: term::Config,
157 diagnostics_enabled: bool,
158 errors_emitted: usize,
159 pub files: SimpleFiles<&'a str, &'a str>,
160 current_file: usize,
161 pub syntax_trees: Vec<ast::Root>,
162 pub dc_data: DCData,
163}
164
165impl Drop for PipelineData<'_> {
170 fn drop(&mut self) {
171 if self.errors_emitted > 0 {
172 let diag = Diagnostic::error().with_message(format!(
173 "Failed to read DC files due to {} previous errors.",
174 self.errors_emitted
175 ));
176
177 self.emit_diagnostic(diag).expect("Failed to emit diagnostic.");
178 }
179 }
180}
181
182impl Default for PipelineData<'_> {
183 fn default() -> Self {
184 Self {
185 stage: PipelineStage::default(),
186 _writer: StandardStream::stderr(ColorChoice::Always),
187 _config: term::Config::default(),
188 diagnostics_enabled: {
189 cfg_if! {
191 if #[cfg(test)] {
192 false
193 } else {
194 true
195 }
196 }
197 },
198 errors_emitted: 0,
199 files: SimpleFiles::new(),
200 current_file: 0,
201 syntax_trees: vec![],
202 dc_data: DCData::default(),
203 }
204 }
205}
206
207impl PipelineData<'_> {
208 pub(crate) fn emit_diagnostic(&mut self, diag: Diagnostic<usize>) -> Result<(), files::Error> {
210 if diag.severity == Severity::Error {
211 self.errors_emitted += 1;
212 }
213 if !self.diagnostics_enabled {
214 return Ok(());
215 }
216 term::emit(&mut self._writer.lock(), &self._config, &self.files, &diag)
217 }
218
219 #[inline(always)]
220 pub(crate) fn current_stage(&self) -> PipelineStage {
221 self.stage.clone()
222 }
223
224 pub(crate) fn next_stage(&mut self) {
225 self.stage = self.stage.next();
226 self.current_file = 0;
227 }
228
229 #[inline(always)]
230 pub(crate) fn current_file(&self) -> usize {
231 self.current_file
232 }
233
234 pub(crate) fn next_file(&mut self) {
235 self.current_file += 1
236 }
237
238 #[inline(always)]
239 pub(crate) fn failing(&self) -> bool {
240 self.errors_emitted > 0
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn next_stage_state() {
250 let mut pipeline: PipelineData = PipelineData::default();
251
252 assert_eq!(pipeline.stage, PipelineStage::Parser);
253
254 pipeline.next_file(); pipeline.next_stage(); assert_eq!(pipeline.stage, PipelineStage::SemanticAnalyzer);
259 assert_eq!(pipeline.current_file, 0);
260
261 pipeline.next_stage();
262 assert_eq!(pipeline.stage, PipelineStage::Generation);
263 }
264}