1use crate::tokens::{Token, TokenType};
2use crate::visitor::ExprVisitor;
3
4#[derive(Clone)]
5pub(crate) enum Expr {
6 Variable(VariableExpr),
7 Logical(LogicalExpr),
8 Binary(BinaryExpr),
9 Unary(UnaryExpr),
10 Call(CallExpr),
11 Literal(ExprValue),
12}
13
14impl Expr {
15 pub(crate) fn new_variable(name: Token) -> Self {
16 Self::Variable(VariableExpr { name })
17 }
18 pub(crate) fn new_logical(left: Expr, operator: TokenType, right: Expr) -> Self {
19 Self::Logical(LogicalExpr {
20 left: Box::new(left),
21 operator,
22 right: Box::new(right),
23 })
24 }
25
26 pub(crate) fn new_binary(left: Expr, operator: TokenType, right: Expr) -> Self {
27 Self::Binary(BinaryExpr {
28 left: Box::new(left),
29 operator,
30 right: Box::new(right),
31 })
32 }
33
34 pub(crate) fn new_unary(operator: TokenType, right: Expr) -> Self {
35 Self::Unary(UnaryExpr {
36 operator,
37 right: Box::new(right),
38 })
39 }
40
41 pub(crate) fn new_call(name: String, arguments: Vec<Expr>) -> Self {
42 Self::Call(CallExpr { name, arguments })
43 }
44
45 pub(crate) fn new_literal(value: ExprValue) -> Self {
46 Self::Literal(value)
47 }
48
49 pub(crate) fn accept<U, V>(&self, visitor: &mut V) -> U
50 where
51 V: ExprVisitor<U>,
52 {
53 match self {
54 Expr::Variable(expr) => visitor.visit_variable_expr(expr),
55 Expr::Logical(expr) => visitor.visit_logical_expr(expr),
56 Expr::Binary(expr) => visitor.visit_binary_expr(expr),
57 Expr::Unary(expr) => visitor.visit_unary_expr(expr),
58 Expr::Call(expr) => visitor.visit_call_expr(expr),
59 Expr::Literal(expr) => visitor.visit_literal_expr(expr),
60 }
61 }
62}
63
64#[derive(Clone)]
65pub(crate) struct AssignExpr {
66 pub(crate) name: Token,
67 pub(crate) value: Box<Expr>,
68}
69
70#[derive(Clone)]
71pub(crate) struct VariableExpr {
72 pub(crate) name: Token,
73}
74
75#[derive(Clone)]
76pub(crate) struct LogicalExpr {
77 pub(crate) left: Box<Expr>,
78 pub(crate) operator: TokenType,
79 pub(crate) right: Box<Expr>,
80}
81
82#[derive(Clone)]
83pub(crate) struct BinaryExpr {
84 pub(crate) left: Box<Expr>,
85 pub(crate) operator: TokenType,
86 pub(crate) right: Box<Expr>,
87}
88
89#[derive(Clone)]
90pub(crate) struct UnaryExpr {
91 pub(crate) operator: TokenType,
92 pub(crate) right: Box<Expr>,
93}
94
95#[derive(Clone)]
96pub(crate) struct CallExpr {
97 pub(crate) name: String,
98 pub(crate) arguments: Vec<Expr>,
99}
100
101#[derive(Clone, PartialEq, Debug)]
103pub enum ExprValue {
104 Boolean(bool),
105 Integer(i64),
106 Decimal(f64),
107 String(String),
108}
109
110impl ExprValue {
111 pub fn is_integer(&self) -> bool {
112 matches!(self, ExprValue::Boolean(_) | ExprValue::Integer(_))
113 }
114
115 pub fn is_decimal(&self) -> bool {
116 matches!(self, ExprValue::Decimal(_))
117 }
118
119 pub fn is_string(&self) -> bool {
120 matches!(self, ExprValue::String(_))
121 }
122
123 pub fn into_string(self) -> String {
124 match self {
125 ExprValue::Boolean(x) => {
126 if x {
127 "true".to_string()
128 } else {
129 "false".to_string()
130 }
131 }
132 ExprValue::Integer(x) => x.to_string(),
133 ExprValue::Decimal(x) => x.to_string(),
134 ExprValue::String(x) => x,
135 }
136 }
137
138 pub fn into_integer(self) -> i64 {
139 match self {
140 ExprValue::Boolean(x) => {
141 if x {
142 1
143 } else {
144 0
145 }
146 }
147 ExprValue::Integer(x) => x,
148 _ => panic!("Not an integer"),
149 }
150 }
151
152 pub fn into_decimal(self) -> f64 {
153 match self {
154 ExprValue::Boolean(x) => x as i32 as f64,
155 ExprValue::Integer(x) => x as f64,
156 ExprValue::Decimal(x) => x,
157 ExprValue::String(_) => panic!("Not a decimal"),
158 }
159 }
160
161 pub fn into_boolean(self) -> Option<bool> {
162 match self {
163 ExprValue::Boolean(x) => Some(x),
164 ExprValue::Integer(x) => Some(x != 0),
165 ExprValue::Decimal(x) => Some(x != 0.0),
166 ExprValue::String(_) => None,
167 }
168 }
169
170 pub(crate) fn increment(&mut self) -> Result<(), &'static str> {
171 match self {
172 ExprValue::Integer(x) => *x += 1,
173 ExprValue::Decimal(x) => *x += 1.0,
174 _ => return Err("Can only increment numbers."),
175 }
176
177 Ok(())
178 }
179}