xbasic/
expr.rs

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/// Represents an xBASIC value.
102#[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}