aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes3
-rw-r--r--doc/docs/.vitepress/config.mts35
-rw-r--r--doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.pngbin0 -> 309025 bytes
-rw-r--r--doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zipbin0 -> 10132610 bytes
-rw-r--r--doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.pngbin0 -> 3464576 bytes
-rw-r--r--doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.pngbin0 -> 3199600 bytes
-rw-r--r--doc/docs/.vitepress/theme/components/prism-manual.js1
-rw-r--r--doc/docs/.vitepress/theme/custom.css32
-rw-r--r--doc/docs/de/doc/advanced/the-yuescript-library.md (renamed from doc/docs/de/doc/reference/the-yuescript-library.md)0
-rw-r--r--doc/docs/de/doc/extras/license-mit.md (renamed from doc/docs/de/doc/reference/license-mit.md)0
-rw-r--r--doc/docs/de/doc/extras/mascot.md39
-rw-r--r--doc/docs/de/index.md2
-rw-r--r--doc/docs/doc/advanced/the-yuescript-library.md (renamed from doc/docs/doc/reference/the-yuescript-library.md)0
-rw-r--r--doc/docs/doc/extras/license-mit.md (renamed from doc/docs/doc/reference/license-mit.md)0
-rw-r--r--doc/docs/doc/extras/mascot.md39
-rw-r--r--doc/docs/id-id/doc/advanced/the-yuescript-library.md (renamed from doc/docs/id-id/doc/reference/the-yuescript-library.md)0
-rw-r--r--doc/docs/id-id/doc/extras/license-mit.md (renamed from doc/docs/id-id/doc/reference/license-mit.md)0
-rw-r--r--doc/docs/id-id/doc/extras/mascot.md39
-rw-r--r--doc/docs/id-id/index.md2
-rw-r--r--doc/docs/index.md2
-rw-r--r--doc/docs/pt-br/doc/advanced/the-yuescript-library.md (renamed from doc/docs/pt-br/doc/reference/the-yuescript-library.md)0
-rw-r--r--doc/docs/pt-br/doc/extras/license-mit.md (renamed from doc/docs/pt-br/doc/reference/license-mit.md)0
-rw-r--r--doc/docs/pt-br/doc/extras/mascot.md39
-rw-r--r--doc/docs/pt-br/index.md2
-rw-r--r--doc/docs/zh/doc/advanced/the-yuescript-library.md (renamed from doc/docs/zh/doc/reference/the-yuescript-library.md)0
-rw-r--r--doc/docs/zh/doc/extras/license-mit.md (renamed from doc/docs/zh/doc/reference/license-mit.md)0
-rw-r--r--doc/docs/zh/doc/extras/mascot.md39
-rw-r--r--doc/docs/zh/index.md2
-rwxr-xr-xspec/cli/cli_test_helper.sh27
-rwxr-xr-xspec/cli/run_all_tests.sh1
-rwxr-xr-xspec/cli/test_reserve_comments.sh189
-rw-r--r--spec/inputs/compile_doc.yue2
-rw-r--r--spec/inputs/luarocks_upload.yue64
-rw-r--r--spec/inputs/test/reserve_comments_spec.yue413
-rw-r--r--spec/inputs/whitespace.yue39
-rw-r--r--spec/outputs/compile_doc.lua2
-rw-r--r--spec/outputs/luarocks_upload.lua25
-rw-r--r--spec/outputs/test/reserve_comments_spec.lua471
-rw-r--r--spec/outputs/whitespace.lua33
-rw-r--r--src/yuescript/yue_compiler.cpp11
-rw-r--r--src/yuescript/yue_parser.cpp45
-rw-r--r--src/yuescript/yue_parser.h1
-rw-r--r--yuescript-dev-1.rockspec5
43 files changed, 1537 insertions, 67 deletions
diff --git a/.gitattributes b/.gitattributes
index f0f3b61..efb0469 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,6 @@
1src/3rdParty/** linguist-vendored 1src/3rdParty/** linguist-vendored
2spec/lib/** linguist-vendored 2spec/lib/** linguist-vendored
3win-build/** linguist-vendored 3win-build/** linguist-vendored
4spec/ export-ignore
5doc/ export-ignore
6.github/ export-ignore \ No newline at end of file
diff --git a/doc/docs/.vitepress/config.mts b/doc/docs/.vitepress/config.mts
index 872791c..5a04667 100644
--- a/doc/docs/.vitepress/config.mts
+++ b/doc/docs/.vitepress/config.mts
@@ -64,6 +64,7 @@ const sidebarText = {
64 functionStubs: "Funktions-Stubs", 64 functionStubs: "Funktions-Stubs",
65 usingClause: "Die Using-Klausel; Kontrolle destruktiver Zuweisung", 65 usingClause: "Die Using-Klausel; Kontrolle destruktiver Zuweisung",
66 yuescriptLibrary: "Die YueScript-Bibliothek", 66 yuescriptLibrary: "Die YueScript-Bibliothek",
67 mascot: "Maskottchen – Xiaoyu",
67 licenseMit: "Lizenz: MIT", 68 licenseMit: "Lizenz: MIT",
68 }, 69 },
69 en: { 70 en: {
@@ -99,6 +100,7 @@ const sidebarText = {
99 functionStubs: "Function Stubs", 100 functionStubs: "Function Stubs",
100 usingClause: "The Using Clause; Controlling Destructive Assignment", 101 usingClause: "The Using Clause; Controlling Destructive Assignment",
101 yuescriptLibrary: "The YueScript Library", 102 yuescriptLibrary: "The YueScript Library",
103 mascot: "Mascot - Xiaoyu",
102 licenseMit: "License: MIT", 104 licenseMit: "License: MIT",
103 }, 105 },
104 idId: { 106 idId: {
@@ -134,6 +136,7 @@ const sidebarText = {
134 functionStubs: "Fungsi Sementara", 136 functionStubs: "Fungsi Sementara",
135 usingClause: "Klausa Using; Mengontrol Penugasan Destruktif", 137 usingClause: "Klausa Using; Mengontrol Penugasan Destruktif",
136 yuescriptLibrary: "Pustaka YueScript", 138 yuescriptLibrary: "Pustaka YueScript",
139 mascot: "Maskot – Xiaoyu",
137 licenseMit: "Lisensi: MIT", 140 licenseMit: "Lisensi: MIT",
138 }, 141 },
139 ptBr: { 142 ptBr: {
@@ -169,6 +172,7 @@ const sidebarText = {
169 functionStubs: "Stubs de função", 172 functionStubs: "Stubs de função",
170 usingClause: "Cláusula using; controlando atribuição destrutiva", 173 usingClause: "Cláusula using; controlando atribuição destrutiva",
171 yuescriptLibrary: "A biblioteca do YueScript", 174 yuescriptLibrary: "A biblioteca do YueScript",
175 mascot: "Mascote – Xiaoyu",
172 licenseMit: "Licença: MIT", 176 licenseMit: "Licença: MIT",
173 }, 177 },
174 zh: { 178 zh: {
@@ -204,6 +208,7 @@ const sidebarText = {
204 functionStubs: "函数存根", 208 functionStubs: "函数存根",
205 usingClause: "使用 using 语句:防止破坏性赋值", 209 usingClause: "使用 using 语句:防止破坏性赋值",
206 yuescriptLibrary: "月之脚本语言库", 210 yuescriptLibrary: "月之脚本语言库",
211 mascot: "吉祥物 – 小玉",
207 licenseMit: "MIT 许可证", 212 licenseMit: "MIT 许可证",
208 }, 213 },
209} as const; 214} as const;
@@ -219,7 +224,7 @@ type SidebarGroupText = {
219 dataStructures: string; 224 dataStructures: string;
220 objects: string; 225 objects: string;
221 advancedFeatures: string; 226 advancedFeatures: string;
222 reference: string; 227 extras: string;
223}; 228};
224 229
225const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = { 230const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
@@ -232,7 +237,7 @@ const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
232 dataStructures: "Datenstrukturen", 237 dataStructures: "Datenstrukturen",
233 objects: "Objekte", 238 objects: "Objekte",
234 advancedFeatures: "Erweiterte Funktionen", 239 advancedFeatures: "Erweiterte Funktionen",
235 reference: "Referenz", 240 extras: "Extras",
236 }, 241 },
237 en: { 242 en: {
238 gettingStarted: "Getting Started", 243 gettingStarted: "Getting Started",
@@ -243,7 +248,7 @@ const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
243 dataStructures: "Data Structures", 248 dataStructures: "Data Structures",
244 objects: "Objects", 249 objects: "Objects",
245 advancedFeatures: "Advanced Features", 250 advancedFeatures: "Advanced Features",
246 reference: "Reference", 251 extras: "Extras",
247 }, 252 },
248 idId: { 253 idId: {
249 gettingStarted: "Memulai", 254 gettingStarted: "Memulai",
@@ -254,7 +259,7 @@ const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
254 dataStructures: "Struktur Data", 259 dataStructures: "Struktur Data",
255 objects: "Objek", 260 objects: "Objek",
256 advancedFeatures: "Fitur Lanjutan", 261 advancedFeatures: "Fitur Lanjutan",
257 reference: "Referensi", 262 extras: "Ekstra",
258 }, 263 },
259 ptBr: { 264 ptBr: {
260 gettingStarted: "Primeiros passos", 265 gettingStarted: "Primeiros passos",
@@ -265,7 +270,7 @@ const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
265 dataStructures: "Estruturas de dados", 270 dataStructures: "Estruturas de dados",
266 objects: "Objetos", 271 objects: "Objetos",
267 advancedFeatures: "Recursos avançados", 272 advancedFeatures: "Recursos avançados",
268 reference: "Referência", 273 extras: "Extras",
269 }, 274 },
270 zh: { 275 zh: {
271 gettingStarted: "起步", 276 gettingStarted: "起步",
@@ -276,7 +281,7 @@ const sidebarGroups: Record<SidebarLocale, SidebarGroupText> = {
276 dataStructures: "数据结构", 281 dataStructures: "数据结构",
277 objects: "面向对象", 282 objects: "面向对象",
278 advancedFeatures: "高级特性", 283 advancedFeatures: "高级特性",
279 reference: "", 284 extras: "",
280 }, 285 },
281}; 286};
282 287
@@ -414,17 +419,18 @@ function createSidebar(basePath: string, locale: SidebarLocale) {
414 }, 419 },
415 { text: text.do, link: `${basePath}/advanced/do` }, 420 { text: text.do, link: `${basePath}/advanced/do` },
416 { text: text.try, link: `${basePath}/advanced/try` }, 421 { text: text.try, link: `${basePath}/advanced/try` },
422 {
423 text: text.yuescriptLibrary,
424 link: `${basePath}/advanced/the-yuescript-library`,
425 },
417 ], 426 ],
418 }, 427 },
419 { 428 {
420 text: group.reference, 429 text: group.extras,
421 collapsed: true, 430 collapsed: true,
422 items: [ 431 items: [
423 { 432 { text: text.mascot, link: `${basePath}/extras/mascot` },
424 text: text.yuescriptLibrary, 433 { text: text.licenseMit, link: `${basePath}/extras/license-mit` },
425 link: `${basePath}/reference/the-yuescript-library`,
426 },
427 { text: text.licenseMit, link: `${basePath}/reference/license-mit` },
428 ], 434 ],
429 }, 435 },
430 ]; 436 ];
@@ -450,7 +456,10 @@ export default defineConfig({
450 }, 456 },
451 ], 457 ],
452 ["meta", { property: "og:type", content: "website" }], 458 ["meta", { property: "og:type", content: "website" }],
453 ["meta", { property: "og:image", content: withBase("/image/yuescript.png") }], 459 [
460 "meta",
461 { property: "og:image", content: withBase("/image/yuescript.png") },
462 ],
454 [ 463 [
455 "meta", 464 "meta",
456 { 465 {
diff --git a/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
new file mode 100644
index 0000000..4c5ff87
--- /dev/null
+++ b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
Binary files differ
diff --git a/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip
new file mode 100644
index 0000000..e84ff36
--- /dev/null
+++ b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip
Binary files differ
diff --git a/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png
new file mode 100644
index 0000000..fdf8475
--- /dev/null
+++ b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png
Binary files differ
diff --git a/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png
new file mode 100644
index 0000000..90e4f47
--- /dev/null
+++ b/doc/docs/.vitepress/public/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png
Binary files differ
diff --git a/doc/docs/.vitepress/theme/components/prism-manual.js b/doc/docs/.vitepress/theme/components/prism-manual.js
index 8f73abd..076dcf3 100644
--- a/doc/docs/.vitepress/theme/components/prism-manual.js
+++ b/doc/docs/.vitepress/theme/components/prism-manual.js
@@ -4,4 +4,3 @@ if (typeof window !== "undefined") {
4 window.Prism = window.Prism || {}; 4 window.Prism = window.Prism || {};
5 window.Prism.manual = true; 5 window.Prism.manual = true;
6} 6}
7
diff --git a/doc/docs/.vitepress/theme/custom.css b/doc/docs/.vitepress/theme/custom.css
index 4050784..7e3a04b 100644
--- a/doc/docs/.vitepress/theme/custom.css
+++ b/doc/docs/.vitepress/theme/custom.css
@@ -40,16 +40,36 @@
40 --vp-c-text-2: #4a5568; 40 --vp-c-text-2: #4a5568;
41} 41}
42 42
43/* Hero image - enlarge container to fit 450px image without overflow */ 43/* Hero image - adjust container to fit mascot artwork without overflow */
44@media (min-width: 960px) { 44@media (min-width: 960px) {
45 .VPHero .image-container { 45 .VPHero .image-container {
46 width: 450px !important; 46 width: 420px !important;
47 }
48
49 .VPHero .image-src {
50 margin-top: 2.7rem !important;
51 padding-bottom: 2.7rem !important;
47 } 52 }
48} 53}
49 54
50.VPHero :deep(.image-src) { 55@media (max-width: 960px) {
51 max-width: 450px; 56 .VPHero .image-src {
52 max-height: 450px; 57 margin-top: 1rem !important;
58 padding-bottom: 3.2rem !important;
59 }
60}
61
62@media (max-width: 639px) {
63 .VPHero .image-src {
64 margin-top: 3.2rem !important;
65 padding-bottom: 7.4rem !important;
66 }
67}
68
69.VPHero .image-src {
70 max-width: 420px;
71 max-height: 360px;
72 object-fit: contain;
53} 73}
54 74
55/* --- DARK MODE THEME (Midnight Blue) --- */ 75/* --- DARK MODE THEME (Midnight Blue) --- */
@@ -221,4 +241,4 @@ h6,
221/* Slight adjustment to code block background to fit the midnight theme */ 241/* Slight adjustment to code block background to fit the midnight theme */
222.dark .vp-code-group .tabs label { 242.dark .vp-code-group .tabs label {
223 background-color: #1a1f2e; 243 background-color: #1a1f2e;
224} \ No newline at end of file 244}
diff --git a/doc/docs/de/doc/reference/the-yuescript-library.md b/doc/docs/de/doc/advanced/the-yuescript-library.md
index 0c371bf..0c371bf 100644
--- a/doc/docs/de/doc/reference/the-yuescript-library.md
+++ b/doc/docs/de/doc/advanced/the-yuescript-library.md
diff --git a/doc/docs/de/doc/reference/license-mit.md b/doc/docs/de/doc/extras/license-mit.md
index a5e9f70..a5e9f70 100644
--- a/doc/docs/de/doc/reference/license-mit.md
+++ b/doc/docs/de/doc/extras/license-mit.md
diff --git a/doc/docs/de/doc/extras/mascot.md b/doc/docs/de/doc/extras/mascot.md
new file mode 100644
index 0000000..ad0e982
--- /dev/null
+++ b/doc/docs/de/doc/extras/mascot.md
@@ -0,0 +1,39 @@
1# Maskottchen – Xiaoyu
2
3## Über
4
5<img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png" alt="Xiaoyu das Cyber-Kaninchen" style="max-width: 420px; width: 100%; border-radius: 12px; margin-bottom: 1.5em;" />
6
7Xiaoyu (小玉, „kleines Jade") ist ein Cyber-Kaninchen und das offizielle Maskottchen des YueScript-Projekts. Man findet sie meistens auf einer Mondsichel sitzend, an ihrem Laptop tüftelnd – natürlich YueScript schreibend.
8
9Ihr vollständiger Titel ist Xiaoyu das Cyber-Kaninchen (机兔小玉), und sie verkörpert alles, was YueScript sein möchte: elegant, ausdrucksstark und ein kleines bisschen verspielt.
10
11Xiaoyu wurde von **[Tyson Tan](https://tysontan.com)** entworfen und illustriert, der sie großzügigerweise kostenlos für das Projekt erstellt hat – wofür wir unglaublich dankbar sind.
12
13## Bilder
14
15Hochauflösende Kunstwerke stehen unten zum Download bereit. Klicken Sie auf ein Bild, um es in voller Größe zu öffnen.
16
17### Vollständiges Kunstwerk
18
19<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" target="_blank">
20 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" alt="Xiaoyu — vollständiges Kunstwerk mit Hintergrund" style="max-width: 480px; width: 100%; border-radius: 12px;" />
21</a>
22
23<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" download>Vollständiges PNG herunterladen</a></p>
24
25### Transparenter Hintergrund
26
27<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" target="_blank">
28 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" alt="Xiaoyu — transparenter Hintergrund" style="max-width: 480px; width: 100%; border-radius: 12px;" />
29</a>
30
31<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" download>Transparentes PNG herunterladen</a></p>
32
33### Gezippte .kra-Datei
34
35<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip" download>Gezippte .kra-Datei herunterladen</a></p>
36
37## Lizenz
38
39Xiaoyu ist unter der [MIT-Lizenz](https://opensource.org/licenses/MIT) und der Creative-Commons-Lizenz [CC‑BY‑SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) doppelt lizenziert.
diff --git a/doc/docs/de/index.md b/doc/docs/de/index.md
index 94bd00f..d9ebff0 100644
--- a/doc/docs/de/index.md
+++ b/doc/docs/de/index.md
@@ -4,7 +4,7 @@ hero:
4 name: YueScript 4 name: YueScript
5 tagline: Eine Sprache, die zu Lua kompiliert 5 tagline: Eine Sprache, die zu Lua kompiliert
6 image: 6 image:
7 src: /image/yuescript.svg 7 src: /image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
8 alt: YueScript 8 alt: YueScript
9 actions: 9 actions:
10 - theme: brand 10 - theme: brand
diff --git a/doc/docs/doc/reference/the-yuescript-library.md b/doc/docs/doc/advanced/the-yuescript-library.md
index 817bfab..817bfab 100644
--- a/doc/docs/doc/reference/the-yuescript-library.md
+++ b/doc/docs/doc/advanced/the-yuescript-library.md
diff --git a/doc/docs/doc/reference/license-mit.md b/doc/docs/doc/extras/license-mit.md
index 49eae7e..49eae7e 100644
--- a/doc/docs/doc/reference/license-mit.md
+++ b/doc/docs/doc/extras/license-mit.md
diff --git a/doc/docs/doc/extras/mascot.md b/doc/docs/doc/extras/mascot.md
new file mode 100644
index 0000000..028d17f
--- /dev/null
+++ b/doc/docs/doc/extras/mascot.md
@@ -0,0 +1,39 @@
1# Mascot - Xiaoyu
2
3## About
4
5<img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png" alt="Xiaoyu the Cyber Rabbit" style="max-width: 420px; width: 100%; border-radius: 12px; margin-bottom: 1.5em;" />
6
7Xiaoyu (小玉, "little jade") is a cyber rabbit and the official mascot of the YueScript project. She can usually be found perched atop a crescent moon, tinkering away on her laptop - writing YueScript, naturally.
8
9Her full title is Xiaoyu the Cyber Rabbit (机兔小玉), and she embodies everything YueScript strives to be: elegant, expressive, and a little bit playful.
10
11Xiaoyu was designed and illustrated by **[Tyson Tan](https://tysontan.com)**, who generously created her for the project free of charge - something we're incredibly grateful for.
12
13## Images
14
15Full‑resolution artwork is available for download below. Click any image to open it at full size.
16
17### Full Artwork
18
19<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" target="_blank">
20 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" alt="Xiaoyu — full artwork with background" style="max-width: 480px; width: 100%; border-radius: 12px;" />
21</a>
22
23<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" download>Download full-size PNG</a></p>
24
25### Transparent Background
26
27<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" target="_blank">
28 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" alt="Xiaoyu — transparent background" style="max-width: 480px; width: 100%; border-radius: 12px;" />
29</a>
30
31<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" download>Download transparent PNG</a></p>
32
33### Zipped .kra File
34
35<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip" download>Download zipped .kra file</a></p>
36
37## License
38
39Xiaoyu is dual‑licensed under the [MIT License](https://opensource.org/licenses/MIT) and the Creative Commons [CC‑BY‑SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/doc/docs/id-id/doc/reference/the-yuescript-library.md b/doc/docs/id-id/doc/advanced/the-yuescript-library.md
index 3adfe63..3adfe63 100644
--- a/doc/docs/id-id/doc/reference/the-yuescript-library.md
+++ b/doc/docs/id-id/doc/advanced/the-yuescript-library.md
diff --git a/doc/docs/id-id/doc/reference/license-mit.md b/doc/docs/id-id/doc/extras/license-mit.md
index 5289f50..5289f50 100644
--- a/doc/docs/id-id/doc/reference/license-mit.md
+++ b/doc/docs/id-id/doc/extras/license-mit.md
diff --git a/doc/docs/id-id/doc/extras/mascot.md b/doc/docs/id-id/doc/extras/mascot.md
new file mode 100644
index 0000000..1b16706
--- /dev/null
+++ b/doc/docs/id-id/doc/extras/mascot.md
@@ -0,0 +1,39 @@
1# Maskot – Xiaoyu
2
3## Tentang
4
5<img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png" alt="Xiaoyu si Kelinci Siber" style="max-width: 420px; width: 100%; border-radius: 12px; margin-bottom: 1.5em;" />
6
7Xiaoyu (小玉, "giok kecil") adalah seekor kelinci siber dan maskot resmi proyek YueScript. Ia biasanya ditemukan bertengger di atas bulan sabit, mengutak-atik laptopnya – menulis YueScript, tentu saja.
8
9Gelar lengkapnya adalah Xiaoyu si Kelinci Siber (机兔小玉), dan ia mewujudkan segala hal yang dicita-citakan YueScript: elegan, ekspresif, dan sedikit menyenangkan.
10
11Xiaoyu dirancang dan diilustrasikan oleh **[Tyson Tan](https://tysontan.com)**, yang dengan murah hati menciptakannya untuk proyek ini secara gratis – sesuatu yang sangat kami syukuri.
12
13## Gambar
14
15Karya seni resolusi penuh tersedia untuk diunduh di bawah ini. Klik gambar mana saja untuk membukanya dalam ukuran penuh.
16
17### Karya Seni Lengkap
18
19<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" target="_blank">
20 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" alt="Xiaoyu — karya seni lengkap dengan latar belakang" style="max-width: 480px; width: 100%; border-radius: 12px;" />
21</a>
22
23<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" download>Unduh PNG ukuran penuh</a></p>
24
25### Latar Belakang Transparan
26
27<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" target="_blank">
28 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" alt="Xiaoyu — latar belakang transparan" style="max-width: 480px; width: 100%; border-radius: 12px;" />
29</a>
30
31<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" download>Unduh PNG transparan</a></p>
32
33### File .kra Terkompresi
34
35<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip" download>Unduh file .kra terkompresi</a></p>
36
37## Lisensi
38
39Xiaoyu dilisensikan ganda di bawah [Lisensi MIT](https://opensource.org/licenses/MIT) dan Creative Commons [CC‑BY‑SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/doc/docs/id-id/index.md b/doc/docs/id-id/index.md
index c8b5fab..feef760 100644
--- a/doc/docs/id-id/index.md
+++ b/doc/docs/id-id/index.md
@@ -4,7 +4,7 @@ hero:
4 name: YueScript 4 name: YueScript
5 tagline: Bahasa yang dikompilasi ke Lua 5 tagline: Bahasa yang dikompilasi ke Lua
6 image: 6 image:
7 src: /image/yuescript.svg 7 src: /image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
8 alt: YueScript 8 alt: YueScript
9 actions: 9 actions:
10 - theme: brand 10 - theme: brand
diff --git a/doc/docs/index.md b/doc/docs/index.md
index 016b688..7d34f11 100644
--- a/doc/docs/index.md
+++ b/doc/docs/index.md
@@ -4,7 +4,7 @@ hero:
4 name: YueScript 4 name: YueScript
5 tagline: A language that compiles to Lua 5 tagline: A language that compiles to Lua
6 image: 6 image:
7 src: /image/yuescript.svg 7 src: /image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
8 alt: YueScript 8 alt: YueScript
9 actions: 9 actions:
10 - theme: brand 10 - theme: brand
diff --git a/doc/docs/pt-br/doc/reference/the-yuescript-library.md b/doc/docs/pt-br/doc/advanced/the-yuescript-library.md
index 7775cd5..7775cd5 100644
--- a/doc/docs/pt-br/doc/reference/the-yuescript-library.md
+++ b/doc/docs/pt-br/doc/advanced/the-yuescript-library.md
diff --git a/doc/docs/pt-br/doc/reference/license-mit.md b/doc/docs/pt-br/doc/extras/license-mit.md
index 0e00e90..0e00e90 100644
--- a/doc/docs/pt-br/doc/reference/license-mit.md
+++ b/doc/docs/pt-br/doc/extras/license-mit.md
diff --git a/doc/docs/pt-br/doc/extras/mascot.md b/doc/docs/pt-br/doc/extras/mascot.md
new file mode 100644
index 0000000..e2ff951
--- /dev/null
+++ b/doc/docs/pt-br/doc/extras/mascot.md
@@ -0,0 +1,39 @@
1# Mascote – Xiaoyu
2
3## Sobre
4
5<img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png" alt="Xiaoyu, a Coelha Cibernética" style="max-width: 420px; width: 100%; border-radius: 12px; margin-bottom: 1.5em;" />
6
7Xiaoyu (小玉, "pequeno jade") é uma coelha cibernética e a mascote oficial do projeto YueScript. Ela geralmente pode ser encontrada empoleirada em uma lua crescente, mexendo em seu laptop – escrevendo YueScript, naturalmente.
8
9Seu título completo é Xiaoyu, a Coelha Cibernética (机兔小玉), e ela incorpora tudo o que o YueScript aspira ser: elegante, expressivo e um pouquinho divertido.
10
11Xiaoyu foi projetada e ilustrada por **[Tyson Tan](https://tysontan.com)**, que generosamente a criou para o projeto de forma gratuita – algo pelo qual somos incrivelmente gratos.
12
13## Imagens
14
15Artes em resolução completa estão disponíveis para download abaixo. Clique em qualquer imagem para abri-la em tamanho real.
16
17### Arte Completa
18
19<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" target="_blank">
20 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" alt="Xiaoyu — arte completa com fundo" style="max-width: 480px; width: 100%; border-radius: 12px;" />
21</a>
22
23<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" download>Baixar PNG em tamanho real</a></p>
24
25### Fundo Transparente
26
27<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" target="_blank">
28 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" alt="Xiaoyu — fundo transparente" style="max-width: 480px; width: 100%; border-radius: 12px;" />
29</a>
30
31<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" download>Baixar PNG transparente</a></p>
32
33### Arquivo .kra Compactado
34
35<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip" download>Baixar arquivo .kra compactado</a></p>
36
37## Licença
38
39Xiaoyu é duplamente licenciada sob a [Licença MIT](https://opensource.org/licenses/MIT) e a Creative Commons [CC‑BY‑SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/doc/docs/pt-br/index.md b/doc/docs/pt-br/index.md
index e62095f..ce0a516 100644
--- a/doc/docs/pt-br/index.md
+++ b/doc/docs/pt-br/index.md
@@ -4,7 +4,7 @@ hero:
4 name: YueScript 4 name: YueScript
5 tagline: Uma linguagem que compila para Lua 5 tagline: Uma linguagem que compila para Lua
6 image: 6 image:
7 src: /image/yuescript.svg 7 src: /image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
8 alt: YueScript 8 alt: YueScript
9 actions: 9 actions:
10 - theme: brand 10 - theme: brand
diff --git a/doc/docs/zh/doc/reference/the-yuescript-library.md b/doc/docs/zh/doc/advanced/the-yuescript-library.md
index 9565b01..9565b01 100644
--- a/doc/docs/zh/doc/reference/the-yuescript-library.md
+++ b/doc/docs/zh/doc/advanced/the-yuescript-library.md
diff --git a/doc/docs/zh/doc/reference/license-mit.md b/doc/docs/zh/doc/extras/license-mit.md
index 7979663..7979663 100644
--- a/doc/docs/zh/doc/reference/license-mit.md
+++ b/doc/docs/zh/doc/extras/license-mit.md
diff --git a/doc/docs/zh/doc/extras/mascot.md b/doc/docs/zh/doc/extras/mascot.md
new file mode 100644
index 0000000..cc6c80e
--- /dev/null
+++ b/doc/docs/zh/doc/extras/mascot.md
@@ -0,0 +1,39 @@
1# 吉祥物 – 小玉
2
3## 简介
4
5<img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png" alt="机兔小玉" style="max-width: 420px; width: 100%; border-radius: 12px; margin-bottom: 1.5em;" />
6
7小玉(Xiaoyu,意为"小小的玉")是一只赛博兔,也是 YueScript 项目的官方吉祥物。她通常栖息在一弯新月之上,在笔记本电脑上忙碌着——当然是在写 YueScript。
8
9她的全称是机兔小玉,体现了 YueScript 所追求的一切:优雅、富有表现力,还带着一点俏皮。
10
11小玉由 **[Tyson Tan](https://tysontan.com)** 设计和绘制,他慷慨地免费为本项目创作了她——我们对此深表感激。
12
13## 图片
14
15以下提供全分辨率画作供下载。点击任意图片可查看原始尺寸。
16
17### 完整画作
18
19<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" target="_blank">
20 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" alt="小玉 — 含背景的完整画作" style="max-width: 480px; width: 100%; border-radius: 12px;" />
21</a>
22
23<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_full.png" download>下载完整 PNG</a></p>
24
25### 透明背景
26
27<a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" target="_blank">
28 <img src="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" alt="小玉 — 透明背景" style="max-width: 480px; width: 100%; border-radius: 12px;" />
29</a>
30
31<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu_trans.png" download>下载透明背景 PNG</a></p>
32
33### .kra 压缩文件
34
35<p><a href="/image/mascot/electrichearts_20260211A_yuescript_xiaoyu.zip" download>下载 .kra 压缩文件</a></p>
36
37## 许可证
38
39小玉采用 [MIT 许可证](https://opensource.org/licenses/MIT) 和知识共享 [CC‑BY‑SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) 双重许可。
diff --git a/doc/docs/zh/index.md b/doc/docs/zh/index.md
index 4e518b9..0146468 100644
--- a/doc/docs/zh/index.md
+++ b/doc/docs/zh/index.md
@@ -4,7 +4,7 @@ hero:
4 name: 月之脚本 4 name: 月之脚本
5 tagline: 一门编译到 Lua 的语言 5 tagline: 一门编译到 Lua 的语言
6 image: 6 image:
7 src: /image/yuescript.svg 7 src: /image/mascot/electrichearts_20260211A_yuescript_xiaoyu.png
8 alt: 月之脚本 8 alt: 月之脚本
9 actions: 9 actions:
10 - theme: brand 10 - theme: brand
diff --git a/spec/cli/cli_test_helper.sh b/spec/cli/cli_test_helper.sh
index ade1546..0f46969 100755
--- a/spec/cli/cli_test_helper.sh
+++ b/spec/cli/cli_test_helper.sh
@@ -123,6 +123,33 @@ assert_output_equals() {
123 fi 123 fi
124} 124}
125 125
126# Assert that output does NOT contain expected string
127assert_output_not_contains() {
128 local description="$1"
129 local unexpected="$2"
130 shift 2
131 TESTS_RUN=$((TESTS_RUN + 1))
132
133 if "$@" > /tmp/test_stdout.txt 2> /tmp/test_stderr.txt; then
134 if grep -qF -- "$unexpected" /tmp/test_stdout.txt || grep -qF -- "$unexpected" /tmp/test_stderr.txt; then
135 echo -e "${RED}✗${NC} $description (output contains '$unexpected')"
136 echo -e " ${YELLOW}STDOUT:$(cat /tmp/test_stdout.txt)${NC}"
137 echo -e " ${YELLOW}STDERR:$(cat /tmp/test_stderr.txt)${NC}"
138 TESTS_FAILED=$((TESTS_FAILED + 1))
139 return 1
140 else
141 echo -e "${GREEN}✓${NC} $description"
142 TESTS_PASSED=$((TESTS_PASSED + 1))
143 return 0
144 fi
145 else
146 echo -e "${RED}✗${NC} $description (command failed)"
147 echo -e " ${YELLOW}Exit code: $?${NC}"
148 TESTS_FAILED=$((TESTS_FAILED + 1))
149 return 1
150 fi
151}
152
126# Assert file exists 153# Assert file exists
127assert_file_exists() { 154assert_file_exists() {
128 local description="$1" 155 local description="$1"
diff --git a/spec/cli/run_all_tests.sh b/spec/cli/run_all_tests.sh
index 43b74bc..c4836ca 100755
--- a/spec/cli/run_all_tests.sh
+++ b/spec/cli/run_all_tests.sh
@@ -105,6 +105,7 @@ run_test_suite() {
105# Run all test suites 105# Run all test suites
106run_test_suite "Basic Options Test" "$SCRIPT_DIR/test_basic_options.sh" 106run_test_suite "Basic Options Test" "$SCRIPT_DIR/test_basic_options.sh"
107run_test_suite "Compilation Test" "$SCRIPT_DIR/test_compilation.sh" 107run_test_suite "Compilation Test" "$SCRIPT_DIR/test_compilation.sh"
108run_test_suite "Reserve Comments Test" "$SCRIPT_DIR/test_reserve_comments.sh"
108run_test_suite "Error Handling Test" "$SCRIPT_DIR/test_error_handling.sh" 109run_test_suite "Error Handling Test" "$SCRIPT_DIR/test_error_handling.sh"
109run_test_suite "Execution Test" "$SCRIPT_DIR/test_execution.sh" 110run_test_suite "Execution Test" "$SCRIPT_DIR/test_execution.sh"
110 111
diff --git a/spec/cli/test_reserve_comments.sh b/spec/cli/test_reserve_comments.sh
new file mode 100755
index 0000000..6c0c1a7
--- /dev/null
+++ b/spec/cli/test_reserve_comments.sh
@@ -0,0 +1,189 @@
1#!/bin/bash
2# Test Reserve Comments Functionality for YueScript CLI
3# Tests: -c, --reserve-comments option
4
5SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6source "$SCRIPT_DIR/cli_test_helper.sh"
7
8# Check binary
9check_yue_binary
10
11# Setup test environment
12setup_test_env
13TMP_DIR=$(get_test_tmp_dir)
14
15echo "========================================"
16echo "Testing Reserve Comments (-c) Option"
17echo "========================================"
18echo ""
19
20# Test 1: Reserve top-level comments
21echo "Testing top-level comments preservation..."
22cat > "$TMP_DIR/top_level.yue" << 'EOF'
23-- Top level comment
24x = 1
25-- Another comment
26y = 2
27EOF
28
29assert_output_contains "Reserve top-level comments" "Top level comment" $YUE_BIN -c -p "$TMP_DIR/top_level.yue"
30assert_output_contains "Reserve second comment" "Another comment" $YUE_BIN -c -p "$TMP_DIR/top_level.yue"
31
32# Test 2: Without -c option, comments should not appear
33echo ""
34echo "Testing comments are removed without -c option..."
35assert_output_not_contains "Comments should be removed without -c" "Top level comment" $YUE_BIN -p "$TMP_DIR/top_level.yue"
36
37# Test 3: Reserve comments in table
38echo ""
39echo "Testing comments in tables..."
40cat > "$TMP_DIR/table_comments.yue" << 'EOF'
41t = {
42 -- First value comment
43 1,
44 -- Second value comment
45 2
46}
47EOF
48
49assert_output_contains "Table comments should be preserved" "First value comment" $YUE_BIN -c -p "$TMP_DIR/table_comments.yue"
50assert_output_contains "Table second comment preserved" "Second value comment" $YUE_BIN -c -p "$TMP_DIR/table_comments.yue"
51
52# Test 4: Reserve comments in if statement
53echo ""
54echo "Testing comments in if statements..."
55cat > "$TMP_DIR/if_comments.yue" << 'EOF'
56if true
57 -- Inside if block
58 print "test"
59EOF
60
61assert_output_contains "If block comments should be preserved" "Inside if block" $YUE_BIN -c -p "$TMP_DIR/if_comments.yue"
62
63# Test 5: Reserve comments in function
64echo ""
65echo "Testing comments in functions..."
66cat > "$TMP_DIR/func_comments.yue" << 'EOF'
67func = =>
68 -- Inside function
69 print "hello"
70EOF
71
72assert_output_contains "Function comments should be preserved" "Inside function" $YUE_BIN -c -p "$TMP_DIR/func_comments.yue"
73
74# Test 6: Reserve comments with empty lines
75echo ""
76echo "Testing empty lines preservation..."
77cat > "$TMP_DIR/empty_lines.yue" << 'EOF'
78-- First comment
79x = 1
80-- Second comment
81EOF
82
83OUTPUT_WITHOUT_C=$($YUE_BIN -p "$TMP_DIR/empty_lines.yue")
84OUTPUT_WITH_C=$($YUE_BIN -c -p "$TMP_DIR/empty_lines.yue")
85if [ $? -eq 0 ]; then
86 # Count newlines - with -c should have more (or equal) lines due to comment preservation
87 LINES_WITHOUT_C=$(echo "$OUTPUT_WITHOUT_C" | wc -l)
88 LINES_WITH_C=$(echo "$OUTPUT_WITH_C" | wc -l)
89 if [ $LINES_WITH_C -ge $LINES_WITHOUT_C ]; then
90 echo -e "${GREEN}✓${NC} Empty lines and comments should be preserved"
91 TESTS_PASSED=$((TESTS_PASSED + 1))
92 else
93 echo -e "${RED}✗${NC} Empty lines and comments should be preserved"
94 echo -e " ${YELLOW}Lines without -c: $LINES_WITHOUT_C, with -c: $LINES_WITH_C${NC}"
95 TESTS_FAILED=$((TESTS_FAILED + 1))
96 fi
97 TESTS_RUN=$((TESTS_RUN + 1))
98else
99 echo -e "${RED}✗${NC} Empty lines test failed"
100 TESTS_FAILED=$((TESTS_FAILED + 1))
101 TESTS_RUN=$((TESTS_RUN + 1))
102fi
103
104# Test 7: Reserve comments in table with TableBlock syntax
105echo ""
106echo "Testing comments in TableBlock..."
107cat > "$TMP_DIR/tableblock_comments.yue" << 'EOF'
108tbl = {
109 -- Key comment
110 key: "value"
111 -- Another key
112 another: 123
113}
114EOF
115
116assert_output_contains "TableBlock key comment preserved" "Key comment" $YUE_BIN -c -p "$TMP_DIR/tableblock_comments.yue"
117assert_output_contains "TableBlock second comment preserved" "Another key" $YUE_BIN -c -p "$TMP_DIR/tableblock_comments.yue"
118
119# Test 8: Reserve comments - long form option
120echo ""
121echo "Testing --reserve-comments long form option..."
122assert_output_contains "Long form option should preserve comments" "First value comment" $YUE_BIN --reserve-comments -p "$TMP_DIR/table_comments.yue"
123
124# Test 9: Compile to file with reserve comments
125echo ""
126echo "Testing compilation to file with comments..."
127cat > "$TMP_DIR/file_comment.yue" << 'EOF'
128-- This is a test
129value = 42
130EOF
131
132assert_success "Compile with -c to file" $YUE_BIN -c "$TMP_DIR/file_comment.yue" -o "$TMP_DIR/file_comment.lua"
133assert_file_exists "Output file should exist" "$TMP_DIR/file_comment.lua"
134assert_output_contains "Compiled file should contain comments" "This is a test" cat "$TMP_DIR/file_comment.lua"
135
136# Test 10: Reserve comments with multiple statements
137echo ""
138echo "Testing comments with multiple statements..."
139cat > "$TMP_DIR/multi_stmt.yue" << 'EOF'
140-- Assign x
141x = 1
142-- Assign y
143y = 2
144-- Assign z
145z = 3
146EOF
147
148OUTPUT=$($YUE_BIN -c -p "$TMP_DIR/multi_stmt.yue")
149if [ $? -eq 0 ]; then
150 if echo "$OUTPUT" | grep -q "Assign x" && echo "$OUTPUT" | grep -q "Assign y" && echo "$OUTPUT" | grep -q "Assign z"; then
151 echo -e "${GREEN}✓${NC} All comments should be preserved"
152 TESTS_PASSED=$((TESTS_PASSED + 1))
153 else
154 echo -e "${RED}✗${NC} All comments should be preserved"
155 echo -e " ${YELLOW}Output: $OUTPUT${NC}"
156 TESTS_FAILED=$((TESTS_FAILED + 1))
157 fi
158 TESTS_RUN=$((TESTS_RUN + 1))
159else
160 echo -e "${RED}✗${NC} Multiple statements test failed"
161 TESTS_FAILED=$((TESTS_FAILED + 1))
162 TESTS_RUN=$((TESTS_RUN + 1))
163fi
164
165# Test 11: Comments in while loop
166echo ""
167echo "Testing comments in while loop..."
168cat > "$TMP_DIR/while_comments.yue" << 'EOF'
169while true
170 -- Loop body comment
171 print "looping"
172 break
173EOF
174
175assert_output_contains "While loop comments preserved" "Loop body comment" $YUE_BIN -c -p "$TMP_DIR/while_comments.yue"
176
177# Test 12: Comments in for loop
178echo ""
179echo "Testing comments in for loop..."
180cat > "$TMP_DIR/for_comments.yue" << 'EOF'
181for i = 1, 3
182 -- For loop comment
183 print i
184EOF
185
186assert_output_contains "For loop comments preserved" "For loop comment" $YUE_BIN -c -p "$TMP_DIR/for_comments.yue"
187
188echo ""
189print_summary
diff --git a/spec/inputs/compile_doc.yue b/spec/inputs/compile_doc.yue
index f6a8d49..34f810c 100644
--- a/spec/inputs/compile_doc.yue
+++ b/spec/inputs/compile_doc.yue
@@ -35,7 +35,7 @@ getFiles = (locale) ->
35 "doc/docs/#{locale}doc/language-basics/literals.md" 35 "doc/docs/#{locale}doc/language-basics/literals.md"
36 "doc/docs/#{locale}doc/language-basics/module.md" 36 "doc/docs/#{locale}doc/language-basics/module.md"
37 "doc/docs/#{locale}doc/reference/license-mit.md" 37 "doc/docs/#{locale}doc/reference/license-mit.md"
38 "doc/docs/#{locale}doc/reference/the-yuescript-library.md" 38 "doc/docs/#{locale}doc/advanced/the-yuescript-library.md"
39 ] 39 ]
40docs = [ ["codes_from_doc_#{locale}.lua", "yue-#{locale}.md", getFiles locale] for locale in *["en", "zh", "pt-br", "de", "id-id"]] 40docs = [ ["codes_from_doc_#{locale}.lua", "yue-#{locale}.md", getFiles locale] for locale in *["en", "zh", "pt-br", "de", "id-id"]]
41for [compiledFile, docFile, docFiles] in *docs 41for [compiledFile, docFile, docFiles] in *docs
diff --git a/spec/inputs/luarocks_upload.yue b/spec/inputs/luarocks_upload.yue
index 30e8434..8409484 100644
--- a/spec/inputs/luarocks_upload.yue
+++ b/spec/inputs/luarocks_upload.yue
@@ -1,4 +1,5 @@
1luarocksKey = ... 1luarocksKey = ...
2
2local version 3local version
3with? io.open "src/yuescript/yue_compiler.cpp" 4with? io.open "src/yuescript/yue_compiler.cpp"
4 codes = \read "*a" 5 codes = \read "*a"
@@ -8,17 +9,52 @@ unless version?
8 print "failed to get version!" 9 print "failed to get version!"
9 os.exit 1 10 os.exit 1
10 11
12-- ==============================
13-- 1. Prepare minimal source tree
14-- ==============================
15
16local tmpBase = os.getenv("RUNNER_TEMP") or os.getenv("TMPDIR") or "/tmp"
17local pkgRoot = "#{tmpBase}/yuescript_pack_#{version}"
18local srcDir = "#{pkgRoot}/yuescript-#{version}"
19local tarFile = "#{pkgRoot}/yuescript-#{version}.tar.gz"
20
21run = (cmd) ->
22 print cmd
23 ok = os.execute cmd
24 unless ok == true or ok == 0
25 print "Command failed!"
26 os.exit 1
27
28-- clean & create
29run "rm -rf '#{pkgRoot}'"
30run "mkdir -p '#{srcDir}'"
31
32-- copy whitelist files
33run "cp CMakeLists.txt '#{srcDir}/'"
34run "cp README.md '#{srcDir}/'"
35run "cp LICENSE '#{srcDir}/'"
36run "cp -R src '#{srcDir}/'"
37
38-- create tar.gz
39run "tar -C '#{pkgRoot}' -czf '#{tarFile}' 'yuescript-#{version}'"
40
41local sourceUrl = "file://#{tarFile}"
42
43-- =========================
44-- 2. Generate rockspec
45-- =========================
46
11rockspec = "rockspec_format = '3.0' 47rockspec = "rockspec_format = '3.0'
12package = 'Yuescript' 48package = 'Yuescript'
13version = '#{version}-1' 49version = '#{version}-1'
14source = { 50source = {
15 url = 'git+https://github.com/pigpigyyy/yuescript' 51 url = '#{sourceUrl}'
16} 52}
17description = { 53description = {
18 summary = 'Yuescript is a Moonscript dialect.', 54 summary = 'Yuescript is a Moonscript dialect.',
19 detailed = [[ 55 detailed = [[
20 Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]], 56 Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]],
21 homepage = 'https://github.com/pigpigyyy/yuescript', 57 homepage = 'https://github.com/IppClub/YueScript',
22 maintainer = 'Li Jin <dragon-fly@qq.com>', 58 maintainer = 'Li Jin <dragon-fly@qq.com>',
23 labels = {'yuescript','cpp','transpiler','moonscript'}, 59 labels = {'yuescript','cpp','transpiler','moonscript'},
24 license = 'MIT' 60 license = 'MIT'
@@ -29,8 +65,8 @@ dependencies = {
29build = { 65build = {
30 type = 'cmake', 66 type = 'cmake',
31 variables = { 67 variables = {
32 LUA='$(LUA)', 68 LUA = '$(LUA)',
33 LUA_INCDIR='$(LUA_INCDIR)', 69 LUA_INCDIR = '$(LUA_INCDIR)',
34 CMAKE_BUILD_TYPE='Release' 70 CMAKE_BUILD_TYPE='Release'
35 }, 71 },
36 install = { 72 install = {
@@ -40,14 +76,34 @@ build = {
40 bin = { 76 bin = {
41 'build.luarocks/yue' 77 'build.luarocks/yue'
42 } 78 }
79 },
80 platforms = {
81 windows = {
82 install = {
83 lib = {
84 'build.luarocks/Release/yue.dll'
85 },
86 bin = {
87 'build.luarocks/Release/yue.exe'
88 }
89 }
90 }
43 } 91 }
44}" 92}"
45 93
46specFile = "yuescript-#{version}-1.rockspec" 94specFile = "yuescript-#{version}-1.rockspec"
95
47with? io.open specFile, "w+" 96with? io.open specFile, "w+"
48 \write rockspec 97 \write rockspec
49 \close! 98 \close!
50 99
100print "Using source: #{sourceUrl}"
101print "Uploading rockspec: #{specFile}"
102
103-- =========================
104-- 3. Upload
105-- =========================
106
51result = io.popen("luarocks upload --api-key #{luarocksKey} #{specFile}")\read '*a' 107result = io.popen("luarocks upload --api-key #{luarocksKey} #{specFile}")\read '*a'
52unless result\match "Done:" 108unless result\match "Done:"
53 print result 109 print result
diff --git a/spec/inputs/test/reserve_comments_spec.yue b/spec/inputs/test/reserve_comments_spec.yue
new file mode 100644
index 0000000..3c0b824
--- /dev/null
+++ b/spec/inputs/test/reserve_comments_spec.yue
@@ -0,0 +1,413 @@
1describe "reserve_comments option", ->
2 import to_lua from require("yue")
3
4 it "should preserve top-level comments with reserve_comment option", ->
5 code = [[
6-- Top level comment
7x = 1
8-- Another comment
9y = 2
10]]
11 result = to_lua code, {reserve_comment: true}
12 assert.is_true result\match("Top level comment") ~= nil
13 assert.is_true result\match("Another comment") ~= nil
14
15 it "should NOT preserve comments without reserve_comment option", ->
16 code = [[
17-- Top level comment
18x = 1
19-- Another comment
20y = 2
21]]
22 result = to_lua code, {}
23 assert.is_true result\match("Top level comment") == nil
24 assert.is_true result\match("Another comment") == nil
25
26 it "should preserve comments in table literals", ->
27 code = [[
28t = {
29 -- First value comment
30 1,
31 -- Second value comment
32 2
33}
34]]
35 result = to_lua code, {reserve_comment: true}
36 assert.is_true result\match("First value comment") ~= nil
37 assert.is_true result\match("Second value comment") ~= nil
38
39 it "should preserve comments in if statement", ->
40 code = [[
41if true
42 -- Inside if block
43 print "test"
44]]
45 result = to_lua code, {reserve_comment: true}
46 assert.is_true result\match("Inside if block") ~= nil
47
48 it "should preserve comments in function body", ->
49 code = [[
50func = =>
51 -- Inside function
52 print "hello"
53]]
54 result = to_lua code, {reserve_comment: true}
55 assert.is_true result\match("Inside function") ~= nil
56
57 it "should preserve comments in while loop", ->
58 code = [[
59while true
60 -- Loop body comment
61 print "looping"
62 break
63]]
64 result = to_lua code, {reserve_comment: true}
65 assert.is_true result\match("Loop body comment") ~= nil
66
67 it "should preserve comments in for loop", ->
68 code = [[
69for i = 1, 3
70 -- For loop comment
71 print i
72]]
73 result = to_lua code, {reserve_comment: true}
74 assert.is_true result\match("For loop comment") ~= nil
75
76 it "should preserve comments in TableBlock syntax", ->
77 code = [[
78tbl = {
79 -- Key comment
80 key: "value"
81 -- Another key
82 another: 123
83}
84]]
85 result = to_lua code, {reserve_comment: true}
86 assert.is_true result\match("Key comment") ~= nil
87 assert.is_true result\match("Another key") ~= nil
88
89 it "should preserve multiple comments across statements", ->
90 code = [[
91-- Assign x
92x = 1
93-- Assign y
94y = 2
95-- Assign z
96z = 3
97]]
98 result = to_lua code, {reserve_comment: true}
99 assert.is_true result\match("Assign x") ~= nil
100 assert.is_true result\match("Assign y") ~= nil
101 assert.is_true result\match("Assign z") ~= nil
102
103 it "should handle table with mixed values and comments", ->
104 code = [[
105t = {
106 -- First item
107 1,
108 -- Second item
109 2,
110 -- Third item
111 3
112}
113]]
114 result = to_lua code, {reserve_comment: true}
115 assert.is_true result\match("First item") ~= nil
116 assert.is_true result\match("Second item") ~= nil
117 assert.is_true result\match("Third item") ~= nil
118
119 it "should preserve comments in nested structures", ->
120 code = [[
121outer = {
122 -- outer comment
123 inner: {
124 -- inner comment
125 value: 42
126 }
127}
128]]
129 result = to_lua code, {reserve_comment: true}
130 assert.is_true result\match("outer comment") ~= nil
131 assert.is_true result\match("inner comment") ~= nil
132
133 it "should preserve comments in else block", ->
134 code = [[
135if false
136 print "if"
137else
138 -- else comment
139 print "else"
140]]
141 result = to_lua code, {reserve_comment: true}
142 assert.is_true result\match("else comment") ~= nil
143
144 it "should preserve comments in elseif block", ->
145 code = [[
146if false
147 print "if"
148elseif true
149 -- elseif comment
150 print "elseif"
151]]
152 result = to_lua code, {reserve_comment: true}
153 assert.is_true result\match("elseif comment") ~= nil
154
155 it "should preserve comments before return statement", ->
156 code = [[
157func = =>
158 -- before return
159 return 42
160]]
161 result = to_lua code, {reserve_comment: true}
162 assert.is_true result\match("before return") ~= nil
163
164 it "should preserve comments in switch statement", ->
165 code = [[
166switch 2
167 when 1
168 -- case 1 comment
169 print "one"
170 when 2
171 -- case 2 comment
172 print "two"
173]]
174 result = to_lua code, {reserve_comment: true}
175 assert.is_true result\match("case 1 comment") ~= nil
176 assert.is_true result\match("case 2 comment") ~= nil
177
178 it "should preserve comments in with statement", ->
179 code = [[
180with t
181 -- with body comment
182 .value = 10
183]]
184 result = to_lua code, {reserve_comment: true}
185 assert.is_true result\match("with body comment") ~= nil
186
187 it "should handle empty lines with reserve_comment", ->
188 code = [[
189-- First comment
190x = 1
191-- Second comment
192]]
193 -- Just verify it compiles without error
194 result = to_lua code, {reserve_comment: true}
195 assert.is_true result ~= nil
196 assert.is_true type(result) == "string"
197
198 it "should preserve comments in class body", ->
199 code = [[
200class MyClass
201 -- property comment
202 value: 10
203 -- method comment
204 method: => print "hello"
205]]
206 result = to_lua code, {reserve_comment: true}
207 assert.is_true result\match("property comment") ~= nil
208 assert.is_true result\match("method comment") ~= nil
209
210 it "should preserve comments in class with inheritance", ->
211 code = [[
212class Child extends Parent
213 -- child property
214 value: 100
215]]
216 result = to_lua code, {reserve_comment: true}
217 assert.is_true result\match("child property") ~= nil
218
219 it "should preserve comments in export statement", ->
220 code = [[
221-- export value comment
222export x = 42
223]]
224 result = to_lua code, {reserve_comment: true}
225 assert.is_true result\match("export value comment") ~= nil
226
227 it "should preserve comments in import statement", ->
228 code = [[
229-- import comment
230import format from "string"
231]]
232 result = to_lua code, {reserve_comment: true}
233 assert.is_true result\match("import comment") ~= nil
234
235 -- Additional tests for TableBlock syntax with multiple empty lines
236 it "should preserve empty lines between comments in TableBlock", ->
237 code = "tb =\n\t-- line\n\n\n\n\t--[[ajdjd]]\n\ta: ->\n\n\t-- line 2\n\tb: 123\n"
238 result = to_lua code, {reserve_comment: true}
239 assert.is_true result\match("line") ~= nil
240 assert.is_true result\match("ajdjd") ~= nil
241 assert.is_true result\match("line 2") ~= nil
242
243 it "should preserve block comments in TableBlock", ->
244 code = "tb =\n\t--[[block comment]]\n\ta: 1\n\n\t--[[another block]]\n\tb: 2\n"
245 result = to_lua code, {reserve_comment: true}
246 assert.is_true result\match("block comment") ~= nil
247 assert.is_true result\match("another block") ~= nil
248
249 it "should preserve multiple empty lines in table literal", ->
250 code = "tb = {\n\t-- line\n\n\n\n\t--[[ajdjd]]\n\ta: ->\n\n\t-- line 2\n\tb: 123\n}\n"
251 result = to_lua code, {reserve_comment: true}
252 assert.is_true result\match("line") ~= nil
253 assert.is_true result\match("ajdjd") ~= nil
254 assert.is_true result\match("line 2") ~= nil
255
256 it "should preserve mixed single and block comments in TableBlock", ->
257 code = "tb =\n\t-- single line comment\n\ta: 1\n\n\t--[[multi\n\tline\n\tblock\n\tcomment]]\n\tb: 2\n\n\t-- another single\n\tc: 3\n"
258 result = to_lua code, {reserve_comment: true}
259 assert.is_true result\match("single line comment") ~= nil
260 assert.is_true result\match("multi") ~= nil
261 assert.is_true result\match("another single") ~= nil
262
263 it "should preserve comments and empty lines in table with colon syntax", ->
264 code = "tbl = {\n\t-- first key\n\tkey1: \"value1\"\n\n\n\t-- second key\n\tkey2: \"value2\"\n\n\t-- third key\n\tkey3: \"value3\"\n}\n"
265 result = to_lua code, {reserve_comment: true}
266 assert.is_true result\match("first key") ~= nil
267 assert.is_true result\match("second key") ~= nil
268 assert.is_true result\match("third key") ~= nil
269
270 it "should preserve comments in nested TableBlock structures", ->
271 code = "outer =\n\t-- outer item\n\ta: 1\n\n\t-- inner tableblock\n\tinner:\n\t\t-- inner item 1\n\t\tx: 10\n\t\t-- inner item 2\n\t\ty: 20\n"
272 result = to_lua code, {reserve_comment: true}
273 assert.is_true result\match("outer item") ~= nil
274 assert.is_true result\match("inner tableblock") ~= nil
275 assert.is_true result\match("inner item 1") ~= nil
276 assert.is_true result\match("inner item 2") ~= nil
277
278 it "should handle function values in TableBlock with comments", ->
279 code = "tb =\n\t-- comment before function\n\tfunc1: => print \"a\"\n\n\t-- another function\n\tfunc2: (x) => x * 2\n\n\t-- method\n\tmethod: =>\n\t\t-- inside method\n\t\tprint \"method\"\n"
280 result = to_lua code, {reserve_comment: true}
281 assert.is_true result\match("comment before function") ~= nil
282 assert.is_true result\match("another function") ~= nil
283 assert.is_true result\match("method") ~= nil
284 assert.is_true result\match("inside method") ~= nil
285
286 it "should preserve comments in TableBlock with various value types", ->
287 code = "tb =\n\t-- string value\n\tstr: \"hello\"\n\n\t-- number value\n\tnum: 42\n\n\t-- boolean value\n\tbool: true\n\n\t-- table value\n\ttbl: {1, 2, 3}\n"
288 result = to_lua code, {reserve_comment: true}
289 assert.is_true result\match("string value") ~= nil
290 assert.is_true result\match("number value") ~= nil
291 assert.is_true result\match("boolean value") ~= nil
292 assert.is_true result\match("table value") ~= nil
293
294 it "should preserve empty lines at end of TableBlock", ->
295 code = "tb =\n\t-- item 1\n\ta: 1\n\n\t-- item 2\n\tb: 2\n\n\n"
296 result = to_lua code, {reserve_comment: true}
297 assert.is_true result\match("item 1") ~= nil
298 assert.is_true result\match("item 2") ~= nil
299
300 -- Tests specifically for empty lines between comments
301 it "should preserve empty lines in TableBlock between comments", ->
302 code = "tb =\n\t-- a\n\t\n\t\n\t\n\tval: 1\n"
303 result = to_lua code, {reserve_comment: true}
304 -- Empty lines should produce line number comments in output
305 -- Check that there's a line with just a comment marker (line number)
306 assert.is_true result\match("-- %d+") ~= nil
307
308 it "should preserve empty lines in TableBlock with comments", ->
309 code = "tb =\n\t-- first\n\t\n\t\n\tval: 1\n\t\n\t-- second\n\tval2: 2\n"
310 result = to_lua code, {reserve_comment: true}
311 assert.is_true result\match("first") ~= nil
312 assert.is_true result\match("second") ~= nil
313 -- Should have empty line representations (lines with line number comments)
314 assert.is_true result\match("-- %d+") ~= nil
315
316 it "should preserve empty lines in table literal", ->
317 code = "t = {\n\t-- item1\n\t\n\t\n\t1,\n\t\n\t-- item2\n\t2\n}\n"
318 result = to_lua code, {reserve_comment: true}
319 assert.is_true result\match("item1") ~= nil
320 assert.is_true result\match("item2") ~= nil
321 -- Empty lines should produce line comments
322 assert.is_true result\match("-- %d+") ~= nil
323
324 it "should have more newlines with reserve_comment than without", ->
325 code = "-- comment1\nx = 1\n-- comment2\ny = 2\n"
326 result_with = to_lua code, {reserve_comment: true}
327 result_without = to_lua code, {}
328 -- Count newlines in both results using gmatch
329 newlines_with = 0
330 newlines_without = 0
331 for _ in result_with\gmatch("\n")
332 newlines_with += 1
333 for _ in result_without\gmatch("\n")
334 newlines_without += 1
335 -- With reserve_comment should have equal or more newlines
336 assert.is_true newlines_with >= newlines_without
337
338 it "should preserve empty lines in TableBlock between entries", ->
339 code = "tb =\n\t-- key1\n\tkey1: 1\n\t\n\t\n\t-- key2\n\tkey2: 2\n"
340 result = to_lua code, {reserve_comment: true}
341 assert.is_true result\match("key1") ~= nil
342 assert.is_true result\match("key2") ~= nil
343 -- Empty lines should produce lines with line number comments
344 assert.is_true result\match("\t-- %d+\n") ~= nil
345
346 it "should preserve empty lines in class body", ->
347 code = "class C\n\t-- prop1\n\tprop1: 1\n\t\n\t\n\t-- prop2\n\tprop2: 2\n"
348 result = to_lua code, {reserve_comment: true}
349 assert.is_true result\match("prop1") ~= nil
350 assert.is_true result\match("prop2") ~= nil
351
352 it "should preserve empty lines between comments in table", ->
353 code = "t = {\n\t-- first\n\t\n\t-- second\n\t\n\t-- third\n\tval: 1\n}\n"
354 result = to_lua code, {reserve_comment: true}
355 assert.is_true result\match("first") ~= nil
356 assert.is_true result\match("second") ~= nil
357 assert.is_true result\match("third") ~= nil
358 -- Empty lines should produce line comments
359 assert.is_true result\match("-- %d+") ~= nil
360
361 it "should preserve multiple consecutive empty lines in TableBlock", ->
362 code = "tb =\n\t-- start\n\tval1: 1\n\t\n\t\n\t\n\t-- middle\n\tval2: 2\n\t\n\t\n\t-- end\n\tval3: 3\n"
363 result = to_lua code, {reserve_comment: true}
364 assert.is_true result\match("start") ~= nil
365 assert.is_true result\match("middle") ~= nil
366 assert.is_true result\match("end") ~= nil
367 -- Should have line number comments for empty lines
368 assert.is_true result\match("-- %d+") ~= nil
369
370 -- Comparison tests: Table literal vs TableBlock vs Class
371 it "should preserve comments in table literal", ->
372 code = "t = {\n\t-- comment\n\tkey: 1\n}\n"
373 result = to_lua code, {reserve_comment: true}
374 assert.is_true result\match("comment") ~= nil
375
376 it "should preserve comments in TableBlock", ->
377 code = "t =\n\t-- comment\n\tkey: 1\n"
378 result = to_lua code, {reserve_comment: true}
379 assert.is_true result\match("comment") ~= nil
380
381 it "should preserve comments in class body", ->
382 code = "class C\n\t-- comment\n\tkey: 1\n"
383 result = to_lua code, {reserve_comment: true}
384 assert.is_true result\match("comment") ~= nil
385
386 it "should preserve multiple comments in class body", ->
387 code = "class C\n\t-- prop1\n\tprop1: 1\n\t-- prop2\n\tprop2: 2\n"
388 result = to_lua code, {reserve_comment: true}
389 assert.is_true result\match("prop1") ~= nil
390 assert.is_true result\match("prop2") ~= nil
391
392 it "should preserve empty lines in table literal", ->
393 code = "t = {\n\t-- a\n\t\n\t-- b\n\tkey: 1\n}\n"
394 result = to_lua code, {reserve_comment: true}
395 assert.is_true result\match("a") ~= nil
396 assert.is_true result\match("b") ~= nil
397 -- Empty lines produce line comments
398 assert.is_true result\match("-- %d+") ~= nil
399
400 it "should preserve empty lines in TableBlock", ->
401 code = "t =\n\t-- a\n\t\n\t-- b\n\tkey: 1\n"
402 result = to_lua code, {reserve_comment: true}
403 assert.is_true result\match("a") ~= nil
404 assert.is_true result\match("b") ~= nil
405 -- Empty lines produce line comments
406 assert.is_true result\match("-- %d+") ~= nil
407
408 it "should preserve empty lines in class body", ->
409 code = "class C\n\t-- a\n\ta: 1\n\t\n\t-- b\n\tb: 2\n"
410 result = to_lua code, {reserve_comment: true}
411 assert.is_true result\match("a") ~= nil
412 assert.is_true result\match("b") ~= nil
413 -- Empty lines in class should also be preserved
diff --git a/spec/inputs/whitespace.yue b/spec/inputs/whitespace.yue
index e501d3d..a999143 100644
--- a/spec/inputs/whitespace.yue
+++ b/spec/inputs/whitespace.yue
@@ -160,4 +160,43 @@ local a,\
160 b,\ 160 b,\
161 c 161 c
162 162
163do
164 tb =
165
166
167 -- one
168
169
170 -- a
171 a: 1 -- 1
172
173 -- two
174 b: -> -- 2
175
176 tb2 = {
177
178
179 -- one
180
181
182 -- a
183 a: 1 -- 1
184
185 -- two
186 b: -> -- 2
187 }
188
189 tb3 = class -- dsd
190
191
192
193 -- one
194
195 -- a
196 a: 1 -- 1
197
198 -- two
199 b: -> -- 2
200
201
163nil 202nil
diff --git a/spec/outputs/compile_doc.lua b/spec/outputs/compile_doc.lua
index f661bbd..470257d 100644
--- a/spec/outputs/compile_doc.lua
+++ b/spec/outputs/compile_doc.lua
@@ -45,7 +45,7 @@ getFiles = function(locale)
45 "doc/docs/" .. tostring(locale) .. "doc/language-basics/literals.md", 45 "doc/docs/" .. tostring(locale) .. "doc/language-basics/literals.md",
46 "doc/docs/" .. tostring(locale) .. "doc/language-basics/module.md", 46 "doc/docs/" .. tostring(locale) .. "doc/language-basics/module.md",
47 "doc/docs/" .. tostring(locale) .. "doc/reference/license-mit.md", 47 "doc/docs/" .. tostring(locale) .. "doc/reference/license-mit.md",
48 "doc/docs/" .. tostring(locale) .. "doc/reference/the-yuescript-library.md" 48 "doc/docs/" .. tostring(locale) .. "doc/advanced/the-yuescript-library.md"
49 } 49 }
50end 50end
51local docs 51local docs
diff --git a/spec/outputs/luarocks_upload.lua b/spec/outputs/luarocks_upload.lua
index 96988d7..7fa2f73 100644
--- a/spec/outputs/luarocks_upload.lua
+++ b/spec/outputs/luarocks_upload.lua
@@ -12,7 +12,28 @@ if not (version ~= nil) then
12 print("failed to get version!") 12 print("failed to get version!")
13 os.exit(1) 13 os.exit(1)
14end 14end
15local rockspec = "rockspec_format = '3.0'\npackage = 'Yuescript'\nversion = '" .. tostring(version) .. "-1'\nsource = {\n url = 'git+https://github.com/pigpigyyy/yuescript'\n}\ndescription = {\n summary = 'Yuescript is a Moonscript dialect.',\n detailed = [[\n Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]],\n homepage = 'https://github.com/pigpigyyy/yuescript',\n maintainer = 'Li Jin <dragon-fly@qq.com>',\n labels = {'yuescript','cpp','transpiler','moonscript'},\n license = 'MIT'\n}\ndependencies = {\n 'lua >= 5.1',\n}\nbuild = {\n type = 'cmake',\n variables = {\n LUA='$(LUA)',\n LUA_INCDIR='$(LUA_INCDIR)',\n CMAKE_BUILD_TYPE='Release'\n },\n install = {\n lib = {\n 'build.luarocks/yue.so'\n },\n bin = {\n 'build.luarocks/yue'\n }\n }\n}" 15local tmpBase = os.getenv("RUNNER_TEMP") or os.getenv("TMPDIR") or "/tmp"
16local pkgRoot = tostring(tmpBase) .. "/yuescript_pack_" .. tostring(version)
17local srcDir = tostring(pkgRoot) .. "/yuescript-" .. tostring(version)
18local tarFile = tostring(pkgRoot) .. "/yuescript-" .. tostring(version) .. ".tar.gz"
19local run
20run = function(cmd)
21 print(cmd)
22 local ok = os.execute(cmd)
23 if not (ok == true or ok == 0) then
24 print("Command failed!")
25 return os.exit(1)
26 end
27end
28run("rm -rf '" .. tostring(pkgRoot) .. "'")
29run("mkdir -p '" .. tostring(srcDir) .. "'")
30run("cp CMakeLists.txt '" .. tostring(srcDir) .. "/'")
31run("cp README.md '" .. tostring(srcDir) .. "/'")
32run("cp LICENSE '" .. tostring(srcDir) .. "/'")
33run("cp -R src '" .. tostring(srcDir) .. "/'")
34run("tar -C '" .. tostring(pkgRoot) .. "' -czf '" .. tostring(tarFile) .. "' 'yuescript-" .. tostring(version) .. "'")
35local sourceUrl = "file://" .. tostring(tarFile)
36local rockspec = "rockspec_format = '3.0'\npackage = 'Yuescript'\nversion = '" .. tostring(version) .. "-1'\nsource = {\n url = '" .. tostring(sourceUrl) .. "'\n}\ndescription = {\n summary = 'Yuescript is a Moonscript dialect.',\n detailed = [[\n Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]],\n homepage = 'https://github.com/IppClub/YueScript',\n maintainer = 'Li Jin <dragon-fly@qq.com>',\n labels = {'yuescript','cpp','transpiler','moonscript'},\n license = 'MIT'\n}\ndependencies = {\n 'lua >= 5.1',\n}\nbuild = {\n type = 'cmake',\n variables = {\n LUA = '$(LUA)',\n LUA_INCDIR = '$(LUA_INCDIR)',\n CMAKE_BUILD_TYPE='Release'\n },\n install = {\n lib = {\n 'build.luarocks/yue.so'\n },\n bin = {\n 'build.luarocks/yue'\n }\n },\n platforms = {\n windows = {\n install = {\n lib = {\n 'build.luarocks/Release/yue.dll'\n },\n bin = {\n 'build.luarocks/Release/yue.exe'\n }\n }\n }\n }\n}"
16local specFile = "yuescript-" .. tostring(version) .. "-1.rockspec" 37local specFile = "yuescript-" .. tostring(version) .. "-1.rockspec"
17do 38do
18 local _with_0 = io.open(specFile, "w+") 39 local _with_0 = io.open(specFile, "w+")
@@ -21,6 +42,8 @@ do
21 _with_0:close() 42 _with_0:close()
22 end 43 end
23end 44end
45print("Using source: " .. tostring(sourceUrl))
46print("Uploading rockspec: " .. tostring(specFile))
24local result = io.popen("luarocks upload --api-key " .. tostring(luarocksKey) .. " " .. tostring(specFile)):read('*a') 47local result = io.popen("luarocks upload --api-key " .. tostring(luarocksKey) .. " " .. tostring(specFile)):read('*a')
25if not result:match("Done:") then 48if not result:match("Done:") then
26 print(result) 49 print(result)
diff --git a/spec/outputs/test/reserve_comments_spec.lua b/spec/outputs/test/reserve_comments_spec.lua
new file mode 100644
index 0000000..b4e8174
--- /dev/null
+++ b/spec/outputs/test/reserve_comments_spec.lua
@@ -0,0 +1,471 @@
1return describe("reserve_comments option", function()
2 local to_lua
3 do
4 local _obj_0 = require("yue")
5 to_lua = _obj_0.to_lua
6 end
7 it("should preserve top-level comments with reserve_comment option", function()
8 local code = [[-- Top level comment
9x = 1
10-- Another comment
11y = 2
12]]
13 local result = to_lua(code, {
14 reserve_comment = true
15 })
16 assert.is_true(result:match("Top level comment") ~= nil)
17 return assert.is_true(result:match("Another comment") ~= nil)
18 end)
19 it("should NOT preserve comments without reserve_comment option", function()
20 local code = [[-- Top level comment
21x = 1
22-- Another comment
23y = 2
24]]
25 local result = to_lua(code, { })
26 assert.is_true(result:match("Top level comment") == nil)
27 return assert.is_true(result:match("Another comment") == nil)
28 end)
29 it("should preserve comments in table literals", function()
30 local code = [[t = {
31 -- First value comment
32 1,
33 -- Second value comment
34 2
35}
36]]
37 local result = to_lua(code, {
38 reserve_comment = true
39 })
40 assert.is_true(result:match("First value comment") ~= nil)
41 return assert.is_true(result:match("Second value comment") ~= nil)
42 end)
43 it("should preserve comments in if statement", function()
44 local code = [[if true
45 -- Inside if block
46 print "test"
47]]
48 local result = to_lua(code, {
49 reserve_comment = true
50 })
51 return assert.is_true(result:match("Inside if block") ~= nil)
52 end)
53 it("should preserve comments in function body", function()
54 local code = [[func = =>
55 -- Inside function
56 print "hello"
57]]
58 local result = to_lua(code, {
59 reserve_comment = true
60 })
61 return assert.is_true(result:match("Inside function") ~= nil)
62 end)
63 it("should preserve comments in while loop", function()
64 local code = [[while true
65 -- Loop body comment
66 print "looping"
67 break
68]]
69 local result = to_lua(code, {
70 reserve_comment = true
71 })
72 return assert.is_true(result:match("Loop body comment") ~= nil)
73 end)
74 it("should preserve comments in for loop", function()
75 local code = [[for i = 1, 3
76 -- For loop comment
77 print i
78]]
79 local result = to_lua(code, {
80 reserve_comment = true
81 })
82 return assert.is_true(result:match("For loop comment") ~= nil)
83 end)
84 it("should preserve comments in TableBlock syntax", function()
85 local code = [[tbl = {
86 -- Key comment
87 key: "value"
88 -- Another key
89 another: 123
90}
91]]
92 local result = to_lua(code, {
93 reserve_comment = true
94 })
95 assert.is_true(result:match("Key comment") ~= nil)
96 return assert.is_true(result:match("Another key") ~= nil)
97 end)
98 it("should preserve multiple comments across statements", function()
99 local code = [[-- Assign x
100x = 1
101-- Assign y
102y = 2
103-- Assign z
104z = 3
105]]
106 local result = to_lua(code, {
107 reserve_comment = true
108 })
109 assert.is_true(result:match("Assign x") ~= nil)
110 assert.is_true(result:match("Assign y") ~= nil)
111 return assert.is_true(result:match("Assign z") ~= nil)
112 end)
113 it("should handle table with mixed values and comments", function()
114 local code = [[t = {
115 -- First item
116 1,
117 -- Second item
118 2,
119 -- Third item
120 3
121}
122]]
123 local result = to_lua(code, {
124 reserve_comment = true
125 })
126 assert.is_true(result:match("First item") ~= nil)
127 assert.is_true(result:match("Second item") ~= nil)
128 return assert.is_true(result:match("Third item") ~= nil)
129 end)
130 it("should preserve comments in nested structures", function()
131 local code = [[outer = {
132 -- outer comment
133 inner: {
134 -- inner comment
135 value: 42
136 }
137}
138]]
139 local result = to_lua(code, {
140 reserve_comment = true
141 })
142 assert.is_true(result:match("outer comment") ~= nil)
143 return assert.is_true(result:match("inner comment") ~= nil)
144 end)
145 it("should preserve comments in else block", function()
146 local code = [[if false
147 print "if"
148else
149 -- else comment
150 print "else"
151]]
152 local result = to_lua(code, {
153 reserve_comment = true
154 })
155 return assert.is_true(result:match("else comment") ~= nil)
156 end)
157 it("should preserve comments in elseif block", function()
158 local code = [[if false
159 print "if"
160elseif true
161 -- elseif comment
162 print "elseif"
163]]
164 local result = to_lua(code, {
165 reserve_comment = true
166 })
167 return assert.is_true(result:match("elseif comment") ~= nil)
168 end)
169 it("should preserve comments before return statement", function()
170 local code = [[func = =>
171 -- before return
172 return 42
173]]
174 local result = to_lua(code, {
175 reserve_comment = true
176 })
177 return assert.is_true(result:match("before return") ~= nil)
178 end)
179 it("should preserve comments in switch statement", function()
180 local code = [[switch 2
181 when 1
182 -- case 1 comment
183 print "one"
184 when 2
185 -- case 2 comment
186 print "two"
187]]
188 local result = to_lua(code, {
189 reserve_comment = true
190 })
191 assert.is_true(result:match("case 1 comment") ~= nil)
192 return assert.is_true(result:match("case 2 comment") ~= nil)
193 end)
194 it("should preserve comments in with statement", function()
195 local code = [[with t
196 -- with body comment
197 .value = 10
198]]
199 local result = to_lua(code, {
200 reserve_comment = true
201 })
202 return assert.is_true(result:match("with body comment") ~= nil)
203 end)
204 it("should handle empty lines with reserve_comment", function()
205 local code = [[-- First comment
206x = 1
207-- Second comment
208]]
209 local result = to_lua(code, {
210 reserve_comment = true
211 })
212 assert.is_true(result ~= nil)
213 return assert.is_true(type(result) == "string")
214 end)
215 it("should preserve comments in class body", function()
216 local code = [[class MyClass
217 -- property comment
218 value: 10
219 -- method comment
220 method: => print "hello"
221]]
222 local result = to_lua(code, {
223 reserve_comment = true
224 })
225 assert.is_true(result:match("property comment") ~= nil)
226 return assert.is_true(result:match("method comment") ~= nil)
227 end)
228 it("should preserve comments in class with inheritance", function()
229 local code = [[class Child extends Parent
230 -- child property
231 value: 100
232]]
233 local result = to_lua(code, {
234 reserve_comment = true
235 })
236 return assert.is_true(result:match("child property") ~= nil)
237 end)
238 it("should preserve comments in export statement", function()
239 local code = [[-- export value comment
240export x = 42
241]]
242 local result = to_lua(code, {
243 reserve_comment = true
244 })
245 return assert.is_true(result:match("export value comment") ~= nil)
246 end)
247 it("should preserve comments in import statement", function()
248 local code = [[-- import comment
249import format from "string"
250]]
251 local result = to_lua(code, {
252 reserve_comment = true
253 })
254 return assert.is_true(result:match("import comment") ~= nil)
255 end)
256 it("should preserve empty lines between comments in TableBlock", function()
257 local code = "tb =\n\t-- line\n\n\n\n\t--[[ajdjd]]\n\ta: ->\n\n\t-- line 2\n\tb: 123\n"
258 local result = to_lua(code, {
259 reserve_comment = true
260 })
261 assert.is_true(result:match("line") ~= nil)
262 assert.is_true(result:match("ajdjd") ~= nil)
263 return assert.is_true(result:match("line 2") ~= nil)
264 end)
265 it("should preserve block comments in TableBlock", function()
266 local code = "tb =\n\t--[[block comment]]\n\ta: 1\n\n\t--[[another block]]\n\tb: 2\n"
267 local result = to_lua(code, {
268 reserve_comment = true
269 })
270 assert.is_true(result:match("block comment") ~= nil)
271 return assert.is_true(result:match("another block") ~= nil)
272 end)
273 it("should preserve multiple empty lines in table literal", function()
274 local code = "tb = {\n\t-- line\n\n\n\n\t--[[ajdjd]]\n\ta: ->\n\n\t-- line 2\n\tb: 123\n}\n"
275 local result = to_lua(code, {
276 reserve_comment = true
277 })
278 assert.is_true(result:match("line") ~= nil)
279 assert.is_true(result:match("ajdjd") ~= nil)
280 return assert.is_true(result:match("line 2") ~= nil)
281 end)
282 it("should preserve mixed single and block comments in TableBlock", function()
283 local code = "tb =\n\t-- single line comment\n\ta: 1\n\n\t--[[multi\n\tline\n\tblock\n\tcomment]]\n\tb: 2\n\n\t-- another single\n\tc: 3\n"
284 local result = to_lua(code, {
285 reserve_comment = true
286 })
287 assert.is_true(result:match("single line comment") ~= nil)
288 assert.is_true(result:match("multi") ~= nil)
289 return assert.is_true(result:match("another single") ~= nil)
290 end)
291 it("should preserve comments and empty lines in table with colon syntax", function()
292 local code = "tbl = {\n\t-- first key\n\tkey1: \"value1\"\n\n\n\t-- second key\n\tkey2: \"value2\"\n\n\t-- third key\n\tkey3: \"value3\"\n}\n"
293 local result = to_lua(code, {
294 reserve_comment = true
295 })
296 assert.is_true(result:match("first key") ~= nil)
297 assert.is_true(result:match("second key") ~= nil)
298 return assert.is_true(result:match("third key") ~= nil)
299 end)
300 it("should preserve comments in nested TableBlock structures", function()
301 local code = "outer =\n\t-- outer item\n\ta: 1\n\n\t-- inner tableblock\n\tinner:\n\t\t-- inner item 1\n\t\tx: 10\n\t\t-- inner item 2\n\t\ty: 20\n"
302 local result = to_lua(code, {
303 reserve_comment = true
304 })
305 assert.is_true(result:match("outer item") ~= nil)
306 assert.is_true(result:match("inner tableblock") ~= nil)
307 assert.is_true(result:match("inner item 1") ~= nil)
308 return assert.is_true(result:match("inner item 2") ~= nil)
309 end)
310 it("should handle function values in TableBlock with comments", function()
311 local code = "tb =\n\t-- comment before function\n\tfunc1: => print \"a\"\n\n\t-- another function\n\tfunc2: (x) => x * 2\n\n\t-- method\n\tmethod: =>\n\t\t-- inside method\n\t\tprint \"method\"\n"
312 local result = to_lua(code, {
313 reserve_comment = true
314 })
315 assert.is_true(result:match("comment before function") ~= nil)
316 assert.is_true(result:match("another function") ~= nil)
317 assert.is_true(result:match("method") ~= nil)
318 return assert.is_true(result:match("inside method") ~= nil)
319 end)
320 it("should preserve comments in TableBlock with various value types", function()
321 local code = "tb =\n\t-- string value\n\tstr: \"hello\"\n\n\t-- number value\n\tnum: 42\n\n\t-- boolean value\n\tbool: true\n\n\t-- table value\n\ttbl: {1, 2, 3}\n"
322 local result = to_lua(code, {
323 reserve_comment = true
324 })
325 assert.is_true(result:match("string value") ~= nil)
326 assert.is_true(result:match("number value") ~= nil)
327 assert.is_true(result:match("boolean value") ~= nil)
328 return assert.is_true(result:match("table value") ~= nil)
329 end)
330 it("should preserve empty lines at end of TableBlock", function()
331 local code = "tb =\n\t-- item 1\n\ta: 1\n\n\t-- item 2\n\tb: 2\n\n\n"
332 local result = to_lua(code, {
333 reserve_comment = true
334 })
335 assert.is_true(result:match("item 1") ~= nil)
336 return assert.is_true(result:match("item 2") ~= nil)
337 end)
338 it("should preserve empty lines in TableBlock between comments", function()
339 local code = "tb =\n\t-- a\n\t\n\t\n\t\n\tval: 1\n"
340 local result = to_lua(code, {
341 reserve_comment = true
342 })
343 return assert.is_true(result:match("-- %d+") ~= nil)
344 end)
345 it("should preserve empty lines in TableBlock with comments", function()
346 local code = "tb =\n\t-- first\n\t\n\t\n\tval: 1\n\t\n\t-- second\n\tval2: 2\n"
347 local result = to_lua(code, {
348 reserve_comment = true
349 })
350 assert.is_true(result:match("first") ~= nil)
351 assert.is_true(result:match("second") ~= nil)
352 return assert.is_true(result:match("-- %d+") ~= nil)
353 end)
354 it("should preserve empty lines in table literal", function()
355 local code = "t = {\n\t-- item1\n\t\n\t\n\t1,\n\t\n\t-- item2\n\t2\n}\n"
356 local result = to_lua(code, {
357 reserve_comment = true
358 })
359 assert.is_true(result:match("item1") ~= nil)
360 assert.is_true(result:match("item2") ~= nil)
361 return assert.is_true(result:match("-- %d+") ~= nil)
362 end)
363 it("should have more newlines with reserve_comment than without", function()
364 local code = "-- comment1\nx = 1\n-- comment2\ny = 2\n"
365 local result_with = to_lua(code, {
366 reserve_comment = true
367 })
368 local result_without = to_lua(code, { })
369 local newlines_with = 0
370 local newlines_without = 0
371 for _ in result_with:gmatch("\n") do
372 newlines_with = newlines_with + 1
373 end
374 for _ in result_without:gmatch("\n") do
375 newlines_without = newlines_without + 1
376 end
377 return assert.is_true(newlines_with >= newlines_without)
378 end)
379 it("should preserve empty lines in TableBlock between entries", function()
380 local code = "tb =\n\t-- key1\n\tkey1: 1\n\t\n\t\n\t-- key2\n\tkey2: 2\n"
381 local result = to_lua(code, {
382 reserve_comment = true
383 })
384 assert.is_true(result:match("key1") ~= nil)
385 assert.is_true(result:match("key2") ~= nil)
386 return assert.is_true(result:match("\t-- %d+\n") ~= nil)
387 end)
388 it("should preserve empty lines in class body", function()
389 local code = "class C\n\t-- prop1\n\tprop1: 1\n\t\n\t\n\t-- prop2\n\tprop2: 2\n"
390 local result = to_lua(code, {
391 reserve_comment = true
392 })
393 assert.is_true(result:match("prop1") ~= nil)
394 return assert.is_true(result:match("prop2") ~= nil)
395 end)
396 it("should preserve empty lines between comments in table", function()
397 local code = "t = {\n\t-- first\n\t\n\t-- second\n\t\n\t-- third\n\tval: 1\n}\n"
398 local result = to_lua(code, {
399 reserve_comment = true
400 })
401 assert.is_true(result:match("first") ~= nil)
402 assert.is_true(result:match("second") ~= nil)
403 assert.is_true(result:match("third") ~= nil)
404 return assert.is_true(result:match("-- %d+") ~= nil)
405 end)
406 it("should preserve multiple consecutive empty lines in TableBlock", function()
407 local code = "tb =\n\t-- start\n\tval1: 1\n\t\n\t\n\t\n\t-- middle\n\tval2: 2\n\t\n\t\n\t-- end\n\tval3: 3\n"
408 local result = to_lua(code, {
409 reserve_comment = true
410 })
411 assert.is_true(result:match("start") ~= nil)
412 assert.is_true(result:match("middle") ~= nil)
413 assert.is_true(result:match("end") ~= nil)
414 return assert.is_true(result:match("-- %d+") ~= nil)
415 end)
416 it("should preserve comments in table literal", function()
417 local code = "t = {\n\t-- comment\n\tkey: 1\n}\n"
418 local result = to_lua(code, {
419 reserve_comment = true
420 })
421 return assert.is_true(result:match("comment") ~= nil)
422 end)
423 it("should preserve comments in TableBlock", function()
424 local code = "t =\n\t-- comment\n\tkey: 1\n"
425 local result = to_lua(code, {
426 reserve_comment = true
427 })
428 return assert.is_true(result:match("comment") ~= nil)
429 end)
430 it("should preserve comments in class body", function()
431 local code = "class C\n\t-- comment\n\tkey: 1\n"
432 local result = to_lua(code, {
433 reserve_comment = true
434 })
435 return assert.is_true(result:match("comment") ~= nil)
436 end)
437 it("should preserve multiple comments in class body", function()
438 local code = "class C\n\t-- prop1\n\tprop1: 1\n\t-- prop2\n\tprop2: 2\n"
439 local result = to_lua(code, {
440 reserve_comment = true
441 })
442 assert.is_true(result:match("prop1") ~= nil)
443 return assert.is_true(result:match("prop2") ~= nil)
444 end)
445 it("should preserve empty lines in table literal", function()
446 local code = "t = {\n\t-- a\n\t\n\t-- b\n\tkey: 1\n}\n"
447 local result = to_lua(code, {
448 reserve_comment = true
449 })
450 assert.is_true(result:match("a") ~= nil)
451 assert.is_true(result:match("b") ~= nil)
452 return assert.is_true(result:match("-- %d+") ~= nil)
453 end)
454 it("should preserve empty lines in TableBlock", function()
455 local code = "t =\n\t-- a\n\t\n\t-- b\n\tkey: 1\n"
456 local result = to_lua(code, {
457 reserve_comment = true
458 })
459 assert.is_true(result:match("a") ~= nil)
460 assert.is_true(result:match("b") ~= nil)
461 return assert.is_true(result:match("-- %d+") ~= nil)
462 end)
463 return it("should preserve empty lines in class body", function()
464 local code = "class C\n\t-- a\n\ta: 1\n\t\n\t-- b\n\tb: 2\n"
465 local result = to_lua(code, {
466 reserve_comment = true
467 })
468 assert.is_true(result:match("a") ~= nil)
469 return assert.is_true(result:match("b") ~= nil)
470 end)
471end)
diff --git a/spec/outputs/whitespace.lua b/spec/outputs/whitespace.lua
index 864f085..60e98bb 100644
--- a/spec/outputs/whitespace.lua
+++ b/spec/outputs/whitespace.lua
@@ -107,4 +107,37 @@ for i = 1, 10, -1 do
107 print(i) 107 print(i)
108end 108end
109local a, b, c 109local a, b, c
110do
111 local tb = {
112 a = 1,
113 b = function() end
114 }
115 local tb2 = {
116 a = 1,
117 b = function() end
118 }
119 local tb3
120 local _class_0
121 local _base_0 = {
122 a = 1,
123 b = function() end
124 }
125 if _base_0.__index == nil then
126 _base_0.__index = _base_0
127 end
128 _class_0 = setmetatable({
129 __init = function() end,
130 __base = _base_0,
131 __name = "tb3"
132 }, {
133 __index = _base_0,
134 __call = function(cls, ...)
135 local _self_0 = setmetatable({ }, _base_0)
136 cls.__init(_self_0, ...)
137 return _self_0
138 end
139 })
140 _base_0.__class = _class_0
141 tb3 = _class_0
142end
110return nil 143return nil
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index a4ce15c..6cf0fc7 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -1033,9 +1033,6 @@ private:
1033 1033
1034 const std::string nl(ast_node* node) const { 1034 const std::string nl(ast_node* node) const {
1035 if (_config.reserveLineNumber) { 1035 if (_config.reserveLineNumber) {
1036 if (ast_is<EmptyLine_t>(node)) {
1037 return _newLine;
1038 }
1039 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; 1036 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
1040 } else { 1037 } else {
1041 return _newLine; 1038 return _newLine;
@@ -7996,13 +7993,13 @@ private:
7996 case id<YueComment_t>(): { 7993 case id<YueComment_t>(): {
7997 if (_config.reserveComment) { 7994 if (_config.reserveComment) {
7998 auto comment = static_cast<YueComment_t*>(item); 7995 auto comment = static_cast<YueComment_t*>(item);
7999 temp.push_back(indent() + comment->to_string(&_config) + nl(item)); 7996 temp.push_back(indent() + comment->to_string(&_config) + '\n');
8000 } 7997 }
8001 break; 7998 break;
8002 } 7999 }
8003 case id<EmptyLine_t>(): { 8000 case id<EmptyLine_t>(): {
8004 if (_config.reserveComment) { 8001 if (_config.reserveComment) {
8005 temp.push_back(nl(item)); 8002 temp.push_back("\n"s);
8006 } 8003 }
8007 break; 8004 break;
8008 } 8005 }
@@ -8356,7 +8353,7 @@ private:
8356 } 8353 }
8357 if (!isMetamethod) { 8354 if (!isMetamethod) {
8358 if (skipComma) { 8355 if (skipComma) {
8359 temp.back() = indent() + temp.back() + nl(value); 8356 temp.back() = indent() + temp.back() + '\n';
8360 } else { 8357 } else {
8361 temp.back() = indent() + (value == lastValueNode ? temp.back() : temp.back() + ',') + nl(value); 8358 temp.back() = indent() + (value == lastValueNode ? temp.back() : temp.back() + ',') + nl(value);
8362 } 8359 }
@@ -9984,7 +9981,7 @@ private:
9984 case id<YueComment_t>(): { 9981 case id<YueComment_t>(): {
9985 if (_config.reserveComment) { 9982 if (_config.reserveComment) {
9986 auto comment = static_cast<YueComment_t*>(content); 9983 auto comment = static_cast<YueComment_t*>(content);
9987 baseEntries.emplace_back(indent(1) + comment->to_string(&_config) + nl(content), false); 9984 baseEntries.emplace_back(indent(1) + comment->to_string(&_config) + '\n', false);
9988 } 9985 }
9989 break; 9986 break;
9990 } 9987 }
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index f712db7..c5c3ef7 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -63,6 +63,7 @@ public:
63YueParser::YueParser() { 63YueParser::YueParser() {
64 plain_space = *set(" \t"); 64 plain_space = *set(" \t");
65 line_break = nl(-expr('\r') >> '\n'); 65 line_break = nl(-expr('\r') >> '\n');
66 plain_space_break = plain_space >> line_break;
66 any_char = line_break | any(); 67 any_char = line_break | any();
67 stop = line_break | eof(); 68 stop = line_break | eof();
68 comment = "--" >> *(not_(set("\r\n")) >> any_char) >> and_(stop); 69 comment = "--" >> *(not_(set("\r\n")) >> any_char) >> and_(stop);
@@ -888,43 +889,37 @@ YueParser::YueParser() {
888 SpreadExp | 889 SpreadExp |
889 NormalDef; 890 NormalDef;
890 891
891 table_lit_line = 892 table_lit_line = -EmptyLine >> push_indent_match >> (
892 -EmptyLine >> ( 893 space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> space >> -(',' >> space) >> pop_indent |
893 push_indent_match >> ( 894 YueComment >> pop_indent |
894 space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | 895 pop_indent
895 YueComment >> pop_indent | 896 );
896 pop_indent
897 )
898 ) | (
899 space
900 );
901 897
902 table_lit_lines = space_break >> table_lit_line >> *(-(space >> ',') >> space_break >> table_lit_line) >> -(space >> ','); 898 table_lit_lines = +plain_space_break >> table_lit_line >> *(line_break >> table_lit_line);
903 899
904 TableLit = 900 TableLit =
905 '{' >> Seperator >> 901 '{' >> Seperator >>
906 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >> 902 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >> space >>
907 ( 903 (
908 table_lit_lines >> white >> end_braces_expression | 904 table_lit_lines >> white >> end_braces_expression |
909 white >> '}' 905 white >> '}'
910 ); 906 );
911 907
912 table_block_inner = Seperator >> key_value_line >> *(((plain_space >> line_break) >> key_value_line) | (+space_break >> not_(expr("--")) >> key_value_line)); 908 table_block_inner = Seperator >> key_value_line >> *(line_break >> key_value_line);
913 TableBlock = ((+(plain_space >> line_break)) | (+space_break >> not_(expr("--")))) >> advance_match >> ensure(table_block_inner, pop_indent); 909 TableBlock = +plain_space_break >> advance_match >> ensure(table_block_inner, pop_indent);
914 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule( 910 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
915 space >> key_value_list >> -(space >> ',') >> 911 space >> key_value_list >> -(space >> ',') >>
916 -((plain_space >> line_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(((plain_space >> line_break) >> key_value_line) | (+space_break >> not_(expr("--")) >> key_value_line)), pop_indent)) | 912 -(plain_space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(plain_space_break >> key_value_line), pop_indent)));
917 (+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))));
918 913
919 ClassMemberList = Seperator >> key_value >> *(space >> ',' >> space >> key_value); 914 ClassMemberList = Seperator >> key_value >> *(space >> ',' >> space >> key_value);
920 class_line = 915 class_line = -EmptyLine >> (
921 (EmptyLine >> YueComment) |
922 YueComment | 916 YueComment |
923 check_indent_match >> space >> (ClassMemberList | Statement) >> -(space >> ','); 917 check_indent_match >> space >> (ClassMemberList | Statement) >> -(space >> ',')
918 ) >> space;
924 ClassBlock = 919 ClassBlock =
925 ((+(plain_space >> line_break)) | (+space_break >> not_(expr("--")))) >> 920 +plain_space_break >>
926 advance_match >> Seperator >> 921 advance_match >> Seperator >>
927 class_line >> *(((plain_space >> line_break) >> class_line) | (+space_break >> not_(expr("--")) >> class_line)) >> 922 class_line >> *(plain_space_break >> class_line) >>
928 pop_indent; 923 pop_indent;
929 924
930 ClassDecl = 925 ClassDecl =
@@ -932,7 +927,7 @@ YueParser::YueParser() {
932 -(space >> Assignable) >> 927 -(space >> Assignable) >>
933 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >> 928 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >>
934 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent)) 929 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent))
935 ) >> -ClassBlock; 930 ) >> space >> -ClassBlock;
936 931
937 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpList | expected_expression_error)); 932 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpList | expected_expression_error));
938 GlobalOp = expr('*') | '^'; 933 GlobalOp = expr('*') | '^';
@@ -1021,14 +1016,14 @@ YueParser::YueParser() {
1021 MetaVariablePair | 1016 MetaVariablePair |
1022 MetaNormalPair; 1017 MetaNormalPair;
1023 key_value_list = key_value >> *(space >> ',' >> space >> key_value); 1018 key_value_list = key_value >> *(space >> ',' >> space >> key_value);
1024 key_value_line = 1019 key_value_line = -EmptyLine >> (
1025 (EmptyLine >> YueComment) |
1026 YueComment | 1020 YueComment |
1027 check_indent_match >> space >> ( 1021 check_indent_match >> space >> (
1028 key_value_list >> -(space >> ',') | 1022 key_value_list >> -(space >> ',') |
1029 TableBlockIndent | 1023 TableBlockIndent |
1030 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock) 1024 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
1031 ); 1025 ) >> space
1026 );
1032 1027
1033 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 1028 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
1034 1029
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index df9f39c..12b19ac 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -200,6 +200,7 @@ private:
200 NONE_AST_RULE(num_expo_hex); 200 NONE_AST_RULE(num_expo_hex);
201 NONE_AST_RULE(lj_num); 201 NONE_AST_RULE(lj_num);
202 NONE_AST_RULE(plain_space); 202 NONE_AST_RULE(plain_space);
203 NONE_AST_RULE(plain_space_break);
203 NONE_AST_RULE(line_break); 204 NONE_AST_RULE(line_break);
204 NONE_AST_RULE(any_char); 205 NONE_AST_RULE(any_char);
205 NONE_AST_RULE(white); 206 NONE_AST_RULE(white);
diff --git a/yuescript-dev-1.rockspec b/yuescript-dev-1.rockspec
index 1d69998..864cf2e 100644
--- a/yuescript-dev-1.rockspec
+++ b/yuescript-dev-1.rockspec
@@ -2,13 +2,13 @@ rockspec_format = "3.0"
2package = "Yuescript" 2package = "Yuescript"
3version = "dev-1" 3version = "dev-1"
4source = { 4source = {
5 url = "git+https://github.com/pigpigyyy/yuescript" 5 url = "git+https://github.com/IppClub/YueScript"
6} 6}
7description = { 7description = {
8 summary = "Yuescript is a Moonscript dialect.", 8 summary = "Yuescript is a Moonscript dialect.",
9 detailed = [[ 9 detailed = [[
10 Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]], 10 Yuescript is a Moonscript dialect. It is derived from Moonscript language 0.5.0 and continuously adopting new features to be more up to date. ]],
11 homepage = "https://github.com/pigpigyyy/yuescript", 11 homepage = "https://github.com/IppClub/YueScript",
12 maintainer = "Li Jin <dragon-fly@qq.com>", 12 maintainer = "Li Jin <dragon-fly@qq.com>",
13 labels = {"yuescript","cpp","transpiler","moonscript"}, 13 labels = {"yuescript","cpp","transpiler","moonscript"},
14 license = "MIT" 14 license = "MIT"
@@ -16,7 +16,6 @@ description = {
16dependencies = { 16dependencies = {
17 "lua >= 5.1", 17 "lua >= 5.1",
18} 18}
19
20build = { 19build = {
21 type = "cmake", 20 type = "cmake",
22 variables = { 21 variables = {