|
| 1 | +use core::str; |
1 | 2 | use std::{
|
| 3 | + borrow::Cow, |
2 | 4 | env,
|
3 | 5 | fs::{self, File},
|
4 | 6 | io::Write,
|
| 7 | + ops::Deref, |
5 | 8 | process::Command,
|
6 | 9 | };
|
7 | 10 |
|
8 | 11 | //use bevy::asset::FileAssetIo;
|
9 | 12 | use bevy::asset::io::file::FileAssetReader;
|
10 | 13 | use bevy_mod_scripting_core::prelude::*;
|
11 |
| -use tealr::{TypeGenerator, TypeWalker}; |
| 14 | +use tealr::{NameContainer, TypeGenerator, TypeWalker}; |
12 | 15 |
|
13 | 16 | pub type TypeWalkerBuilder = fn(TypeWalker) -> TypeWalker;
|
14 | 17 |
|
@@ -97,7 +100,24 @@ impl DocFragment for LuaDocFragment {
|
97 | 100 | // fixes bug in tealr which causes syntax errors in teal due to duplicate fields (from having both getters and setters)
|
98 | 101 | tw.given_types.iter_mut().for_each(|tg| {
|
99 | 102 | if let TypeGenerator::Record(rg) = tg {
|
| 103 | + rg.fields |
| 104 | + .sort_by(|f1, f2| f1.name.deref().cmp(&f2.name.deref())); |
100 | 105 | rg.fields.dedup_by(|a, b| a.name == b.name);
|
| 106 | + rg.static_fields |
| 107 | + .sort_by(|f1, f2| f1.name.deref().cmp(&f2.name.deref())); |
| 108 | + rg.static_fields.dedup_by(|a, b| a.name == b.name); |
| 109 | + for field in rg.fields.iter_mut().chain(rg.static_fields.iter_mut()) { |
| 110 | + escape_name(&mut field.name); |
| 111 | + } |
| 112 | + for func in rg |
| 113 | + .functions |
| 114 | + .iter_mut() |
| 115 | + .chain(rg.mut_functions.iter_mut()) |
| 116 | + .chain(rg.methods.iter_mut()) |
| 117 | + .chain(rg.mut_methods.iter_mut()) |
| 118 | + { |
| 119 | + escape_name(&mut func.name); |
| 120 | + } |
101 | 121 | }
|
102 | 122 | });
|
103 | 123 |
|
@@ -172,3 +192,36 @@ impl DocFragment for LuaDocFragment {
|
172 | 192 | Ok(())
|
173 | 193 | }
|
174 | 194 | }
|
| 195 | + |
| 196 | +/// Escapes a name of a table field, if that table field is a reserved keyword. |
| 197 | +/// |
| 198 | +/// ## Background |
| 199 | +/// |
| 200 | +/// String keys in a Lua table are allowed to be anything, even reserved |
| 201 | +/// keywords. By default when tealr generates the type definition for a table |
| 202 | +/// field, the string it generates is `{name} : {type}`. This causes a syntax |
| 203 | +/// error when writing a bare keyword, since `nil : {type}` is considered trying |
| 204 | +/// to add a type to the *value* nil (which is invalid). |
| 205 | +/// |
| 206 | +/// To get around this tealr allows us to escape table fields using the |
| 207 | +/// `["{name}"] : {value}` syntax. This function detects if a name is one of the |
| 208 | +/// Lua reserved words and fixes it if so. |
| 209 | +fn escape_name(raw: &mut NameContainer) { |
| 210 | + // List of Lua reserved keywords |
| 211 | + const KEYWORD_FIELDS: &[&str] = &[ |
| 212 | + "false", "true", "nil", // Values |
| 213 | + "and", "not", "or", // Operators |
| 214 | + "if", "then", "else", "elseif", "end", // If-Else |
| 215 | + "for", "in", "break", "do", "repeat", "until", "while", // Loops |
| 216 | + "function", "return", // Funcs |
| 217 | + "local", // Declarations |
| 218 | + "record", // Teal extra |
| 219 | + ]; |
| 220 | + let Ok(name) = str::from_utf8(&raw) else { |
| 221 | + return; |
| 222 | + }; |
| 223 | + if KEYWORD_FIELDS.contains(&name) { |
| 224 | + let mapped = format!("[\"{name}\"]"); |
| 225 | + *raw = NameContainer::from(Cow::Owned(mapped)); |
| 226 | + } |
| 227 | +} |
0 commit comments