Skip to main content

brooks_lib/mel/
ast.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18use crate::common::TextLocation;
19use crate::mel::grammar::GrammarNode;
20use brooks_macros::{grammar_location, grammar_name};
21use regex::Regex;
22use std::{fmt::Debug, net::IpAddr, sync::Arc};
23
24#[grammar_name(mel)]
25#[grammar_location]
26#[derive(Debug, Clone)]
27pub struct Mel<A: Debug + Clone> {
28    pub testing: usize,
29    pub aug: A,
30}
31
32#[grammar_name(function_call_expr)]
33#[grammar_location]
34#[derive(Debug, Clone)]
35pub struct FunctionCall<A: Debug + Clone> {
36    pub callee: Expr<A>,
37    pub arguments: ArgumentList<A>,
38    pub aug: A,
39}
40
41#[grammar_name(identifier)]
42#[grammar_location]
43#[derive(Debug, Clone)]
44pub struct Identifier<A: Debug + Clone> {
45    pub identifier: String,
46    pub aug: A,
47}
48
49#[grammar_name(member_access)]
50#[derive(Debug, Clone)]
51pub enum MemberAccessOperator {
52    MemberAccess,
53}
54
55#[grammar_name(member_access_expr)]
56#[grammar_location]
57#[derive(Debug, Clone)]
58pub struct MemberAccessExpression<A: Debug + Clone> {
59    pub base: Expr<A>,
60    pub oper: MemberAccessOperator,
61    pub member: Identifier<A>,
62    pub aug: A,
63}
64
65#[grammar_name(argument)]
66#[grammar_location]
67#[derive(Debug, Clone)]
68pub struct Argument<A: Debug + Clone> {
69    pub expr: Expr<A>,
70    pub aug: A,
71}
72
73#[grammar_name(argument_list)]
74#[grammar_location]
75#[derive(Debug, Clone)]
76pub struct ArgumentList<A: Debug + Clone> {
77    pub arguments: Vec<Argument<A>>,
78    pub aug: A,
79}
80
81#[derive(Debug, Clone)]
82pub enum BinaryInfixOperator {
83    Logic(LogicOperator),
84    Comparison(ComparisonOperator),
85    Math(MathOperator),
86    Concat(StringConcatOperator),
87    MemberAccess(MemberAccessOperator),
88}
89
90#[grammar_name(eq, ne, lt, lte, gt, gte, regex_eq, ipmatch)]
91#[derive(Debug, Clone)]
92pub enum ComparisonOperator {
93    Eq,
94    Ne,
95    Lt,
96    Lte,
97    Gt,
98    Gte,
99    Re,
100    IP,
101}
102
103#[grammar_name(and, or)]
104#[derive(Debug, Clone)]
105pub enum LogicOperator {
106    And,
107    Or,
108}
109
110#[grammar_name(string_concat)]
111#[derive(Debug, Clone)]
112pub struct StringConcatOperator {}
113
114#[grammar_name(plus, minus, mul, div, modulo)]
115#[derive(Debug, Clone)]
116pub enum MathOperator {
117    Plus,
118    Minus,
119    Multiply,
120    Divide,
121    Modulo,
122}
123
124#[grammar_name(binary_expr)]
125#[grammar_location]
126#[derive(Debug, Clone)]
127pub struct BinaryExpr<A: Debug + Clone> {
128    pub left: Expr<A>,
129    pub op: BinaryInfixOperator,
130    pub right: Expr<A>,
131    pub aug: A,
132}
133
134#[grammar_name(ternary_question, ternary_colon)]
135#[derive(Debug, Clone)]
136pub enum TernaryOperator {
137    Question,
138    Colon,
139}
140
141#[grammar_name(ternary_expr)]
142#[grammar_location]
143#[derive(Debug, Clone)]
144pub struct TernaryExpr<A: Debug + Clone> {
145    pub condition: Expr<A>,
146    pub yes: Expr<A>,
147    pub no: Expr<A>,
148    pub aug: A,
149}
150
151#[grammar_name(expr)]
152#[derive(Debug, Clone)]
153pub enum Expr<A: Debug + Clone> {
154    FunctionCall(Arc<FunctionCall<A>>),
155    BinaryExpr(Arc<BinaryExpr<A>>),
156    TernaryExpr(Arc<TernaryExpr<A>>),
157    Identifier(Arc<Identifier<A>>),
158    ArgumentList(Arc<ArgumentList<A>>),
159    Argument(Arc<Argument<A>>),
160    Literal(Literal, TextLocation, A),
161    MemberAccess(Arc<MemberAccessExpression<A>>),
162}
163
164impl<A: Debug + Clone> Expr<A> {
165    pub fn location(&self) -> TextLocation {
166        match self {
167            Expr::FunctionCall(function_call) => function_call.location.clone(),
168            Expr::BinaryExpr(binary_expr) => binary_expr.location.clone(),
169            Expr::TernaryExpr(ternary_expr) => ternary_expr.location.clone(),
170            Expr::Identifier(identifier) => identifier.location.clone(),
171            Expr::ArgumentList(argument_list) => argument_list.location.clone(),
172            Expr::Argument(argument) => argument.location.clone(),
173            Expr::MemberAccess(member_access) => member_access.location.clone(),
174            Expr::Literal(_, location, _) => location.clone(),
175        }
176    }
177}
178
179#[grammar_name(literal)]
180#[derive(Debug, Clone)]
181pub enum Literal {
182    Boolean(BooleanLiteral),
183    Number(NumberLiteral),
184    String(StringLiteral),
185    Regex(RegexLiteral),
186    IPAddress(IPAddressLiteral),
187}
188
189#[grammar_name(boolean_literal)]
190#[derive(Debug, Clone, PartialEq)]
191pub enum BooleanLiteral {
192    True,
193    False,
194}
195
196#[derive(Debug, Clone)]
197#[grammar_name(number_literal)]
198pub struct NumberLiteral {
199    pub literal: usize,
200}
201
202#[derive(Debug, Clone)]
203#[grammar_name(string_literal)]
204pub struct StringLiteral {
205    pub literal: String,
206}
207
208#[derive(Debug, Clone)]
209#[grammar_name(regex_literal)]
210pub struct RegexLiteral {
211    pub literal: Regex,
212}
213
214#[derive(Debug, Clone)]
215#[grammar_name(ip_literal)]
216pub struct IPAddressLiteral {
217    pub literal: IpAddr,
218}
219
220pub type AstVisitorResult<T, E> = Result<T, E>;
221
222pub trait AstVisitor<T, A: Debug + Clone, E> {
223    fn visit_function_call(
224        &self,
225        ast: &FunctionCall<A>,
226        context: T,
227        driver: &AstVisitorDriver,
228    ) -> AstVisitorResult<T, E>;
229    fn visit_identifier(
230        &self,
231        ast: &Identifier<A>,
232        context: T,
233        driver: &AstVisitorDriver,
234    ) -> AstVisitorResult<T, E>;
235    fn visit_argument_list(
236        &self,
237        ast: &ArgumentList<A>,
238        context: T,
239        driver: &AstVisitorDriver,
240    ) -> AstVisitorResult<T, E>;
241    fn visit_argument(
242        &self,
243        ast: &Argument<A>,
244        context: T,
245        driver: &AstVisitorDriver,
246    ) -> AstVisitorResult<T, E>;
247    fn visit_member_access_expr(
248        &self,
249        ast: &MemberAccessExpression<A>,
250        context: T,
251        driver: &AstVisitorDriver,
252    ) -> AstVisitorResult<T, E>;
253    fn visit_binary_expr(
254        &self,
255        ast: &BinaryExpr<A>,
256        context: T,
257        driver: &AstVisitorDriver,
258    ) -> AstVisitorResult<T, E>;
259    fn visit_ternary_expr(
260        &self,
261        ast: &TernaryExpr<A>,
262        context: T,
263        driver: &AstVisitorDriver,
264    ) -> AstVisitorResult<T, E>;
265    fn visit_literal(
266        &self,
267        ast: (&Literal, &TextLocation, &A),
268        context: T,
269        driver: &AstVisitorDriver,
270    ) -> AstVisitorResult<T, E>;
271}
272
273pub struct AstVisitorDriver {}
274
275impl AstVisitorDriver {
276    #[allow(dead_code)]
277    pub fn visit<T, A: Debug + Clone, E>(
278        &self,
279        node: &Expr<A>,
280        visitor: &impl AstVisitor<T, A, E>,
281        context: T,
282    ) -> AstVisitorResult<T, E> {
283        match node {
284            Expr::Argument(argument) => visitor.visit_argument(argument, context, self),
285            Expr::ArgumentList(argument_list) => {
286                visitor.visit_argument_list(argument_list, context, self)
287            }
288            Expr::Identifier(identifier) => visitor.visit_identifier(identifier, context, self),
289            Expr::FunctionCall(function_call) => {
290                visitor.visit_function_call(function_call, context, self)
291            }
292            Expr::BinaryExpr(binary_expr) => visitor.visit_binary_expr(binary_expr, context, self),
293            Expr::MemberAccess(member_access_expr) => {
294                visitor.visit_member_access_expr(member_access_expr, context, self)
295            }
296            Expr::TernaryExpr(ternary_expr) => {
297                visitor.visit_ternary_expr(ternary_expr, context, self)
298            }
299            Expr::Literal(literal, location, aug) => {
300                visitor.visit_literal((literal, location, aug), context, self)
301            }
302        }
303    }
304}