use std::collections::{HashMap, HashSet};
use crate::dag_id::DagId;
use crate::desugar::desugared_ast::{AssertBody, Expr, FigureDecl, LayerDecl, PlotDecl};
use crate::registry::declared_type::IndexTypeRef;
use crate::syntax::names::{
DeclName, IndexName, IndexVariantName, NamePath, ResolvedIndexVariant, ScopedName,
};
use crate::syntax::span::Span;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AggregationFn {
Sum,
Min,
Max,
Mean,
Count,
}
impl AggregationFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"sum" => Some(Self::Sum),
"min" => Some(Self::Min),
"max" => Some(Self::Max),
"mean" => Some(Self::Mean),
"count" => Some(Self::Count),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Sum => "sum",
Self::Min => "min",
Self::Max => "max",
Self::Mean => "mean",
Self::Count => "count",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeConversionFn {
ToFloat,
ToInt,
}
impl TypeConversionFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"to_float" => Some(Self::ToFloat),
"to_int" => Some(Self::ToInt),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::ToFloat => "to_float",
Self::ToInt => "to_int",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConstructorFn {
Datetime,
Epoch,
}
impl ConstructorFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"datetime" => Some(Self::Datetime),
"epoch" => Some(Self::Epoch),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Datetime => "datetime",
Self::Epoch => "epoch",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DatetimeExtractFn {
Year,
Month,
Day,
Hour,
Minute,
Second,
Weekday,
DayOfYear,
}
impl DatetimeExtractFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"year" => Some(Self::Year),
"month" => Some(Self::Month),
"day" => Some(Self::Day),
"hour" => Some(Self::Hour),
"minute" => Some(Self::Minute),
"second" => Some(Self::Second),
"weekday" => Some(Self::Weekday),
"day_of_year" => Some(Self::DayOfYear),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Year => "year",
Self::Month => "month",
Self::Day => "day",
Self::Hour => "hour",
Self::Minute => "minute",
Self::Second => "second",
Self::Weekday => "weekday",
Self::DayOfYear => "day_of_year",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DatetimeFromFn {
FromJd,
FromMjd,
FromUnix,
}
impl DatetimeFromFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"from_jd" => Some(Self::FromJd),
"from_mjd" => Some(Self::FromMjd),
"from_unix" => Some(Self::FromUnix),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::FromJd => "from_jd",
Self::FromMjd => "from_mjd",
Self::FromUnix => "from_unix",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DatetimeToFn {
ToJd,
ToMjd,
ToUnix,
}
impl DatetimeToFn {
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"to_jd" => Some(Self::ToJd),
"to_mjd" => Some(Self::ToMjd),
"to_unix" => Some(Self::ToUnix),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::ToJd => "to_jd",
Self::ToMjd => "to_mjd",
Self::ToUnix => "to_unix",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpecialFnKind {
Aggregation(AggregationFn),
TypeConversion(TypeConversionFn),
TimeScaleConversion(crate::registry::time_scale::TimeScale),
Constructor(ConstructorFn),
DatetimeExtract(DatetimeExtractFn),
DatetimeFrom(DatetimeFromFn),
DatetimeTo(DatetimeToFn),
}
#[must_use]
pub fn classify_special_fn(name: &str) -> Option<SpecialFnKind> {
if let Some(f) = AggregationFn::parse(name) {
return Some(SpecialFnKind::Aggregation(f));
}
if let Some(f) = TypeConversionFn::parse(name) {
return Some(SpecialFnKind::TypeConversion(f));
}
if let Some(scale) = crate::registry::time_scale::time_scale_from_conversion_fn(name) {
return Some(SpecialFnKind::TimeScaleConversion(scale));
}
if let Some(f) = ConstructorFn::parse(name) {
return Some(SpecialFnKind::Constructor(f));
}
if let Some(f) = DatetimeExtractFn::parse(name) {
return Some(SpecialFnKind::DatetimeExtract(f));
}
if let Some(f) = DatetimeFromFn::parse(name) {
return Some(SpecialFnKind::DatetimeFrom(f));
}
if let Some(f) = DatetimeToFn::parse(name) {
return Some(SpecialFnKind::DatetimeTo(f));
}
None
}
#[must_use]
pub fn is_aggregation_fn(name: &str) -> bool {
AggregationFn::parse(name).is_some()
}
#[must_use]
pub fn is_time_scale_name(name: &str) -> bool {
crate::registry::time_scale::TimeScale::ALL_NAMES.contains(&name)
}
#[derive(Debug, Default, Clone)]
pub struct ImportedValueNames {
pub const_names: Vec<(ScopedName, Span)>,
pub param_names: Vec<(ScopedName, Span)>,
pub node_names: Vec<(ScopedName, Span)>,
pub assert_names: Vec<(DeclName, Span)>,
pub plot_names: Vec<(ScopedName, Span)>,
}
#[derive(Debug, Clone, Copy)]
pub enum DeclCategory {
Const,
Param,
Node,
Assert,
Plot,
Figure,
Layer,
}
impl std::fmt::Display for DeclCategory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Const => write!(f, "const"),
Self::Param => write!(f, "param"),
Self::Node => write!(f, "node"),
Self::Assert => write!(f, "assert"),
Self::Plot => write!(f, "plot"),
Self::Figure => write!(f, "figure"),
Self::Layer => write!(f, "layer"),
}
}
}
#[derive(Debug)]
pub struct ResolvedConstEntry {
pub name: String,
pub expr: Expr,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedParamEntry {
pub name: String,
pub default_expr: Option<Expr>,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedNodeEntry {
pub name: String,
pub expr: Expr,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedAssertEntry {
pub name: String,
pub body: AssertBody,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedPlotEntry {
pub name: String,
pub decl: PlotDecl,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedFigureEntry {
pub name: String,
pub decl: FigureDecl,
pub span: Span,
}
#[derive(Debug)]
pub struct ResolvedLayerEntry {
pub name: String,
pub decl: LayerDecl,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExpectedFailKeyPart {
Named {
index: IndexTypeRef,
variant: IndexVariantName,
source_index_path: Option<NamePath>,
span: Span,
},
RangeStep { step: u64, span: Span },
}
impl ExpectedFailKeyPart {
fn unresolved_owner() -> DagId {
DagId::root("<expected-fail-unresolved>")
}
#[must_use]
pub fn unresolved(index_path: NamePath, variant: IndexVariantName, span: Span) -> Self {
Self::Named {
index: IndexTypeRef::with_owner(
Self::unresolved_owner(),
IndexName::from_atom(index_path.leaf().clone()),
),
variant,
source_index_path: Some(index_path),
span,
}
}
#[must_use]
pub fn with_owner(
owner: DagId,
index: IndexName,
variant: IndexVariantName,
span: Span,
) -> Self {
Self::Named {
index: IndexTypeRef::with_owner(owner, index),
variant,
source_index_path: None,
span,
}
}
#[must_use]
pub fn resolved(resolved: ResolvedIndexVariant, span: Span) -> Self {
let (index, variant) = resolved.into_parts();
Self::Named {
index: IndexTypeRef::from_resolved(index),
variant,
source_index_path: None,
span,
}
}
#[must_use]
pub fn with_resolved_variant(&self, resolved: ResolvedIndexVariant) -> Self {
Self::resolved(resolved, self.span())
}
#[must_use]
pub const fn span(&self) -> Span {
match self {
Self::Named { span, .. } | Self::RangeStep { span, .. } => *span,
}
}
#[must_use]
pub const fn named_index(&self) -> Option<&IndexTypeRef> {
match self {
Self::Named { index, .. } => Some(index),
Self::RangeStep { .. } => None,
}
}
#[must_use]
pub const fn source_index_path(&self) -> Option<&NamePath> {
match self {
Self::Named {
source_index_path, ..
} => source_index_path.as_ref(),
Self::RangeStep { .. } => None,
}
}
#[must_use]
pub fn variant(&self) -> IndexVariantName {
match self {
Self::Named { variant, .. } => variant.clone(),
Self::RangeStep { step, .. } => IndexVariantName::range_step(*step),
}
}
#[must_use]
pub fn matches_entry(&self, index: &IndexTypeRef, variant: &IndexVariantName) -> bool {
match self {
Self::Named {
index: expected,
variant: expected_variant,
..
} => expected.matches_ref(index) && variant == expected_variant,
Self::RangeStep { step, .. } => {
matches!(index, IndexTypeRef::NatRange(_))
&& *variant == IndexVariantName::range_step(*step)
}
}
}
#[must_use]
pub fn display(&self) -> String {
match self {
Self::Named { index, variant, .. } => format!("{}.{variant}", index.display_name()),
Self::RangeStep { step, .. } => format!("#{step}"),
}
}
}
pub type ExpectedFailKey = Vec<ExpectedFailKeyPart>;
#[derive(Debug, Clone)]
pub enum ExpectedFail {
All,
Variants(Vec<ExpectedFailKey>),
}
#[derive(Debug)]
pub struct ResolvedFile {
pub consts: Vec<ResolvedConstEntry>,
pub params: Vec<ResolvedParamEntry>,
pub nodes: Vec<ResolvedNodeEntry>,
pub asserts: Vec<ResolvedAssertEntry>,
pub plots: Vec<ResolvedPlotEntry>,
pub figures: Vec<ResolvedFigureEntry>,
pub layers: Vec<ResolvedLayerEntry>,
pub source_order: Vec<(DeclName, DeclCategory)>,
pub assert_names: HashSet<DeclName>,
pub assumes_map: HashMap<DeclName, Vec<DeclName>>,
pub expected_fail: HashMap<DeclName, ExpectedFail>,
pub hidden_plots: HashSet<DeclName>,
pub pub_names: HashSet<DeclName>,
}