rtlola_hir/modes.rs
1pub(crate) mod ast_conversion;
2pub(crate) mod dependencies;
3pub(crate) mod memory_bounds;
4pub(crate) mod ordering;
5pub(crate) mod types;
6
7use std::collections::HashMap;
8use std::time::Duration;
9
10use rtlola_reporting::RtLolaError;
11
12use self::dependencies::{
13 DependencyGraph, Origin, StreamDependencies, TransitiveDependencies, WindowDependencies,
14};
15use self::types::HirType;
16use crate::config::FrontendConfig;
17use crate::hir::{ConcretePacingType, ExprId, Hir, SRef, StreamAccessKind, WRef};
18use crate::modes::memory_bounds::MemorizationBound;
19use crate::modes::ordering::StreamLayers;
20use crate::type_check::{ConcreteValueType, StreamType};
21
22/// Defines the construct of a mode
23///
24/// This trait groups all available mode, adding different functionality to the [RtLolaHir](crate::RtLolaHir).
25/// The trait [HirStage] declares the progress function that each mode needs to implement.
26/// Each mode implements a separate trait defining the functionality that is added by the new mode, e.g., the [TypedMode] implements the [TypedTrait], providing an interface to get the types of a stream or expression.
27/// With a new mode, a compiler flag derives the functionality of the previous modes.
28/// The [RtLolaHir](crate::RtLolaHir) progesses the following modes:
29/// [BaseMode] -> [TypedMode] -> [DepAnaMode] -> [OrderedMode] -> [MemBoundMode] -> [CompleteMode]
30pub trait HirMode {}
31
32/// Defines the functionality to progress one mode to the next one
33pub trait HirStage: Sized {
34 /// Defines the next mode that is produced by the `progress` function
35 type NextStage: HirMode;
36
37 /// Returns an [RtLolaHir](crate::RtLolaHir) with additional functionality
38 fn progress(self, cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError>;
39}
40
41/// Represents the first stage in the [RtLolaHir](crate::RtLolaHir)(crate::RtLolaHir)
42///
43/// This struct represents the mode that is created with a new [RtLolaHir](crate::RtLolaHir)(crate::RtLolaHir).
44/// The mode does not provide any additonal information and is therefore empty.
45#[derive(Clone, Debug, HirMode, Copy)]
46pub struct BaseMode {}
47
48impl HirStage for Hir<BaseMode> {
49 type NextStage = TypedMode;
50
51 fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
52 let tts = crate::type_check::type_check(&self)?;
53
54 let mode = TypedMode { types: tts };
55
56 Ok(Hir {
57 inputs: self.inputs,
58 outputs: self.outputs,
59 next_output_ref: self.next_output_ref,
60 next_input_ref: self.next_input_ref,
61 expr_maps: self.expr_maps,
62 global_tags: self.global_tags,
63 mode,
64 })
65 }
66}
67
68impl Hir<BaseMode> {
69 /// Returns the [RtLolaHir](crate::RtLolaHir) with the type information for each stream and expression
70 ///
71 /// The function returns the [RtLolaHir](crate::RtLolaHir) after the type analysis.
72 /// The new mode implements the same functionality as the [BaseMode] and additionally holds for each stream and expression its [StreamType].
73 /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
74 ///
75 /// # Fails
76 /// The function fails if the type checker finds a type error in the specification and returns a string with a detailed description.
77 pub fn check_types(self, cfg: &FrontendConfig) -> Result<Hir<TypedMode>, RtLolaError> {
78 self.progress(cfg)
79 }
80}
81
82/// Represents the results of the type checker
83#[derive(Debug, Clone)]
84pub struct Typed {
85 stream_types: HashMap<SRef, StreamType>,
86 expression_types: HashMap<ExprId, StreamType>,
87 param_types: HashMap<(SRef, usize), ConcreteValueType>,
88 eval_types: HashMap<(SRef, usize), ConcretePacingType>,
89}
90
91/// Represents the mode after the type checker call
92///
93/// This struct represents the mode after the type checker call.
94/// Besides this result, this mode has the same functionality as all the previous modes.
95/// The [TypedTrait] defines the new functionality of the mode.
96#[covers_functionality(TypedTrait, types)]
97#[derive(Debug, Clone, HirMode)]
98pub struct TypedMode {
99 types: Typed,
100}
101
102impl Typed {
103 pub(crate) fn new(
104 stream_types: HashMap<SRef, StreamType>,
105 expression_types: HashMap<ExprId, StreamType>,
106 param_types: HashMap<(SRef, usize), ConcreteValueType>,
107 eval_types: HashMap<(SRef, usize), ConcretePacingType>,
108 ) -> Self {
109 Typed {
110 stream_types,
111 expression_types,
112 param_types,
113 eval_types,
114 }
115 }
116}
117
118/// Describes the functionality of a mode after checking and inferring types
119#[mode_functionality]
120pub trait TypedTrait {
121 /// Returns the [StreamType] of the given stream
122 ///
123 /// # Panic
124 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
125 fn stream_type(&self, sr: SRef) -> HirType;
126
127 /// Returns true if the given stream has a periodic evaluation pacing
128 ///
129 /// # Panic
130 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
131 fn is_periodic(&self, sr: SRef) -> bool;
132
133 /// Returns true if the given stream has a event-based evaluation pacing
134 ///
135 /// # Panic
136 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
137 fn is_event(&self, sr: SRef) -> bool;
138
139 /// Returns the [StreamType] of the given expression
140 ///
141 /// # Panic
142 /// The function panics if the [ExprId] is invalid.
143 fn expr_type(&self, eid: ExprId) -> HirType;
144
145 /// Returns the [ConcreteValueType] of the `idx` parameter of the `sr` stream template
146 ///
147 /// # Panic
148 /// The function panics if the [StreamReference](crate::hir::StreamReference) or the index is invalid.
149 fn get_parameter_type(&self, sr: SRef, idx: usize) -> ConcreteValueType;
150
151 /// Returns the [ConcretePacingType] of the given stream
152 ///
153 /// # Panic
154 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid
155 /// or the index of the eval clause is out of bounds.
156 fn eval_pacing_type(&self, sr: SRef, idx: usize) -> ConcretePacingType;
157}
158
159impl HirStage for Hir<TypedMode> {
160 type NextStage = DepAnaMode;
161
162 fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
163 let dependencies = DepAna::analyze(&self)?;
164
165 let mode = DepAnaMode {
166 dependencies,
167 types: self.mode.types,
168 };
169
170 Ok(Hir {
171 inputs: self.inputs,
172 outputs: self.outputs,
173 next_output_ref: self.next_output_ref,
174 next_input_ref: self.next_input_ref,
175 expr_maps: self.expr_maps,
176 global_tags: self.global_tags,
177 mode,
178 })
179 }
180}
181
182impl Hir<TypedMode> {
183 /// Returns the [RtLolaHir](crate::RtLolaHir) with additional information about the dependencies between streams
184 ///
185 /// The function returns the [RtLolaHir](crate::RtLolaHir) after the dependency analysis.
186 /// The new mode implements the same functionality as the [TypedMode] and additionally contains the dependencies between streams in the specification.
187 /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
188 ///
189 /// # Fails
190 /// The function returns a [RtLolaError] if the specification is not well-formed.
191 pub fn analyze_dependencies(
192 self,
193 cfg: &FrontendConfig,
194 ) -> Result<Hir<DepAnaMode>, RtLolaError> {
195 self.progress(cfg)
196 }
197}
198
199/// Represents the results of the dependency analysis
200#[derive(Debug, Clone)]
201pub struct DepAna {
202 direct_accesses: StreamDependencies,
203 transitive_accesses: TransitiveDependencies,
204 direct_accessed_by: StreamDependencies,
205 transitive_accessed_by: TransitiveDependencies,
206 aggregated_by: WindowDependencies,
207 aggregates: WindowDependencies,
208 graph: DependencyGraph,
209}
210
211/// Represents the mode after the dependency analysis
212///
213/// This struct represents the mode after the dependency analysis.
214/// Besides this result, this mode has the same functionality as all the previous modes.
215/// The [DepAnaTrait] defines the new functionality of the mode.
216#[covers_functionality(TypedTrait, types)]
217#[covers_functionality(DepAnaTrait, dependencies)]
218#[derive(Debug, Clone, HirMode)]
219pub struct DepAnaMode {
220 types: Typed,
221 dependencies: DepAna,
222}
223
224/// Describes the functionality of a mode after analyzing the dependencies
225#[mode_functionality]
226pub trait DepAnaTrait {
227 /// Returns all streams that are direct accessed by `who`
228 ///
229 /// The function returns all streams that are direct accessed by `who`.
230 /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to `res`.
231 /// Direct accesses are all accesses appearing in the expressions of the stream itself.
232 fn direct_accesses(&self, who: SRef) -> Vec<SRef>;
233
234 /// Returns all streams that are direct accessed by `who` together with the corresponding stream access kinds.
235 ///
236 /// The function returns all streams that are direct accessed by `who` with all the stream access kinds that
237 /// are used to access that stream.
238 /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to `res`.
239 /// Direct accesses are all accesses appearing in the expressions of the stream itself.
240 fn direct_accesses_with(&self, who: SRef) -> Vec<(SRef, Vec<(Origin, StreamAccessKind)>)>;
241
242 /// Returns all streams that are transitive accessed by `who`
243 ///
244 /// The function returns all streams that are transitive accessed by `who`.
245 /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to 'res'.
246 /// Transitive accesses are all accesses appearing in the expressions of the stream itself or indirect by another stream lookup.
247 fn transitive_accesses(&self, who: SRef) -> Vec<SRef>;
248
249 /// Returns all streams that direct access `who`
250 ///
251 /// The function returns all streams that direct access `who`.
252 /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
253 /// Direct accesses are all accesses appearing in the expressions of the stream itself.
254 fn direct_accessed_by(&self, who: SRef) -> Vec<SRef>;
255
256 /// Returns all streams that direct access `who` together with the corresponding stream access kinds.
257 ///
258 /// The function returns all streams that direct access `who` together with all the stream access kinds
259 /// that they use to access `who`.
260 /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
261 /// Direct accesses are all accesses appearing in the expressions of the stream itself.
262 fn direct_accessed_by_with(&self, who: SRef) -> Vec<(SRef, Vec<(Origin, StreamAccessKind)>)>;
263
264 /// Returns all streams that transitive access `who`
265 ///
266 /// The function returns all streams that transitive access `who`.
267 /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
268 /// Transitive accesses are all accesses appearing in the expressions of the stream itself or indirect by another stream lookup.
269 fn transitive_accessed_by(&self, who: SRef) -> Vec<SRef>;
270
271 /// Returns all windows that aggregate `who` and the stream that uses the window
272 ///
273 /// The function returns all windows that aggregate `who` and the stream that uses the window.
274 /// The result contains only the windows that are direct.
275 fn aggregated_by(&self, who: SRef) -> Vec<(SRef, Origin, WRef)>; // (non-transitive)
276
277 /// Returns all windows that are used in `who` and the corresponding stream that is aggregated
278 ///
279 /// The function returns all windows that are used in `who` and the corresponding stream that is aggregated.
280 /// The result contains only the windows that are direct.
281 fn aggregates(&self, who: SRef) -> Vec<(SRef, Origin, WRef)>; // (non-transitive)
282
283 /// Returns the (Dependency Graph)[DependencyGraph] of the specification
284 fn graph(&self) -> &DependencyGraph;
285}
286
287impl HirStage for Hir<DepAnaMode> {
288 type NextStage = OrderedMode;
289
290 fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
291 let order = Ordered::analyze(&self);
292
293 let mode = OrderedMode {
294 dependencies: self.mode.dependencies,
295 types: self.mode.types,
296 layers: order,
297 };
298
299 Ok(Hir {
300 inputs: self.inputs,
301 outputs: self.outputs,
302 next_output_ref: self.next_output_ref,
303 next_input_ref: self.next_input_ref,
304 expr_maps: self.expr_maps,
305 global_tags: self.global_tags,
306 mode,
307 })
308 }
309}
310
311impl Hir<DepAnaMode> {
312 /// Returns the [RtLolaHir](crate::RtLolaHir) with the spawn and evaluation layer of each stream
313 ///
314 /// # Fails
315 /// The function fails if the evaluation order cannot be determined.
316 pub fn determine_evaluation_order(
317 self,
318 cfg: &FrontendConfig,
319 ) -> Result<Hir<OrderedMode>, RtLolaError> {
320 self.progress(cfg)
321 }
322}
323
324/// Represents the evaluation order
325#[derive(Debug, Clone)]
326pub struct Ordered {
327 stream_layers: HashMap<SRef, StreamLayers>,
328}
329
330/// Represents the mode after determining the evaluation order
331///
332/// This struct represents the mode after determining the evaluation order.
333/// Besides this result, this mode has the same functionality as all the previous modes.
334/// The [OrderedTrait] defines the new functionality of the mode.
335#[covers_functionality(DepAnaTrait, dependencies)]
336#[covers_functionality(TypedTrait, types)]
337#[covers_functionality(OrderedTrait, layers)]
338#[derive(Debug, Clone, HirMode)]
339pub struct OrderedMode {
340 dependencies: DepAna,
341 types: Typed,
342 layers: Ordered,
343}
344
345/// Describes the functionality of a mode after computing the evaluation order
346#[mode_functionality]
347pub trait OrderedTrait {
348 /// Returns the [StreamLayers] of the given stream
349 ///
350 /// # Panic
351 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
352 fn stream_layers(&self, sr: SRef) -> StreamLayers;
353}
354
355impl HirStage for Hir<OrderedMode> {
356 type NextStage = MemBoundMode;
357
358 fn progress(self, cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
359 let memory = MemBound::analyze(&self, cfg.memory_bound_mode());
360
361 let mode = MemBoundMode {
362 dependencies: self.mode.dependencies,
363 types: self.mode.types,
364 layers: self.mode.layers,
365 memory,
366 };
367
368 Ok(Hir {
369 inputs: self.inputs,
370 outputs: self.outputs,
371 next_output_ref: self.next_output_ref,
372 next_input_ref: self.next_input_ref,
373 expr_maps: self.expr_maps,
374 global_tags: self.global_tags,
375 mode,
376 })
377 }
378}
379
380impl Hir<OrderedMode> {
381 /// Returns the [RtLolaHir](crate::RtLolaHir) with the memory-bound for each stream
382 ///
383 /// # Fails
384 /// The function fails if the memory cannot be determined.
385 pub fn determine_memory_bounds(
386 self,
387 cfg: &FrontendConfig,
388 ) -> Result<Hir<MemBoundMode>, RtLolaError> {
389 self.progress(cfg)
390 }
391}
392
393/// Represents the results of the memory analysis
394#[derive(Debug, Clone)]
395pub struct MemBound {
396 memory_bound_per_stream: HashMap<SRef, MemorizationBound>,
397 memory_bound_per_window: HashMap<WRef, MemorizationBound>,
398 sliding_window_bucket_size: HashMap<WRef, Duration>,
399}
400
401/// Represents the mode after the memory analysis
402///
403/// This struct represents the mode after the memory analysis.
404/// Besides this result, this mode has the same functionality as all the previous modes.
405/// The [MemBoundTrait] defines the new functionality of the mode.
406#[covers_functionality(DepAnaTrait, dependencies)]
407#[covers_functionality(TypedTrait, types)]
408#[covers_functionality(OrderedTrait, layers)]
409#[covers_functionality(MemBoundTrait, memory)]
410#[derive(Debug, Clone, HirMode)]
411pub struct MemBoundMode {
412 dependencies: DepAna,
413 types: Typed,
414 layers: Ordered,
415 memory: MemBound,
416}
417
418/// Describes the functionality of a mode after computing the memory bounds
419#[mode_functionality]
420pub trait MemBoundTrait {
421 /// Returns the memory bound of the given stream
422 ///
423 /// # Panic
424 /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
425 fn memory_bound(&self, sr: SRef) -> MemorizationBound;
426
427 /// Returns the memory bound of the given sliding window
428 ///
429 /// # Panic
430 /// The function panics if the [WindowReference](crate::hir::WindowReference) is invalid.
431 fn num_buckets(&self, wr: WRef) -> MemorizationBound;
432
433 /// Returns the time per bucket of a sliding window.
434 ///
435 /// # Panic
436 /// The function panics if the [WindowReference](crate::hir::WindowReference) is not a valid
437 /// sliding window reference.
438 fn bucket_size(&self, wr: WRef) -> Duration;
439}
440
441impl HirStage for Hir<MemBoundMode> {
442 type NextStage = CompleteMode;
443
444 fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
445 let mode = CompleteMode {
446 dependencies: self.mode.dependencies,
447 types: self.mode.types,
448 layers: self.mode.layers,
449 memory: self.mode.memory,
450 };
451
452 Ok(Hir {
453 inputs: self.inputs,
454 outputs: self.outputs,
455 next_output_ref: self.next_output_ref,
456 next_input_ref: self.next_input_ref,
457 expr_maps: self.expr_maps,
458 global_tags: self.global_tags,
459 mode,
460 })
461 }
462}
463
464impl Hir<MemBoundMode> {
465 /// Returns the [RtLolaHir](crate::RtLolaHir) in the last mode
466 ///
467 /// The function returns the [RtLolaHir](crate::RtLolaHir) in the [CompleteMode].
468 /// This mode indicates that the [RtLolaHir](crate::RtLolaHir) has passed all analyzes and now contains all information.
469 /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
470 pub fn finalize(self, cfg: &FrontendConfig) -> Result<Hir<CompleteMode>, RtLolaError> {
471 self.progress(cfg)
472 }
473}
474
475/// Represents the final mode.
476///
477/// This struct represents the final mode and indicates that the [RtLolaHir](crate::RtLolaHir) has passed all analyzes and now contains all information.
478/// This mode has the same functionality as all the previous modes put together.
479#[covers_functionality(DepAnaTrait, dependencies)]
480#[covers_functionality(TypedTrait, types)]
481#[covers_functionality(OrderedTrait, layers)]
482#[covers_functionality(MemBoundTrait, memory)]
483#[derive(Debug, Clone, HirMode)]
484pub struct CompleteMode {
485 dependencies: DepAna,
486 types: Typed,
487 layers: Ordered,
488 memory: MemBound,
489}