use std::cell::RefCell;
use std::convert::TryFrom;
use std::hash::Hash;
use serde::{Deserialize, Serialize};
mod conversion;
mod print;
use std::rc::Rc;
use num::rational::Rational64 as Rational;
use rtlola_reporting::Span;
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct RtLolaAst {
pub imports: Vec<Import>,
pub constants: Vec<Rc<Constant>>,
pub inputs: Vec<Rc<Input>>,
pub outputs: Vec<Rc<Output>>,
pub mirrors: Vec<Rc<Mirror>>,
pub type_declarations: Vec<TypeDeclaration>,
pub next_node_id: RefCell<NodeId>,
pub global_tags: Vec<Tag>,
}
impl RtLolaAst {
pub(crate) fn empty() -> RtLolaAst {
RtLolaAst {
imports: Vec::new(),
constants: Vec::new(),
inputs: Vec::new(),
outputs: Vec::new(),
mirrors: Vec::new(),
type_declarations: Vec::new(),
next_node_id: RefCell::new(NodeId::default()),
global_tags: Vec::new(),
}
}
pub(crate) fn next_id(&self) -> NodeId {
let res = *self.next_node_id.borrow();
self.next_node_id.borrow_mut().0 += 1;
res
}
pub fn clone_deep(&self) -> RtLolaAst {
let RtLolaAst {
imports,
constants,
inputs,
outputs,
mirrors,
type_declarations,
next_node_id,
global_tags,
} = self;
RtLolaAst {
imports: imports.clone(),
constants: constants
.iter()
.map(|c| Rc::new(c.as_ref().clone()))
.collect(),
inputs: inputs.iter().map(|c| Rc::new(c.as_ref().clone())).collect(),
outputs: outputs
.iter()
.map(|c| Rc::new(c.as_ref().clone()))
.collect(),
mirrors: mirrors
.iter()
.map(|c| Rc::new(c.as_ref().clone()))
.collect(),
type_declarations: type_declarations.clone(),
next_node_id: next_node_id.clone(),
global_tags: global_tags.clone(),
}
}
pub(crate) fn primed_name(&self, name: &str) -> String {
let streams = self
.inputs
.iter()
.map(|i| &i.name)
.chain(self.outputs.iter().filter_map(|o| o.name()))
.collect::<Vec<_>>();
let mut name = format!("{name}\'");
loop {
if !streams.iter().any(|s| s.name == name) {
return name;
}
name = format!("{name}\'")
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Import {
pub name: Ident,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Constant {
pub name: Ident,
pub ty: Option<Type>,
pub literal: Literal,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Input {
pub name: Ident,
pub ty: Type,
pub params: Vec<Rc<Parameter>>,
pub tags: TagList,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum OutputKind {
NamedOutput(Ident),
Trigger,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Output {
pub kind: OutputKind,
pub annotated_type: Option<Type>,
pub params: Vec<Rc<Parameter>>,
pub spawn: Option<SpawnSpec>,
pub eval: Vec<EvalSpec>,
pub close: Option<CloseSpec>,
pub tags: TagList,
pub id: NodeId,
pub span: Span,
}
impl Output {
pub fn name(&self) -> Option<&Ident> {
match &self.kind {
OutputKind::NamedOutput(n) => Some(n),
OutputKind::Trigger => None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Mirror {
pub name: Ident,
pub filter: Expression,
pub target: Ident,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Parameter {
pub name: Ident,
pub ty: Option<Type>,
pub param_idx: usize,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct SpawnSpec {
pub expression: Option<Expression>,
pub annotated_pacing: AnnotatedPacingType,
pub condition: Option<Expression>,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct EvalSpec {
pub annotated_pacing: AnnotatedPacingType,
pub condition: Option<Expression>,
pub eval_expression: Option<Expression>,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct CloseSpec {
pub condition: Expression,
pub annotated_pacing: AnnotatedPacingType,
pub id: NodeId,
pub span: Span,
}
#[allow(clippy::vec_box)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeDeclaration {
pub name: Option<Ident>,
pub fields: Vec<Box<TypeDeclField>>,
pub id: NodeId,
pub span: Span,
}
type TagList = Vec<Tag>;
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Tag {
pub key: String,
pub value: Option<String>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeDeclField {
pub ty: Type,
pub name: String,
pub id: NodeId,
pub span: Span,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Type {
pub kind: TypeKind,
pub id: NodeId,
pub span: Span,
}
impl Type {
pub(crate) fn new_simple(id: NodeId, name: String, span: Span) -> Type {
Type {
id,
kind: TypeKind::Simple(name),
span,
}
}
pub(crate) fn new_tuple(id: NodeId, tuple: Vec<Type>, span: Span) -> Type {
Type {
id,
kind: TypeKind::Tuple(tuple),
span,
}
}
pub(crate) fn new_optional(id: NodeId, name: Type, span: Span) -> Type {
Type {
id,
kind: TypeKind::Optional(name.into()),
span,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum TypeKind {
Simple(String),
Tuple(Vec<Type>),
Optional(Box<Type>),
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Expression {
pub kind: ExpressionKind,
pub id: NodeId,
pub span: Span,
}
impl Expression {
pub(crate) fn new(id: NodeId, kind: ExpressionKind, span: Span) -> Expression {
Expression { kind, id, span }
}
}
#[allow(clippy::large_enum_variant, clippy::vec_box)]
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub enum ExpressionKind {
Lit(Literal),
Ident(Ident),
StreamAccess(Box<Expression>, StreamAccessKind),
Default(Box<Expression>, Box<Expression>),
Offset(Box<Expression>, Offset),
DiscreteWindowAggregation {
expr: Box<Expression>,
duration: Box<Expression>,
wait: bool,
aggregation: WindowOperation,
},
SlidingWindowAggregation {
expr: Box<Expression>,
duration: Box<Expression>,
wait: bool,
aggregation: WindowOperation,
},
InstanceAggregation {
expr: Box<Expression>,
selection: InstanceSelection,
aggregation: InstanceOperation,
},
Binary(BinOp, Box<Expression>, Box<Expression>),
Unary(UnOp, Box<Expression>),
Ite(Box<Expression>, Box<Expression>, Box<Expression>),
ParenthesizedExpression(Box<Expression>),
MissingExpression,
Tuple(Vec<Expression>),
Field(Box<Expression>, Ident),
Method(Box<Expression>, FunctionName, Vec<Type>, Vec<Expression>),
Function(FunctionName, Vec<Type>, Vec<Expression>),
Lambda(LambdaExpr),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
pub enum WindowOperation {
Count,
Min,
Max,
Sum,
Product,
Average,
Integral,
Conjunction,
Disjunction,
Last,
Variance,
Covariance,
StandardDeviation,
NthPercentile(u8),
TrueRatio,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
pub enum InstanceOperation {
Count,
Min,
Max,
Sum,
Product,
Average,
Conjunction,
Disjunction,
Variance,
Covariance,
StandardDeviation,
NthPercentile(u8),
TrueRatio,
}
impl TryFrom<WindowOperation> for InstanceOperation {
type Error = String;
fn try_from(value: WindowOperation) -> Result<Self, Self::Error> {
match value {
WindowOperation::Count => Ok(InstanceOperation::Count),
WindowOperation::Min => Ok(InstanceOperation::Min),
WindowOperation::Max => Ok(InstanceOperation::Max),
WindowOperation::Sum => Ok(InstanceOperation::Sum),
WindowOperation::Product => Ok(InstanceOperation::Product),
WindowOperation::Average => Ok(InstanceOperation::Average),
WindowOperation::Conjunction => Ok(InstanceOperation::Conjunction),
WindowOperation::Disjunction => Ok(InstanceOperation::Disjunction),
WindowOperation::Variance => Ok(InstanceOperation::Variance),
WindowOperation::Covariance => Ok(InstanceOperation::Covariance),
WindowOperation::StandardDeviation => Ok(InstanceOperation::StandardDeviation),
WindowOperation::NthPercentile(x) => Ok(InstanceOperation::NthPercentile(x)),
WindowOperation::TrueRatio => Ok(InstanceOperation::TrueRatio),
WindowOperation::Integral | WindowOperation::Last => {
Err(format!("Operation {value} not supported over instances."))
}
}
}
}
impl From<InstanceOperation> for WindowOperation {
fn from(val: InstanceOperation) -> Self {
match val {
InstanceOperation::Count => WindowOperation::Count,
InstanceOperation::Min => WindowOperation::Min,
InstanceOperation::Max => WindowOperation::Max,
InstanceOperation::Sum => WindowOperation::Sum,
InstanceOperation::Product => WindowOperation::Product,
InstanceOperation::Average => WindowOperation::Average,
InstanceOperation::Conjunction => WindowOperation::Conjunction,
InstanceOperation::Disjunction => WindowOperation::Disjunction,
InstanceOperation::Variance => WindowOperation::Variance,
InstanceOperation::Covariance => WindowOperation::Covariance,
InstanceOperation::StandardDeviation => WindowOperation::StandardDeviation,
InstanceOperation::NthPercentile(x) => WindowOperation::NthPercentile(x),
InstanceOperation::TrueRatio => WindowOperation::TrueRatio,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
pub enum StreamAccessKind {
Sync,
Hold,
Get,
Fresh,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Offset {
Discrete(i16),
RealTime(Rational, TimeUnit),
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum TimeUnit {
Nanosecond,
Microsecond,
Millisecond,
Second,
Minute,
Hour,
Day,
Week,
Year,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Literal {
pub kind: LitKind,
pub id: NodeId,
pub span: Span,
}
impl Literal {
pub(crate) fn new_bool(id: NodeId, val: bool, span: Span) -> Literal {
Literal {
id,
kind: LitKind::Bool(val),
span,
}
}
pub(crate) fn new_numeric(id: NodeId, val: &str, unit: Option<String>, span: Span) -> Literal {
Literal {
id,
kind: LitKind::Numeric(val.to_string(), unit),
span,
}
}
pub(crate) fn new_str(id: NodeId, val: &str, span: Span) -> Literal {
Literal {
id,
kind: LitKind::Str(val.to_string()),
span,
}
}
pub(crate) fn new_raw_str(id: NodeId, val: &str, span: Span) -> Literal {
Literal {
id,
kind: LitKind::RawStr(val.to_string()),
span,
}
}
pub(crate) fn new_tuple(id: NodeId, val: Vec<Literal>, span: Span) -> Literal {
Literal {
id,
kind: LitKind::Tuple(val),
span,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum LitKind {
Str(String),
RawStr(String),
Numeric(String, Option<String>),
Bool(bool),
Tuple(Vec<Literal>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Rem,
Pow,
And,
Or,
Implies,
BitXor,
BitAnd,
BitOr,
Shl,
Shr,
Eq,
Lt,
Le,
Ne,
Ge,
Gt,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum UnOp {
Not,
Neg,
BitNot,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord)]
pub struct FunctionName {
pub name: Ident,
pub arg_names: Vec<Option<Ident>>,
}
#[derive(Debug, Clone, Eq, Serialize, Deserialize, PartialOrd, Ord)]
pub struct Ident {
pub name: String,
pub span: Span,
}
impl Ident {
pub(crate) fn new(name: String, span: Span) -> Ident {
Ident { name, span }
}
}
impl PartialEq for Ident {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Hash for Ident {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct LambdaExpr {
pub parameters: Vec<Rc<Parameter>>,
pub expr: Box<Expression>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum InstanceSelection {
Fresh,
All,
FilteredFresh(LambdaExpr),
FilteredAll(LambdaExpr),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AnnotatedPacingType {
NotAnnotated(Span),
Global(Expression),
Local(Expression),
Unspecified(Expression),
}
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct NodeId(u32);
impl NodeId {
pub fn new(x: usize) -> NodeId {
assert!(x < (u32::MAX as usize));
NodeId(x as u32)
}
}