use std::collections::HashMap;
use enum_as_inner::EnumAsInner;
use prqlc_parser::generic;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::{Lineage, TransformCall};
use crate::codegen::write_ty;
use crate::pr::{Ident, Literal, Span, Ty};
#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Expr {
#[serde(flatten)]
pub kind: ExprKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub span: Option<Span>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alias: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_id: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ty: Option<Ty>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lineage: Option<Lineage>,
#[serde(skip)]
pub needs_window: bool,
#[serde(skip)]
pub flatten: bool,
}
#[derive(
Debug, EnumAsInner, PartialEq, Clone, Serialize, Deserialize, strum::AsRefStr, JsonSchema,
)]
pub enum ExprKind {
Ident(Ident),
All {
within: Box<Expr>,
except: Box<Expr>,
},
Literal(Literal),
Tuple(Vec<Expr>),
Array(Vec<Expr>),
FuncCall(FuncCall),
Func(Box<Func>),
TransformCall(TransformCall),
SString(Vec<InterpolateItem>),
FString(Vec<InterpolateItem>),
Case(Vec<SwitchCase>),
RqOperator {
name: String,
args: Vec<Expr>,
},
Param(String),
Internal(String),
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct FuncCall {
pub name: Box<Expr>,
pub args: Vec<Expr>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub named_args: HashMap<String, Expr>,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Func {
pub name_hint: Option<Ident>,
pub return_ty: Option<Ty>,
pub body: Box<Expr>,
pub params: Vec<FuncParam>,
pub named_params: Vec<FuncParam>,
pub args: Vec<Expr>,
pub env: HashMap<String, Expr>,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct FuncParam {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub ty: Option<Ty>,
pub default_value: Option<Box<Expr>>,
}
pub type Range = generic::Range<Box<Expr>>;
pub type InterpolateItem = generic::InterpolateItem<Expr>;
pub type SwitchCase = generic::SwitchCase<Box<Expr>>;
impl From<Literal> for ExprKind {
fn from(value: Literal) -> Self {
ExprKind::Literal(value)
}
}
impl From<Ident> for ExprKind {
fn from(value: Ident) -> Self {
ExprKind::Ident(value)
}
}
impl From<Func> for ExprKind {
fn from(value: Func) -> Self {
ExprKind::Func(Box::new(value))
}
}
impl std::fmt::Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ds = f.debug_struct("Expr");
if let Some(x) = &self.span {
ds.field("span", x);
}
ds.field("kind", &self.kind);
if let Some(x) = &self.alias {
ds.field("alias", x);
}
if let Some(x) = &self.id {
ds.field("id", x);
}
if let Some(x) = &self.target_id {
ds.field("target_id", x);
}
if self.needs_window {
ds.field("needs_window", &self.needs_window);
}
if self.flatten {
ds.field("flatten", &self.flatten);
}
if let Some(x) = &self.ty {
struct DebugTy<'a>(&'a Ty);
impl std::fmt::Debug for DebugTy<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&write_ty(self.0))
}
}
ds.field("ty", &DebugTy(x));
}
if let Some(x) = &self.lineage {
ds.field("lineage", x);
}
ds.finish()
}
}