use std::fmt;
#[derive(Debug, Clone)]
pub struct Program {
pub statements: Vec<Stmt>,
}
impl Program {
pub fn new() -> Self {
Self {
statements: Vec::new(),
}
}
}
impl Default for Program {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub enum Stmt {
VarDeclaration {
name: String,
value: Box<Expr>,
is_varip: bool, },
Assignment { name: String, value: Box<Expr> },
Expression(Expr),
If {
condition: Box<Expr>,
then_branch: Vec<Stmt>,
else_branch: Option<Vec<Stmt>>,
},
For {
variable: String,
start: Box<Expr>,
end: Box<Expr>,
body: Vec<Stmt>,
},
While {
condition: Box<Expr>,
body: Vec<Stmt>,
},
}
#[derive(Debug, Clone)]
pub enum Expr {
Number(f64),
StringLiteral(String),
Boolean(bool),
Variable(String),
BuiltinVariable(BuiltinVar),
Binary {
left: Box<Expr>,
op: BinaryOp,
right: Box<Expr>,
},
Unary { op: UnaryOp, expr: Box<Expr> },
FunctionCall { name: String, args: Vec<Expr> },
MethodCall {
namespace: String,
method: String,
args: Vec<Expr>,
},
Ternary {
condition: Box<Expr>,
then_expr: Box<Expr>,
else_expr: Box<Expr>,
},
ArrayAccess { array: Box<Expr>, index: Box<Expr> },
SeriesOffset { series: Box<Expr>, offset: i32 },
ArrayLiteral(Vec<Expr>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinVar {
Open,
High,
Low,
Close,
Volume,
Time,
}
impl fmt::Display for BuiltinVar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BuiltinVar::Open => write!(f, "open"),
BuiltinVar::High => write!(f, "high"),
BuiltinVar::Low => write!(f, "low"),
BuiltinVar::Close => write!(f, "close"),
BuiltinVar::Volume => write!(f, "volume"),
BuiltinVar::Time => write!(f, "time"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Add,
Subtract,
Multiply,
Divide,
Modulo,
Equal,
NotEqual,
Less,
LessEqual,
Greater,
GreaterEqual,
And,
Or,
}
impl fmt::Display for BinaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
BinaryOp::Add => "+",
BinaryOp::Subtract => "-",
BinaryOp::Multiply => "*",
BinaryOp::Divide => "/",
BinaryOp::Modulo => "%",
BinaryOp::Equal => "==",
BinaryOp::NotEqual => "!=",
BinaryOp::Less => "<",
BinaryOp::LessEqual => "<=",
BinaryOp::Greater => ">",
BinaryOp::GreaterEqual => ">=",
BinaryOp::And => "and",
BinaryOp::Or => "or",
};
write!(f, "{op}")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Negate,
Not,
}
impl fmt::Display for UnaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
UnaryOp::Negate => "-",
UnaryOp::Not => "not",
};
write!(f, "{op}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builtin_var_display() {
assert_eq!(format!("{}", BuiltinVar::Close), "close");
assert_eq!(format!("{}", BuiltinVar::Volume), "volume");
}
#[test]
fn test_binary_op_display() {
assert_eq!(format!("{}", BinaryOp::Add), "+");
assert_eq!(format!("{}", BinaryOp::Equal), "==");
}
}