1use std::fmt;
4
5use crate::utils::{escape_str, Join, Location};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum FunctionKind {
10 Function,
11 Closure,
12 Do,
13}
14
15#[derive(Debug, Clone)]
17pub struct Stmt {
18 pub kind: StmtKind,
19 pub start: Location,
20 pub end: Location,
21}
22
23impl fmt::Display for Stmt {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "{}", self.kind)
26 }
27}
28
29impl From<Block> for Stmt {
30 fn from(value: Block) -> Self {
31 Stmt {
32 start: value.start,
33 end: value.end,
34 kind: StmtKind::Block(Box::new(value)),
35 }
36 }
37}
38
39impl From<Expr> for Stmt {
40 fn from(value: Expr) -> Self {
41 Stmt {
42 start: value.start,
43 end: value.end,
44 kind: StmtKind::Expr(Box::new(value)),
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
51pub enum StmtKind {
52 If {
53 test: Box<Expr>,
54 consequent: Box<Block>,
55 alternate: Option<Box<Stmt>>,
56 },
57 Loop {
58 body: Box<Block>,
59 },
60 While {
61 test: Box<Expr>,
62 body: Box<Block>,
63 },
64 For {
65 left: Vec<Ident>,
66 right: Box<Expr>,
67 body: Box<Block>,
68 },
69 Break,
70 Continue,
71 Return {
72 argument: Box<Expr>,
73 },
74 Throw {
75 argument: Box<Expr>,
76 },
77 Global {
78 arguments: Vec<Ident>,
79 },
80 Import {
81 path: Vec<Ident>,
82 kind: ImportKind,
83 },
84 Assign {
85 left: Box<Expr>,
86 right: Box<Expr>,
87 },
88 AssignOp {
89 operator: BinOp,
90 left: Box<Expr>,
91 right: Box<Expr>,
92 },
93 AssignUnpack {
94 left: Vec<Expr>,
95 right: Box<Expr>,
96 },
97 AssignMulti {
98 left: Vec<Expr>,
99 right: Vec<Expr>,
100 },
101 Block(Box<Block>),
102 Expr(Box<Expr>),
103}
104
105impl fmt::Display for StmtKind {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 match self {
108 StmtKind::If {
109 test,
110 consequent,
111 alternate,
112 } => {
113 if let Some(alternate) = alternate {
114 write!(f, "if {test} {consequent} else {alternate}")
115 } else {
116 write!(f, "if {test} {consequent}")
117 }
118 }
119 StmtKind::Loop { body } => write!(f, "loop {body}"),
120 StmtKind::While { test, body } => write!(f, "while {test} {body}"),
121 StmtKind::For { left, right, body } => {
122 write!(f, "for {} in {right} {body}", left.iter().join(", "))
123 }
124 StmtKind::Break => write!(f, "break"),
125 StmtKind::Continue => write!(f, "continue"),
126 StmtKind::Return { argument } => write!(f, "return {argument}"),
127 StmtKind::Throw { argument } => write!(f, "throw {argument}"),
128 StmtKind::Global { arguments } => write!(f, "global {}", arguments.iter().join(", ")),
129 StmtKind::Import { path, kind } => match kind {
130 ImportKind::Simple(alias) => {
131 write!(f, "import {} as {alias}", path.iter().join("::"))
132 }
133 ImportKind::Nested(v) => write!(
134 f,
135 "import {}::{{{}}}",
136 path.iter().join("::"),
137 v.iter()
138 .map(|(name, alias)| format!("{name} as {alias}"))
139 .join(", ")
140 ),
141 ImportKind::Glob => write!(f, "import {}::*", path.iter().join("::")),
142 },
143 StmtKind::Assign { left, right } => write!(f, "{left} = {right}"),
144 StmtKind::AssignOp {
145 operator,
146 left,
147 right,
148 } => write!(f, "{left} {operator}= {right}"),
149 StmtKind::AssignUnpack { left, right } => {
150 write!(f, "{} = {right}", left.iter().join(", "))
151 }
152 StmtKind::AssignMulti { left, right } => {
153 write!(
154 f,
155 "{} = {}",
156 left.iter().join(", "),
157 right.iter().join(", ")
158 )
159 }
160 StmtKind::Block(block) => write!(f, "{}", block),
161 StmtKind::Expr(expr) => write!(f, "{}", expr),
162 }
163 }
164}
165
166#[derive(Debug, Clone)]
168pub struct Block {
169 pub body: Vec<Stmt>,
170 pub start: Location,
171 pub end: Location,
172}
173
174impl fmt::Display for Block {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 writeln!(f, "{{")?;
177 for stmt in &self.body {
178 writeln!(
179 f,
180 "{}",
181 format!("{}", stmt)
182 .split('\n')
183 .map(|x| format!(" {x}"))
184 .join("\n")
185 )?;
186 }
187 write!(f, "}}")
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct Expr {
194 pub kind: ExprKind,
195 pub start: Location,
196 pub end: Location,
197}
198
199impl fmt::Display for Expr {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 write!(f, "{}", self.kind)
202 }
203}
204
205impl From<Lit> for Expr {
206 fn from(value: Lit) -> Self {
207 Expr {
208 start: value.start,
209 end: value.end,
210 kind: ExprKind::Lit(Box::new(value)),
211 }
212 }
213}
214
215impl From<Ident> for Expr {
216 fn from(value: Ident) -> Self {
217 Expr {
218 start: value.start,
219 end: value.end,
220 kind: ExprKind::Ident(Box::new(value)),
221 }
222 }
223}
224
225#[derive(Debug, Clone)]
227pub enum ExprKind {
228 Lit(Box<Lit>),
229 Ident(Box<Ident>),
230 Function {
231 kind: FunctionKind,
232 params: Vec<Ident>,
233 variadic: Option<Box<Ident>>,
234 body: Box<Block>,
235 },
236 FunctionId(usize),
237 Table {
238 properties: Vec<TableProperty>,
239 },
240 List {
241 items: Vec<Expr>,
242 },
243 Unary {
244 operator: UnOp,
245 argument: Box<Expr>,
246 },
247 Binary {
248 operator: BinOp,
249 left: Box<Expr>,
250 right: Box<Expr>,
251 },
252 Member {
253 table: Box<Expr>,
254 property: Box<Expr>,
255 kind: MemberKind,
256 safe: bool,
257 },
258 MetaMember {
259 table: Box<Expr>,
260 safe: bool,
261 },
262 Call {
263 callee: Box<Expr>,
264 arguments: Vec<Expr>,
265 propagating_error: bool,
266 },
267}
268
269impl fmt::Display for ExprKind {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 match self {
272 ExprKind::Lit(lit) => write!(f, "{lit}"),
273 ExprKind::Ident(ident) => write!(f, "{ident}"),
274 ExprKind::Function {
275 kind,
276 params,
277 variadic,
278 body,
279 } => {
280 if let Some(variadic) = variadic {
281 match kind {
282 FunctionKind::Function => write!(
283 f,
284 "fn ({}, {}) {}",
285 params.iter().join(", "),
286 variadic,
287 body
288 ),
289 FunctionKind::Closure => {
290 write!(f, "|{}, {}| {}", params.iter().join(", "), variadic, body)
291 }
292 FunctionKind::Do => panic!(),
293 }
294 } else {
295 match kind {
296 FunctionKind::Function => {
297 write!(f, "fn ({}) {}", params.iter().join(", "), body)
298 }
299 FunctionKind::Closure => {
300 write!(f, "|{}| {}", params.iter().join(", "), body)
301 }
302 FunctionKind::Do => write!(f, "do {body}"),
303 }
304 }
305 }
306 ExprKind::FunctionId(id) => write!(f, "<function: {id}>"),
307 ExprKind::Table { properties } => {
308 if properties.is_empty() {
309 write!(f, "{{}}")
310 } else {
311 write!(
312 f,
313 "{{\n{}\n}}",
314 properties
315 .iter()
316 .join(",\n")
317 .split('\n')
318 .map(|x| format!(" {x}"))
319 .join("\n")
320 )
321 }
322 }
323 ExprKind::List { items } => {
324 if items.is_empty() {
325 write!(f, "[]")
326 } else {
327 write!(
328 f,
329 "[\n{}\n]",
330 items
331 .iter()
332 .join(",\n")
333 .split('\n')
334 .map(|x| format!(" {x}"))
335 .join("\n")
336 )
337 }
338 }
339 ExprKind::Unary { operator, argument } => write!(f, "{operator} {argument}"),
340 ExprKind::Binary {
341 operator,
342 left,
343 right,
344 } => write!(f, "({left} {operator} {right})"),
345 ExprKind::Member {
346 table,
347 property,
348 kind,
349 safe,
350 } => {
351 if *safe {
352 match kind {
353 MemberKind::Bracket => write!(f, "{table}?[{property}]"),
354 MemberKind::Dot => write!(f, "{table}?.{property}"),
355 MemberKind::DoubleColon => write!(f, "{table}?::{property}"),
356 }
357 } else {
358 match kind {
359 MemberKind::Bracket => write!(f, "{table}[{property}]"),
360 MemberKind::Dot => write!(f, "{table}.{property}"),
361 MemberKind::DoubleColon => write!(f, "{table}::{property}"),
362 }
363 }
364 }
365 ExprKind::MetaMember { table, safe } => {
366 if *safe {
367 write!(f, "{table}?[#]")
368 } else {
369 write!(f, "{table}[#]")
370 }
371 }
372 ExprKind::Call {
373 callee,
374 arguments,
375 propagating_error,
376 } => {
377 if *propagating_error {
378 write!(f, "{callee}({})?", arguments.iter().join(", "))
379 } else {
380 write!(f, "{callee}({})", arguments.iter().join(", "))
381 }
382 }
383 }
384 }
385}
386
387#[derive(Debug, Clone)]
389pub struct Lit {
390 pub value: LitKind,
391 pub start: Location,
392 pub end: Location,
393}
394
395impl fmt::Display for Lit {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 write!(f, "{}", self.value)
398 }
399}
400
401#[derive(Debug, Clone, PartialEq, PartialOrd)]
403pub enum LitKind {
404 Null,
406 Bool(bool),
408 Int(i64),
410 Float(f64),
412 Str(String),
414}
415
416impl fmt::Display for LitKind {
417 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
418 match self {
419 LitKind::Null => write!(f, "null"),
420 LitKind::Bool(v) => write!(f, "{v}"),
421 LitKind::Int(v) => write!(f, "{v}"),
422 LitKind::Float(v) => write!(f, "{v}"),
423 LitKind::Str(v) => write!(f, "\"{}\"", escape_str(v, false)),
424 }
425 }
426}
427
428#[derive(Debug, Clone)]
430pub struct Ident {
431 pub name: String,
432 pub start: Location,
433 pub end: Location,
434}
435
436impl fmt::Display for Ident {
437 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438 write!(f, "{}", self.name)
439 }
440}
441
442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
444pub enum UnOp {
445 Not,
447 Neg,
449}
450
451impl fmt::Display for UnOp {
452 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
453 match self {
454 UnOp::Not => write!(f, "not"),
455 UnOp::Neg => write!(f, "-"),
456 }
457 }
458}
459
460#[derive(Debug, Clone, Copy, PartialEq, Eq)]
462pub enum BinOp {
463 Add,
465 Sub,
467 Mul,
469 Div,
471 Mod,
473 And,
475 Or,
477 Eq,
479 Lt,
481 Le,
483 Ne,
485 Ge,
487 Gt,
489 Is,
491}
492
493impl fmt::Display for BinOp {
494 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495 match self {
496 BinOp::Add => write!(f, "+"),
497 BinOp::Sub => write!(f, "-"),
498 BinOp::Mul => write!(f, "*"),
499 BinOp::Div => write!(f, "/"),
500 BinOp::Mod => write!(f, "%"),
501 BinOp::And => write!(f, "and"),
502 BinOp::Or => write!(f, "or"),
503 BinOp::Eq => write!(f, "=="),
504 BinOp::Lt => write!(f, "<"),
505 BinOp::Le => write!(f, "<="),
506 BinOp::Ne => write!(f, "!="),
507 BinOp::Ge => write!(f, ">"),
508 BinOp::Gt => write!(f, ">="),
509 BinOp::Is => write!(f, "is"),
510 }
511 }
512}
513
514impl BinOp {
515 pub fn precedence(&self) -> u32 {
516 match self {
517 BinOp::Mul => 5,
518 BinOp::Div => 5,
519 BinOp::Mod => 5,
520
521 BinOp::Add => 4,
522 BinOp::Sub => 4,
523
524 BinOp::Eq => 3,
525 BinOp::Lt => 3,
526 BinOp::Le => 3,
527 BinOp::Ne => 3,
528 BinOp::Ge => 3,
529 BinOp::Gt => 3,
530 BinOp::Is => 3,
531
532 BinOp::And => 2,
533
534 BinOp::Or => 1,
535 }
536 }
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq)]
541pub enum MemberKind {
542 Bracket,
544 Dot,
546 DoubleColon,
548}
549
550#[derive(Debug, Clone)]
552pub enum ImportKind {
553 Simple(Box<Ident>),
555 Nested(Vec<(Ident, Ident)>),
557 Glob,
559}
560
561#[derive(Debug, Clone)]
563pub struct TableProperty {
564 pub key: Box<Expr>,
565 pub value: Box<Expr>,
566 pub start: Location,
567 pub end: Location,
568}
569
570impl fmt::Display for TableProperty {
571 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 write!(f, "{}: {}", self.key, self.value)
573 }
574}