1use alloc::{boxed::Box, string::String, vec::Vec};
4
5use crate::Span;
6use super::common::{Identifier, Block, Parameter, TypeAnnotation};
7
8#[derive(Debug, Clone, PartialEq)]
13pub struct Expr {
14 pub kind: ExprKind,
16 pub span: Span,
18}
19
20impl Expr {
21 pub fn new(kind: ExprKind, span: Span) -> Self {
22 Self { kind, span }
23 }
24
25 pub fn synthetic(kind: ExprKind) -> Self {
26 Self { kind, span: 0..0 }
27 }
28}
29
30#[derive(Debug, Clone, PartialEq)]
32pub enum ExprKind {
33 Nil,
35 Boolean(bool),
37 Number(NumberLiteral),
39 String(StringLiteral),
41 Vararg,
43
44 Table(TableConstructor),
46 Function(FunctionExpr),
48
49 Identifier(Identifier),
51 FieldAccess(FieldAccess),
53 IndexAccess(IndexAccess),
55
56 Unary(UnaryExpr),
58 Binary(BinaryExpr),
60
61 Call(CallExpr),
63 MethodCall(MethodCallExpr),
65
66 IfExpression(IfExpression),
68 InterpolatedString(InterpolatedString),
70 TypeAssertion(TypeAssertion),
72
73 Parenthesized(Box<Expr>),
75}
76
77#[derive(Debug, Clone, PartialEq)]
81pub struct NumberLiteral {
82 pub raw: String,
84 pub span: Span,
86}
87
88impl NumberLiteral {
89 pub fn new(raw: String, span: Span) -> Self {
90 Self { raw, span }
91 }
92
93 pub fn parse_f64(&self) -> Option<f64> {
94 let cleaned = self.raw.replace('_', "");
95
96 if cleaned.starts_with("0x") || cleaned.starts_with("0X") {
97 u64::from_str_radix(&cleaned[2..].split('.').next()?, 16)
99 .ok()
100 .map(|v| v as f64)
101 } else if cleaned.starts_with("0b") || cleaned.starts_with("0B") {
102 u64::from_str_radix(&cleaned[2..], 2)
103 .ok()
104 .map(|v| v as f64)
105 } else {
106 cleaned.parse().ok()
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub struct StringLiteral {
114 pub value: String,
116 pub span: Span,
118}
119
120impl StringLiteral {
121 pub fn new(value: String, span: Span) -> Self {
122 Self { value, span }
123 }
124}
125
126#[derive(Debug, Clone, PartialEq)]
128pub struct TableConstructor {
129 pub fields: Vec<TableField>,
131 pub span: Span,
133}
134
135impl TableConstructor {
136 pub fn new(fields: Vec<TableField>, span: Span) -> Self {
137 Self { fields, span }
138 }
139}
140
141#[derive(Debug, Clone, PartialEq)]
143pub struct TableField {
144 pub kind: TableFieldKind,
146 pub span: Span,
148}
149
150impl TableField {
151 pub fn new(kind: TableFieldKind, span: Span) -> Self {
152 Self { kind, span }
153 }
154}
155
156#[derive(Debug, Clone, PartialEq)]
158pub enum TableFieldKind {
159 Bracketed { key: Expr, value: Expr },
161 Named { name: Identifier, value: Expr },
163 Positional(Expr),
165}
166
167#[derive(Debug, Clone, PartialEq)]
169pub struct FunctionExpr {
170 pub parameters: Vec<Parameter>,
172 pub return_type: Option<TypeAnnotation>,
174 pub body: Block,
176 pub span: Span,
178}
179
180impl FunctionExpr {
181 pub fn new(
182 parameters: Vec<Parameter>,
183 return_type: Option<TypeAnnotation>,
184 body: Block,
185 span: Span,
186 ) -> Self {
187 Self {
188 parameters,
189 return_type,
190 body,
191 span,
192 }
193 }
194}
195
196#[derive(Debug, Clone, PartialEq)]
198pub struct FieldAccess {
199 pub base: Box<Expr>,
201 pub field: Identifier,
203 pub span: Span,
205}
206
207impl FieldAccess {
208 pub fn new(base: Expr, field: Identifier, span: Span) -> Self {
209 Self {
210 base: Box::new(base),
211 field,
212 span,
213 }
214 }
215}
216
217#[derive(Debug, Clone, PartialEq)]
219pub struct IndexAccess {
220 pub base: Box<Expr>,
222 pub index: Box<Expr>,
224 pub span: Span,
226}
227
228impl IndexAccess {
229 pub fn new(base: Expr, index: Expr, span: Span) -> Self {
230 Self {
231 base: Box::new(base),
232 index: Box::new(index),
233 span,
234 }
235 }
236}
237
238#[derive(Debug, Clone, PartialEq)]
240pub struct UnaryExpr {
241 pub operator: UnaryOperator,
243 pub operand: Box<Expr>,
245 pub span: Span,
247}
248
249impl UnaryExpr {
250 pub fn new(operator: UnaryOperator, operand: Expr, span: Span) -> Self {
251 Self {
252 operator,
253 operand: Box::new(operand),
254 span,
255 }
256 }
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub enum UnaryOperator {
262 Minus,
264 Not,
266 Length,
268 BitwiseNot,
270}
271
272impl UnaryOperator {
273 pub const fn binding_power(self) -> u8 {
274 14
275 }
276}
277
278#[derive(Debug, Clone, PartialEq)]
280pub struct BinaryExpr {
281 pub operator: BinaryOperator,
283 pub left: Box<Expr>,
285 pub right: Box<Expr>,
287 pub span: Span,
289}
290
291impl BinaryExpr {
292 pub fn new(operator: BinaryOperator, left: Expr, right: Expr, span: Span) -> Self {
293 Self {
294 operator,
295 left: Box::new(left),
296 right: Box::new(right),
297 span,
298 }
299 }
300}
301
302#[derive(Debug, Clone, Copy, PartialEq, Eq)]
304pub enum BinaryOperator {
305 Add,
307 Subtract,
309 Multiply,
311 Divide,
313 FloorDiv,
315 Modulo,
317 Power,
319
320 Concat,
322
323 Equal,
325 NotEqual,
327 Less,
329 LessEqual,
331 Greater,
333 GreaterEqual,
335
336 And,
338 Or,
340
341 BitwiseAnd,
343 BitwiseOr,
345 BitwiseXor,
347 LeftShift,
349 RightShift,
351}
352
353impl BinaryOperator {
354 pub const fn binding_power(self) -> (u8, u8) {
355 match self {
356 Self::Or => (1, 2),
357 Self::And => (3, 4),
358 Self::Equal | Self::NotEqual | Self::Less | Self::LessEqual
359 | Self::Greater | Self::GreaterEqual => (5, 6),
360 Self::BitwiseOr => (6, 7),
361 Self::BitwiseXor => (7, 8),
362 Self::BitwiseAnd => (8, 9),
363 Self::LeftShift | Self::RightShift => (9, 10),
364 Self::Concat => (10, 9),
365 Self::Add | Self::Subtract => (11, 12),
366 Self::Multiply | Self::Divide | Self::FloorDiv | Self::Modulo => (13, 14),
367 Self::Power => (16, 15),
368 }
369 }
370
371 pub const fn is_right_associative(self) -> bool {
372 matches!(self, Self::Concat | Self::Power)
373 }
374}
375
376#[derive(Debug, Clone, PartialEq)]
378pub struct CallExpr {
379 pub function: Box<Expr>,
381 pub arguments: Vec<Expr>,
383 pub span: Span,
385}
386
387impl CallExpr {
388 pub fn new(function: Expr, arguments: Vec<Expr>, span: Span) -> Self {
389 Self {
390 function: Box::new(function),
391 arguments,
392 span,
393 }
394 }
395}
396
397#[derive(Debug, Clone, PartialEq)]
399pub struct MethodCallExpr {
400 pub base: Box<Expr>,
402 pub method: Identifier,
404 pub arguments: Vec<Expr>,
406 pub span: Span,
408}
409
410impl MethodCallExpr {
411 pub fn new(base: Expr, method: Identifier, arguments: Vec<Expr>, span: Span) -> Self {
412 Self {
413 base: Box::new(base),
414 method,
415 arguments,
416 span,
417 }
418 }
419}
420
421#[derive(Debug, Clone, PartialEq)]
423pub struct IfExpression {
424 pub condition: Box<Expr>,
426 pub then_branch: Box<Expr>,
428 pub elseif_branches: Vec<ElseIfExprBranch>,
430 pub else_branch: Box<Expr>,
432 pub span: Span,
434}
435
436impl IfExpression {
437 pub fn new(
438 condition: Expr,
439 then_branch: Expr,
440 elseif_branches: Vec<ElseIfExprBranch>,
441 else_branch: Expr,
442 span: Span,
443 ) -> Self {
444 Self {
445 condition: Box::new(condition),
446 then_branch: Box::new(then_branch),
447 elseif_branches,
448 else_branch: Box::new(else_branch),
449 span,
450 }
451 }
452}
453
454#[derive(Debug, Clone, PartialEq)]
456pub struct ElseIfExprBranch {
457 pub condition: Expr,
459 pub then_branch: Expr,
461}
462
463impl ElseIfExprBranch {
464 pub fn new(condition: Expr, then_branch: Expr) -> Self {
465 Self {
466 condition,
467 then_branch,
468 }
469 }
470}
471
472#[derive(Debug, Clone, PartialEq)]
474pub struct InterpolatedString {
475 pub segments: Vec<InterpolationSegment>,
477 pub span: Span,
479}
480
481impl InterpolatedString {
482 pub fn new(segments: Vec<InterpolationSegment>, span: Span) -> Self {
483 Self { segments, span }
484 }
485}
486
487#[derive(Debug, Clone, PartialEq)]
489pub enum InterpolationSegment {
490 Text(String),
492 Expression(Expr),
494}
495
496#[derive(Debug, Clone, PartialEq)]
498pub struct TypeAssertion {
499 pub expression: Box<Expr>,
501 pub type_annotation: TypeAnnotation,
503 pub span: Span,
505}
506
507impl TypeAssertion {
508 pub fn new(expression: Expr, type_annotation: TypeAnnotation, span: Span) -> Self {
509 Self {
510 expression: Box::new(expression),
511 type_annotation,
512 span,
513 }
514 }
515}