1use std::collections::{HashMap, HashSet};
7
8use crate::dag_id::DagId;
9use crate::desugar::desugared_ast::{AssertBody, Expr, FigureDecl, LayerDecl, PlotDecl};
10use crate::registry::declared_type::IndexTypeRef;
11use crate::syntax::names::{
12 DeclName, IndexName, IndexVariantName, NamePath, ResolvedIndexVariant, ScopedName,
13};
14use crate::syntax::span::Span;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum AggregationFn {
27 Sum,
28 Min,
29 Max,
30 Mean,
31 Count,
32}
33
34impl AggregationFn {
35 #[must_use]
36 pub fn parse(name: &str) -> Option<Self> {
37 match name {
38 "sum" => Some(Self::Sum),
39 "min" => Some(Self::Min),
40 "max" => Some(Self::Max),
41 "mean" => Some(Self::Mean),
42 "count" => Some(Self::Count),
43 _ => None,
44 }
45 }
46
47 #[must_use]
48 pub const fn as_str(self) -> &'static str {
49 match self {
50 Self::Sum => "sum",
51 Self::Min => "min",
52 Self::Max => "max",
53 Self::Mean => "mean",
54 Self::Count => "count",
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum TypeConversionFn {
62 ToFloat,
63 ToInt,
64}
65
66impl TypeConversionFn {
67 #[must_use]
68 pub fn parse(name: &str) -> Option<Self> {
69 match name {
70 "to_float" => Some(Self::ToFloat),
71 "to_int" => Some(Self::ToInt),
72 _ => None,
73 }
74 }
75
76 #[must_use]
77 pub const fn as_str(self) -> &'static str {
78 match self {
79 Self::ToFloat => "to_float",
80 Self::ToInt => "to_int",
81 }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub enum ConstructorFn {
88 Datetime,
89 Epoch,
90}
91
92impl ConstructorFn {
93 #[must_use]
94 pub fn parse(name: &str) -> Option<Self> {
95 match name {
96 "datetime" => Some(Self::Datetime),
97 "epoch" => Some(Self::Epoch),
98 _ => None,
99 }
100 }
101
102 #[must_use]
103 pub const fn as_str(self) -> &'static str {
104 match self {
105 Self::Datetime => "datetime",
106 Self::Epoch => "epoch",
107 }
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub enum DatetimeExtractFn {
114 Year,
115 Month,
116 Day,
117 Hour,
118 Minute,
119 Second,
120 Weekday,
121 DayOfYear,
122}
123
124impl DatetimeExtractFn {
125 #[must_use]
126 pub fn parse(name: &str) -> Option<Self> {
127 match name {
128 "year" => Some(Self::Year),
129 "month" => Some(Self::Month),
130 "day" => Some(Self::Day),
131 "hour" => Some(Self::Hour),
132 "minute" => Some(Self::Minute),
133 "second" => Some(Self::Second),
134 "weekday" => Some(Self::Weekday),
135 "day_of_year" => Some(Self::DayOfYear),
136 _ => None,
137 }
138 }
139
140 #[must_use]
141 pub const fn as_str(self) -> &'static str {
142 match self {
143 Self::Year => "year",
144 Self::Month => "month",
145 Self::Day => "day",
146 Self::Hour => "hour",
147 Self::Minute => "minute",
148 Self::Second => "second",
149 Self::Weekday => "weekday",
150 Self::DayOfYear => "day_of_year",
151 }
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum DatetimeFromFn {
158 FromJd,
159 FromMjd,
160 FromUnix,
161}
162
163impl DatetimeFromFn {
164 #[must_use]
165 pub fn parse(name: &str) -> Option<Self> {
166 match name {
167 "from_jd" => Some(Self::FromJd),
168 "from_mjd" => Some(Self::FromMjd),
169 "from_unix" => Some(Self::FromUnix),
170 _ => None,
171 }
172 }
173
174 #[must_use]
175 pub const fn as_str(self) -> &'static str {
176 match self {
177 Self::FromJd => "from_jd",
178 Self::FromMjd => "from_mjd",
179 Self::FromUnix => "from_unix",
180 }
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186pub enum DatetimeToFn {
187 ToJd,
188 ToMjd,
189 ToUnix,
190}
191
192impl DatetimeToFn {
193 #[must_use]
194 pub fn parse(name: &str) -> Option<Self> {
195 match name {
196 "to_jd" => Some(Self::ToJd),
197 "to_mjd" => Some(Self::ToMjd),
198 "to_unix" => Some(Self::ToUnix),
199 _ => None,
200 }
201 }
202
203 #[must_use]
204 pub const fn as_str(self) -> &'static str {
205 match self {
206 Self::ToJd => "to_jd",
207 Self::ToMjd => "to_mjd",
208 Self::ToUnix => "to_unix",
209 }
210 }
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum SpecialFnKind {
219 Aggregation(AggregationFn),
221 TypeConversion(TypeConversionFn),
223 TimeScaleConversion(crate::registry::time_scale::TimeScale),
225 Constructor(ConstructorFn),
227 DatetimeExtract(DatetimeExtractFn),
229 DatetimeFrom(DatetimeFromFn),
231 DatetimeTo(DatetimeToFn),
233}
234
235#[must_use]
239pub fn classify_special_fn(name: &str) -> Option<SpecialFnKind> {
240 if let Some(f) = AggregationFn::parse(name) {
241 return Some(SpecialFnKind::Aggregation(f));
242 }
243 if let Some(f) = TypeConversionFn::parse(name) {
244 return Some(SpecialFnKind::TypeConversion(f));
245 }
246 if let Some(scale) = crate::registry::time_scale::time_scale_from_conversion_fn(name) {
247 return Some(SpecialFnKind::TimeScaleConversion(scale));
248 }
249 if let Some(f) = ConstructorFn::parse(name) {
250 return Some(SpecialFnKind::Constructor(f));
251 }
252 if let Some(f) = DatetimeExtractFn::parse(name) {
253 return Some(SpecialFnKind::DatetimeExtract(f));
254 }
255 if let Some(f) = DatetimeFromFn::parse(name) {
256 return Some(SpecialFnKind::DatetimeFrom(f));
257 }
258 if let Some(f) = DatetimeToFn::parse(name) {
259 return Some(SpecialFnKind::DatetimeTo(f));
260 }
261 None
262}
263
264#[must_use]
266pub fn is_aggregation_fn(name: &str) -> bool {
267 AggregationFn::parse(name).is_some()
268}
269
270#[must_use]
272pub fn is_time_scale_name(name: &str) -> bool {
273 crate::registry::time_scale::TimeScale::ALL_NAMES.contains(&name)
274}
275
276#[derive(Debug, Default, Clone)]
286pub struct ImportedValueNames {
287 pub const_names: Vec<(ScopedName, Span)>,
289 pub param_names: Vec<(ScopedName, Span)>,
291 pub node_names: Vec<(ScopedName, Span)>,
293 pub assert_names: Vec<(DeclName, Span)>,
295 pub plot_names: Vec<(ScopedName, Span)>,
299}
300
301#[derive(Debug, Clone, Copy)]
303pub enum DeclCategory {
304 Const,
305 Param,
306 Node,
307 Assert,
308 Plot,
309 Figure,
310 Layer,
311}
312
313impl std::fmt::Display for DeclCategory {
314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 match self {
316 Self::Const => write!(f, "const"),
317 Self::Param => write!(f, "param"),
318 Self::Node => write!(f, "node"),
319 Self::Assert => write!(f, "assert"),
320 Self::Plot => write!(f, "plot"),
321 Self::Figure => write!(f, "figure"),
322 Self::Layer => write!(f, "layer"),
323 }
324 }
325}
326
327#[derive(Debug)]
333pub struct ResolvedConstEntry {
334 pub name: String,
335 pub expr: Expr,
336 pub span: Span,
337}
338
339#[derive(Debug)]
341pub struct ResolvedParamEntry {
342 pub name: String,
343 pub default_expr: Option<Expr>,
344 pub span: Span,
345}
346
347#[derive(Debug)]
349pub struct ResolvedNodeEntry {
350 pub name: String,
351 pub expr: Expr,
352 pub span: Span,
353}
354
355#[derive(Debug)]
357pub struct ResolvedAssertEntry {
358 pub name: String,
359 pub body: AssertBody,
360 pub span: Span,
361}
362
363#[derive(Debug)]
365pub struct ResolvedPlotEntry {
366 pub name: String,
367 pub decl: PlotDecl,
368 pub span: Span,
369}
370
371#[derive(Debug)]
373pub struct ResolvedFigureEntry {
374 pub name: String,
375 pub decl: FigureDecl,
376 pub span: Span,
377}
378
379#[derive(Debug)]
381pub struct ResolvedLayerEntry {
382 pub name: String,
383 pub decl: LayerDecl,
384 pub span: Span,
385}
386
387#[derive(Debug, Clone, PartialEq, Eq)]
389pub enum ExpectedFailKeyPart {
390 Named {
397 index: IndexTypeRef,
398 variant: IndexVariantName,
399 source_index_path: Option<NamePath>,
400 span: Span,
401 },
402 RangeStep { step: u64, span: Span },
408}
409
410impl ExpectedFailKeyPart {
411 fn unresolved_owner() -> DagId {
412 DagId::root("<expected-fail-unresolved>")
413 }
414
415 #[must_use]
416 pub fn unresolved(index_path: NamePath, variant: IndexVariantName, span: Span) -> Self {
417 Self::Named {
418 index: IndexTypeRef::with_owner(
419 Self::unresolved_owner(),
420 IndexName::from_atom(index_path.leaf().clone()),
421 ),
422 variant,
423 source_index_path: Some(index_path),
424 span,
425 }
426 }
427
428 #[must_use]
429 pub fn with_owner(
430 owner: DagId,
431 index: IndexName,
432 variant: IndexVariantName,
433 span: Span,
434 ) -> Self {
435 Self::Named {
436 index: IndexTypeRef::with_owner(owner, index),
437 variant,
438 source_index_path: None,
439 span,
440 }
441 }
442
443 #[must_use]
444 pub fn resolved(resolved: ResolvedIndexVariant, span: Span) -> Self {
445 let (index, variant) = resolved.into_parts();
446 Self::Named {
447 index: IndexTypeRef::from_resolved(index),
448 variant,
449 source_index_path: None,
450 span,
451 }
452 }
453
454 #[must_use]
455 pub fn with_resolved_variant(&self, resolved: ResolvedIndexVariant) -> Self {
456 Self::resolved(resolved, self.span())
457 }
458
459 #[must_use]
461 pub const fn span(&self) -> Span {
462 match self {
463 Self::Named { span, .. } | Self::RangeStep { span, .. } => *span,
464 }
465 }
466
467 #[must_use]
469 pub const fn named_index(&self) -> Option<&IndexTypeRef> {
470 match self {
471 Self::Named { index, .. } => Some(index),
472 Self::RangeStep { .. } => None,
473 }
474 }
475
476 #[must_use]
478 pub const fn source_index_path(&self) -> Option<&NamePath> {
479 match self {
480 Self::Named {
481 source_index_path, ..
482 } => source_index_path.as_ref(),
483 Self::RangeStep { .. } => None,
484 }
485 }
486
487 #[must_use]
489 pub fn variant(&self) -> IndexVariantName {
490 match self {
491 Self::Named { variant, .. } => variant.clone(),
492 Self::RangeStep { step, .. } => IndexVariantName::range_step(*step),
493 }
494 }
495
496 #[must_use]
502 pub fn matches_entry(&self, index: &IndexTypeRef, variant: &IndexVariantName) -> bool {
503 match self {
504 Self::Named {
505 index: expected,
506 variant: expected_variant,
507 ..
508 } => expected.matches_ref(index) && variant == expected_variant,
509 Self::RangeStep { step, .. } => {
510 matches!(index, IndexTypeRef::NatRange(_))
511 && *variant == IndexVariantName::range_step(*step)
512 }
513 }
514 }
515
516 #[must_use]
518 pub fn display(&self) -> String {
519 match self {
520 Self::Named { index, variant, .. } => format!("{}.{variant}", index.display_name()),
521 Self::RangeStep { step, .. } => format!("#{step}"),
522 }
523 }
524}
525
526pub type ExpectedFailKey = Vec<ExpectedFailKeyPart>;
531
532#[derive(Debug, Clone)]
534pub enum ExpectedFail {
535 All,
537 Variants(Vec<ExpectedFailKey>),
539}
540
541#[derive(Debug)]
543pub struct ResolvedFile {
544 pub consts: Vec<ResolvedConstEntry>,
546 pub params: Vec<ResolvedParamEntry>,
548 pub nodes: Vec<ResolvedNodeEntry>,
550 pub asserts: Vec<ResolvedAssertEntry>,
552 pub plots: Vec<ResolvedPlotEntry>,
554 pub figures: Vec<ResolvedFigureEntry>,
556 pub layers: Vec<ResolvedLayerEntry>,
558 pub source_order: Vec<(DeclName, DeclCategory)>,
560 pub assert_names: HashSet<DeclName>,
562 pub assumes_map: HashMap<DeclName, Vec<DeclName>>,
565 pub expected_fail: HashMap<DeclName, ExpectedFail>,
568 pub hidden_plots: HashSet<DeclName>,
571 pub pub_names: HashSet<DeclName>,
573}