#![allow(clippy::module_name_repetitions)]
use super::super::raw::{
reduce2, BaseExpr, ExprRaw, IdentRaw, ImutExprRaw, ModuleRaw, ScriptRaw, WithExprsRaw,
};
use super::{
error_generic, error_no_consts, error_no_locals, AggrRegistry, Builder, Cow, GroupBy,
GroupByInt, HashMap, Helper, ImutExpr, Location, NodeMetas, OperatorDecl, OperatorKind,
OperatorStmt, Query, Registry, Result, ScriptDecl, ScriptStmt, Select, SelectStmt, Serialize,
Stmt, StreamStmt, Upable, Value, Warning, WindowDecl, WindowKind, ARGS_CONST_ID,
GROUP_CONST_ID, WINDOW_CONST_ID,
};
use crate::impl_expr;
fn up_params<'script, 'registry>(
params: WithExprsRaw<'script>,
helper: &mut Helper<'script, 'registry>,
) -> Result<HashMap<String, Value<'script>>> {
params
.into_iter()
.map(|(name, value)| Ok((name.id.to_string(), reduce2(value.up(helper)?, &helper)?)))
.collect()
}
fn up_maybe_params<'script, 'registry>(
params: Option<WithExprsRaw<'script>>,
helper: &mut Helper<'script, 'registry>,
) -> Result<Option<HashMap<String, Value<'script>>>> {
params.map(|params| up_params(params, helper)).transpose()
}
#[derive(Debug, PartialEq, Serialize)]
#[allow(clippy::module_name_repetitions)]
pub struct QueryRaw<'script> {
pub(crate) config: WithExprsRaw<'script>,
pub(crate) stmts: StmtsRaw<'script>,
}
impl<'script> QueryRaw<'script> {
pub(crate) fn up_script<'registry>(
self,
mut helper: &mut Helper<'script, 'registry>,
) -> Result<(Query<'script>, usize, Vec<Warning>)> {
let mut stmts = vec![];
for (_i, e) in self.stmts.into_iter().enumerate() {
match e {
StmtRaw::ModuleStmt(m) => {
m.define(helper.reg, helper.aggr_reg, &mut vec![], &mut helper)?;
}
other => {
stmts.push(other.up(&mut helper)?);
}
}
}
Ok((
Query {
config: up_params(self.config, helper)?,
stmts,
node_meta: helper.meta.clone(),
windows: helper.windows.clone(),
scripts: helper.scripts.clone(),
operators: helper.operators.clone(),
},
helper.locals.len(),
helper.warnings.clone(),
))
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub enum StmtRaw<'script> {
WindowDecl(WindowDeclRaw<'script>),
OperatorDecl(Box<OperatorDeclRaw<'script>>),
ScriptDecl(ScriptDeclRaw<'script>),
Stream(StreamStmtRaw),
Operator(OperatorStmtRaw<'script>),
Script(ScriptStmtRaw<'script>),
Select(Box<SelectRaw<'script>>),
ModuleStmt(ModuleStmtRaw<'script>),
Expr(Box<ExprRaw<'script>>),
}
impl<'script> BaseExpr for StmtRaw<'script> {
fn mid(&self) -> usize {
0
}
fn s(&self, meta: &NodeMetas) -> Location {
match self {
StmtRaw::ModuleStmt(s) => s.start,
StmtRaw::Operator(s) => s.start,
StmtRaw::OperatorDecl(s) => s.start,
StmtRaw::Script(s) => s.start,
StmtRaw::ScriptDecl(s) => s.start,
StmtRaw::Select(s) => s.start,
StmtRaw::Stream(s) => s.start,
StmtRaw::WindowDecl(s) => s.start,
StmtRaw::Expr(s) => s.s(meta),
}
}
fn e(&self, meta: &NodeMetas) -> Location {
match self {
StmtRaw::ModuleStmt(e) => e.end,
StmtRaw::Operator(e) => e.end,
StmtRaw::OperatorDecl(e) => e.end,
StmtRaw::Script(e) => e.end,
StmtRaw::ScriptDecl(e) => e.end,
StmtRaw::Select(e) => e.end,
StmtRaw::Stream(e) => e.end,
StmtRaw::WindowDecl(e) => e.end,
StmtRaw::Expr(e) => e.e(meta),
}
}
}
impl<'script> Upable<'script> for StmtRaw<'script> {
type Target = Stmt<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
match self {
StmtRaw::Select(stmt) => {
let mut aggregates = Vec::new();
let mut consts = HashMap::new();
let mut locals = HashMap::new();
helper.swap(&mut aggregates, &mut consts, &mut locals);
let stmt: Select<'script> = stmt.up(helper)?;
helper.swap(&mut aggregates, &mut consts, &mut locals);
let consts = vec![Value::null(), Value::null(), Value::null()];
Ok(Stmt::Select(SelectStmt {
stmt: Box::new(stmt),
aggregates,
consts,
locals: locals.len(),
node_meta: helper.meta.clone(),
}))
}
StmtRaw::Stream(stmt) => Ok(Stmt::Stream(stmt.up(helper)?)),
StmtRaw::OperatorDecl(stmt) => {
let stmt: OperatorDecl<'script> = stmt.up(helper)?;
helper
.operators
.insert(stmt.fqon(&stmt.module), stmt.clone());
Ok(Stmt::OperatorDecl(stmt))
}
StmtRaw::Operator(stmt) => Ok(Stmt::Operator(stmt.up(helper)?)),
StmtRaw::ScriptDecl(stmt) => {
let stmt: ScriptDecl<'script> = stmt.up(helper)?;
helper.scripts.insert(stmt.fqsn(&stmt.module), stmt.clone());
Ok(Stmt::ScriptDecl(Box::new(stmt)))
}
StmtRaw::Script(stmt) => Ok(Stmt::Script(stmt.up(helper)?)),
StmtRaw::WindowDecl(stmt) => {
let stmt: WindowDecl<'script> = stmt.up(helper)?;
helper.windows.insert(stmt.fqwn(&stmt.module), stmt.clone());
Ok(Stmt::WindowDecl(Box::new(stmt)))
}
StmtRaw::ModuleStmt(m) => {
error_generic(&m, &m, &"Module in wrong place error", &helper.meta)
}
StmtRaw::Expr(m) => {
error_generic(&*m, &*m, &"Expression in wrong place error", &helper.meta)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct OperatorDeclRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) kind: OperatorKindRaw,
pub(crate) id: String,
pub(crate) params: Option<WithExprsRaw<'script>>,
}
impl<'script> Upable<'script> for OperatorDeclRaw<'script> {
type Target = OperatorDecl<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
let operator_decl = OperatorDecl {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
module: helper.module.clone(),
id: self.id,
kind: self.kind.up(helper)?,
params: up_maybe_params(self.params, helper)?,
};
helper
.operators
.insert(operator_decl.fqon(&helper.module), operator_decl.clone());
Ok(operator_decl)
}
}
#[derive(Debug, PartialEq, Serialize, Clone)]
pub struct ModuleStmtRaw<'script> {
pub start: Location,
pub end: Location,
pub name: IdentRaw<'script>,
pub stmts: StmtsRaw<'script>,
pub doc: Option<Vec<Cow<'script, str>>>,
}
impl_expr!(ModuleStmtRaw);
impl<'script> ModuleStmtRaw<'script> {
pub(crate) fn define<'registry>(
self,
reg: &'registry Registry,
aggr_reg: &'registry AggrRegistry,
consts: &mut Vec<Value<'script>>,
mut helper: &mut Helper<'script, 'registry>,
) -> Result<()> {
helper.module.push(self.name.id.to_string());
for e in self.stmts {
match e {
StmtRaw::ModuleStmt(m) => {
m.define(reg, aggr_reg, consts, helper)?;
}
StmtRaw::Expr(e) => {
let expr_m = ModuleRaw {
name: self.name.clone(),
start: self.start,
end: self.end,
doc: None,
exprs: vec![*e],
};
helper.module.pop();
expr_m.define(helper)?;
helper.module.push(self.name.id.to_string());
}
StmtRaw::WindowDecl(stmt) => {
let w = stmt.up(&mut helper)?;
helper.windows.insert(w.fqwn(&helper.module), w);
}
StmtRaw::ScriptDecl(stmt) => {
let s = stmt.up(&mut helper)?;
helper.scripts.insert(s.fqsn(&helper.module), s);
}
StmtRaw::OperatorDecl(stmt) => {
let o = stmt.up(&mut helper)?;
helper.operators.insert(o.fqon(&helper.module), o);
}
e => {
return error_generic(
&e,
&e,
&"Can't have statements inside of query modules",
&helper.meta,
)
}
}
}
helper.module.pop();
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct OperatorStmtRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) module: Vec<IdentRaw<'script>>,
pub(crate) id: String,
pub(crate) target: String,
pub(crate) params: Option<WithExprsRaw<'script>>,
}
impl_expr!(OperatorStmtRaw);
impl<'script> Upable<'script> for OperatorStmtRaw<'script> {
type Target = OperatorStmt<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
Ok(OperatorStmt {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
id: self.id,
module: self
.module
.into_iter()
.map(|x| x.id.to_string())
.collect::<Vec<String>>(),
target: self.target,
params: up_maybe_params(self.params, helper)?,
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct ScriptDeclRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) id: String,
pub(crate) params: Option<WithExprsRaw<'script>>,
pub(crate) script: ScriptRaw<'script>,
}
impl<'script> Upable<'script> for ScriptDeclRaw<'script> {
type Target = ScriptDecl<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
helper.module.push(self.id.to_string());
let (script, mut warnings) = self.script.up_script(helper)?;
helper.warnings.append(&mut warnings);
helper.warnings.sort();
helper.warnings.dedup();
let script_decl = ScriptDecl {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
module: helper.module.clone(),
id: self.id,
params: up_maybe_params(self.params, helper)?,
script,
};
helper.module.pop();
helper
.scripts
.insert(script_decl.fqsn(&helper.module), script_decl.clone());
Ok(script_decl)
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct ScriptStmtRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) id: String,
pub(crate) target: String,
pub(crate) module: Vec<IdentRaw<'script>>,
pub(crate) params: Option<WithExprsRaw<'script>>,
}
impl<'script> Upable<'script> for ScriptStmtRaw<'script> {
type Target = ScriptStmt<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
Ok(ScriptStmt {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
id: self.id,
params: up_maybe_params(self.params, helper)?,
target: self.target,
module: self
.module
.into_iter()
.map(|x| x.id.to_string())
.collect::<Vec<String>>(),
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct WindowDeclRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) id: String,
pub(crate) kind: WindowKind,
pub(crate) params: WithExprsRaw<'script>,
pub(crate) script: Option<ScriptRaw<'script>>,
}
impl<'script> Upable<'script> for WindowDeclRaw<'script> {
type Target = WindowDecl<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
let mut maybe_script = self.script.map(|s| s.up_script(helper)).transpose()?;
if let Some((_, ref mut warnings)) = maybe_script {
helper.warnings.append(warnings);
helper.warnings.sort();
helper.warnings.dedup();
};
Ok(WindowDecl {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
module: helper.module.clone(),
id: self.id,
kind: self.kind,
params: up_params(self.params, helper)?,
script: maybe_script.map(|s| s.0),
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct WindowDefnRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub module: Vec<IdentRaw<'script>>,
pub id: String,
}
impl<'script> WindowDefnRaw<'script> {
pub fn fqwn(&self) -> String {
if self.module.is_empty() {
self.id.clone()
} else {
format!(
"{}::{}",
self.module
.iter()
.map(|x| x.id.to_string())
.collect::<Vec<String>>()
.join("::"),
self.id
)
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct SelectRaw<'script> {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) from: (IdentRaw<'script>, Option<IdentRaw<'script>>),
pub(crate) into: (IdentRaw<'script>, Option<IdentRaw<'script>>),
pub(crate) target: ImutExprRaw<'script>,
pub(crate) maybe_where: Option<ImutExprRaw<'script>>,
pub(crate) maybe_having: Option<ImutExprRaw<'script>>,
pub(crate) maybe_group_by: Option<GroupByRaw<'script>>,
pub(crate) windows: Option<Vec<WindowDefnRaw<'script>>>,
}
impl_expr!(SelectRaw);
impl<'script> Upable<'script> for SelectRaw<'script> {
type Target = Select<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
if !helper.consts.is_empty() {
return error_no_consts(&(self.start, self.end), &self.target, &helper.meta);
}
helper
.consts
.insert(vec!["window".to_owned()], WINDOW_CONST_ID);
helper
.consts
.insert(vec!["group".to_owned()], GROUP_CONST_ID);
helper.consts.insert(vec!["args".to_owned()], ARGS_CONST_ID);
let target = self.target.up(helper)?;
if helper.has_locals() {
return error_no_locals(&(self.start, self.end), &target, &helper.meta);
};
let maybe_having = self.maybe_having.up(helper)?;
if helper.has_locals() {
if let Some(definitely) = maybe_having {
return error_no_locals(&(self.start, self.end), &definitely, &helper.meta);
}
};
if helper.consts.remove(&vec!["window".to_owned()]) != Some(WINDOW_CONST_ID)
|| helper.consts.remove(&vec!["group".to_owned()]) != Some(GROUP_CONST_ID)
|| helper.consts.remove(&vec!["args".to_owned()]) != Some(ARGS_CONST_ID)
|| !helper.consts.is_empty()
{
return error_no_consts(&(self.start, self.end), &target, &helper.meta);
}
let maybe_where = self.maybe_where.up(helper)?;
if helper.has_locals() {
if let Some(definitely) = maybe_where {
return error_no_locals(&(self.start, self.end), &definitely, &helper.meta);
}
};
let maybe_group_by = self.maybe_group_by.up(helper)?;
if helper.has_locals() {
if let Some(definitely) = maybe_group_by {
return error_no_locals(&(self.start, self.end), &definitely, &helper.meta);
}
};
let windows = self.windows.unwrap_or_default();
let from = match self.from {
(stream, None) => {
let mut port = stream.clone();
port.id = Cow::Borrowed("out");
(stream, port)
}
(stream, Some(port)) => (stream, port),
};
let into = match self.into {
(stream, None) => {
let mut port = stream.clone();
port.id = Cow::Borrowed("in");
(stream, port)
}
(stream, Some(port)) => (stream, port),
};
Ok(Select {
mid: helper.add_meta(self.start, self.end),
from: (from.0.up(helper)?, from.1.up(helper)?),
into: (into.0.up(helper)?, into.1.up(helper)?),
target: ImutExpr(target),
maybe_where: maybe_where.map(ImutExpr),
maybe_having: maybe_having.map(ImutExpr),
maybe_group_by,
windows,
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub enum GroupByRaw<'script> {
Expr {
start: Location,
end: Location,
expr: ImutExprRaw<'script>,
},
Set {
start: Location,
end: Location,
items: Vec<GroupByRaw<'script>>,
},
Each {
start: Location,
end: Location,
expr: ImutExprRaw<'script>,
},
}
impl<'script> Upable<'script> for GroupByRaw<'script> {
type Target = GroupBy<'script>;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
Ok(match self {
GroupByRaw::Expr { start, end, expr } => GroupBy(GroupByInt::Expr {
mid: helper.add_meta(start, end),
expr: expr.up(helper)?,
}),
GroupByRaw::Each { start, end, expr } => GroupBy(GroupByInt::Each {
mid: helper.add_meta(start, end),
expr: expr.up(helper)?,
}),
GroupByRaw::Set { start, end, items } => GroupBy(GroupByInt::Set {
mid: helper.add_meta(start, end),
items: items.up(helper)?,
}),
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct OperatorKindRaw {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) module: String,
pub(crate) operation: String,
}
impl BaseExpr for OperatorKindRaw {
fn s(&self, _meta: &NodeMetas) -> Location {
self.start
}
fn e(&self, _meta: &NodeMetas) -> Location {
self.end
}
fn mid(&self) -> usize {
0
}
}
impl<'script> Upable<'script> for OperatorKindRaw {
type Target = OperatorKind;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
Ok(OperatorKind {
mid: helper.add_meta_w_name(
self.start,
self.end,
&format!("{}::{}", self.module, self.operation),
),
module: self.module,
operation: self.operation,
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct StreamStmtRaw {
pub(crate) start: Location,
pub(crate) end: Location,
pub(crate) id: String,
}
impl<'script> Upable<'script> for StreamStmtRaw {
type Target = StreamStmt;
fn up<'registry>(self, helper: &mut Helper<'script, 'registry>) -> Result<Self::Target> {
Ok(StreamStmt {
mid: helper.add_meta_w_name(self.start, self.end, &self.id),
id: self.id,
})
}
}
pub type StmtsRaw<'script> = Vec<StmtRaw<'script>>;