1#![doc = include_str!("readme.md")]
2use core::range::Range;
3use oak_core::source::{SourceBuffer, ToSource};
4#[cfg(feature = "oak-pretty-print")]
5use oak_pretty_print::{AsDocument, Document};
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub struct LuaRoot {
13 pub statements: Vec<LuaStatement>,
14 #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
15 pub span: Range<usize>,
16}
17
18impl ToSource for LuaRoot {
19 fn to_source(&self, buffer: &mut SourceBuffer) {
20 for stmt in &self.statements {
21 stmt.to_source(buffer);
22 buffer.push("\n")
23 }
24 }
25}
26
27#[cfg(feature = "oak-pretty-print")]
28impl AsDocument for LuaRoot {
29 fn as_document(&self) -> Document<'_> {
30 Document::join(self.statements.iter().map(|s| s.as_document()), Document::Line)
31 }
32}
33
34#[derive(Debug, Clone)]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37pub enum LuaStatement {
38 Local(LuaLocalStatement),
39 Assignment(LuaAssignmentStatement),
40 Expression(LuaExpression),
41 Return(LuaReturnStatement),
42 If(LuaIfStatement),
43 While(LuaWhileStatement),
44 For(LuaForStatement),
45 Repeat(LuaRepeatStatement),
46 Function(LuaFunctionStatement),
47 Break,
48 Do(Vec<LuaStatement>),
49 Goto(String),
50 Label(String),
51}
52
53impl ToSource for LuaStatement {
54 fn to_source(&self, buffer: &mut SourceBuffer) {
55 match self {
56 LuaStatement::Local(s) => s.to_source(buffer),
57 LuaStatement::Assignment(s) => s.to_source(buffer),
58 LuaStatement::Expression(e) => e.to_source(buffer),
59 LuaStatement::Return(s) => s.to_source(buffer),
60 LuaStatement::If(s) => s.to_source(buffer),
61 LuaStatement::While(s) => s.to_source(buffer),
62 LuaStatement::For(s) => s.to_source(buffer),
63 LuaStatement::Repeat(s) => s.to_source(buffer),
64 LuaStatement::Function(s) => s.to_source(buffer),
65 LuaStatement::Break => buffer.push("break"),
66 LuaStatement::Do(stmts) => {
67 buffer.push("do\n");
68 for stmt in stmts {
69 stmt.to_source(buffer);
70 buffer.push("\n")
71 }
72 buffer.push("end")
73 }
74 LuaStatement::Goto(label) => {
75 buffer.push("goto ");
76 buffer.push(label)
77 }
78 LuaStatement::Label(name) => {
79 buffer.push("::");
80 buffer.push(name);
81 buffer.push("::")
82 }
83 }
84 }
85}
86
87#[cfg(feature = "oak-pretty-print")]
88impl AsDocument for LuaStatement {
89 fn as_document(&self) -> Document<'_> {
90 let mut buffer = SourceBuffer::new();
91 self.to_source(&mut buffer);
92 Document::Text(buffer.finish().into())
93 }
94}
95
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98#[derive(Debug, Clone)]
99pub struct LuaLocalStatement {
100 pub names: Vec<String>,
101 pub values: Vec<LuaExpression>,
102}
103
104impl ToSource for LuaLocalStatement {
105 fn to_source(&self, buffer: &mut SourceBuffer) {
106 buffer.push("local ");
107 for (i, name) in self.names.iter().enumerate() {
108 if i > 0 {
109 buffer.push(", ")
110 }
111 buffer.push(name)
112 }
113 if !self.values.is_empty() {
114 buffer.push(" = ");
115 for (i, val) in self.values.iter().enumerate() {
116 if i > 0 {
117 buffer.push(", ")
118 }
119 val.to_source(buffer)
120 }
121 }
122 }
123}
124
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[derive(Debug, Clone)]
128pub struct LuaAssignmentStatement {
129 pub targets: Vec<LuaExpression>,
130 pub values: Vec<LuaExpression>,
131}
132
133impl ToSource for LuaAssignmentStatement {
134 fn to_source(&self, buffer: &mut SourceBuffer) {
135 for (i, target) in self.targets.iter().enumerate() {
136 if i > 0 {
137 buffer.push(", ")
138 }
139 target.to_source(buffer)
140 }
141 buffer.push(" = ");
142 for (i, val) in self.values.iter().enumerate() {
143 if i > 0 {
144 buffer.push(", ")
145 }
146 val.to_source(buffer)
147 }
148 }
149}
150
151#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
153#[derive(Debug, Clone)]
154pub struct LuaReturnStatement {
155 pub values: Vec<LuaExpression>,
156}
157
158impl ToSource for LuaReturnStatement {
159 fn to_source(&self, buffer: &mut SourceBuffer) {
160 buffer.push("return ");
161 for (i, val) in self.values.iter().enumerate() {
162 if i > 0 {
163 buffer.push(", ")
164 }
165 val.to_source(buffer)
166 }
167 }
168}
169
170#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172#[derive(Debug, Clone)]
173pub struct LuaIfStatement {
174 pub condition: LuaExpression,
175 pub then_block: Vec<LuaStatement>,
176 pub else_ifs: Vec<(LuaExpression, Vec<LuaStatement>)>,
177 pub else_block: Option<Vec<LuaStatement>>,
178}
179
180impl ToSource for LuaIfStatement {
181 fn to_source(&self, buffer: &mut SourceBuffer) {
182 buffer.push("if ");
183 self.condition.to_source(buffer);
184 buffer.push(" then\n");
185 for stmt in &self.then_block {
186 stmt.to_source(buffer);
187 buffer.push("\n")
188 }
189 for (cond, block) in &self.else_ifs {
190 buffer.push("elseif ");
191 cond.to_source(buffer);
192 buffer.push(" then\n");
193 for stmt in block {
194 stmt.to_source(buffer);
195 buffer.push("\n")
196 }
197 }
198 if let Some(block) = &self.else_block {
199 buffer.push("else\n");
200 for stmt in block {
201 stmt.to_source(buffer);
202 buffer.push("\n")
203 }
204 }
205 buffer.push("end")
206 }
207}
208
209#[derive(Debug, Clone)]
211#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
212pub struct LuaWhileStatement {
213 pub condition: LuaExpression,
214 pub block: Vec<LuaStatement>,
215}
216
217impl ToSource for LuaWhileStatement {
218 fn to_source(&self, buffer: &mut SourceBuffer) {
219 buffer.push("while ");
220 self.condition.to_source(buffer);
221 buffer.push(" do\n");
222 for stmt in &self.block {
223 stmt.to_source(buffer);
224 buffer.push("\n")
225 }
226 buffer.push("end")
227 }
228}
229
230#[derive(Debug, Clone)]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233pub enum LuaForStatement {
234 Numeric { variable: String, start: LuaExpression, end: LuaExpression, step: Option<LuaExpression>, block: Vec<LuaStatement> },
235 Generic { variables: Vec<String>, iterators: Vec<LuaExpression>, block: Vec<LuaStatement> },
236}
237
238impl ToSource for LuaForStatement {
239 fn to_source(&self, buffer: &mut SourceBuffer) {
240 match self {
241 LuaForStatement::Numeric { variable, start, end, step, block } => {
242 buffer.push("for ");
243 buffer.push(variable);
244 buffer.push(" = ");
245 start.to_source(buffer);
246 buffer.push(", ");
247 end.to_source(buffer);
248 if let Some(s) = step {
249 buffer.push(", ");
250 s.to_source(buffer)
251 }
252 buffer.push(" do\n");
253 for stmt in block {
254 stmt.to_source(buffer);
255 buffer.push("\n")
256 }
257 buffer.push("end")
258 }
259 LuaForStatement::Generic { variables, iterators, block } => {
260 buffer.push("for ");
261 for (i, var) in variables.iter().enumerate() {
262 if i > 0 {
263 buffer.push(", ")
264 }
265 buffer.push(var)
266 }
267 buffer.push(" in ");
268 for (i, it) in iterators.iter().enumerate() {
269 if i > 0 {
270 buffer.push(", ")
271 }
272 it.to_source(buffer)
273 }
274 buffer.push(" do\n");
275 for stmt in block {
276 stmt.to_source(buffer);
277 buffer.push("\n")
278 }
279 buffer.push("end")
280 }
281 }
282 }
283}
284
285#[derive(Debug, Clone)]
287#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
288pub struct LuaRepeatStatement {
289 pub block: Vec<LuaStatement>,
290 pub condition: LuaExpression,
291}
292
293impl ToSource for LuaRepeatStatement {
294 fn to_source(&self, buffer: &mut SourceBuffer) {
295 buffer.push("repeat\n");
296 for stmt in &self.block {
297 stmt.to_source(buffer);
298 buffer.push("\n")
299 }
300 buffer.push("until ");
301 self.condition.to_source(buffer)
302 }
303}
304
305#[derive(Debug, Clone)]
307#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
308pub struct LuaFunctionStatement {
309 pub name: Vec<String>,
310 pub receiver: Option<String>,
311 pub parameters: Vec<String>,
312 pub is_vararg: bool,
313 pub block: Vec<LuaStatement>,
314}
315
316impl ToSource for LuaFunctionStatement {
317 fn to_source(&self, buffer: &mut SourceBuffer) {
318 buffer.push("function ");
319 for (i, part) in self.name.iter().enumerate() {
320 if i > 0 {
321 buffer.push(".")
322 }
323 buffer.push(part)
324 }
325 if let Some(recv) = &self.receiver {
326 buffer.push(":");
327 buffer.push(recv)
328 }
329 buffer.push("(");
330 for (i, param) in self.parameters.iter().enumerate() {
331 if i > 0 {
332 buffer.push(", ")
333 }
334 buffer.push(param)
335 }
336 if self.is_vararg {
337 if !self.parameters.is_empty() {
338 buffer.push(", ")
339 }
340 buffer.push("...")
341 }
342 buffer.push(")\n");
343 for stmt in &self.block {
344 stmt.to_source(buffer);
345 buffer.push("\n")
346 }
347 buffer.push("end")
348 }
349}
350
351#[derive(Debug, Clone)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354pub enum LuaExpression {
355 Identifier(String),
356 Number(f64),
357 String(String),
358 Boolean(bool),
359 Nil,
360 Binary(Box<LuaBinaryExpression>),
361 Unary(Box<LuaUnaryExpression>),
362 Call(Box<LuaCallExpression>),
363 Table(LuaTableConstructor),
364 Function(LuaFunctionExpression),
365 Index(Box<LuaIndexExpression>),
366 Member(Box<LuaMemberExpression>),
367 Vararg,
368}
369
370impl ToSource for LuaExpression {
371 fn to_source(&self, buffer: &mut SourceBuffer) {
372 match self {
373 LuaExpression::Identifier(id) => buffer.push(id),
374 LuaExpression::Number(n) => buffer.push(&n.to_string()),
375 LuaExpression::String(s) => {
376 buffer.push("\"");
377 buffer.push(s);
378 buffer.push("\"")
379 }
380 LuaExpression::Boolean(b) => buffer.push(if *b { "true" } else { "false" }),
381 LuaExpression::Nil => buffer.push("nil"),
382 LuaExpression::Binary(bin) => bin.to_source(buffer),
383 LuaExpression::Unary(un) => un.to_source(buffer),
384 LuaExpression::Call(call) => call.to_source(buffer),
385 LuaExpression::Table(table) => table.to_source(buffer),
386 LuaExpression::Function(func) => func.to_source(buffer),
387 LuaExpression::Index(idx) => idx.to_source(buffer),
388 LuaExpression::Member(mem) => mem.to_source(buffer),
389 LuaExpression::Vararg => buffer.push("..."),
390 }
391 }
392}
393
394#[cfg(feature = "oak-pretty-print")]
395impl AsDocument for LuaExpression {
396 fn as_document(&self) -> Document<'_> {
397 let mut buffer = SourceBuffer::new();
398 self.to_source(&mut buffer);
399 Document::Text(buffer.finish().into())
400 }
401}
402
403#[derive(Debug, Clone)]
405#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
406pub struct LuaUnaryExpression {
407 pub op: String,
408 pub operand: LuaExpression,
409}
410
411impl ToSource for LuaUnaryExpression {
412 fn to_source(&self, buffer: &mut SourceBuffer) {
413 buffer.push(&self.op);
414 self.operand.to_source(buffer)
415 }
416}
417
418#[derive(Debug, Clone)]
420#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
421pub struct LuaBinaryExpression {
422 pub left: LuaExpression,
423 pub op: String,
424 pub right: LuaExpression,
425}
426
427impl ToSource for LuaBinaryExpression {
428 fn to_source(&self, buffer: &mut SourceBuffer) {
429 self.left.to_source(buffer);
430 buffer.push(" ");
431 buffer.push(&self.op);
432 buffer.push(" ");
433 self.right.to_source(buffer)
434 }
435}
436
437#[derive(Debug, Clone)]
439#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
440pub struct LuaCallExpression {
441 pub function: LuaExpression,
442 pub arguments: Vec<LuaExpression>,
443}
444
445impl ToSource for LuaCallExpression {
446 fn to_source(&self, buffer: &mut SourceBuffer) {
447 self.function.to_source(buffer);
448 buffer.push("(");
449 for (i, arg) in self.arguments.iter().enumerate() {
450 if i > 0 {
451 buffer.push(", ")
452 }
453 arg.to_source(buffer)
454 }
455 buffer.push(")")
456 }
457}
458
459#[derive(Debug, Clone)]
461#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
462pub struct LuaTableConstructor {
463 pub fields: Vec<LuaTableField>,
464}
465
466impl ToSource for LuaTableConstructor {
467 fn to_source(&self, buffer: &mut SourceBuffer) {
468 buffer.push("{");
469 for (i, field) in self.fields.iter().enumerate() {
470 if i > 0 {
471 buffer.push(", ")
472 }
473 field.to_source(buffer)
474 }
475 buffer.push("}")
476 }
477}
478
479#[derive(Debug, Clone)]
480#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
481pub enum LuaTableField {
482 Keyed { key: LuaExpression, value: LuaExpression },
483 Named { name: String, value: LuaExpression },
484 List { value: LuaExpression },
485}
486
487impl ToSource for LuaTableField {
488 fn to_source(&self, buffer: &mut SourceBuffer) {
489 match self {
490 LuaTableField::Keyed { key, value } => {
491 buffer.push("[");
492 key.to_source(buffer);
493 buffer.push("] = ");
494 value.to_source(buffer)
495 }
496 LuaTableField::Named { name, value } => {
497 buffer.push(name);
498 buffer.push(" = ");
499 value.to_source(buffer)
500 }
501 LuaTableField::List { value } => value.to_source(buffer),
502 }
503 }
504}
505
506#[derive(Debug, Clone)]
508#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
509pub struct LuaFunctionExpression {
510 pub parameters: Vec<String>,
511 pub is_vararg: bool,
512 pub block: Vec<LuaStatement>,
513}
514
515impl ToSource for LuaFunctionExpression {
516 fn to_source(&self, buffer: &mut SourceBuffer) {
517 buffer.push("function(");
518 for (i, param) in self.parameters.iter().enumerate() {
519 if i > 0 {
520 buffer.push(", ")
521 }
522 buffer.push(param)
523 }
524 if self.is_vararg {
525 if !self.parameters.is_empty() {
526 buffer.push(", ")
527 }
528 buffer.push("...")
529 }
530 buffer.push(")\n");
531 for stmt in &self.block {
532 stmt.to_source(buffer);
533 buffer.push("\n")
534 }
535 buffer.push("end")
536 }
537}
538
539#[derive(Debug, Clone)]
541#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
542pub struct LuaIndexExpression {
543 pub table: LuaExpression,
544 pub index: LuaExpression,
545}
546
547impl ToSource for LuaIndexExpression {
548 fn to_source(&self, buffer: &mut SourceBuffer) {
549 self.table.to_source(buffer);
550 buffer.push("[");
551 self.index.to_source(buffer);
552 buffer.push("]")
553 }
554}
555
556#[derive(Debug, Clone)]
558#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
559pub struct LuaMemberExpression {
560 pub table: LuaExpression,
561 pub member: String,
562 pub is_method: bool,
563}
564
565impl ToSource for LuaMemberExpression {
566 fn to_source(&self, buffer: &mut SourceBuffer) {
567 self.table.to_source(buffer);
568 if self.is_method {
569 buffer.push(":")
570 }
571 else {
572 buffer.push(".")
573 }
574 buffer.push(&self.member)
575 }
576}