aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/yue-de.md5881
-rw-r--r--doc/yue-en.md5895
-rw-r--r--doc/yue-id-id.md5890
-rw-r--r--doc/yue-pt-br.md5890
-rw-r--r--doc/yue-zh.md5866
-rw-r--r--makefile5
-rw-r--r--spec/inputs/compile_doc.yue10
-rw-r--r--spec/outputs/codes_from_doc_de.lua24
-rw-r--r--spec/outputs/codes_from_doc_en.lua24
-rw-r--r--spec/outputs/codes_from_doc_id-id.lua24
-rw-r--r--spec/outputs/codes_from_doc_pt-br.lua24
-rw-r--r--spec/outputs/codes_from_doc_zh.lua24
-rw-r--r--spec/outputs/compile_doc.lua26
13 files changed, 29573 insertions, 10 deletions
diff --git a/doc/yue-de.md b/doc/yue-de.md
new file mode 100644
index 0000000..36d96cd
--- /dev/null
+++ b/doc/yue-de.md
@@ -0,0 +1,5881 @@
1---
2title: Referenz
3---
4
5# YueScript-Dokumentation
6
7<img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em; padding-bottom: 2em;"/>
8
9Willkommen in der offiziellen <b>YueScript</b>-Dokumentation!<br/>
10Hier findest du Sprachfeatures, Nutzung, Referenzbeispiele und Ressourcen.<br/>
11Bitte wähle ein Kapitel in der Seitenleiste, um mit YueScript zu beginnen.
12
13# Do
14
15Als Statement verhält sich `do` wie in Lua.
16
17```yuescript
18do
19 var = "hallo"
20 print var
21print var -- nil hier
22```
23
24<YueDisplay>
25
26```yue
27do
28 var = "hallo"
29 print var
30print var -- nil hier
31```
32
33</YueDisplay>
34
35YueScripts **do** kann auch als Ausdruck verwendet werden. So kannst du mehrere Zeilen in einem Ausdruck kombinieren. Das Ergebnis des `do`-Ausdrucks ist die letzte Anweisung im Block. `do`-Ausdrücke unterstützen die Verwendung von `break`, um den Kontrollfluss zu unterbrechen und mehrere Rückgabewerte vorzeitig zurückzugeben.
36
37```yuescript
38status, value = do
39 n = 12
40 if n > 10
41 break "large", n
42 break "small", n
43```
44
45<YueDisplay>
46
47```yue
48status, value = do
49 n = 12
50 if n > 10
51 break "large", n
52 break "small", n
53```
54
55</YueDisplay>
56
57```yuescript
58counter = do
59 i = 0
60 ->
61 i += 1
62 i
63
64print counter!
65print counter!
66```
67
68<YueDisplay>
69
70```yue
71counter = do
72 i = 0
73 ->
74 i += 1
75 i
76
77print counter!
78print counter!
79```
80
81</YueDisplay>
82
83```yuescript
84tbl = {
85 key: do
86 print "Schlüssel wird zugewiesen!"
87 1234
88}
89```
90
91<YueDisplay>
92
93```yue
94tbl = {
95 key: do
96 print "Schlüssel wird zugewiesen!"
97 1234
98}
99```
100
101</YueDisplay>
102
103# Line-Decorators
104
105Zur Vereinfachung können `for`-Schleifen und `if`-Anweisungen auf einzelne Anweisungen am Zeilenende angewendet werden:
106
107```yuescript
108print "Hallo Welt" if name == "Rob"
109```
110
111<YueDisplay>
112
113```yue
114print "Hallo Welt" if name == "Rob"
115```
116
117</YueDisplay>
118
119Und mit einfachen Schleifen:
120
121```yuescript
122print "Element: ", item for item in *items
123```
124
125<YueDisplay>
126
127```yue
128print "Element: ", item for item in *items
129```
130
131</YueDisplay>
132
133Und mit `while`-Schleifen:
134
135```yuescript
136game\update! while game\isRunning!
137
138reader\parse_line! until reader\eof!
139```
140
141<YueDisplay>
142
143```yue
144game\update! while game\isRunning!
145
146reader\parse_line! until reader\eof!
147```
148
149</YueDisplay>
150
151# Makros
152
153## Häufige Verwendung
154
155Makrofunktionen werden verwendet, um zur Compile-Zeit einen String auszuwerten und den generierten Code in die finale Kompilierung einzufügen.
156
157```yuescript
158macro PI2 = -> math.pi * 2
159area = $PI2 * 5
160
161macro HELLO = -> "'Hallo Welt'"
162print $HELLO
163
164macro config = (debugging) ->
165 global debugMode = debugging == "true"
166 ""
167
168macro asserts = (cond) ->
169 debugMode and "assert #{cond}" or ""
170
171macro assert = (cond) ->
172 debugMode and "assert #{cond}" or "#{cond}"
173
174$config true
175$asserts item ~= nil
176
177$config false
178value = $assert item
179
180-- übergebene Ausdrücke werden als Strings behandelt
181macro and = (...) -> "#{ table.concat {...}, ' and ' }"
182if $and f1!, f2!, f3!
183 print "OK"
184```
185
186<YueDisplay>
187
188```yue
189macro PI2 = -> math.pi * 2
190area = $PI2 * 5
191
192macro HELLO = -> "'Hallo Welt'"
193print $HELLO
194
195macro config = (debugging) ->
196 global debugMode = debugging == "true"
197 ""
198
199macro asserts = (cond) ->
200 debugMode and "assert #{cond}" or ""
201
202macro assert = (cond) ->
203 debugMode and "assert #{cond}" or "#{cond}"
204
205$config true
206$asserts item ~= nil
207
208$config false
209value = $assert item
210
211-- übergebene Ausdrücke werden als Strings behandelt
212macro and = (...) -> "#{ table.concat {...}, ' and ' }"
213if $and f1!, f2!, f3!
214 print "OK"
215```
216
217</YueDisplay>
218
219## Rohcode einfügen
220
221Eine Makrofunktion kann entweder einen YueScript-String oder eine Konfigurationstabelle mit Lua-Code zurückgeben.
222
223```yuescript
224macro yueFunc = (var) -> "local #{var} = ->"
225$yueFunc funcA
226funcA = -> "Zuweisung an die vom Yue-Makro definierte Variable schlägt fehl"
227
228macro luaFunc = (var) -> {
229 code: "local function #{var}() end"
230 type: "lua"
231}
232$luaFunc funcB
233funcB = -> "Zuweisung an die vom Lua-Makro definierte Variable schlägt fehl"
234
235macro lua = (code) -> {
236 :code
237 type: "lua"
238}
239
240-- führende und abschließende Symbole des Raw-Strings werden automatisch getrimmt
241$lua[==[
242-- Einfügen von rohem Lua-Code
243if cond then
244 print("Ausgabe")
245end
246]==]
247```
248
249<YueDisplay>
250
251```yue
252macro yueFunc = (var) -> "local #{var} = ->"
253$yueFunc funcA
254funcA = -> "Zuweisung an die vom Yue-Makro definierte Variable schlägt fehl"
255
256macro luaFunc = (var) -> {
257 code: "local function #{var}() end"
258 type: "lua"
259}
260$luaFunc funcB
261funcB = -> "Zuweisung an die vom Lua-Makro definierte Variable schlägt fehl"
262
263macro lua = (code) -> {
264 :code
265 type: "lua"
266}
267
268-- führende und abschließende Symbole des Raw-Strings werden automatisch getrimmt
269$lua[==[
270-- Einfügen von rohem Lua-Code
271if cond then
272 print("Ausgabe")
273end
274]==]
275```
276
277</YueDisplay>
278
279## Makros exportieren
280
281Makrofunktionen können aus einem Modul exportiert und in ein anderes Modul importiert werden. Exportierte Makros müssen in einer einzelnen Datei liegen, und im Export-Modul dürfen nur Makrodefinitionen, Makro-Imports und Makro-Expansionen stehen.
282
283```yuescript
284-- Datei: utils.yue
285export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
286export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
287export macro foreach = (items, action) -> "for _ in *#{items}
288 #{action}"
289
290-- Datei main.yue
291import "utils" as {
292 $, -- Symbol zum Importieren aller Makros
293 $foreach: $each -- Makro $foreach in $each umbenennen
294}
295[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
296```
297
298<YueDisplay>
299
300```yue
301-- Datei: utils.yue
302export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
303export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
304export macro foreach = (items, action) -> "for _ in *#{items}
305 #{action}"
306
307-- Datei main.yue
308-- Import-Funktion im Browser nicht verfügbar, in echter Umgebung testen
309--[[
310import "utils" as {
311 $, -- Symbol zum Importieren aller Makros
312 $foreach: $each -- Makro $foreach in $each umbenennen
313}
314[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
315]]
316```
317
318</YueDisplay>
319
320## Eingebaute Makros
321
322Es gibt einige eingebaute Makros, aber du kannst sie überschreiben, indem du Makros mit denselben Namen deklarierst.
323
324```yuescript
325print $FILE -- String des aktuellen Modulnamens
326print $LINE -- gibt 2 aus
327```
328
329<YueDisplay>
330
331```yue
332print $FILE -- String des aktuellen Modulnamens
333print $LINE -- gibt 2 aus
334```
335
336</YueDisplay>
337
338## Makros mit Makros erzeugen
339
340In YueScript erlauben Makrofunktionen Codegenerierung zur Compile-Zeit. Durch das Verschachteln von Makrofunktionen kannst du komplexere Generierungsmuster erzeugen. Damit kannst du eine Makrofunktion definieren, die eine andere Makrofunktion erzeugt.
341
342```yuescript
343macro Enum = (...) ->
344 items = {...}
345 itemSet = {item, true for item in *items}
346 (item) ->
347 error "erhalten: \"#{item}\", erwartet eines von #{table.concat items, ', '}" unless itemSet[item]
348 "\"#{item}\""
349
350macro BodyType = $Enum(
351 Static
352 Dynamic
353 Kinematic
354)
355
356print "Gültiger Enum-Typ:", $BodyType Static
357-- print "Kompilierungsfehler bei Enum-Typ:", $BodyType Unknown
358```
359
360<YueDisplay>
361
362```yue
363macro Enum = (...) ->
364 items = {...}
365 itemSet = {item, true for item in *items}
366 (item) ->
367 error "erhalten: \"#{item}\", erwartet eines von #{table.concat items, ', '}" unless itemSet[item]
368 "\"#{item}\""
369
370macro BodyType = $Enum(
371 Static
372 Dynamic
373 Kinematic
374)
375
376print "Gültiger Enum-Typ:", $BodyType Static
377-- print "Kompilierungsfehler bei Enum-Typ:", $BodyType Unknown
378```
379
380</YueDisplay>
381
382## Argument-Validierung
383
384Du kannst erwartete AST-Knotentypen in der Argumentliste deklarieren und zur Compile-Zeit prüfen, ob die übergebenen Makroargumente den Erwartungen entsprechen.
385
386```yuescript
387macro printNumAndStr = (num `Num, str `String) -> |
388 print(
389 #{num}
390 #{str}
391 )
392
393$printNumAndStr 123, "hallo"
394```
395
396<YueDisplay>
397
398```yue
399macro printNumAndStr = (num `Num, str `String) -> |
400 print(
401 #{num}
402 #{str}
403 )
404
405$printNumAndStr 123, "hallo"
406```
407
408</YueDisplay>
409
410Wenn du flexiblere Argumentprüfungen brauchst, kannst du das eingebaute Makro `$is_ast` verwenden, um manuell an der passenden Stelle zu prüfen.
411
412```yuescript
413macro printNumAndStr = (num, str) ->
414 error "als erstes Argument Num erwartet" unless $is_ast Num, num
415 error "als zweites Argument String erwartet" unless $is_ast String, str
416 "print(#{num}, #{str})"
417
418$printNumAndStr 123, "hallo"
419```
420
421<YueDisplay>
422
423```yue
424macro printNumAndStr = (num, str) ->
425 error "als erstes Argument Num erwartet" unless $is_ast Num, num
426 error "als zweites Argument String erwartet" unless $is_ast String, str
427 "print(#{num}, #{str})"
428
429$printNumAndStr 123, "hallo"
430```
431
432</YueDisplay>
433
434Weitere Details zu verfügbaren AST-Knoten findest du in den großgeschriebenen Definitionen in `yue_parser.cpp`.
435
436# Try
437
438Die Syntax für Fehlerbehandlung in Lua in einer gängigen Form.
439
440```yuescript
441try
442 func 1, 2, 3
443catch err
444 print yue.traceback err
445
446success, result = try
447 func 1, 2, 3
448catch err
449 yue.traceback err
450
451try func 1, 2, 3
452catch err
453 print yue.traceback err
454
455success, result = try func 1, 2, 3
456
457try
458 print "Versuche"
459 func 1, 2, 3
460
461-- Verwendung mit if-Zuweisungsmuster
462if success, result := try func 1, 2, 3
463catch err
464 print yue.traceback err
465 print result
466```
467
468<YueDisplay>
469
470```yue
471try
472 func 1, 2, 3
473catch err
474 print yue.traceback err
475
476success, result = try
477 func 1, 2, 3
478catch err
479 yue.traceback err
480
481try func 1, 2, 3
482catch err
483 print yue.traceback err
484
485success, result = try func 1, 2, 3
486
487try
488 print "Versuche"
489 func 1, 2, 3
490
491-- Verwendung mit if-Zuweisungsmuster
492if success, result := try func 1, 2, 3
493catch err
494 print yue.traceback err
495 print result
496```
497
498</YueDisplay>
499
500## Try?
501
502`try?` ist eine vereinfachte Fehlerbehandlungs-Syntax, die den booleschen Status aus dem `try`-Statement weglässt. Bei Erfolg gibt sie das Ergebnis des `try`-Blocks zurück, ansonsten `nil` statt eines Fehlerobjekts.
503
504```yuescript
505a, b, c = try? func!
506
507-- mit Nil-Verschmelzungs-Operator
508a = (try? func!) ?? "Standardwert"
509
510-- als Funktionsargument
511f try? func!
512
513-- mit catch-Block
514f try?
515 print 123
516 func!
517catch e
518 print e
519 e
520```
521
522<YueDisplay>
523
524```yue
525a, b, c = try? func!
526
527-- mit Nil-Verschmelzungs-Operator
528a = (try? func!) ?? "Standardwert"
529
530-- als Funktionsargument
531f try? func!
532
533-- mit catch-Block
534f try?
535 print 123
536 func!
537catch e
538 print e
539 e
540```
541
542</YueDisplay>
543
544# Tabellenliterale
545
546Wie in Lua werden Tabellen mit geschweiften Klammern definiert.
547
548```yuescript
549some_values = [1, 2, 3, 4]
550```
551
552<YueDisplay>
553
554```yue
555some_values = [1, 2, 3, 4]
556```
557
558</YueDisplay>
559
560Anders als in Lua weist man einem Schlüssel in einer Tabelle mit **:** (statt **=**) einen Wert zu.
561
562```yuescript
563some_values = {
564 name: "Bill",
565 age: 200,
566 ["Lieblingsessen"]: "Reis"
567}
568```
569
570<YueDisplay>
571
572```yue
573some_values = {
574 name: "Bill",
575 age: 200,
576 ["Lieblingsessen"]: "Reis"
577}
578```
579
580</YueDisplay>
581
582Die geschweiften Klammern können weggelassen werden, wenn eine einzelne Tabelle aus Schlüssel-Wert-Paaren zugewiesen wird.
583
584```yuescript
585profile =
586 height: "4 Fuß",
587 shoe_size: 13,
588 favorite_foods: ["Eis", "Donuts"]
589```
590
591<YueDisplay>
592
593```yue
594profile =
595 height: "4 Fuß",
596 shoe_size: 13,
597 favorite_foods: ["Eis", "Donuts"]
598```
599
600</YueDisplay>
601
602Zeilenumbrüche können Werte statt eines Kommas trennen (oder zusätzlich):
603
604```yuescript
605values = {
606 1, 2, 3, 4
607 5, 6, 7, 8
608 name: "Superman"
609 occupation: "Verbrechensbekämpfung"
610}
611```
612
613<YueDisplay>
614
615```yue
616values = {
617 1, 2, 3, 4
618 5, 6, 7, 8
619 name: "Superman"
620 occupation: "Verbrechensbekämpfung"
621}
622```
623
624</YueDisplay>
625
626Beim Erstellen eines einzeiligen Tabellenliterals können die geschweiften Klammern ebenfalls weggelassen werden:
627
628```yuescript
629my_function dance: "Tango", partner: "keiner"
630
631y = type: "Hund", legs: 4, tails: 1
632```
633
634<YueDisplay>
635
636```yue
637my_function dance: "Tango", partner: "keiner"
638
639y = type: "Hund", legs: 4, tails: 1
640```
641
642</YueDisplay>
643
644Die Schlüssel eines Tabellenliterals können Sprach-Schlüsselwörter sein, ohne sie zu escapen:
645
646```yuescript
647tbl = {
648 do: "etwas"
649 end: "Hunger"
650}
651```
652
653<YueDisplay>
654
655```yue
656tbl = {
657 do: "etwas"
658 end: "Hunger"
659}
660```
661
662</YueDisplay>
663
664Wenn du eine Tabelle aus Variablen konstruierst und die Schlüssel den Variablennamen entsprechen sollen, kannst du den Präfix-Operator **:** verwenden:
665
666```yuescript
667hair = "golden"
668height = 200
669person = { :hair, :height, shoe_size: 40 }
670
671print_table :hair, :height
672```
673
674<YueDisplay>
675
676```yue
677hair = "golden"
678height = 200
679person = { :hair, :height, shoe_size: 40 }
680
681print_table :hair, :height
682```
683
684</YueDisplay>
685
686Wenn der Schlüssel eines Feldes das Ergebnis eines Ausdrucks sein soll, kannst du ihn wie in Lua in **[ ]** setzen. Du kannst auch ein String-Literal direkt als Schlüssel verwenden und die eckigen Klammern weglassen. Das ist nützlich, wenn dein Schlüssel Sonderzeichen enthält.
687
688```yuescript
689t = {
690 [1 + 2]: "hallo"
691 "Hallo Welt": true
692}
693```
694
695<YueDisplay>
696
697```yue
698t = {
699 [1 + 2]: "hallo"
700 "Hallo Welt": true
701}
702```
703
704</YueDisplay>
705
706Lua-Tabellen haben einen Array-Teil und einen Hash-Teil, aber manchmal möchte man beim Schreiben von Lua-Tabellen eine semantische Unterscheidung zwischen Array- und Hash-Nutzung machen. Dann kannst du eine Lua-Tabelle mit **[ ]** statt **{ }** schreiben, um eine Array-Tabelle darzustellen, und das Schreiben von Schlüssel-Wert-Paaren in einer Listentabelle ist nicht erlaubt.
707
708```yuescript
709some_values = [1, 2, 3, 4]
710list_with_one_element = [1, ]
711```
712
713<YueDisplay>
714
715```yue
716some_values = [1, 2, 3, 4]
717list_with_one_element = [1, ]
718```
719
720</YueDisplay>
721
722# Comprehensions
723
724Comprehensions bieten eine bequeme Syntax, um eine neue Tabelle zu erzeugen, indem man über ein bestehendes Objekt iteriert und einen Ausdruck auf seine Werte anwendet. Es gibt zwei Arten: Listen-Comprehensions und Tabellen-Comprehensions. Beide erzeugen Lua-Tabellen; Listen-Comprehensions sammeln Werte in einer array-ähnlichen Tabelle, und Tabellen-Comprehensions erlauben es, Schlüssel und Wert pro Iteration zu setzen.
725
726## Listen-Comprehensions
727
728Das folgende Beispiel erstellt eine Kopie der `items`-Tabelle, aber mit verdoppelten Werten.
729
730```yuescript
731items = [ 1, 2, 3, 4 ]
732doubled = [item * 2 for i, item in ipairs items]
733```
734
735<YueDisplay>
736
737```yue
738items = [ 1, 2, 3, 4 ]
739doubled = [item * 2 for i, item in ipairs items]
740```
741
742</YueDisplay>
743
744Die Elemente in der neuen Tabelle können mit einer `when`-Klausel eingeschränkt werden:
745
746```yuescript
747slice = [item for i, item in ipairs items when i > 1 and i < 3]
748```
749
750<YueDisplay>
751
752```yue
753slice = [item for i, item in ipairs items when i > 1 and i < 3]
754```
755
756</YueDisplay>
757
758Da es üblich ist, über die Werte einer numerisch indizierten Tabelle zu iterieren, gibt es den **\***-Operator. Das Verdopplungsbeispiel kann so umgeschrieben werden:
759
760```yuescript
761doubled = [item * 2 for item in *items]
762```
763
764<YueDisplay>
765
766```yue
767doubled = [item * 2 for item in *items]
768```
769
770</YueDisplay>
771
772In Listen-Comprehensions kannst du außerdem den Spread-Operator `...` verwenden, um verschachtelte Listen zu flatten und einen Flat-Map-Effekt zu erzielen:
773
774```yuescript
775data =
776 a: [1, 2, 3]
777 b: [4, 5, 6]
778
779flat = [...v for k,v in pairs data]
780-- flat ist jetzt [1, 2, 3, 4, 5, 6]
781```
782
783<YueDisplay>
784
785```yue
786data =
787 a: [1, 2, 3]
788 b: [4, 5, 6]
789
790flat = [...v for k,v in pairs data]
791-- flat ist jetzt [1, 2, 3, 4, 5, 6]
792```
793
794</YueDisplay>
795
796Die `for`- und `when`-Klauseln können beliebig oft verkettet werden. Die einzige Anforderung ist, dass eine Comprehension mindestens eine `for`-Klausel enthält.
797
798Mehrere `for`-Klauseln entsprechen verschachtelten Schleifen:
799
800```yuescript
801x_coords = [4, 5, 6, 7]
802y_coords = [9, 2, 3]
803
804points = [ [x, y] for x in *x_coords \
805for y in *y_coords]
806```
807
808<YueDisplay>
809
810```yue
811x_coords = [4, 5, 6, 7]
812y_coords = [9, 2, 3]
813
814points = [ [x, y] for x in *x_coords \
815for y in *y_coords]
816```
817
818</YueDisplay>
819
820Numerische `for`-Schleifen können ebenfalls in Comprehensions verwendet werden:
821
822```yuescript
823evens = [i for i = 1, 100 when i % 2 == 0]
824```
825
826<YueDisplay>
827
828```yue
829evens = [i for i = 1, 100 when i % 2 == 0]
830```
831
832</YueDisplay>
833
834## Tabellen-Comprehensions
835
836Die Syntax für Tabellen-Comprehensions ist sehr ähnlich, unterscheidet sich jedoch dadurch, dass **{** und **}** verwendet werden und pro Iteration zwei Werte erzeugt werden.
837
838Dieses Beispiel erstellt eine Kopie von `thing`:
839
840```yuescript
841thing = {
842 color: "rot"
843 name: "schnell"
844 width: 123
845}
846
847thing_copy = {k, v for k, v in pairs thing}
848```
849
850<YueDisplay>
851
852```yue
853thing = {
854 color: "rot"
855 name: "schnell"
856 width: 123
857}
858
859thing_copy = {k, v for k, v in pairs thing}
860```
861
862</YueDisplay>
863
864```yuescript
865no_color = {k, v for k, v in pairs thing when k != "color"}
866```
867
868<YueDisplay>
869
870```yue
871no_color = {k, v for k, v in pairs thing when k != "color"}
872```
873
874</YueDisplay>
875
876Der **\***-Operator wird ebenfalls unterstützt. Hier erstellen wir eine Nachschlagetabelle für Quadratwurzeln einiger Zahlen.
877
878```yuescript
879numbers = [1, 2, 3, 4]
880sqrts = {i, math.sqrt i for i in *numbers}
881```
882
883<YueDisplay>
884
885```yue
886numbers = [1, 2, 3, 4]
887sqrts = {i, math.sqrt i for i in *numbers}
888```
889
890</YueDisplay>
891
892Das Schlüssel-Wert-Tupel in einer Tabellen-Comprehension kann auch aus einem einzelnen Ausdruck stammen; der Ausdruck muss dann zwei Werte zurückgeben. Der erste wird als Schlüssel und der zweite als Wert verwendet:
893
894In diesem Beispiel konvertieren wir ein Array von Paaren in eine Tabelle, wobei das erste Element des Paars der Schlüssel und das zweite der Wert ist.
895
896```yuescript
897tuples = [ ["hallo", "Welt"], ["foo", "bar"]]
898tbl = {unpack tuple for tuple in *tuples}
899```
900
901<YueDisplay>
902
903```yue
904tuples = [ ["hallo", "Welt"], ["foo", "bar"]]
905tbl = {unpack tuple for tuple in *tuples}
906```
907
908</YueDisplay>
909
910## Slicing
911
912Eine spezielle Syntax erlaubt es, die iterierten Elemente bei Verwendung des **\***-Operators einzuschränken. Das ist äquivalent zum Setzen von Iterationsgrenzen und Schrittweite in einer `for`-Schleife.
913
914Hier setzen wir die minimalen und maximalen Grenzen und nehmen alle Elemente mit Indizes zwischen 1 und 5 (inklusive):
915
916```yuescript
917slice = [item for item in *items[1, 5]]
918```
919
920<YueDisplay>
921
922```yue
923slice = [item for item in *items[1, 5]]
924```
925
926</YueDisplay>
927
928Jedes der Slice-Argumente kann weggelassen werden, um einen sinnvollen Standard zu verwenden. Wenn der maximale Index weggelassen wird, entspricht er der Länge der Tabelle. Dieses Beispiel nimmt alles außer dem ersten Element:
929
930```yuescript
931slice = [item for item in *items[2,]]
932```
933
934<YueDisplay>
935
936```yue
937slice = [item for item in *items[2,]]
938```
939
940</YueDisplay>
941
942Wenn die Mindestgrenze weggelassen wird, ist sie standardmäßig 1. Hier geben wir nur die Schrittweite an und lassen die anderen Grenzen leer. Das nimmt alle ungerad indizierten Elemente (1, 3, 5, …):
943
944```yuescript
945slice = [item for item in *items[,,2]]
946```
947
948<YueDisplay>
949
950```yue
951slice = [item for item in *items[,,2]]
952```
953
954</YueDisplay>
955
956Sowohl die Mindest- als auch die Maximalgrenze können negativ sein; dann werden die Grenzen vom Ende der Tabelle gezählt.
957
958```yuescript
959-- die letzten 4 Elemente nehmen
960slice = [item for item in *items[-4,-1]]
961```
962
963<YueDisplay>
964
965```yue
966-- die letzten 4 Elemente nehmen
967slice = [item for item in *items[-4,-1]]
968```
969
970</YueDisplay>
971
972Die Schrittweite kann ebenfalls negativ sein, wodurch die Elemente in umgekehrter Reihenfolge genommen werden.
973
974```yuescript
975reverse_slice = [item for item in *items[-1,1,-1]]
976```
977
978<YueDisplay>
979
980```yue
981reverse_slice = [item for item in *items[-1,1,-1]]
982```
983
984</YueDisplay>
985
986### Slicing-Ausdruck
987
988Slicing kann auch als Ausdruck verwendet werden. Das ist nützlich, um eine Teilliste einer Tabelle zu erhalten.
989
990```yuescript
991-- das 2. und 4. Element als neue Liste nehmen
992sub_list = items[2, 4]
993
994-- die letzten 4 Elemente nehmen
995last_four_items = items[-4, -1]
996```
997
998<YueDisplay>
999
1000```yue
1001-- das 2. und 4. Element als neue Liste nehmen
1002sub_list = items[2, 4]
1003
1004-- die letzten 4 Elemente nehmen
1005last_four_items = items[-4, -1]
1006```
1007
1008</YueDisplay>
1009
1010# Objektorientierte Programmierung
1011
1012In diesen Beispielen kann der generierte Lua-Code überwältigend wirken. Am besten konzentrierst du dich zunächst auf die Bedeutung des YueScript-Codes und schaust dir den Lua-Code nur an, wenn du die Implementierungsdetails wissen möchtest.
1013
1014Eine einfache Klasse:
1015
1016```yuescript
1017class Inventory
1018 new: =>
1019 @items = {}
1020
1021 add_item: (name) =>
1022 if @items[name]
1023 @items[name] += 1
1024 else
1025 @items[name] = 1
1026```
1027
1028<YueDisplay>
1029
1030```yue
1031class Inventory
1032 new: =>
1033 @items = {}
1034
1035 add_item: (name) =>
1036 if @items[name]
1037 @items[name] += 1
1038 else
1039 @items[name] = 1
1040```
1041
1042</YueDisplay>
1043
1044Eine Klasse wird mit einem `class`-Statement deklariert, gefolgt von einer tabellenähnlichen Deklaration mit allen Methoden und Eigenschaften.
1045
1046Die Eigenschaft `new` ist besonders, da sie zum Konstruktor wird.
1047
1048Beachte, dass alle Methoden in der Klasse die Fat-Arrow-Syntax verwenden. Beim Aufruf von Methoden auf einer Instanz wird die Instanz selbst als erstes Argument übergeben. Der Fat-Arrow übernimmt die Erstellung des `self`-Arguments.
1049
1050Das `@`-Präfix ist Kurzform für `self.`. `@items` wird zu `self.items`.
1051
1052Eine Instanz der Klasse wird erstellt, indem man den Klassennamen wie eine Funktion aufruft.
1053
1054```yuescript
1055inv = Inventory!
1056inv\add_item "T-Shirt"
1057inv\add_item "Hose"
1058```
1059
1060<YueDisplay>
1061
1062```yue
1063inv = Inventory!
1064inv\add_item "T-Shirt"
1065inv\add_item "Hose"
1066```
1067
1068</YueDisplay>
1069
1070Da die Instanz bei Methodenaufrufen an die Methoden übergeben werden muss, wird der `\`-Operator verwendet.
1071
1072Alle Eigenschaften einer Klasse werden von allen Instanzen gemeinsam genutzt. Für Funktionen ist das ok, aber bei anderen Objekten kann das zu unerwünschten Ergebnissen führen.
1073
1074Im folgenden Beispiel wird die Eigenschaft `clothes` von allen Instanzen geteilt, sodass Änderungen in einer Instanz in einer anderen sichtbar werden:
1075
1076```yuescript
1077class Person
1078 clothes: []
1079 give_item: (name) =>
1080 table.insert @clothes, name
1081
1082a = Person!
1083b = Person!
1084
1085a\give_item "Hose"
1086b\give_item "Hemd"
1087
1088-- gibt sowohl Hose als auch Hemd aus
1089print item for item in *a.clothes
1090```
1091
1092<YueDisplay>
1093
1094```yue
1095class Person
1096 clothes: []
1097 give_item: (name) =>
1098 table.insert @clothes, name
1099
1100a = Person!
1101b = Person!
1102
1103a\give_item "Hose"
1104b\give_item "Hemd"
1105
1106-- gibt sowohl Hose als auch Hemd aus
1107print item for item in *a.clothes
1108```
1109
1110</YueDisplay>
1111
1112Der richtige Weg, das zu vermeiden, ist, den veränderlichen Zustand im Konstruktor zu erstellen:
1113
1114```yuescript
1115class Person
1116 new: =>
1117 @clothes = []
1118```
1119
1120<YueDisplay>
1121
1122```yue
1123class Person
1124 new: =>
1125 @clothes = []
1126```
1127
1128</YueDisplay>
1129
1130## Vererbung
1131
1132Das Schlüsselwort `extends` kann in einer Klassendeklaration verwendet werden, um Eigenschaften und Methoden von einer anderen Klasse zu erben.
1133
1134```yuescript
1135class BackPack extends Inventory
1136 size: 10
1137 add_item: (name) =>
1138 if #@items > size then error "Rucksack ist voll"
1139 super name
1140```
1141
1142<YueDisplay>
1143
1144```yue
1145class BackPack extends Inventory
1146 size: 10
1147 add_item: (name) =>
1148 if #@items > size then error "Rucksack ist voll"
1149 super name
1150```
1151
1152</YueDisplay>
1153
1154Hier erweitern wir unsere `Inventory`-Klasse und begrenzen die Anzahl der Elemente.
1155
1156In diesem Beispiel definieren wir keinen Konstruktor in der Subklasse, daher wird der Konstruktor der Elternklasse beim Erstellen einer neuen Instanz aufgerufen. Definieren wir einen Konstruktor, können wir mit `super` den Elternkonstruktor aufrufen.
1157
1158Wenn eine Klasse von einer anderen erbt, sendet sie eine Nachricht an die Elternklasse, indem die Methode `__inherited` der Elternklasse aufgerufen wird, falls vorhanden. Die Funktion erhält zwei Argumente: die Klasse, die vererbt wird, und die Kindklasse.
1159
1160```yuescript
1161class Shelf
1162 @__inherited: (child) =>
1163 print @__name, "wurde vererbt von", child.__name
1164
1165-- gibt aus: Shelf wurde von Cupboard geerbt
1166class Cupboard extends Shelf
1167```
1168
1169<YueDisplay>
1170
1171```yue
1172class Shelf
1173 @__inherited: (child) =>
1174 print @__name, "wurde vererbt von", child.__name
1175
1176-- gibt aus: Shelf wurde von Cupboard geerbt
1177class Cupboard extends Shelf
1178```
1179
1180</YueDisplay>
1181
1182## Super
1183
1184**super** ist ein spezielles Schlüsselwort, das auf zwei Arten verwendet werden kann: als Objekt oder als Funktionsaufruf. Es hat besondere Funktionalität nur innerhalb einer Klasse.
1185
1186Wenn es als Funktion aufgerufen wird, ruft es die gleichnamige Funktion in der Elternklasse auf. `self` wird automatisch als erstes Argument übergeben (wie im Vererbungsbeispiel oben).
1187
1188Wenn `super` als normaler Wert verwendet wird, ist es eine Referenz auf das Objekt der Elternklasse.
1189
1190Du kannst es wie jedes andere Objekt verwenden, um Werte der Elternklasse zu lesen, die von der Kindklasse überschattet wurden.
1191
1192Wenn der `\`-Aufrufoperator mit `super` verwendet wird, wird `self` als erstes Argument eingefügt statt des Wertes von `super`. Wenn man `.` zum Abrufen einer Funktion verwendet, wird die rohe Funktion zurückgegeben.
1193
1194Ein paar Beispiele für `super` in unterschiedlichen Formen:
1195
1196```yuescript
1197class MyClass extends ParentClass
1198 a_method: =>
1199 -- Folgendes hat dieselbe Wirkung:
1200 super "hallo", "Welt"
1201 super\a_method "hallo", "Welt"
1202 super.a_method self, "hallo", "Welt"
1203
1204 -- super als Wert entspricht der Elternklasse:
1205 assert super == ParentClass
1206```
1207
1208<YueDisplay>
1209
1210```yue
1211class MyClass extends ParentClass
1212 a_method: =>
1213 -- Folgendes hat dieselbe Wirkung:
1214 super "hallo", "Welt"
1215 super\a_method "hallo", "Welt"
1216 super.a_method self, "hallo", "Welt"
1217
1218 -- super als Wert entspricht der Elternklasse:
1219 assert super == ParentClass
1220```
1221
1222</YueDisplay>
1223
1224**super** kann auch links einer Funktions-Stub verwendet werden. Der einzige große Unterschied ist, dass die resultierende Funktion statt an `super` an `self` gebunden wird.
1225
1226## Typen
1227
1228Jede Instanz einer Klasse trägt ihren Typ in sich. Dieser wird in der speziellen Eigenschaft `__class` gespeichert. Diese Eigenschaft enthält das Klassenobjekt. Das Klassenobjekt wird aufgerufen, um eine neue Instanz zu erstellen. Wir können das Klassenobjekt auch indizieren, um Klassenmethoden und Eigenschaften abzurufen.
1229
1230```yuescript
1231b = BackPack!
1232assert b.__class == BackPack
1233
1234print BackPack.size -- gibt 10 aus
1235```
1236
1237<YueDisplay>
1238
1239```yue
1240b = BackPack!
1241assert b.__class == BackPack
1242
1243print BackPack.size -- gibt 10 aus
1244```
1245
1246</YueDisplay>
1247
1248## Klassenobjekte
1249
1250Das Klassenobjekt entsteht, wenn wir ein `class`-Statement verwenden. Es wird in einer Variablen mit dem Klassennamen gespeichert.
1251
1252Das Klassenobjekt kann wie eine Funktion aufgerufen werden, um neue Instanzen zu erstellen. So haben wir die Instanzen in den Beispielen oben erstellt.
1253
1254Eine Klasse besteht aus zwei Tabellen: der Klassentabelle selbst und der Basistabelle. Die Basis wird als Metatable für alle Instanzen verwendet. Alle in der Klassendeklaration aufgeführten Eigenschaften werden in der Basis platziert.
1255
1256Das Metatable des Klassenobjekts liest Eigenschaften aus der Basis, wenn sie im Klassenobjekt nicht existieren. Das bedeutet, dass wir Funktionen und Eigenschaften direkt von der Klasse aus aufrufen können.
1257
1258Wichtig: Zuweisungen an das Klassenobjekt schreiben nicht in die Basis. Das ist keine gültige Methode, um neue Methoden zu Instanzen hinzuzufügen. Stattdessen muss die Basis explizit geändert werden. Siehe das Feld `__base` unten.
1259
1260Das Klassenobjekt hat einige spezielle Eigenschaften:
1261
1262Der Name der Klasse, wie sie deklariert wurde, wird im Feld `__name` gespeichert.
1263
1264```yuescript
1265print BackPack.__name -- gibt Backpack aus
1266```
1267
1268<YueDisplay>
1269
1270```yue
1271print BackPack.__name -- gibt Backpack aus
1272```
1273
1274</YueDisplay>
1275
1276Die Basistabelle ist in `__base` gespeichert. Du kannst diese Tabelle ändern, um Instanzen Funktionalität hinzuzufügen, die bereits existieren oder noch erstellt werden.
1277
1278Wenn die Klasse von etwas erbt, ist das Elternklassenobjekt in `__parent` gespeichert.
1279
1280## Klassenvariablen
1281
1282Du kannst Variablen direkt im Klassenobjekt statt in der Basis erstellen, indem du in der Klassendeklaration `@` vor den Eigenschaftsnamen setzt.
1283
1284```yuescript
1285class Things
1286 @some_func: => print "Hallo von", @__name
1287
1288Things\some_func!
1289
1290-- Klassenvariablen in Instanzen nicht sichtbar
1291assert Things().some_func == nil
1292```
1293
1294<YueDisplay>
1295
1296```yue
1297class Things
1298 @some_func: => print "Hallo von", @__name
1299
1300Things\some_func!
1301
1302-- Klassenvariablen in Instanzen nicht sichtbar
1303assert Things().some_func == nil
1304```
1305
1306</YueDisplay>
1307
1308In Ausdrücken können wir `@@` verwenden, um auf einen Wert zuzugreifen, der in `self.__class` gespeichert ist. `@@hello` ist also eine Kurzform für `self.__class.hello`.
1309
1310```yuescript
1311class Counter
1312 @count: 0
1313
1314 new: =>
1315 @@count += 1
1316
1317Counter!
1318Counter!
1319
1320print Counter.count -- gibt 2 aus
1321```
1322
1323<YueDisplay>
1324
1325```yue
1326class Counter
1327 @count: 0
1328
1329 new: =>
1330 @@count += 1
1331
1332Counter!
1333Counter!
1334
1335print Counter.count -- gibt 2 aus
1336```
1337
1338</YueDisplay>
1339
1340Die Aufrufsemantik von `@@` ist ähnlich wie bei `@`. Wenn du einen `@@`-Namen aufrufst, wird die Klasse als erstes Argument übergeben (Lua-`:`-Syntax).
1341
1342```yuescript
1343@@hello 1,2,3,4
1344```
1345
1346<YueDisplay>
1347
1348```yue
1349@@hello 1,2,3,4
1350```
1351
1352</YueDisplay>
1353
1354## Klassendeklarations-Statements
1355
1356Im Rumpf einer Klassendeklaration können wir normale Ausdrücke zusätzlich zu Schlüssel/Wert-Paaren haben. In diesem Kontext ist `self` gleich dem Klassenobjekt.
1357
1358Hier ist eine alternative Möglichkeit, eine Klassenvariable zu erstellen:
1359
1360```yuescript
1361class Things
1362 @class_var = "Hallo Welt"
1363```
1364
1365<YueDisplay>
1366
1367```yue
1368class Things
1369 @class_var = "Hallo Welt"
1370```
1371
1372</YueDisplay>
1373
1374Diese Ausdrücke werden ausgeführt, nachdem alle Eigenschaften zur Basis hinzugefügt wurden.
1375
1376Alle Variablen, die im Klassenkörper deklariert werden, sind lokal zu den Klasseneigenschaften. Das ist praktisch, um private Werte oder Hilfsfunktionen zu platzieren, auf die nur die Klassenmethoden zugreifen können:
1377
1378```yuescript
1379class MoreThings
1380 secret = 123
1381 log = (msg) -> print "LOG:", msg
1382
1383 some_method: =>
1384 log "Hallo Welt: " .. secret
1385```
1386
1387<YueDisplay>
1388
1389```yue
1390class MoreThings
1391 secret = 123
1392 log = (msg) -> print "LOG:", msg
1393
1394 some_method: =>
1395 log "Hallo Welt: " .. secret
1396```
1397
1398</YueDisplay>
1399
1400## @- und @@-Werte
1401
1402Wenn `@` und `@@` vor einem Namen stehen, repräsentieren sie den Namen in `self` bzw. `self.__class`.
1403
1404Wenn sie alleine verwendet werden, sind sie Aliase für `self` und `self.__class`.
1405
1406```yuescript
1407assert @ == self
1408assert @@ == self.__class
1409```
1410
1411<YueDisplay>
1412
1413```yue
1414assert @ == self
1415assert @@ == self.__class
1416```
1417
1418</YueDisplay>
1419
1420Zum Beispiel kannst du mit `@@` in einer Instanzmethode schnell eine neue Instanz derselben Klasse erzeugen:
1421
1422```yuescript
1423some_instance_method = (...) => @@ ...
1424```
1425
1426<YueDisplay>
1427
1428```yue
1429some_instance_method = (...) => @@ ...
1430```
1431
1432</YueDisplay>
1433
1434## Konstruktor-Property-Promotion
1435
1436Um Boilerplate beim Definieren einfacher Value-Objekte zu reduzieren, kannst du eine Klasse so schreiben:
1437
1438```yuescript
1439class Something
1440 new: (@foo, @bar, @@biz, @@baz) =>
1441
1442-- Kurzform für
1443
1444class Something
1445 new: (foo, bar, biz, baz) =>
1446 @foo = foo
1447 @bar = bar
1448 @@biz = biz
1449 @@baz = baz
1450```
1451
1452<YueDisplay>
1453
1454```yue
1455class Something
1456 new: (@foo, @bar, @@biz, @@baz) =>
1457
1458-- Kurzform für
1459
1460class Something
1461 new: (foo, bar, biz, baz) =>
1462 @foo = foo
1463 @bar = bar
1464 @@biz = biz
1465 @@baz = baz
1466```
1467
1468</YueDisplay>
1469
1470Du kannst diese Syntax auch für eine gemeinsame Funktion verwenden, um Objektfelder zu initialisieren.
1471
1472```yuescript
1473new = (@fieldA, @fieldB) => @
1474obj = new {}, 123, "abc"
1475print obj
1476```
1477
1478<YueDisplay>
1479
1480```yue
1481new = (@fieldA, @fieldB) => @
1482obj = new {}, 123, "abc"
1483print obj
1484```
1485
1486</YueDisplay>
1487
1488## Klassenausdrücke
1489
1490Die `class`-Syntax kann auch als Ausdruck verwendet werden, der einer Variable zugewiesen oder explizit zurückgegeben wird.
1491
1492```yuescript
1493x = class Bucket
1494 drops: 0
1495 add_drop: => @drops += 1
1496```
1497
1498<YueDisplay>
1499
1500```yue
1501x = class Bucket
1502 drops: 0
1503 add_drop: => @drops += 1
1504```
1505
1506</YueDisplay>
1507
1508## Anonyme Klassen
1509
1510Der Name kann beim Deklarieren einer Klasse weggelassen werden. Das `__name`-Attribut ist dann `nil`, es sei denn, der Klassenausdruck steht in einer Zuweisung. In diesem Fall wird der Name auf der linken Seite statt `nil` verwendet.
1511
1512```yuescript
1513BigBucket = class extends Bucket
1514 add_drop: => @drops += 10
1515
1516assert Bucket.__name == "BigBucket"
1517```
1518
1519<YueDisplay>
1520
1521```yue
1522BigBucket = class extends Bucket
1523 add_drop: => @drops += 10
1524
1525assert Bucket.__name == "BigBucket"
1526```
1527
1528</YueDisplay>
1529
1530Du kannst sogar den Körper weglassen und eine leere anonyme Klasse schreiben:
1531
1532```yuescript
1533x = class
1534```
1535
1536<YueDisplay>
1537
1538```yue
1539x = class
1540```
1541
1542</YueDisplay>
1543
1544## Class Mixing
1545
1546Du kannst mit dem Schlüsselwort `using` mischen, um Funktionen aus einer einfachen Tabelle oder einem vordefinierten Klassenobjekt in deine neue Klasse zu kopieren. Beim Mischen mit einer einfachen Tabelle kannst du die Klassen-Indexing-Funktion (Metamethod `__index`) überschreiben. Beim Mischen mit einem bestehenden Klassenobjekt werden dessen Metamethoden nicht kopiert.
1547
1548```yuescript
1549MyIndex = __index: var: 1
1550
1551class X using MyIndex
1552 func: =>
1553 print 123
1554
1555x = X!
1556print x.var
1557
1558class Y using X
1559
1560y = Y!
1561y\func!
1562
1563assert y.__class.__parent ~= X -- X ist nicht die Elternklasse von Y
1564```
1565
1566<YueDisplay>
1567
1568```yue
1569MyIndex = __index: var: 1
1570
1571class X using MyIndex
1572 func: =>
1573 print 123
1574
1575x = X!
1576print x.var
1577
1578class Y using X
1579
1580y = Y!
1581y\func!
1582
1583assert y.__class.__parent ~= X -- X ist nicht die Elternklasse von Y
1584```
1585
1586</YueDisplay>
1587
1588# With-Statement
1589
1590Ein häufiges Muster bei der Erstellung eines Objekts ist, unmittelbar danach eine Reihe von Funktionen aufzurufen und Eigenschaften zu setzen.
1591
1592Das führt dazu, dass der Objektname mehrfach wiederholt wird und unnötiges Rauschen entsteht. Eine gängige Lösung ist, eine Tabelle als Argument zu übergeben, die eine Sammlung von Schlüsseln und Werten enthält, die überschrieben werden sollen. Der Nachteil ist, dass der Konstruktor dieses Objekts diese Form unterstützen muss.
1593
1594Der `with`-Block hilft, das zu vermeiden. Innerhalb eines `with`-Blocks können wir spezielle Anweisungen verwenden, die mit `.` oder `\` beginnen und die Operationen auf das Objekt anwenden, mit dem wir gerade arbeiten.
1595
1596Zum Beispiel arbeiten wir mit einem neu erstellten Objekt:
1597
1598```yuescript
1599with Person!
1600 .name = "Oswald"
1601 \add_relative my_dad
1602 \save!
1603 print .name
1604```
1605
1606<YueDisplay>
1607
1608```yue
1609with Person!
1610 .name = "Oswald"
1611 \add_relative my_dad
1612 \save!
1613 print .name
1614```
1615
1616</YueDisplay>
1617
1618Das `with`-Statement kann auch als Ausdruck verwendet werden und gibt den Wert zurück, auf den es Zugriff gewährt.
1619
1620```yuescript
1621file = with File "Lieblingsessen.txt"
1622 \set_encoding "utf8"
1623```
1624
1625<YueDisplay>
1626
1627```yue
1628file = with File "Lieblingsessen.txt"
1629 \set_encoding "utf8"
1630```
1631
1632</YueDisplay>
1633
1634`with`-Ausdrücke unterstützen `break` mit genau einem Wert:
1635
1636```yuescript
1637result = with obj
1638 break .value
1639```
1640
1641<YueDisplay>
1642
1643```yue
1644result = with obj
1645 break .value
1646```
1647
1648</YueDisplay>
1649
1650Sobald `break value` in `with` verwendet wird, gibt der `with`-Ausdruck nicht mehr sein Zielobjekt zurück, sondern den von `break` gelieferten Wert.
1651
1652```yuescript
1653a = with obj
1654 .x = 1
1655-- a ist obj
1656
1657b = with obj
1658 break .x
1659-- b ist .x, nicht obj
1660```
1661
1662<YueDisplay>
1663
1664```yue
1665a = with obj
1666 .x = 1
1667-- a ist obj
1668
1669b = with obj
1670 break .x
1671-- b ist .x, nicht obj
1672```
1673
1674</YueDisplay>
1675
1676Im Unterschied zu `for` / `while` / `repeat` / `do` unterstützt `with` nur einen `break`-Wert.
1677
1678Oder …
1679
1680```yuescript
1681create_person = (name, relatives) ->
1682 with Person!
1683 .name = name
1684 \add_relative relative for relative in *relatives
1685
1686me = create_person "Leaf", [dad, mother, sister]
1687```
1688
1689<YueDisplay>
1690
1691```yue
1692create_person = (name, relatives) ->
1693 with Person!
1694 .name = name
1695 \add_relative relative for relative in *relatives
1696
1697me = create_person "Leaf", [dad, mother, sister]
1698```
1699
1700</YueDisplay>
1701
1702In dieser Verwendung kann `with` als spezielle Form des K-Kombinators gesehen werden.
1703
1704Der Ausdruck im `with`-Statement kann auch eine Zuweisung sein, wenn du dem Ausdruck einen Namen geben willst.
1705
1706```yuescript
1707with str := "Hallo"
1708 print "Original:", str
1709 print "Großbuchstaben:", \upper!
1710```
1711
1712<YueDisplay>
1713
1714```yue
1715with str := "Hallo"
1716 print "Original:", str
1717 print "Großbuchstaben:", \upper!
1718```
1719
1720</YueDisplay>
1721
1722Du kannst in einem `with`-Statement über `[]` auf spezielle Schlüssel zugreifen.
1723
1724```yuescript
1725with tb
1726 [1] = 1
1727 print [2]
1728 with [abc]
1729 [3] = [2]\func!
1730 ["key-name"] = value
1731 [] = "abc" -- an "tb" anhängen
1732```
1733
1734<YueDisplay>
1735
1736```yue
1737with tb
1738 [1] = 1
1739 print [2]
1740 with [abc]
1741 [3] = [2]\func!
1742 ["key-name"] = value
1743 [] = "abc" -- an "tb" anhängen
1744```
1745
1746</YueDisplay>
1747
1748`with?` ist eine erweiterte Version der `with`-Syntax, die einen Existenz-Check einführt, um Objekte, die `nil` sein könnten, sicher zuzugreifen, ohne explizite Nullprüfungen.
1749
1750```yuescript
1751with? obj
1752 print obj.name
1753```
1754
1755<YueDisplay>
1756
1757```yue
1758with? obj
1759 print obj.name
1760```
1761
1762</YueDisplay>
1763
1764# Zuweisung
1765
1766Variablen sind dynamisch typisiert und standardmäßig `local`. Du kannst den Geltungsbereich mit den Statements **local** und **global** ändern.
1767
1768```yuescript
1769hello = "world"
1770a, b, c = 1, 2, 3
1771hello = 123 -- nutzt die bestehende Variable
1772```
1773
1774<YueDisplay>
1775
1776```yue
1777hello = "world"
1778a, b, c = 1, 2, 3
1779hello = 123 -- nutzt die bestehende Variable
1780```
1781
1782</YueDisplay>
1783
1784## Update-Zuweisung
1785
1786Du kannst Update-Zuweisungen mit vielen binären Operatoren durchführen.
1787
1788```yuescript
1789x = 1
1790x += 1
1791x -= 1
1792x *= 10
1793x /= 10
1794x %= 10
1795s ..= "world" -- legt eine neue lokale Variable an, wenn sie nicht existiert
1796arg or= "default value"
1797```
1798
1799<YueDisplay>
1800
1801```yue
1802x = 1
1803x += 1
1804x -= 1
1805x *= 10
1806x /= 10
1807x %= 10
1808s ..= "world" -- legt eine neue lokale Variable an, wenn sie nicht existiert
1809arg or= "default value"
1810```
1811
1812</YueDisplay>
1813
1814## Verkettete Zuweisung
1815
1816Mit verketteten Zuweisungen kannst du mehrere Variablen auf denselben Wert setzen.
1817
1818```yuescript
1819a = b = c = d = e = 0
1820x = y = z = f!
1821```
1822
1823<YueDisplay>
1824
1825```yue
1826a = b = c = d = e = 0
1827x = y = z = f!
1828```
1829
1830</YueDisplay>
1831
1832## Explizite Locals
1833
1834```yuescript
1835do
1836 local a = 1
1837 local *
1838 print "forward declare all variables as locals"
1839 x = -> 1 + y + z
1840 y, z = 2, 3
1841 global instance = Item\new!
1842
1843do
1844 local X = 1
1845 local ^
1846 print "only forward declare upper case variables"
1847 a = 1
1848 B = 2
1849```
1850
1851<YueDisplay>
1852
1853```yue
1854do
1855 local a = 1
1856 local *
1857 print "forward declare all variables as locals"
1858 x = -> 1 + y + z
1859 y, z = 2, 3
1860 global instance = Item\new!
1861
1862do
1863 local X = 1
1864 local ^
1865 print "only forward declare upper case variables"
1866 a = 1
1867 B = 2
1868```
1869
1870</YueDisplay>
1871
1872## Explizite Globals
1873
1874```yuescript
1875do
1876 global a = 1
1877 global *
1878 print "declare all variables as globals"
1879 x = -> 1 + y + z
1880 y, z = 2, 3
1881
1882do
1883 global X = 1
1884 global ^
1885 print "only declare upper case variables as globals"
1886 a = 1
1887 B = 2
1888 local Temp = "a local value"
1889```
1890
1891<YueDisplay>
1892
1893```yue
1894do
1895 global a = 1
1896 global *
1897 print "declare all variables as globals"
1898 x = -> 1 + y + z
1899 y, z = 2, 3
1900
1901do
1902 global X = 1
1903 global ^
1904 print "only declare upper case variables as globals"
1905 a = 1
1906 B = 2
1907 local Temp = "a local value"
1908```
1909
1910</YueDisplay>
1911
1912# Varargs-Zuweisung
1913
1914Du kannst Rückgabewerte einer Funktion dem Varargs-Symbol `...` zuweisen und dann den Inhalt auf die Lua-Weise auslesen.
1915
1916```yuescript
1917list = [1, 2, 3, 4, 5]
1918fn = (ok) -> ok, table.unpack list
1919ok, ... = fn true
1920count = select '#', ...
1921first = select 1, ...
1922print ok, count, first
1923```
1924
1925<YueDisplay>
1926
1927```yue
1928list = [1, 2, 3, 4, 5]
1929fn = (ok) -> ok, table.unpack list
1930ok, ... = fn true
1931count = select '#', ...
1932first = select 1, ...
1933print ok, count, first
1934```
1935
1936</YueDisplay>
1937
1938# If-Zuweisung
1939
1940`if`- und `elseif`-Blöcke können eine Zuweisung anstelle eines Bedingungsausdrucks enthalten. Beim Auswerten der Bedingung findet die Zuweisung statt, und der zugewiesene Wert wird als Bedingung verwendet. Die zugewiesene Variable ist nur im Geltungsbereich des Bedingungsblocks verfügbar, d. h. sie ist nicht verfügbar, wenn der Wert nicht truthy ist. Für die Zuweisung musst du den "Walrus-Operator" `:=` statt `=` verwenden.
1941
1942```yuescript
1943if user := database.find_user "moon"
1944 print user.name
1945```
1946
1947<YueDisplay>
1948
1949```yue
1950if user := database.find_user "moon"
1951 print user.name
1952```
1953
1954</YueDisplay>
1955
1956```yuescript
1957if hello := os.getenv "hello"
1958 print "Du hast hello", hello
1959elseif world := os.getenv "world"
1960 print "Du hast world", world
1961else
1962 print "nichts :("
1963```
1964
1965<YueDisplay>
1966
1967```yue
1968if hello := os.getenv "hello"
1969 print "Du hast hello", hello
1970elseif world := os.getenv "world"
1971 print "Du hast world", world
1972else
1973 print "nichts :("
1974```
1975
1976</YueDisplay>
1977
1978If-Zuweisung mit mehreren Rückgabewerten. Nur der erste Wert wird geprüft, andere Werte bleiben im Scope.
1979
1980```yuescript
1981if success, result := pcall -> "Ergebnis ohne Probleme erhalten"
1982 print result -- Variable result ist im Scope
1983print "OK"
1984```
1985
1986<YueDisplay>
1987
1988```yue
1989if success, result := pcall -> "Ergebnis ohne Probleme erhalten"
1990 print result -- Variable result ist im Scope
1991print "OK"
1992```
1993
1994</YueDisplay>
1995
1996## While-Zuweisung
1997
1998Du kannst if-Zuweisung auch in einer while-Schleife verwenden, um den Wert als Schleifenbedingung zu nutzen.
1999
2000```yuescript
2001while byte := stream\read_one!
2002 -- mit dem Byte etwas anfangen
2003 print byte
2004```
2005
2006<YueDisplay>
2007
2008```yue
2009while byte := stream\read_one!
2010 -- mit dem Byte etwas anfangen
2011 print byte
2012```
2013
2014</YueDisplay>
2015
2016# Destructuring-Zuweisung
2017
2018Destructuring-Zuweisung ist eine Möglichkeit, schnell Werte aus einer Tabelle nach Name oder Position in array-basierten Tabellen zu extrahieren.
2019
2020Normalerweise steht ein Tabellenliteral wie `{1,2,3}` auf der rechten Seite einer Zuweisung, weil es ein Wert ist. Destructuring-Zuweisung tauscht die Rolle des Tabellenliterals und setzt es auf die linke Seite der Zuweisung.
2021
2022Am besten lässt sich das mit Beispielen erklären. So entpackst du die ersten zwei Werte einer Tabelle:
2023
2024```yuescript
2025thing = [1, 2]
2026
2027[a, b] = thing
2028print a, b
2029```
2030
2031<YueDisplay>
2032
2033```yue
2034thing = [1, 2]
2035
2036[a, b] = thing
2037print a, b
2038```
2039
2040</YueDisplay>
2041
2042Im Destructuring-Tabellenliteral repräsentiert der Schlüssel den zu lesenden Schlüssel der rechten Seite, und der Wert ist der Name, dem der gelesene Wert zugewiesen wird.
2043
2044```yuescript
2045obj = {
2046 hello: "Welt"
2047 day: "Dienstag"
2048 length: 20
2049}
2050
2051{hello: hello, day: the_day} = obj
2052print hello, the_day
2053
2054:day = obj -- einfache Destructuring-Zuweisung ohne Klammern ist ok
2055```
2056
2057<YueDisplay>
2058
2059```yue
2060obj = {
2061 hello: "Welt"
2062 day: "Dienstag"
2063 length: 20
2064}
2065
2066{hello: hello, day: the_day} = obj
2067print hello, the_day
2068
2069:day = obj -- einfache Destructuring-Zuweisung ohne Klammern ist ok
2070```
2071
2072</YueDisplay>
2073
2074Das funktioniert auch mit verschachtelten Datenstrukturen:
2075
2076```yuescript
2077obj2 = {
2078 numbers: [1, 2, 3, 4]
2079 properties: {
2080 color: "grün"
2081 height: 13.5
2082 }
2083}
2084
2085{numbers: [first, second], properties: {color: color}} = obj2
2086print first, second, color
2087```
2088
2089<YueDisplay>
2090
2091```yue
2092obj2 = {
2093 numbers: [1, 2, 3, 4]
2094 properties: {
2095 color: "grün"
2096 height: 13.5
2097 }
2098}
2099
2100{numbers: [first, second], properties: {color: color}} = obj2
2101print first, second, color
2102```
2103
2104</YueDisplay>
2105
2106Wenn die Destructuring-Anweisung kompliziert ist, kannst du sie gerne auf mehrere Zeilen verteilen. Ein etwas komplexeres Beispiel:
2107
2108```yuescript
2109{
2110 numbers: [first, second]
2111 properties: {
2112 color: color
2113 }
2114} = obj2
2115```
2116
2117<YueDisplay>
2118
2119```yue
2120{
2121 numbers: [first, second]
2122 properties: {
2123 color: color
2124 }
2125} = obj2
2126```
2127
2128</YueDisplay>
2129
2130Es ist üblich, Werte aus einer Tabelle zu extrahieren und ihnen lokale Variablen mit demselben Namen wie der Schlüssel zuzuweisen. Um Wiederholungen zu vermeiden, kannst du den Präfix-Operator **:** verwenden:
2131
2132```yuescript
2133{:concat, :insert} = table
2134```
2135
2136<YueDisplay>
2137
2138```yue
2139{:concat, :insert} = table
2140```
2141
2142</YueDisplay>
2143
2144Das ist effektiv dasselbe wie `import`, aber du kannst Felder umbenennen, indem du die Syntax mischst:
2145
2146```yuescript
2147{:mix, :max, random: rand} = math
2148```
2149
2150<YueDisplay>
2151
2152```yue
2153{:mix, :max, random: rand} = math
2154```
2155
2156</YueDisplay>
2157
2158Du kannst Standardwerte beim Destructuring angeben, z. B.:
2159
2160```yuescript
2161{:name = "namenlos", :job = "arbeitlos"} = person
2162```
2163
2164<YueDisplay>
2165
2166```yue
2167{:name = "namenlos", :job = "arbeitlos"} = person
2168```
2169
2170</YueDisplay>
2171
2172Du kannst `_` als Platzhalter verwenden, wenn du eine Listen-Destructuring-Zuweisung machst:
2173
2174```yuescript
2175[_, two, _, four] = items
2176```
2177
2178<YueDisplay>
2179
2180```yue
2181[_, two, _, four] = items
2182```
2183
2184</YueDisplay>
2185
2186## Bereichs-Destructuring
2187
2188Du kannst den Spread-Operator `...` in Listen-Destructuring verwenden, um einen Wertebereich zu erfassen. Das ist nützlich, wenn du bestimmte Elemente am Anfang und Ende einer Liste extrahieren und den Rest dazwischen sammeln willst.
2189
2190```yuescript
2191orders = ["erster", "zweiter", "dritter", "vierter", "letzter"]
2192[first, ...bulk, last] = orders
2193print first -- gibt aus: erster
2194print bulk -- gibt aus: {"zweiter", "dritter", "vierter"}
2195print last -- gibt aus: letzter
2196```
2197
2198<YueDisplay>
2199
2200```yue
2201orders = ["erster", "zweiter", "dritter", "vierter", "letzter"]
2202[first, ...bulk, last] = orders
2203print first -- gibt aus: erster
2204print bulk -- gibt aus: {"zweiter", "dritter", "vierter"}
2205print last -- gibt aus: letzter
2206```
2207
2208</YueDisplay>
2209
2210Der Spread-Operator kann an unterschiedlichen Positionen verwendet werden, um unterschiedliche Bereiche zu erfassen, und du kannst `_` als Platzhalter für Werte verwenden, die du nicht erfassen willst:
2211
2212```yuescript
2213-- Alles nach dem ersten Element erfassen
2214[first, ...rest] = orders
2215
2216-- Alles vor dem letzten Element erfassen
2217[...start, last] = orders
2218
2219-- Alles außer den mittleren Elementen erfassen
2220[first, ..._, last] = orders
2221```
2222
2223<YueDisplay>
2224
2225```yue
2226-- Alles nach dem ersten Element erfassen
2227[first, ...rest] = orders
2228
2229-- Alles vor dem letzten Element erfassen
2230[...start, last] = orders
2231
2232-- Alles außer den mittleren Elementen erfassen
2233[first, ..._, last] = orders
2234```
2235
2236</YueDisplay>
2237
2238## Destructuring an anderen Stellen
2239
2240Destructuring kann auch an Stellen vorkommen, an denen eine Zuweisung implizit erfolgt. Ein Beispiel ist eine `for`-Schleife:
2241
2242```yuescript
2243tuples = [
2244 ["hallo", "Welt"]
2245 ["Ei", "Kopf"]
2246]
2247
2248for [left, right] in *tuples
2249 print left, right
2250```
2251
2252<YueDisplay>
2253
2254```yue
2255tuples = [
2256 ["hallo", "Welt"]
2257 ["Ei", "Kopf"]
2258]
2259
2260for [left, right] in *tuples
2261 print left, right
2262```
2263
2264</YueDisplay>
2265
2266Wir wissen, dass jedes Element der Array-Tabelle ein 2er-Tupel ist, daher können wir es direkt in der Namensliste der `for`-Anweisung mittels Destructuring entpacken.
2267
2268# Die Using-Klausel: Destruktive Zuweisung kontrollieren
2269
2270Lexikalisches Scoping kann die Komplexität des Codes stark reduzieren, aber mit wachsendem Codeumfang kann es unübersichtlich werden. Betrachte folgendes Beispiel:
2271
2272```yuescript
2273i = 100
2274
2275-- viele Zeilen Code...
2276
2277my_func = ->
2278 i = 10
2279 while i > 0
2280 print i
2281 i -= 1
2282
2283my_func!
2284
2285print i -- wird 0 ausgeben
2286```
2287
2288<YueDisplay>
2289
2290```yue
2291i = 100
2292
2293-- viele Zeilen Code...
2294
2295my_func = ->
2296 i = 10
2297 while i > 0
2298 print i
2299 i -= 1
2300
2301my_func!
2302
2303print i -- wird 0 ausgeben
2304```
2305
2306</YueDisplay>
2307
2308In `my_func` haben wir den Wert von `i` versehentlich überschrieben. In diesem Beispiel ist es offensichtlich, aber in einer großen oder fremden Codebasis ist oft nicht klar, welche Namen bereits deklariert wurden.
2309
2310Es wäre hilfreich, anzugeben, welche Variablen aus dem umschließenden Scope wir verändern wollen, um versehentliche Änderungen zu vermeiden.
2311
2312Das Schlüsselwort `using` ermöglicht das. `using nil` stellt sicher, dass keine geschlossenen Variablen bei Zuweisungen überschrieben werden. Die `using`-Klausel steht nach der Argumentliste einer Funktion oder ersetzt sie, wenn es keine Argumente gibt.
2313
2314```yuescript
2315i = 100
2316
2317my_func = (using nil) ->
2318 i = "hello" -- hier wird eine neue lokale Variable erstellt
2319
2320my_func!
2321print i -- gibt 100 aus, i bleibt unverändert
2322```
2323
2324<YueDisplay>
2325
2326```yue
2327i = 100
2328
2329my_func = (using nil) ->
2330 i = "hello" -- hier wird eine neue lokale Variable erstellt
2331
2332my_func!
2333print i -- gibt 100 aus, i bleibt unverändert
2334```
2335
2336</YueDisplay>
2337
2338Mehrere Namen können durch Kommas getrennt werden. Closure-Werte können weiterhin gelesen, aber nicht verändert werden:
2339
2340```yuescript
2341tmp = 1213
2342i, k = 100, 50
2343
2344my_func = (add using k, i) ->
2345 tmp = tmp + add -- ein neues lokales tmp wird erstellt
2346 i += tmp
2347 k += tmp
2348
2349my_func(22)
2350print i, k -- diese wurden aktualisiert
2351```
2352
2353<YueDisplay>
2354
2355```yue
2356tmp = 1213
2357i, k = 100, 50
2358
2359my_func = (add using k, i) ->
2360 tmp = tmp + add -- ein neues lokales tmp wird erstellt
2361 i += tmp
2362 k += tmp
2363
2364my_func(22)
2365print i, k -- diese wurden aktualisiert
2366```
2367
2368</YueDisplay>
2369
2370# Verwendung
2371
2372## Lua-Modul
2373
2374YueScript-Modul in Lua verwenden:
2375
2376- **Fall 1**
2377
2378 "your_yuescript_entry.yue" in Lua require'n.
2379
2380 ```Lua
2381 require("yue")("your_yuescript_entry")
2382 ```
2383
2384 Dieser Code funktioniert weiterhin, wenn du "your_yuescript_entry.yue" im gleichen Pfad zu "your_yuescript_entry.lua" kompilierst. In den restlichen YueScript-Dateien verwendest du einfach normales **require** oder **import**. Die Zeilennummern in Fehlermeldungen werden korrekt behandelt.
2385
2386- **Fall 2**
2387
2388 YueScript-Modul require'n und das Fehlermapping manuell umschreiben.
2389
2390 ```lua
2391 local yue = require("yue")
2392 yue.insert_loader()
2393 local success, result = xpcall(function()
2394 return require("yuescript_module_name")
2395 end, function(err)
2396 return yue.traceback(err)
2397 end)
2398 ```
2399
2400- **Fall 3**
2401
2402 Die YueScript-Compilerfunktion in Lua verwenden.
2403
2404 ```lua
2405 local yue = require("yue")
2406 local codes, err, globals = yue.to_lua([[
2407 f = ->
2408 print "Hallo Welt"
2409 f!
2410 ]],{
2411 implicit_return_root = true,
2412 reserve_line_number = true,
2413 lint_global = true,
2414 space_over_tab = false,
2415 options = {
2416 target = "5.4",
2417 path = "/script"
2418 }
2419 })
2420 ```
2421
2422## YueScript-Tool
2423
2424YueScript-Tool verwenden mit:
2425
2426```shell
2427> yue -h
2428Verwendung: yue
2429 [Optionen] [<Datei/Verzeichnis>] ...
2430 yue -e <code_oder_datei> [argumente...]
2431 yue -w [<verzeichnis>] [optionen]
2432 yue -
2433
2434Hinweise:
2435 - '-' / '--' muss das erste und einzige Argument sein.
2436 - '-o/--output' kann nicht mit mehreren Eingabedateien verwendet werden.
2437 - '-w/--watch' kann nicht mit Dateieingabe verwendet werden (nur Verzeichnisse).
2438 - Mit '-e/--execute' werden verbleibende Tokens als Skriptargumente behandelt.
2439
2440Optionen:
2441 -h, --help Zeigt diese Hilfemeldung an und beendet das Programm.
2442 -e <str>, --execute <str> Datei oder Quellcode ausführen
2443 -m, --minify Minimierten Code erzeugen
2444 -r, --rewrite Ausgabe so umschreiben, dass die Zeilennummern dem Original entsprechen
2445 -t <ziel>, --output-to <ziel>
2446 Ziel für kompilierte Dateien angeben
2447 -o <datei>, --output <datei>
2448 Schreibe die Ausgabe in eine Datei
2449 -p, --print Schreibe die Ausgabe auf die Standardausgabe
2450 -b, --benchmark Gibt die Kompilierungszeit aus (keine Ausgabe schreiben)
2451 -g, --globals Gibt verwendete globale Variablen im Format NAME ZEILE SPALTE aus
2452 -s, --spaces Verwende Leerzeichen anstelle von Tabs im generierten Code
2453 -l, --line-numbers Schreibe Zeilennummern aus dem Quellcode
2454 -j, --no-implicit-return Deaktiviert implizites Rückgabe am Datei-Ende
2455 -c, --reserve-comments Kommentare aus dem Quellcode vor Anweisungen beibehalten
2456 -w [<verz>], --watch [<verz>]
2457 Änderungen beobachten und alle Dateien im Verzeichnis kompilieren
2458 -v, --version Version ausgeben
2459 - Lese von Standardinput, schreibe auf Standardausgabe
2460 (muss das erste und einzige Argument sein)
2461 -- Wie '-', bleibt zur Abwärtskompatibilität bestehen
2462
2463 --target <version> Gib an, welche Lua-Version erzeugt werden soll
2464 (Version nur von 5.1 bis 5.5 möglich)
2465 --path <pfad_str> Füge einen zusätzlichen Lua-Suchpfad zu package.path hinzu
2466 --<schlüssel>=<wert> Übertrage Compileroption im Schlüssel=Wert-Format (bestehendes Verhalten)
2467
2468 Ohne Optionen wird die REPL gestartet, gebe das Symbol '$'
2469 in eine einzelne Zeile ein, um den Multi-Line-Modus zu starten/beenden
2470```
2471
2472Anwendungsfälle:
2473
2474Rekursiv jede YueScript-Datei mit der Endung **.yue** unter dem aktuellen Pfad kompilieren: **yue .**
2475
2476Kompilieren und Ergebnisse in einen Zielpfad schreiben: **yue -t /target/path/ .**
2477
2478Kompilieren und Debug-Infos beibehalten: **yue -l .**
2479
2480Kompilieren und minifizierten Code erzeugen: **yue -m .**
2481
2482Rohcode ausführen: **yue -e 'print 123'**
2483
2484Eine YueScript-Datei ausführen: **yue -e main.yue**
2485
2486# Einführung
2487
2488YueScript ist eine dynamische Sprache, die zu Lua kompiliert. Sie ist ein Dialekt von [MoonScript](https://github.com/leafo/moonscript). Code, der in YueScript geschrieben wird, ist ausdrucksstark und sehr kompakt. YueScript eignet sich zum Schreiben von veränderlicher Anwendungslogik mit besser wartbarem Code und läuft in eingebetteten Lua-Umgebungen wie Spielen oder Webservern.
2489
2490Yue (月) ist das chinesische Wort für Mond und wird als [jyɛ] ausgesprochen.
2491
2492## Ein Überblick über YueScript
2493
2494```yuescript
2495-- Import-Syntax
2496import p, to_lua from "yue"
2497
2498-- Objekt-Literale
2499inventory =
2500 equipment:
2501 - "Schwert"
2502 - "Schild"
2503 items:
2504 - name: "Trank"
2505 count: 10
2506 - name: "Brot"
2507 count: 3
2508
2509-- Listen-Abstraktion
2510map = (arr, action) ->
2511 [action item for item in *arr]
2512
2513filter = (arr, cond) ->
2514 [item for item in *arr when cond item]
2515
2516reduce = (arr, init, action): init ->
2517 init = action init, item for item in *arr
2518
2519-- Pipe-Operator
2520[1, 2, 3]
2521 |> map (x) -> x * 2
2522 |> filter (x) -> x > 4
2523 |> reduce 0, (a, b) -> a + b
2524 |> print
2525
2526-- Metatable-Manipulation
2527apple =
2528 size: 15
2529 <index>:
2530 color: 0x00ffff
2531
2532with apple
2533 p .size, .color, .<index> if .<>?
2534
2535-- export-Syntax (ähnlich wie in JavaScript)
2536export 🌛 = "Skript des Mondes"
2537```
2538
2539<YueDisplay>
2540
2541```yue
2542-- Import-Syntax
2543import p, to_lua from "yue"
2544
2545-- Objekt-Literale
2546inventory =
2547 equipment:
2548 - "Schwert"
2549 - "Schild"
2550 items:
2551 - name: "Trank"
2552 count: 10
2553 - name: "Brot"
2554 count: 3
2555
2556-- Listen-Abstraktion
2557map = (arr, action) ->
2558 [action item for item in *arr]
2559
2560filter = (arr, cond) ->
2561 [item for item in *arr when cond item]
2562
2563reduce = (arr, init, action): init ->
2564 init = action init, item for item in *arr
2565
2566-- Pipe-Operator
2567[1, 2, 3]
2568 |> map (x) -> x * 2
2569 |> filter (x) -> x > 4
2570 |> reduce 0, (a, b) -> a + b
2571 |> print
2572
2573-- Metatable-Manipulation
2574apple =
2575 size: 15
2576 <index>:
2577 color: 0x00ffff
2578
2579with apple
2580 p .size, .color, .<index> if .<>?
2581
2582-- export-Syntax (ähnlich wie in JavaScript)
2583export 🌛 = "Skript des Mondes"
2584```
2585
2586</YueDisplay>
2587
2588## Über Dora SSR
2589
2590YueScript wird zusammen mit der Open-Source-Spiel-Engine [Dora SSR](https://github.com/Dora-SSR/Dora-SSR) entwickelt und gepflegt. Es wird zum Erstellen von Engine-Tools, Spiel-Demos und Prototypen eingesetzt und hat seine Leistungsfähigkeit in realen Szenarien unter Beweis gestellt, während es gleichzeitig die Dora-SSR-Entwicklungserfahrung verbessert.
2591
2592# Installation
2593
2594## Lua-Modul
2595
2596Installiere [luarocks](https://luarocks.org), einen Paketmanager für Lua-Module. Installiere YueScript dann als Lua-Modul und ausführbare Datei mit:
2597
2598```shell
2599luarocks install yuescript
2600```
2601
2602Oder du kannst die Datei `yue.so` bauen mit:
2603
2604```shell
2605make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua
2606```
2607
2608Anschließend findest du die Binärdatei unter **bin/shared/yue.so**.
2609
2610## Binär-Tool bauen
2611
2612Klone dieses Repo und baue/installiere die ausführbare Datei mit:
2613
2614```shell
2615make install
2616```
2617
2618YueScript-Tool ohne Makro-Feature bauen:
2619
2620```shell
2621make install NO_MACRO=true
2622```
2623
2624YueScript-Tool ohne eingebautes Lua-Binary bauen:
2625
2626```shell
2627make install NO_LUA=true
2628```
2629
2630## Vorgefertigtes Binary herunterladen
2631
2632Du kannst vorkompilierte Binärdateien herunterladen, inklusive ausführbarer Dateien für unterschiedliche Lua-Versionen und Bibliotheksdateien.
2633
2634Lade vorkompilierte Binärdateien von [hier](https://github.com/IppClub/YueScript/releases) herunter.
2635
2636# Bedingungen
2637
2638```yuescript
2639have_coins = false
2640if have_coins
2641 print "Münzen erhalten"
2642else
2643 print "Keine Münzen"
2644```
2645
2646<YueDisplay>
2647
2648```yue
2649have_coins = false
2650if have_coins
2651 print "Münzen erhalten"
2652else
2653 print "Keine Münzen"
2654```
2655
2656</YueDisplay>
2657
2658Eine Kurzsyntax für einzelne Anweisungen kann ebenfalls verwendet werden:
2659
2660```yuescript
2661have_coins = false
2662if have_coins then print "Münzen erhalten" else print "Keine Münzen"
2663```
2664
2665<YueDisplay>
2666
2667```yue
2668have_coins = false
2669if have_coins then print "Münzen erhalten" else print "Keine Münzen"
2670```
2671
2672</YueDisplay>
2673
2674Da `if`-Anweisungen als Ausdrücke verwendet werden können, kann man das auch so schreiben:
2675
2676```yuescript
2677have_coins = false
2678print if have_coins then "Münzen erhalten" else "Keine Münzen"
2679```
2680
2681<YueDisplay>
2682
2683```yue
2684have_coins = false
2685print if have_coins then "Münzen erhalten" else "Keine Münzen"
2686```
2687
2688</YueDisplay>
2689
2690Bedingungen können auch in `return`-Anweisungen und Zuweisungen verwendet werden:
2691
2692```yuescript
2693is_tall = (name) ->
2694 if name == "Rob"
2695 true
2696 else
2697 false
2698
2699message = if is_tall "Rob"
2700 "Ich bin sehr groß"
2701else
2702 "Ich bin nicht so groß"
2703
2704print message -- gibt aus: Ich bin sehr groß
2705```
2706
2707<YueDisplay>
2708
2709```yue
2710is_tall = (name) ->
2711 if name == "Rob"
2712 true
2713 else
2714 false
2715
2716message = if is_tall "Rob"
2717 "Ich bin sehr groß"
2718else
2719 "Ich bin nicht so groß"
2720
2721print message -- gibt aus: Ich bin sehr groß
2722```
2723
2724</YueDisplay>
2725
2726Das Gegenteil von `if` ist `unless`:
2727
2728```yuescript
2729unless os.date("%A") == "Monday"
2730 print "Es ist nicht Montag!"
2731```
2732
2733<YueDisplay>
2734
2735```yue
2736unless os.date("%A") == "Monday"
2737 print "Es ist nicht Montag!"
2738```
2739
2740</YueDisplay>
2741
2742```yuescript
2743print "You're lucky!" unless math.random! > 0.1
2744```
2745
2746<YueDisplay>
2747
2748```yue
2749print "You're lucky!" unless math.random! > 0.1
2750```
2751
2752</YueDisplay>
2753
2754## In-Ausdruck
2755
2756Mit einem `in`-Ausdruck kannst du Bereichsprüfungen schreiben.
2757
2758```yuescript
2759a = 5
2760
2761if a in [1, 3, 5, 7]
2762 print "Gleichheitsprüfung mit diskreten Werten"
2763
2764if a in list
2765 print "Prüfen, ob `a` in einer Liste ist"
2766```
2767
2768<YueDisplay>
2769
2770```yue
2771a = 5
2772
2773if a in [1, 3, 5, 7]
2774 print "Gleichheitsprüfung mit diskreten Werten"
2775
2776if a in list
2777 print "Prüfen, ob `a` in einer Liste ist"
2778```
2779
2780</YueDisplay>
2781
2782# For-Schleife
2783
2784Es gibt zwei Formen der `for`-Schleife, genau wie in Lua: eine numerische und eine generische.
2785
2786```yuescript
2787for i = 10, 20
2788 print i
2789
2790for k = 1, 15, 2 -- ein optionaler Schritt
2791 print k
2792
2793for key, value in pairs object
2794 print key, value
2795```
2796
2797<YueDisplay>
2798
2799```yue
2800for i = 10, 20
2801 print i
2802
2803for k = 1, 15, 2 -- ein optionaler Schritt
2804 print k
2805
2806for key, value in pairs object
2807 print key, value
2808```
2809
2810</YueDisplay>
2811
2812Die Slicing- und **\***-Operatoren können verwendet werden, genau wie bei Comprehensions:
2813
2814```yuescript
2815for item in *items[2, 4]
2816 print item
2817```
2818
2819<YueDisplay>
2820
2821```yue
2822for item in *items[2, 4]
2823 print item
2824```
2825
2826</YueDisplay>
2827
2828Eine kürzere Syntax ist für alle Varianten verfügbar, wenn der Rumpf nur eine Zeile hat:
2829
2830```yuescript
2831for item in *items do print item
2832
2833for j = 1, 10, 3 do print j
2834```
2835
2836<YueDisplay>
2837
2838```yue
2839for item in *items do print item
2840
2841for j = 1, 10, 3 do print j
2842```
2843
2844</YueDisplay>
2845
2846Eine `for`-Schleife kann auch als Ausdruck verwendet werden. Die letzte Anweisung im Schleifenrumpf wird in einen Ausdruck umgewandelt und an eine wachsende Array-Tabelle angehängt.
2847
2848Alle geraden Zahlen verdoppeln:
2849
2850```yuescript
2851doubled_evens = for i = 1, 20
2852 if i % 2 == 0
2853 i * 2
2854 else
2855 i
2856```
2857
2858<YueDisplay>
2859
2860```yue
2861doubled_evens = for i = 1, 20
2862 if i % 2 == 0
2863 i * 2
2864 else
2865 i
2866```
2867
2868</YueDisplay>
2869
2870Zusätzlich unterstützen `for`-Schleifen `break` mit Rückgabewerten, sodass die Schleife selbst als Ausdruck verwendet werden kann, der früh mit einem sinnvollen Ergebnis endet. `for`-Ausdrücke unterstützen mehrere `break`-Werte.
2871
2872Beispiel: die erste Zahl größer als 10 finden:
2873
2874```yuescript
2875first_large = for n in *numbers
2876 break n if n > 10
2877```
2878
2879<YueDisplay>
2880
2881```yue
2882first_large = for n in *numbers
2883 break n if n > 10
2884```
2885
2886</YueDisplay>
2887
2888Diese `break`-mit-Wert-Syntax ermöglicht knappe und ausdrucksstarke Such- bzw. Early-Exit-Muster direkt in Schleifenausdrücken.
2889
2890```yuescript
2891key, score = for k, v in pairs data
2892 break k, v * 10 if k == "target"
2893```
2894
2895<YueDisplay>
2896
2897```yue
2898key, score = for k, v in pairs data
2899 break k, v * 10 if k == "target"
2900```
2901
2902</YueDisplay>
2903
2904Du kannst Werte auch filtern, indem du den `for`-Ausdruck mit `continue` kombinierst.
2905
2906`for`-Schleifen am Ende eines Funktionsrumpfs werden nicht in eine Tabelle für einen Rückgabewert gesammelt (stattdessen gibt die Funktion `nil` zurück). Du kannst entweder explizit `return` verwenden oder die Schleife in eine Listen-Comprehension umwandeln.
2907
2908```yuescript
2909func_a = -> for i = 1, 10 do print i
2910func_b = -> return for i = 1, 10 do i
2911
2912print func_a! -- gibt nil aus
2913print func_b! -- gibt Tabellenobjekt aus
2914```
2915
2916<YueDisplay>
2917
2918```yue
2919func_a = -> for i = 1, 10 do print i
2920func_b = -> return for i = 1, 10 do i
2921
2922print func_a! -- gibt nil aus
2923print func_b! -- gibt Tabellenobjekt aus
2924```
2925
2926</YueDisplay>
2927
2928Das verhindert die unnötige Erstellung von Tabellen in Funktionen, die die Ergebnisse der Schleife nicht zurückgeben müssen.
2929
2930# Continue
2931
2932Eine `continue`-Anweisung überspringt die aktuelle Iteration einer Schleife.
2933
2934```yuescript
2935i = 0
2936while i < 10
2937 i += 1
2938 continue if i % 2 == 0
2939 print i
2940```
2941
2942<YueDisplay>
2943
2944```yue
2945i = 0
2946while i < 10
2947 i += 1
2948 continue if i % 2 == 0
2949 print i
2950```
2951
2952</YueDisplay>
2953
2954`continue` kann auch mit Schleifenausdrücken verwendet werden, um zu verhindern, dass diese Iteration in das Ergebnis akkumuliert wird. Dieses Beispiel filtert die Array-Tabelle auf gerade Zahlen:
2955
2956```yuescript
2957my_numbers = [1, 2, 3, 4, 5, 6]
2958odds = for x in *my_numbers
2959 continue if x % 2 == 1
2960 x
2961```
2962
2963<YueDisplay>
2964
2965```yue
2966my_numbers = [1, 2, 3, 4, 5, 6]
2967odds = for x in *my_numbers
2968 continue if x % 2 == 1
2969 x
2970```
2971
2972</YueDisplay>
2973
2974# Switch
2975
2976Die `switch`-Anweisung ist eine Kurzform für eine Reihe von `if`-Anweisungen, die gegen denselben Wert prüfen. Der Wert wird nur einmal ausgewertet. Wie bei `if` kann `switch` einen `else`-Block haben, wenn keine Übereinstimmung gefunden wird. Verglichen wird mit dem Operator `==`. In einer `switch`-Anweisung kannst du auch eine Zuweisung verwenden, um den temporären Wert zu speichern.
2977
2978```yuescript
2979switch name := "Dan"
2980 when "Robert"
2981 print "Du bist Robert"
2982 when "Dan", "Daniel"
2983 print "Dein Name ist Dan"
2984 else
2985 print "Ich kenne dich nicht mit dem Namen #{name}"
2986```
2987
2988<YueDisplay>
2989
2990```yue
2991switch name := "Dan"
2992 when "Robert"
2993 print "Du bist Robert"
2994 when "Dan", "Daniel"
2995 print "Dein Name ist Dan"
2996 else
2997 print "Ich kenne dich nicht mit dem Namen #{name}"
2998```
2999
3000</YueDisplay>
3001
3002Eine `when`-Klausel kann mehrere Werte prüfen, indem sie kommasepariert aufgelistet werden.
3003
3004`switch` kann auch als Ausdruck verwendet werden. Hier wird das Ergebnis der `switch`-Anweisung einer Variable zugewiesen:
3005
3006```yuescript
3007b = 1
3008next_number = switch b
3009 when 1
3010 2
3011 when 2
3012 3
3013 else
3014 error "so hoch kann ich nicht zählen!"
3015```
3016
3017<YueDisplay>
3018
3019```yue
3020b = 1
3021next_number = switch b
3022 when 1
3023 2
3024 when 2
3025 3
3026 else
3027 error "so hoch kann ich nicht zählen!"
3028```
3029
3030</YueDisplay>
3031
3032Du kannst das Schlüsselwort `then` verwenden, um einen `when`-Block in einer Zeile zu schreiben. Für den `else`-Block braucht es kein zusätzliches Schlüsselwort.
3033
3034```yuescript
3035msg = switch math.random(1, 5)
3036 when 1 then "Du hast Glück"
3037 when 2 then "Du hast fast Glück"
3038 else "nicht so viel Glück"
3039```
3040
3041<YueDisplay>
3042
3043```yue
3044msg = switch math.random(1, 5)
3045 when 1 then "Du hast Glück"
3046 when 2 then "Du hast fast Glück"
3047 else "nicht so viel Glück"
3048```
3049
3050</YueDisplay>
3051
3052Wenn du eine Einrückung weniger möchtest, kannst du die erste `when`-Klausel in die Startzeile der Anweisung setzen und alle weiteren Klauseln mit einer Einrückung weniger schreiben.
3053
3054```yuescript
3055switch math.random(1, 5)
3056 when 1
3057 print "Du hast Glück" -- zwei Einrückungen
3058 else
3059 print "nicht so viel Glück"
3060
3061switch math.random(1, 5) when 1
3062 print "Du hast Glück" -- eine Einrückung
3063else
3064 print "nicht so viel Glück"
3065```
3066
3067<YueDisplay>
3068
3069```yue
3070switch math.random(1, 5)
3071 when 1
3072 print "Du hast Glück" -- zwei Einrückungen
3073 else
3074 print "nicht so viel Glück"
3075
3076switch math.random(1, 5) when 1
3077 print "Du hast Glück" -- eine Einrückung
3078else
3079 print "nicht so viel Glück"
3080```
3081
3082</YueDisplay>
3083
3084Beachte die Reihenfolge des Case-Vergleichsausdrucks. Der Case-Ausdruck steht auf der linken Seite. Das kann nützlich sein, wenn der Case-Ausdruck die Vergleichslogik über eine `__eq`-Metamethod selbst definiert.
3085
3086## Tabellen-Matching
3087
3088Du kannst in einer `switch`-`when`-Klausel Tabellen-Matching verwenden, wenn die Tabelle durch eine bestimmte Struktur destrukturiert werden kann und dabei nicht-`nil`-Werte liefert.
3089
3090```yuescript
3091items =
3092 * x: 100
3093 y: 200
3094 * width: 300
3095 height: 400
3096
3097for item in *items
3098 switch item
3099 when :x, :y
3100 print "Vec2 #{x}, #{y}"
3101 when :width, :height
3102 print "Größe #{width}, #{height}"
3103```
3104
3105<YueDisplay>
3106
3107```yue
3108items =
3109 * x: 100
3110 y: 200
3111 * width: 300
3112 height: 400
3113
3114for item in *items
3115 switch item
3116 when :x, :y
3117 print "Vec2 #{x}, #{y}"
3118 when :width, :height
3119 print "Größe #{width}, #{height}"
3120```
3121
3122</YueDisplay>
3123
3124Du kannst Standardwerte verwenden, um bestimmte Felder optional zu destrukturieren.
3125
3126```yuescript
3127item = {}
3128
3129{pos: {:x = 50, :y = 200}} = item -- Fehler: Versuch, einen nil-Wert zu indexieren (Feld 'pos')
3130
3131switch item
3132 when {pos: {:x = 50, :y = 200}}
3133 print "Vec2 #{x}, #{y}" -- Tabellen-Destrukturierung greift trotzdem
3134```
3135
3136<YueDisplay>
3137
3138```yue
3139item = {}
3140
3141{pos: {:x = 50, :y = 200}} = item -- Fehler: Versuch, einen nil-Wert zu indexieren (Feld 'pos')
3142
3143switch item
3144 when {pos: {:x = 50, :y = 200}}
3145 print "Vec2 #{x}, #{y}" -- Tabellen-Destrukturierung greift trotzdem
3146```
3147
3148</YueDisplay>
3149
3150Du kannst auch gegen Array-Elemente, Tabellenfelder und sogar verschachtelte Strukturen mit Array- oder Tabellenliteralen matchen.
3151
3152Matchen gegen Array-Elemente.
3153
3154```yuescript
3155switch tb
3156 when [1, 2, 3]
3157 print "1, 2, 3"
3158 when [1, b, 3]
3159 print "1, #{b}, 3"
3160 when [1, 2, b = 3] -- b hat einen Standardwert
3161 print "1, 2, #{b}"
3162```
3163
3164<YueDisplay>
3165
3166```yue
3167switch tb
3168 when [1, 2, 3]
3169 print "1, 2, 3"
3170 when [1, b, 3]
3171 print "1, #{b}, 3"
3172 when [1, 2, b = 3] -- b hat einen Standardwert
3173 print "1, 2, #{b}"
3174```
3175
3176</YueDisplay>
3177
3178Matchen gegen Tabellenfelder mit Destructuring.
3179
3180```yuescript
3181switch tb
3182 when success: true, :result
3183 print "Erfolg", result
3184 when success: false
3185 print "fehlgeschlagen", result
3186 else
3187 print "ungültig"
3188```
3189
3190<YueDisplay>
3191
3192```yue
3193switch tb
3194 when success: true, :result
3195 print "Erfolg", result
3196 when success: false
3197 print "fehlgeschlagen", result
3198 else
3199 print "ungültig"
3200```
3201
3202</YueDisplay>
3203
3204Matchen gegen verschachtelte Tabellenstrukturen.
3205
3206```yuescript
3207switch tb
3208 when data: {type: "success", :content}
3209 print "Erfolg", content
3210 when data: {type: "error", :content}
3211 print "fehlgeschlagen", content
3212 else
3213 print "ungültig"
3214```
3215
3216<YueDisplay>
3217
3218```yue
3219switch tb
3220 when data: {type: "success", :content}
3221 print "Erfolg", content
3222 when data: {type: "error", :content}
3223 print "fehlgeschlagen", content
3224 else
3225 print "ungültig"
3226```
3227
3228</YueDisplay>
3229
3230Matchen gegen Array von Tabellen.
3231
3232```yuescript
3233switch tb
3234 when [
3235 {a: 1, b: 2}
3236 {a: 3, b: 4}
3237 {a: 5, b: 6}
3238 fourth
3239 ]
3240 print "getroffen", fourth
3241```
3242
3243<YueDisplay>
3244
3245```yue
3246switch tb
3247 when [
3248 {a: 1, b: 2}
3249 {a: 3, b: 4}
3250 {a: 5, b: 6}
3251 fourth
3252 ]
3253 print "getroffen", fourth
3254```
3255
3256</YueDisplay>
3257
3258Matchen gegen eine Liste und einen Bereich von Elementen erfassen.
3259
3260```yuescript
3261segments = ["admin", "users", "logs", "view"]
3262switch segments
3263 when [...groups, resource, action]
3264 print "Gruppe:", groups -- gibt aus: {"admin", "users"}
3265 print "Ressource:", resource -- gibt aus: "logs"
3266 print "Aktion:", action -- gibt aus: "view"
3267```
3268
3269<YueDisplay>
3270
3271```yue
3272segments = ["admin", "users", "logs", "view"]
3273switch segments
3274 when [...groups, resource, action]
3275 print "Gruppe:", groups -- gibt aus: {"admin", "users"}
3276 print "Ressource:", resource -- gibt aus: "logs"
3277 print "Aktion:", action -- gibt aus: "view"
3278```
3279
3280</YueDisplay>
3281
3282# While-Schleife
3283
3284Die `while`-Schleife gibt es ebenfalls in vier Variationen:
3285
3286```yuescript
3287i = 10
3288while i > 0
3289 print i
3290 i -= 1
3291
3292while running == true do my_function!
3293```
3294
3295<YueDisplay>
3296
3297```yue
3298i = 10
3299while i > 0
3300 print i
3301 i -= 1
3302
3303while running == true do my_function!
3304```
3305
3306</YueDisplay>
3307
3308```yuescript
3309i = 10
3310until i == 0
3311 print i
3312 i -= 1
3313
3314until running == false do my_function!
3315```
3316
3317<YueDisplay>
3318
3319```yue
3320i = 10
3321until i == 0
3322 print i
3323 i -= 1
3324until running == false do my_function!
3325```
3326
3327</YueDisplay>
3328
3329Wie bei `for`-Schleifen kann die `while`-Schleife auch als Ausdruck verwendet werden. `while`- und `until`-Ausdrücke unterstützen `break` mit mehreren Rückgabewerten.
3330
3331```yuescript
3332value, doubled = while true
3333 n = get_next!
3334 break n, n * 2 if n > 10
3335```
3336
3337<YueDisplay>
3338
3339```yue
3340value, doubled = while true
3341 n = get_next!
3342 break n, n * 2 if n > 10
3343```
3344
3345</YueDisplay>
3346
3347Damit eine Funktion den akkumulierten Wert einer `while`-Schleife zurückgibt, muss die Anweisung explizit mit `return` zurückgegeben werden.
3348
3349## Repeat-Schleife
3350
3351Die `repeat`-Schleife stammt aus Lua:
3352
3353```yuescript
3354i = 10
3355repeat
3356 print i
3357 i -= 1
3358until i == 0
3359```
3360
3361<YueDisplay>
3362
3363```yue
3364i = 10
3365repeat
3366 print i
3367 i -= 1
3368until i == 0
3369```
3370
3371</YueDisplay>
3372
3373`repeat`-Ausdrücke unterstützen ebenfalls `break` mit mehreren Rückgabewerten:
3374
3375```yuescript
3376i = 1
3377value, scaled = repeat
3378 break i, i * 100 if i > 3
3379 i += 1
3380until false
3381```
3382
3383<YueDisplay>
3384
3385```yue
3386i = 1
3387value, scaled = repeat
3388 break i, i * 100 if i > 3
3389 i += 1
3390until false
3391```
3392
3393</YueDisplay>
3394
3395# Funktions-Stubs
3396
3397Es ist üblich, eine Funktion eines Objekts als Wert weiterzureichen, z. B. eine Instanzmethode als Callback. Wenn die Funktion das Objekt, auf dem sie arbeitet, als erstes Argument erwartet, musst du dieses Objekt irgendwie mit der Funktion bündeln, damit sie korrekt aufgerufen werden kann.
3398
3399Die Funktions-Stub-Syntax ist eine Kurzform, um eine neue Closure-Funktion zu erstellen, die sowohl Objekt als auch Funktion bündelt. Diese neue Funktion ruft die umschlossene Funktion im richtigen Kontext des Objekts auf.
3400
3401Die Syntax entspricht dem Aufruf einer Instanzmethode mit dem `\`-Operator, jedoch ohne Argumentliste.
3402
3403```yuescript
3404my_object = {
3405 value: 1000
3406 write: => print "der Wert:", @value
3407}
3408
3409run_callback = (func) ->
3410 print "Callback wird ausgeführt..."
3411 func!
3412
3413-- das funktioniert nicht:
3414-- die Funktion darf keine Referenz auf my_object haben
3415run_callback my_object.write
3416
3417-- Funktions-Stub-Syntax
3418-- bindet das Objekt in eine neue Funktion ein
3419run_callback my_object\write
3420```
3421
3422<YueDisplay>
3423
3424```yue
3425my_object = {
3426 value: 1000
3427 write: => print "der Wert:", @value
3428}
3429
3430run_callback = (func) ->
3431 print "Callback wird ausgeführt..."
3432 func!
3433
3434-- das funktioniert nicht:
3435-- die Funktion darf keine Referenz auf my_object haben
3436run_callback my_object.write
3437
3438-- Funktions-Stub-Syntax
3439-- bindet das Objekt in eine neue Funktion ein
3440run_callback my_object\write
3441```
3442
3443</YueDisplay>
3444
3445# Backcalls
3446
3447Backcalls werden verwendet, um Callbacks zu entkoppeln (unnesting). Sie werden mit Pfeilen nach links definiert und füllen standardmäßig als letzter Parameter einen Funktionsaufruf. Die Syntax ist weitgehend wie bei normalen Pfeilfunktionen, nur dass der Pfeil in die andere Richtung zeigt und der Funktionskörper keine Einrückung benötigt.
3448
3449```yuescript
3450x <- f
3451print "hallo" .. x
3452```
3453
3454<YueDisplay>
3455
3456```yue
3457x <- f
3458print "hallo" .. x
3459```
3460
3461</YueDisplay>
3462
3463Fat-Arrow-Funktionen sind ebenfalls verfügbar.
3464
3465```yuescript
3466<= f
3467print @value
3468```
3469
3470<YueDisplay>
3471
3472```yue
3473<= f
3474print @value
3475```
3476
3477</YueDisplay>
3478
3479Du kannst einen Platzhalter angeben, an welcher Stelle die Backcall-Funktion als Parameter eingesetzt werden soll.
3480
3481```yuescript
3482(x) <- map _, [1, 2, 3]
3483x * 2
3484```
3485
3486<YueDisplay>
3487
3488```yue
3489(x) <- map _, [1, 2, 3]
3490x * 2
3491```
3492
3493</YueDisplay>
3494
3495Wenn du nach deinen Backcalls weiteren Code haben willst, kannst du sie mit einem `do`-Statement absetzen. Bei Nicht-Fat-Arrow-Funktionen können die Klammern weggelassen werden.
3496
3497```yuescript
3498result, msg = do
3499 data <- readAsync "dateiname.txt"
3500 print data
3501 info <- processAsync data
3502 check info
3503print result, msg
3504```
3505
3506<YueDisplay>
3507
3508```yue
3509result, msg = do
3510 data <- readAsync "dateiname.txt"
3511 print data
3512 info <- processAsync data
3513 check info
3514print result, msg
3515```
3516
3517</YueDisplay>
3518
3519# Funktionsliterale
3520
3521Alle Funktionen werden mit einem Funktionsausdruck erstellt. Eine einfache Funktion wird mit dem Pfeil **->** notiert.
3522
3523```yuescript
3524my_function = ->
3525my_function() -- leere Funktion aufrufen
3526```
3527
3528<YueDisplay>
3529
3530```yue
3531my_function = ->
3532my_function() -- leere Funktion aufrufen
3533```
3534
3535</YueDisplay>
3536
3537Der Funktionskörper kann entweder eine einzelne Anweisung direkt nach dem Pfeil sein oder aus mehreren Anweisungen bestehen, die in den folgenden Zeilen eingerückt werden:
3538
3539```yuescript
3540func_a = -> print "Hallo Welt"
3541
3542func_b = ->
3543 value = 100
3544 print "Der Wert:", value
3545```
3546
3547<YueDisplay>
3548
3549```yue
3550func_a = -> print "Hallo Welt"
3551
3552func_b = ->
3553 value = 100
3554 print "Der Wert:", value
3555```
3556
3557</YueDisplay>
3558
3559Wenn eine Funktion keine Argumente hat, kann sie mit dem `!`-Operator statt leerer Klammern aufgerufen werden. Der `!`-Aufruf ist die bevorzugte Art, Funktionen ohne Argumente aufzurufen.
3560
3561```yuescript
3562func_a!
3563func_b()
3564```
3565
3566<YueDisplay>
3567
3568```yue
3569func_a!
3570func_b()
3571```
3572
3573</YueDisplay>
3574
3575Funktionen mit Argumenten werden erstellt, indem der Pfeil von einer Argumentliste in Klammern eingeleitet wird:
3576
3577```yuescript
3578sum = (x, y) -> print "Summe", x + y
3579```
3580
3581<YueDisplay>
3582
3583```yue
3584sum = (x, y) -> print "Summe", x + y
3585```
3586
3587</YueDisplay>
3588
3589Funktionen können aufgerufen werden, indem die Argumente hinter dem Namen eines Ausdrucks stehen, der zu einer Funktion evaluiert. Beim Verketten mehrerer Funktionsaufrufe werden die Argumente der nächstliegenden Funktion links zugeordnet.
3590
3591```yuescript
3592sum 10, 20
3593print sum 10, 20
3594
3595a b c "a", "b", "c"
3596```
3597
3598<YueDisplay>
3599
3600```yue
3601sum 10, 20
3602print sum 10, 20
3603
3604a b c "a", "b", "c"
3605```
3606
3607</YueDisplay>
3608
3609Um Mehrdeutigkeiten beim Aufruf zu vermeiden, können die Argumente auch in Klammern gesetzt werden. Das ist hier nötig, damit die richtigen Argumente an die richtigen Funktionen gehen.
3610
3611```yuescript
3612print "x:", sum(10, 20), "y:", sum(30, 40)
3613```
3614
3615<YueDisplay>
3616
3617```yue
3618print "x:", sum(10, 20), "y:", sum(30, 40)
3619```
3620
3621</YueDisplay>
3622
3623Zwischen öffnender Klammer und Funktionsname darf kein Leerzeichen stehen.
3624
3625Funktionen wandeln die letzte Anweisung im Funktionskörper in ein `return` um. Das nennt sich implizites Return:
3626
3627```yuescript
3628sum = (x, y) -> x + y
3629print "Die Summe ist ", sum 10, 20
3630```
3631
3632<YueDisplay>
3633
3634```yue
3635sum = (x, y) -> x + y
3636print "Die Summe ist ", sum 10, 20
3637```
3638
3639</YueDisplay>
3640
3641Wenn du explizit zurückgeben willst, verwende `return`:
3642
3643```yuescript
3644sum = (x, y) -> return x + y
3645```
3646
3647<YueDisplay>
3648
3649```yue
3650sum = (x, y) -> return x + y
3651```
3652
3653</YueDisplay>
3654
3655Wie in Lua können Funktionen mehrere Werte zurückgeben. Die letzte Anweisung muss eine Liste von Werten sein, getrennt durch Kommas:
3656
3657```yuescript
3658mystery = (x, y) -> x + y, x - y
3659a, b = mystery 10, 20
3660```
3661
3662<YueDisplay>
3663
3664```yue
3665mystery = (x, y) -> x + y, x - y
3666a, b = mystery 10, 20
3667```
3668
3669</YueDisplay>
3670
3671## Fat Arrows
3672
3673Da es in Lua üblich ist, beim Methodenaufruf ein Objekt als erstes Argument zu übergeben, gibt es eine spezielle Syntax zum Erstellen von Funktionen, die automatisch ein `self`-Argument enthalten.
3674
3675```yuescript
3676func = (num) => @value + num
3677```
3678
3679<YueDisplay>
3680
3681```yue
3682func = (num) => @value + num
3683```
3684
3685</YueDisplay>
3686
3687## Standardwerte für Argumente
3688
3689Es ist möglich, Standardwerte für Funktionsargumente anzugeben. Ein Argument gilt als leer, wenn sein Wert `nil` ist. Alle `nil`-Argumente mit Standardwert werden vor Ausführung des Funktionskörpers ersetzt.
3690
3691```yuescript
3692my_function = (name = "etwas", height = 100) ->
3693 print "Hallo, ich bin", name
3694 print "Meine Größe ist", height
3695```
3696
3697<YueDisplay>
3698
3699```yue
3700my_function = (name = "etwas", height = 100) ->
3701 print "Hallo, ich bin", name
3702 print "Meine Größe ist", height
3703```
3704
3705</YueDisplay>
3706
3707Der Ausdruck für den Standardwert wird im Funktionskörper in der Reihenfolge der Argumentdeklarationen ausgewertet. Daher können Standardwerte auf zuvor deklarierte Argumente zugreifen.
3708
3709```yuescript
3710some_args = (x = 100, y = x + 1000) ->
3711 print x + y
3712```
3713
3714<YueDisplay>
3715
3716```yue
3717some_args = (x = 100, y = x + 1000) ->
3718 print x + y
3719```
3720
3721</YueDisplay>
3722
3723## Hinweise
3724
3725Aufgrund der ausdrucksstarken, klammerlosen Funktionsaufrufe müssen einige Einschränkungen gelten, um Parsing-Mehrdeutigkeiten mit Leerraum zu vermeiden.
3726
3727Das Minuszeichen hat zwei Rollen: unäre Negation und binäre Subtraktion. Sieh dir an, wie die folgenden Beispiele kompiliert werden:
3728
3729```yuescript
3730a = x - 10
3731b = x-10
3732c = x -y
3733d = x- z
3734```
3735
3736<YueDisplay>
3737
3738```yue
3739a = x - 10
3740b = x-10
3741c = x -y
3742d = x- z
3743```
3744
3745</YueDisplay>
3746
3747Die Präzedenz des ersten Arguments eines Funktionsaufrufs kann mit Leerraum gesteuert werden, wenn das Argument ein String-Literal ist. In Lua lässt man bei Aufrufen mit einem einzelnen String- oder Tabellenliteral häufig die Klammern weg.
3748
3749Wenn kein Leerzeichen zwischen Variable und String-Literal steht, hat der Funktionsaufruf Vorrang vor nachfolgenden Ausdrücken. In dieser Form können keine weiteren Argumente übergeben werden.
3750
3751Steht ein Leerzeichen zwischen Variable und String-Literal, verhält sich der Aufruf wie oben gezeigt. Das String-Literal gehört dann zu nachfolgenden Ausdrücken (falls vorhanden) und dient als Argumentliste.
3752
3753```yuescript
3754x = func"hallo" + 100
3755y = func "hallo" + 100
3756```
3757
3758<YueDisplay>
3759
3760```yue
3761x = func"hallo" + 100
3762y = func "hallo" + 100
3763```
3764
3765</YueDisplay>
3766
3767## Mehrzeilige Argumente
3768
3769Wenn Funktionsaufrufe viele Argumente haben, ist es praktisch, die Argumentliste auf mehrere Zeilen zu verteilen. Wegen der whitespace-sensitiven Natur der Sprache muss man dabei sorgfältig sein.
3770
3771Wenn eine Argumentliste in der nächsten Zeile fortgesetzt wird, muss die aktuelle Zeile mit einem Komma enden. Die folgende Zeile muss stärker eingerückt sein als die aktuelle. Sobald eingerückt, müssen alle weiteren Argumentzeilen auf derselben Einrückungsebene liegen, um Teil der Argumentliste zu sein.
3772
3773```yuescript
3774my_func 5, 4, 3,
3775 8, 9, 10
3776
3777cool_func 1, 2,
3778 3, 4,
3779 5, 6,
3780 7, 8
3781```
3782
3783<YueDisplay>
3784
3785```yue
3786my_func 5, 4, 3,
3787 8, 9, 10
3788
3789cool_func 1, 2,
3790 3, 4,
3791 5, 6,
3792 7, 8
3793```
3794
3795</YueDisplay>
3796
3797Diese Art des Aufrufs kann verschachtelt werden. Die Einrückungsebene bestimmt, zu welcher Funktion die Argumente gehören.
3798
3799```yuescript
3800my_func 5, 6, 7,
3801 6, another_func 6, 7, 8,
3802 9, 1, 2,
3803 5, 4
3804```
3805
3806<YueDisplay>
3807
3808```yue
3809my_func 5, 6, 7,
3810 6, another_func 6, 7, 8,
3811 9, 1, 2,
3812 5, 4
3813```
3814
3815</YueDisplay>
3816
3817Da Tabellen ebenfalls das Komma als Trennzeichen verwenden, hilft diese Einrückungssyntax dabei, Werte zur Argumentliste gehören zu lassen, statt zur Tabelle.
3818
3819```yuescript
3820x = [
3821 1, 2, 3, 4, a_func 4, 5,
3822 5, 6,
3823 8, 9, 10
3824]
3825```
3826
3827<YueDisplay>
3828
3829```yue
3830x = [
3831 1, 2, 3, 4, a_func 4, 5,
3832 5, 6,
3833 8, 9, 10
3834]
3835```
3836
3837</YueDisplay>
3838
3839Obwohl es selten ist: Du kannst Funktionsargumente tiefer einrücken, wenn du weißt, dass du später eine geringere Einrückungsebene verwenden wirst.
3840
3841```yuescript
3842y = [ my_func 1, 2, 3,
3843 4, 5,
3844 5, 6, 7
3845]
3846```
3847
3848<YueDisplay>
3849
3850```yue
3851y = [ my_func 1, 2, 3,
3852 4, 5,
3853 5, 6, 7
3854]
3855```
3856
3857</YueDisplay>
3858
3859Dasselbe lässt sich mit anderen Block-Statements wie Bedingungen machen. Wir können die Einrückungsebene verwenden, um zu bestimmen, zu welcher Anweisung ein Wert gehört:
3860
3861```yuescript
3862if func 1, 2, 3,
3863 "hallo",
3864 "Welt"
3865 print "hallo"
3866 print "Ich bin innerhalb der if-Bedingung"
3867
3868if func 1, 2, 3,
3869 "hallo",
3870 "Welt"
3871 print "hallo"
3872 print "Ich bin innerhalb der if-Bedingung"
3873```
3874
3875<YueDisplay>
3876
3877```yue
3878if func 1, 2, 3,
3879 "hallo",
3880 "Welt"
3881 print "hallo"
3882 print "Ich bin innerhalb der if-Bedingung"
3883
3884if func 1, 2, 3,
3885 "hallo",
3886 "Welt"
3887 print "hallo"
3888 print "Ich bin innerhalb der if-Bedingung"
3889```
3890
3891</YueDisplay>
3892
3893## Parameter-Destructuring
3894
3895YueScript unterstützt jetzt Destructuring von Funktionsparametern, wenn das Argument ein Objekt ist. Es gibt zwei Formen von Destructuring-Tabellenliteralen:
3896
3897- **Geschweifte Klammern/Objektparameter**, die optionale Standardwerte erlauben, wenn Felder fehlen (z. B. `{:a, :b}`, `{a: a1 = 123}`).
3898- **Unverpackte einfache Tabellensyntax**, die mit einer Sequenz aus Key-Value- oder Shorthand-Bindings beginnt und so lange läuft, bis ein anderer Ausdruck sie beendet (z. B. `:a, b: b1, :c`). Diese Form extrahiert mehrere Felder aus demselben Objekt.
3899
3900```yuescript
3901f1 = (:a, :b, :c) ->
3902 print a, b, c
3903
3904f1 a: 1, b: "2", c: {}
3905
3906f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3907 print a1, b, c
3908
3909arg1 = {a: 0}
3910f2 arg1, arg2
3911```
3912
3913<YueDisplay>
3914
3915```yue
3916f1 = (:a, :b, :c) ->
3917 print a, b, c
3918
3919f1 a: 1, b: "2", c: {}
3920
3921f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3922print a1, b, c
3923
3924arg1 = {a: 0}
3925f2 arg1, arg2
3926```
3927
3928</YueDisplay>
3929
3930## Präfixiertes Return-Expression
3931
3932Wenn du mit tief verschachtelten Funktionskörpern arbeitest, kann es mühsam sein, die Lesbarkeit und Konsistenz des Rückgabewerts zu erhalten. Dafür führt YueScript die Syntax der **präfixierten Return-Expression** ein. Sie hat folgende Form:
3933
3934```yuescript
3935findFirstEven = (list): nil ->
3936 for item in *list
3937 if type(item) == "table"
3938 for sub in *item
3939 if sub % 2 == 0
3940 return sub
3941```
3942
3943<YueDisplay>
3944
3945```yue
3946findFirstEven = (list): nil ->
3947 for item in *list
3948 if type(item) == "table"
3949 for sub in *item
3950 if sub % 2 == 0
3951 return sub
3952```
3953
3954</YueDisplay>
3955
3956Das ist äquivalent zu:
3957
3958```yuescript
3959findFirstEven = (list) ->
3960 for item in *list
3961 if type(item) == "table"
3962 for sub in *item
3963 if sub % 2 == 0
3964 return sub
3965 nil
3966```
3967
3968<YueDisplay>
3969
3970```yue
3971findFirstEven = (list) ->
3972 for item in *list
3973 if type(item) == "table"
3974 for sub in *item
3975 if sub % 2 == 0
3976 return sub
3977 nil
3978```
3979
3980</YueDisplay>
3981
3982Der einzige Unterschied ist, dass du den finalen Rückgabeausdruck vor das `->`- oder `=>`-Token ziehen kannst, um den impliziten Rückgabewert der Funktion als letzte Anweisung zu kennzeichnen. So musst du selbst bei Funktionen mit mehreren verschachtelten Schleifen oder bedingten Zweigen kein abschließendes `return` am Ende des Funktionskörpers mehr schreiben, was die Logikstruktur klarer und leichter nachvollziehbar macht.
3983
3984## Benannte Varargs
3985
3986Mit der Syntax `(...t) ->` kannst du Varargs automatisch in einer benannten Tabelle speichern. Diese Tabelle enthält alle übergebenen Argumente (einschließlich `nil`-Werten), und das Feld `n` der Tabelle speichert die tatsächliche Anzahl übergebener Argumente (einschließlich `nil`-Werten).
3987
3988```yuescript
3989f = (...t) ->
3990 print "Anzahl der Argumente:", t.n
3991 print "Tabellenlänge:", #t
3992 for i = 1, t.n
3993 print t[i]
3994
3995f 1, 2, 3
3996f "a", "b", "c", "d"
3997f!
3998
3999-- Fälle mit nil-Werten behandeln
4000process = (...args) ->
4001 sum = 0
4002 for i = 1, args.n
4003 if args[i] != nil and type(args[i]) == "number"
4004 sum += args[i]
4005 sum
4006
4007process 1, nil, 3, nil, 5
4008```
4009
4010<YueDisplay>
4011
4012```yue
4013f = (...t) ->
4014 print "Anzahl der Argumente:", t.n
4015 print "Tabellenlänge:", #t
4016 for i = 1, t.n
4017 print t[i]
4018
4019f 1, 2, 3
4020f "a", "b", "c", "d"
4021f!
4022
4023-- Fälle mit nil-Werten behandeln
4024process = (...args) ->
4025 sum = 0
4026 for i = 1, args.n
4027 if args[i] != nil and type(args[i]) == "number"
4028 sum += args[i]
4029 sum
4030
4031process 1, nil, 3, nil, 5
4032```
4033
4034</YueDisplay>
4035
4036# Leerraum
4037
4038YueScript ist eine whitespace-sensible Sprache. Du musst bestimmte Code-Blöcke mit derselben Einrückung (Leerzeichen **' '** oder Tab **'\t'**) schreiben, z. B. Funktionskörper, Wertelisten und Kontrollblöcke. Ausdrücke mit unterschiedlichem Leerraum können unterschiedliche Bedeutungen haben. Ein Tab wird wie 4 Leerzeichen behandelt, aber es ist besser, Leerzeichen und Tabs nicht zu mischen.
4039
4040## Anweisungs-Trenner
4041
4042Eine Anweisung endet normalerweise an einem Zeilenumbruch. Du kannst auch ein Semikolon `;` verwenden, um eine Anweisung explizit zu beenden, wodurch mehrere Anweisungen in einer Zeile möglich sind:
4043
4044```yuescript
4045a = 1; b = 2; print a + b
4046```
4047
4048<YueDisplay>
4049
4050```yue
4051a = 1; b = 2; print a + b
4052```
4053
4054</YueDisplay>
4055
4056## Mehrzeiliges Chaining
4057
4058Du kannst mehrzeilige, verkettete Funktionsaufrufe mit derselben Einrückung schreiben.
4059
4060```yuescript
4061Rx.Observable
4062 .fromRange 1, 8
4063 \filter (x) -> x % 2 == 0
4064 \concat Rx.Observable.of 'who do we appreciate'
4065 \map (value) -> value .. '!'
4066 \subscribe print
4067```
4068
4069<YueDisplay>
4070
4071```yue
4072Rx.Observable
4073 .fromRange 1, 8
4074 \filter (x) -> x % 2 == 0
4075 \concat Rx.Observable.of 'who do we appreciate'
4076 \map (value) -> value .. '!'
4077 \subscribe print
4078```
4079
4080</YueDisplay>
4081
4082# Kommentare
4083
4084```yuescript
4085-- Ich bin ein Kommentar
4086
4087str = --[[
4088Dies ist ein mehrzeiliger Kommentar.
4089Alles okay.
4090]] strA \ -- Kommentar 1
4091 .. strB \ -- Kommentar 2
4092 .. strC
4093
4094func --[[Port]] 3000, --[[IP]] "192.168.1.1"
4095```
4096
4097<YueDisplay>
4098
4099```yue
4100-- Ich bin ein Kommentar
4101
4102str = --[[
4103Dies ist ein mehrzeiliger Kommentar.
4104Alles okay.
4105]] strA \ -- Kommentar 1
4106 .. strB \ -- Kommentar 2
4107 .. strC
4108
4109func --[[Port]] 3000, --[[IP]] "192.168.1.1"
4110```
4111
4112</YueDisplay>
4113
4114# Attribute
4115
4116Syntax-Unterstützung für Lua-5.4-Attribute. Du kannst weiterhin die Deklarationen `const` und `close` verwenden und erhältst Konstantenprüfung sowie Scoped-Callbacks, wenn du auf Lua-Versionen unter 5.4 zielst.
4117
4118```yuescript
4119const a = 123
4120close _ = <close>: -> print "Außerhalb des Gültigkeitsbereichs."
4121```
4122
4123<YueDisplay>
4124
4125```yue
4126const a = 123
4127close _ = <close>: -> print "Außerhalb des Gültigkeitsbereichs."
4128```
4129
4130</YueDisplay>
4131
4132Du kannst Destructuring mit als konstant markierten Variablen verwenden.
4133
4134```yuescript
4135const {:a, :b, c, d} = tb
4136-- a = 1
4137```
4138
4139<YueDisplay>
4140
4141```yue
4142const {:a, :b, c, d} = tb
4143-- a = 1
4144```
4145
4146</YueDisplay>
4147
4148Du kannst auch eine globale Variable als `const` deklarieren.
4149
4150```yuescript
4151global const Constant = 123
4152-- Constant = 1
4153```
4154
4155<YueDisplay>
4156
4157```yue
4158global const Constant = 123
4159-- Constant = 1
4160```
4161
4162</YueDisplay>
4163
4164# Operatoren
4165
4166Alle binären und unären Operatoren von Lua sind verfügbar. Zusätzlich ist **!=** ein Alias für **~=**, und entweder **\*\* oder **::\*\* kann für verkettete Funktionsaufrufe wie `tb\func!` oder `tb::func!` verwendet werden. Außerdem bietet YueScript einige spezielle Operatoren für ausdrucksstärkeren Code.
4167
4168```yuescript
4169tb\func! if tb ~= nil
4170tb::func! if tb != nil
4171```
4172
4173<YueDisplay>
4174
4175```yue
4176tb\func! if tb ~= nil
4177tb::func! if tb != nil
4178```
4179
4180</YueDisplay>
4181
4182## Verkettete Vergleiche
4183
4184Vergleiche können beliebig verkettet werden:
4185
4186```yuescript
4187print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4188-- Ausgabe: true
4189
4190a = 5
4191print 1 <= a <= 10
4192-- Ausgabe: true
4193```
4194
4195<YueDisplay>
4196
4197```yue
4198print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4199-- Ausgabe: true
4200
4201a = 5
4202print 1 <= a <= 10
4203-- Ausgabe: true
4204```
4205
4206</YueDisplay>
4207
4208Beachte das Auswertungsverhalten verketteter Vergleiche:
4209
4210```yuescript
4211v = (x) ->
4212 print x
4213 x
4214
4215print v(1) < v(2) <= v(3)
4216--[[
4217 Ausgabe:
4218 2
4219 1
4220 3
4221 true
4222]]
4223
4224print v(1) > v(2) <= v(3)
4225--[[
4226 Ausgabe:
4227 2
4228 1
4229 false
4230]]
4231```
4232
4233<YueDisplay>
4234
4235```yue
4236v = (x) ->
4237 print x
4238 x
4239
4240print v(1) < v(2) <= v(3)
4241--[[
4242 Ausgabe:
4243 2
4244 1
4245 3
4246 true
4247]]
4248
4249print v(1) > v(2) <= v(3)
4250--[[
4251 Ausgabe:
4252 2
4253 1
4254 false
4255]]
4256```
4257
4258</YueDisplay>
4259
4260Der mittlere Ausdruck wird nur einmal ausgewertet, nicht zweimal wie bei `v(1) < v(2) and v(2) <= v(3)`. Die Auswertungsreihenfolge in verketteten Vergleichen ist jedoch undefiniert. Es wird dringend empfohlen, in verketteten Vergleichen keine Ausdrücke mit Seiteneffekten (z. B. `print`) zu verwenden. Wenn Seiteneffekte nötig sind, sollte der Short-Circuit-Operator `and` explizit verwendet werden.
4261
4262## Tabellenerweiterung
4263
4264Der Operator **[] =** wird verwendet, um Werte an Tabellen anzuhängen.
4265
4266```yuescript
4267tab = []
4268tab[] = "Wert"
4269```
4270
4271<YueDisplay>
4272
4273```yue
4274tab = []
4275tab[] = "Wert"
4276```
4277
4278</YueDisplay>
4279
4280Du kannst auch den Spread-Operator `...` verwenden, um alle Elemente einer Liste an eine andere anzuhängen:
4281
4282```yuescript
4283tbA = [1, 2, 3]
4284tbB = [4, 5, 6]
4285tbA[] = ...tbB
4286-- tbA ist jetzt [1, 2, 3, 4, 5, 6]
4287```
4288
4289<YueDisplay>
4290
4291```yue
4292tbA = [1, 2, 3]
4293tbB = [4, 5, 6]
4294tbA[] = ...tbB
4295-- tbA ist jetzt [1, 2, 3, 4, 5, 6]
4296```
4297
4298</YueDisplay>
4299
4300## Tabellen-Spread
4301
4302Du kannst Array-Tabellen oder Hash-Tabellen mit dem Spread-Operator `...` vor Ausdrücken in Tabellenliteralen zusammenführen.
4303
4304```yuescript
4305parts =
4306 * "Schultern"
4307 * "Knie"
4308lyrics =
4309 * "Kopf"
4310 * ...parts
4311 * "und"
4312 * "Zehen"
4313
4314copy = {...other}
4315
4316a = {1, 2, 3, x: 1}
4317b = {4, 5, y: 1}
4318merge = {...a, ...b}
4319```
4320
4321<YueDisplay>
4322
4323```yue
4324parts =
4325 * "Schultern"
4326 * "Knie"
4327lyrics =
4328 * "Kopf"
4329 * ...parts
4330 * "und"
4331 * "Zehen"
4332
4333copy = {...other}
4334
4335a = {1, 2, 3, x: 1}
4336b = {4, 5, y: 1}
4337merge = {...a, ...b}
4338```
4339
4340</YueDisplay>
4341
4342## Umgekehrter Tabellenindex
4343
4344Mit dem Operator **#** kannst du auf die letzten Elemente einer Tabelle zugreifen.
4345
4346```yuescript
4347last = data.items[#]
4348second_last = data.items[#-1]
4349data.items[#] = 1
4350```
4351
4352<YueDisplay>
4353
4354```yue
4355last = data.items[#]
4356second_last = data.items[#-1]
4357data.items[#] = 1
4358```
4359
4360</YueDisplay>
4361
4362## Metatable
4363
4364Der Operator **<>** kann als Abkürzung für Metatable-Manipulation verwendet werden.
4365
4366### Metatable erstellen
4367
4368Erzeuge eine normale Tabelle mit leeren Klammern **<>** oder einem Metamethod-Schlüssel, der von **<>** umschlossen ist.
4369
4370```yuescript
4371mt = {}
4372add = (right) => <>: mt, value: @value + right.value
4373mt.__add = add
4374
4375a = <>: mt, value: 1
4376 -- Feld mit gleichnamiger Variable setzen
4377b = :<add>, value: 2
4378c = <add>: mt.__add, value: 3
4379
4380d = a + b + c
4381print d.value
4382
4383close _ = <close>: -> print "Außerhalb des Gültigkeitsbereichs"
4384```
4385
4386<YueDisplay>
4387
4388```yue
4389mt = {}
4390add = (right) => <>: mt, value: @value + right.value
4391mt.__add = add
4392
4393a = <>: mt, value: 1
4394 -- Feld mit gleichnamiger Variable setzen
4395b = :<add>, value: 2
4396c = <add>: mt.__add, value: 3
4397
4398d = a + b + c
4399print d.value
4400
4401close _ = <close>: -> print "Außerhalb des Gültigkeitsbereichs"
4402```
4403
4404</YueDisplay>
4405
4406### Metatable-Zugriff
4407
4408Metatable mit **<>** oder einem von **<>** umschlossenen Metamethod-Namen aufrufen oder einen Ausdruck in **<>** schreiben.
4409
4410```yuescript
4411-- erstellen mit Metatable, das das Feld "value" enthält
4412tb = <"value">: 123
4413tb.<index> = tb.<>
4414print tb.value
4415
4416tb.<> = __index: {item: "hallo"}
4417print tb.item
4418```
4419
4420<YueDisplay>
4421
4422```yue
4423-- erstellen mit Metatable, das das Feld "value" enthält
4424tb = <"value">: 123
4425tb.<index> = tb.<>
4426print tb.value
4427tb.<> = __index: {item: "hallo"}
4428print tb.item
4429```
4430
4431</YueDisplay>
4432
4433### Metatable-Destrukturierung
4434
4435Destrukturiere Metatable mit Metamethoden-Schlüssel, der von **<>** umschlossen ist.
4436
4437```yuescript
4438{item, :new, :<close>, <index>: getter} = tb
4439print item, new, close, getter
4440```
4441
4442<YueDisplay>
4443
4444```yue
4445{item, :new, :<close>, <index>: getter} = tb
4446print item, new, close, getter
4447```
4448
4449</YueDisplay>
4450
4451## Existenz
4452
4453Der Operator **?** kann in verschiedenen Kontexten verwendet werden, um die Existenz zu prüfen.
4454
4455```yuescript
4456func?!
4457print abc?["hello world"]?.xyz
4458
4459x = tab?.value
4460len = utf8?.len or string?.len or (o) -> #o
4461
4462if print and x?
4463 print x
4464
4465with? io.open "test.txt", "w"
4466 \write "hello"
4467 \close!
4468```
4469
4470<YueDisplay>
4471
4472```yue
4473func?!
4474print abc?["hello world"]?.xyz
4475
4476x = tab?.value
4477len = utf8?.len or string?.len or (o) -> #o
4478
4479if print and x?
4480 print x
4481
4482with? io.open "test.txt", "w"
4483 \write "hello"
4484 \close!
4485```
4486
4487</YueDisplay>
4488
4489## Piping
4490
4491Anstelle einer Reihe verschachtelter Funktionsaufrufe kannst du Werte mit dem Operator **|>** weiterleiten.
4492
4493```yuescript
4494"hello" |> print
44951 |> print 2 -- Pipe-Element als erstes Argument einfügen
44962 |> print 1, _, 3 -- Pipe mit Platzhalter
4497
4498-- Pipe-Ausdruck über mehrere Zeilen
4499readFile "example.txt"
4500 |> extract language, {}
4501 |> parse language
4502 |> emit
4503 |> render
4504 |> print
4505```
4506
4507<YueDisplay>
4508
4509```yue
4510"hello" |> print
45111 |> print 2 -- Pipe-Element als erstes Argument einfügen
45122 |> print 1, _, 3 -- Pipe mit Platzhalter
4513-- Pipe-Ausdruck über mehrere Zeilen
4514readFile "example.txt"
4515 |> extract language, {}
4516 |> parse language
4517 |> emit
4518 |> render
4519 |> print
4520```
4521
4522</YueDisplay>
4523
4524## Nil-Coalescing
4525
4526Der Nil-Coalescing-Operator **??** gibt den Wert des linken Operanden zurück, wenn er nicht **nil** ist; andernfalls wird der rechte Operand ausgewertet und sein Ergebnis zurückgegeben. Der **??**-Operator wertet seinen rechten Operanden nicht aus, wenn der linke Operand nicht nil ergibt.
4527
4528```yuescript
4529local a, b, c, d
4530a = b ?? c ?? d
4531func a ?? {}
4532
4533a ??= false
4534```
4535
4536<YueDisplay>
4537
4538```yue
4539local a, b, c, d
4540a = b ?? c ?? d
4541func a ?? {}
4542a ??= false
4543```
4544
4545</YueDisplay>
4546
4547## Implizites Objekt
4548
4549Du kannst innerhalb eines Tabellenblocks eine Liste impliziter Strukturen schreiben, die mit dem Symbol **\*** oder **-** beginnt. Beim Erstellen eines impliziten Objekts müssen die Felder des Objekts dieselbe Einrückung haben.
4550
4551```yuescript
4552-- Zuweisung mit implizitem Objekt
4553list =
4554 * 1
4555 * 2
4556 * 3
4557
4558-- Funktionsaufruf mit implizitem Objekt
4559func
4560 * 1
4561 * 2
4562 * 3
4563
4564-- Rückgabe mit implizitem Objekt
4565f = ->
4566 return
4567 * 1
4568 * 2
4569 * 3
4570
4571-- Tabelle mit implizitem Objekt
4572tb =
4573 name: "abc"
4574
4575 values:
4576 - "a"
4577 - "b"
4578 - "c"
4579
4580 objects:
4581 - name: "a"
4582 value: 1
4583 func: => @value + 1
4584 tb:
4585 fieldA: 1
4586
4587 - name: "b"
4588 value: 2
4589 func: => @value + 2
4590 tb: { }
4591
4592```
4593
4594<YueDisplay>
4595
4596```yue
4597-- Zuweisung mit implizitem Objekt
4598list =
4599 * 1
4600 * 2
4601 * 3
4602
4603-- Funktionsaufruf mit implizitem Objekt
4604func
4605 * 1
4606 * 2
4607 * 3
4608
4609-- Rückgabe mit implizitem Objekt
4610f = ->
4611 return
4612 * 1
4613 * 2
4614 * 3
4615
4616-- Tabelle mit implizitem Objekt
4617tb =
4618 name: "abc"
4619
4620 values:
4621 - "a"
4622 - "b"
4623 - "c"
4624
4625 objects:
4626 - name: "a"
4627 value: 1
4628 func: => @value + 1
4629 tb:
4630 fieldA: 1
4631
4632 - name: "b"
4633 value: 2
4634 func: => @value + 2
4635 tb: { }
4636```
4637
4638</YueDisplay>
4639
4640# Literale
4641
4642Alle primitiven Literale in Lua können verwendet werden. Das gilt für Zahlen, Strings, Booleans und **nil**.
4643
4644Anders als in Lua sind Zeilenumbrüche innerhalb einfacher und doppelter Anführungszeichen ohne Escape-Sequenz erlaubt:
4645
4646```yuescript
4647some_string = "Hier ist ein String
4648 mit einem Zeilenumbruch."
4649
4650-- Mit der #{}-Syntax kannst du Ausdrücke in String-Literale einbinden.
4651-- String-Interpolation gibt es nur in doppelt angeführten Strings.
4652print "Ich bin mir zu #{math.random! * 100}% sicher."
4653```
4654
4655<YueDisplay>
4656
4657```yue
4658some_string = "Hier ist ein String
4659 mit einem Zeilenumbruch."
4660
4661-- Mit der #{}-Syntax kannst du Ausdrücke in String-Literale einbinden.
4662-- String-Interpolation gibt es nur in doppelt angeführten Strings.
4663print "Ich bin mir zu #{math.random! * 100}% sicher."
4664```
4665
4666</YueDisplay>
4667
4668## Zahlenliterale
4669
4670Du kannst Unterstriche in Zahlenliteralen verwenden, um die Lesbarkeit zu erhöhen.
4671
4672```yuescript
4673integer = 1_000_000
4674hex = 0xEF_BB_BF
4675binary = 0B10011
4676```
4677
4678<YueDisplay>
4679
4680```yue
4681integer = 1_000_000
4682hex = 0xEF_BB_BF
4683binary = 0B10011
4684```
4685
4686</YueDisplay>
4687
4688## YAML-Mehrzeilen-String
4689
4690Das Präfix `|` führt ein mehrzeiliges String-Literal im YAML-Stil ein:
4691
4692```yuescript
4693str = |
4694 key: value
4695 list:
4696 - item1
4697 - #{expr}
4698```
4699
4700<YueDisplay>
4701
4702```yue
4703str = |
4704 key: value
4705 list:
4706 - item1
4707 - #{expr}
4708```
4709
4710</YueDisplay>
4711
4712Damit lässt sich strukturierter, mehrzeiliger Text bequem schreiben. Alle Zeilenumbrüche und Einrückungen bleiben relativ zur ersten nicht-leeren Zeile erhalten, und Ausdrücke innerhalb von `#{...}` werden automatisch als `tostring(expr)` interpoliert.
4713
4714Der YAML-Mehrzeilen-String erkennt automatisch das gemeinsame führende Leerraumpräfix (minimale Einrückung über alle nicht-leeren Zeilen) und entfernt es aus allen Zeilen. So kannst du deinen Code optisch einrücken, ohne den resultierenden String zu verändern.
4715
4716```yuescript
4717fn = ->
4718 str = |
4719 foo:
4720 bar: baz
4721 return str
4722```
4723
4724<YueDisplay>
4725
4726```yue
4727fn = ->
4728 str = |
4729 foo:
4730 bar: baz
4731 return str
4732```
4733
4734</YueDisplay>
4735
4736Die interne Einrückung bleibt relativ zum entfernten gemeinsamen Präfix erhalten, wodurch saubere, verschachtelte Strukturen möglich sind.
4737
4738Alle Sonderzeichen wie Anführungszeichen (`"`) und Backslashes (`\`) im YAML-Mehrzeilen-Block werden automatisch escaped, sodass der erzeugte Lua-String syntaktisch korrekt ist und wie erwartet funktioniert.
4739
4740```yuescript
4741str = |
4742 path: "C:\Program Files\App"
4743 note: 'He said: "#{Hello}!"'
4744```
4745
4746<YueDisplay>
4747
4748```yue
4749str = |
4750 path: "C:\Program Files\App"
4751 note: 'He said: "#{Hello}!"'
4752```
4753
4754</YueDisplay>
4755
4756# Module
4757
4758## Import
4759
4760Die `import`-Anweisung ist syntaktischer Zucker für `require` und hilft beim Extrahieren von Einträgen aus importierten Modulen. Importierte Elemente sind standardmäßig `const`.
4761
4762```yuescript
4763-- als Tabellen-Destrukturierung
4764do
4765 import insert, concat from table
4766 -- Fehler beim Zuweisen zu insert, concat
4767 import C, Ct, Cmt from require "lpeg"
4768 -- Kurzform für implizites Require
4769 import x, y, z from 'mymodule'
4770 -- Import im Python-Stil
4771 from 'module' import a, b, c
4772
4773-- Kurzform zum Laden eines Moduls
4774do
4775 import 'module'
4776 import 'module_x'
4777 import "d-a-s-h-e-s"
4778 import "module.part"
4779
4780-- Modul mit Alias oder Tabellen-Destrukturierung laden
4781do
4782 import "player" as PlayerModule
4783 import "lpeg" as :C, :Ct, :Cmt
4784 import "export" as {one, two, Something:{umm:{ch}}}
4785```
4786
4787<YueDisplay>
4788
4789```yue
4790-- als Tabellen-Destrukturierung
4791do
4792 import insert, concat from table
4793 -- Fehler beim Zuweisen zu insert, concat
4794 import C, Ct, Cmt from require "lpeg"
4795 -- Kurzform für implizites Require
4796 import x, y, z from 'mymodule'
4797 -- Import im Python-Stil
4798 from 'module' import a, b, c
4799
4800-- Kurzform zum Laden eines Moduls
4801do
4802 import 'module'
4803 import 'module_x'
4804 import "d-a-s-h-e-s"
4805 import "module.part"
4806
4807-- Modul mit Alias oder Tabellen-Destrukturierung laden
4808do
4809 import "player" as PlayerModule
4810 import "lpeg" as :C, :Ct, :Cmt
4811 import "export" as {one, two, Something:{umm:{ch}}}
4812```
4813
4814</YueDisplay>
4815
4816## Import von Globals
4817
4818Du kannst mit `import` bestimmte Globals in lokale Variablen importieren. Wenn du eine Kette von Globalzugriffen importierst, wird das letzte Feld der lokalen Variable zugewiesen.
4819
4820```yuescript
4821do
4822 import tostring
4823 import table.concat
4824 print concat ["a", tostring 1]
4825```
4826
4827<YueDisplay>
4828
4829```yue
4830do
4831 import tostring
4832 import table.concat
4833 print concat ["a", tostring 1]
4834```
4835
4836</YueDisplay>
4837
4838### Automatischer Global-Import
4839
4840Du kannst `import global` am Anfang eines Blocks platzieren, um automatisch alle Namen zu importieren, die im aktuellen Scope nicht explizit deklariert oder zugewiesen sind. Diese impliziten Importe werden als lokale `const` behandelt, die an die entsprechenden Globals zum Zeitpunkt der Anweisung gebunden sind.
4841
4842Namen, die im selben Scope explizit als `global` deklariert werden, werden nicht importiert, sodass du sie weiterhin zuweisen kannst.
4843
4844```yuescript
4845do
4846 import global
4847 print "hallo"
4848 math.random 3
4849 -- print = nil -- Fehler: importierte Globals sind const
4850
4851do
4852 -- explizite globale Variable wird nicht importiert
4853 import global
4854 global FLAG
4855 print FLAG
4856 FLAG = 123
4857```
4858
4859<YueDisplay>
4860
4861```yue
4862do
4863 import global
4864 print "hallo"
4865 math.random 3
4866 -- print = nil -- Fehler: importierte Globals sind const
4867
4868do
4869 -- explizite globale Variable wird nicht importiert
4870 import global
4871 global FLAG
4872 print FLAG
4873 FLAG = 123
4874```
4875
4876</YueDisplay>
4877
4878## Export
4879
4880Die `export`-Anweisung bietet eine knappe Möglichkeit, Module zu definieren.
4881
4882### Benannter Export
4883
4884Benannter Export definiert eine lokale Variable und fügt ein Feld in die exportierte Tabelle ein.
4885
4886```yuescript
4887export a, b, c = 1, 2, 3
4888export cool = "Katze"
4889
4890export What = if this
4891 "abc"
4892else
4893 "def"
4894
4895export y = ->
4896 hallo = 3434
4897
4898export class Something
4899 umm: "cool"
4900```
4901
4902<YueDisplay>
4903
4904```yue
4905export a, b, c = 1, 2, 3
4906export cool = "Katze"
4907
4908export What = if this
4909 "abc"
4910else
4911 "def"
4912
4913export y = ->
4914 hallo = 3434
4915
4916export class Something
4917 umm: "cool"
4918```
4919
4920</YueDisplay>
4921
4922Benannter Export mit Destructuring.
4923
4924```yuescript
4925export :loadstring, to_lua: tolua = yue
4926export {itemA: {:fieldA = 'default'}} = tb
4927```
4928
4929<YueDisplay>
4930
4931```yue
4932export :loadstring, to_lua: tolua = yue
4933export {itemA: {:fieldA = 'default'}} = tb
4934```
4935
4936</YueDisplay>
4937
4938Benannte Elemente aus dem Modul exportieren, ohne lokale Variablen zu erstellen.
4939
4940```yuescript
4941export.itemA = tb
4942export.<index> = items
4943export["a-b-c"] = 123
4944```
4945
4946<YueDisplay>
4947
4948```yue
4949export.itemA = tb
4950export.<index> = items
4951export["a-b-c"] = 123
4952```
4953
4954</YueDisplay>
4955
4956### Unbenannter Export
4957
4958Unbenannter Export fügt das Ziel-Element in den Array-Teil der exportierten Tabelle ein.
4959
4960```yuescript
4961d, e, f = 3, 2, 1
4962export d, e, f
4963
4964export if this
4965 123
4966else
4967 456
4968
4969export with tmp
4970 j = 2000
4971```
4972
4973<YueDisplay>
4974
4975```yue
4976d, e, f = 3, 2, 1
4977export d, e, f
4978
4979export if this
4980 123
4981else
4982 456
4983
4984export with tmp
4985 j = 2000
4986```
4987
4988</YueDisplay>
4989
4990### Default-Export
4991
4992Mit dem Schlüsselwort **default** in einer `export`-Anweisung wird die exportierte Tabelle durch ein beliebiges Objekt ersetzt.
4993
4994```yuescript
4995export default ->
4996 print "hallo"
4997 123
4998```
4999
5000<YueDisplay>
5001
5002```yue
5003export default ->
5004 print "hallo"
5005 123
5006```
5007
5008</YueDisplay>
5009
5010# Lizenz: MIT
5011
5012Hinweis: Die MIT-Lizenz ist unten im englischen Originaltext wiedergegeben.
5013
5014Urheberrecht (c) 2017-2026 Li Jin <dragon-fly@qq.com>
5015
5016Hiermit wird unentgeltlich jeder Person, die eine Kopie dieser Software und der zugehörigen Dokumentationsdateien (die "Software") erhält, die Erlaubnis erteilt, uneingeschränkt mit der Software zu verfahren, einschließlich und ohne Beschränkung der Rechte, die Software zu benutzen, zu kopieren, zu verändern, zusammenzuführen, zu veröffentlichen, zu verbreiten, zu unterlizenzieren und/oder zu verkaufen, sowie Personen, denen die Software zur Verfügung gestellt wird, dies ebenfalls zu gestatten, unter den folgenden Bedingungen:
5017
5018Der obige Urheberrechtshinweis und dieser Genehmigungshinweis müssen in allen Kopien oder wesentlichen Teilen der Software enthalten sein.
5019
5020DIE SOFTWARE WIRD OHNE JEGLICHE AUSDRÜCKLICHE ODER STILLSCHWEIGENDE GARANTIE ZUR VERFÜGUNG GESTELLT, EINSCHLIESSLICH DER GARANTIEN DER MARKTGÄNGIGKEIT, DER EIGNUNG FÜR EINEN BESTIMMTEN ZWECK UND DER NICHTVERLETZUNG. IN KEINEM FALL SIND DIE AUTOREN ODER URHEBERRECHTSINHABER FÜR ANSPRÜCHE, SCHÄDEN ODER SONSTIGE HAFTUNGEN VERANTWORTLICH, SEI ES AUS EINEM VERTRAG, EINER UNERLAUBTEN HANDLUNG ODER ANDERWEITIG, DIE SICH AUS DER SOFTWARE ODER DER BENUTZUNG DER SOFTWARE ODER ANDEREN GESCHÄFTEN MIT DER SOFTWARE ERGEBEN ODER DAMIT IN ZUSAMMENHANG STEHEN.
5021
5022# Die YueScript-Bibliothek
5023
5024Zugriff in Lua über `local yue = require("yue")`.
5025
5026## yue
5027
5028**Beschreibung:**
5029
5030Die YueScript-Sprachbibliothek.
5031
5032### version
5033
5034**Typ:** Feld.
5035
5036**Beschreibung:**
5037
5038Die YueScript-Version.
5039
5040**Signatur:**
5041
5042```lua
5043version: string
5044```
5045
5046### dirsep
5047
5048**Typ:** Feld.
5049
5050**Beschreibung:**
5051
5052Der Dateitrennzeichen-String der aktuellen Plattform.
5053
5054**Signatur:**
5055
5056```lua
5057dirsep: string
5058```
5059
5060### yue_compiled
5061
5062**Typ:** Feld.
5063
5064**Beschreibung:**
5065
5066Der Cache für kompilierten Modulcode.
5067
5068**Signatur:**
5069
5070```lua
5071yue_compiled: {string: string}
5072```
5073
5074### to_lua
5075
5076**Typ:** Funktion.
5077
5078**Beschreibung:**
5079
5080Die YueScript-Compilerfunktion. Sie kompiliert YueScript-Code zu Lua-Code.
5081
5082**Signatur:**
5083
5084```lua
5085to_lua: function(code: string, config?: Config):
5086 --[[codes]] string | nil,
5087 --[[error]] string | nil,
5088 --[[globals]] {{string, integer, integer}} | nil
5089```
5090
5091**Parameter:**
5092
5093| Parameter | Typ | Beschreibung |
5094| --------- | ------ | --------------------------------- |
5095| code | string | Der YueScript-Code. |
5096| config | Config | [Optional] Die Compiler-Optionen. |
5097
5098**Rückgabe:**
5099
5100| Rückgabetyp | Beschreibung |
5101| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
5102| string \| nil | Der kompilierte Lua-Code oder `nil`, falls die Kompilierung fehlgeschlagen ist. |
5103| string \| nil | Die Fehlermeldung oder `nil`, falls die Kompilierung erfolgreich war. |
5104| {{string, integer, integer}} \| nil | Die globalen Variablen im Code (mit Name, Zeile und Spalte) oder `nil`, wenn die Compiler-Option `lint_global` false ist. |
5105
5106### file_exist
5107
5108**Typ:** Funktion.
5109
5110**Beschreibung:**
5111
5112Prüft, ob eine Quelldatei existiert. Kann überschrieben werden, um das Verhalten anzupassen.
5113
5114**Signatur:**
5115
5116```lua
5117file_exist: function(filename: string): boolean
5118```
5119
5120**Parameter:**
5121
5122| Parameter | Typ | Beschreibung |
5123| --------- | ------ | -------------- |
5124| filename | string | Der Dateiname. |
5125
5126**Rückgabe:**
5127
5128| Rückgabetyp | Beschreibung |
5129| ----------- | ----------------------- |
5130| boolean | Ob die Datei existiert. |
5131
5132### read_file
5133
5134**Typ:** Funktion.
5135
5136**Beschreibung:**
5137
5138Liest eine Quelldatei. Kann überschrieben werden, um das Verhalten anzupassen.
5139
5140**Signatur:**
5141
5142```lua
5143read_file: function(filename: string): string
5144```
5145
5146**Parameter:**
5147
5148| Parameter | Typ | Beschreibung |
5149| --------- | ------ | -------------- |
5150| filename | string | Der Dateiname. |
5151
5152**Rückgabe:**
5153
5154| Rückgabetyp | Beschreibung |
5155| ----------- | ---------------- |
5156| string | Der Dateiinhalt. |
5157
5158### insert_loader
5159
5160**Typ:** Funktion.
5161
5162**Beschreibung:**
5163
5164Fügt den YueScript-Loader in die Package-Loader (Searcher) ein.
5165
5166**Signatur:**
5167
5168```lua
5169insert_loader: function(pos?: integer): boolean
5170```
5171
5172**Parameter:**
5173
5174| Parameter | Typ | Beschreibung |
5175| --------- | ------- | ---------------------------------------------------------------------- |
5176| pos | integer | [Optional] Position, an der der Loader eingefügt wird. Standard ist 3. |
5177
5178**Rückgabe:**
5179
5180| Rückgabetyp | Beschreibung |
5181| ----------- | ------------------------------------------------------------------------------------ |
5182| boolean | Ob der Loader erfolgreich eingefügt wurde. Scheitert, wenn er bereits eingefügt ist. |
5183
5184### remove_loader
5185
5186**Typ:** Funktion.
5187
5188**Beschreibung:**
5189
5190Entfernt den YueScript-Loader aus den Package-Loadern (Searchern).
5191
5192**Signatur:**
5193
5194```lua
5195remove_loader: function(): boolean
5196```
5197
5198**Rückgabe:**
5199
5200| Rückgabetyp | Beschreibung |
5201| ----------- | --------------------------------------------------------------------------------- |
5202| boolean | Ob der Loader erfolgreich entfernt wurde. Scheitert, wenn er nicht eingefügt ist. |
5203
5204### loadstring
5205
5206**Typ:** Funktion.
5207
5208**Beschreibung:**
5209
5210Lädt YueScript-Code aus einem String in eine Funktion.
5211
5212**Signatur:**
5213
5214```lua
5215loadstring: function(input: string, chunkname: string, env: table, config?: Config):
5216 --[[loaded function]] nil | function(...: any): (any...),
5217 --[[error]] string | nil
5218```
5219
5220**Parameter:**
5221
5222| Parameter | Typ | Beschreibung |
5223| --------- | ------ | --------------------------------- |
5224| input | string | Der YueScript-Code. |
5225| chunkname | string | Der Name des Code-Chunks. |
5226| env | table | Die Environment-Tabelle. |
5227| config | Config | [Optional] Die Compiler-Optionen. |
5228
5229**Rückgabe:**
5230
5231| Rückgabetyp | Beschreibung |
5232| --------------- | --------------------------------------------------------------------- |
5233| function \| nil | Die geladene Funktion oder `nil`, falls das Laden fehlgeschlagen ist. |
5234| string \| nil | Die Fehlermeldung oder `nil`, falls das Laden erfolgreich war. |
5235
5236### loadstring
5237
5238**Typ:** Funktion.
5239
5240**Beschreibung:**
5241
5242Lädt YueScript-Code aus einem String in eine Funktion.
5243
5244**Signatur:**
5245
5246```lua
5247loadstring: function(input: string, chunkname: string, config?: Config):
5248 --[[loaded function]] nil | function(...: any): (any...),
5249 --[[error]] string | nil
5250```
5251
5252**Parameter:**
5253
5254| Parameter | Typ | Beschreibung |
5255| --------- | ------ | --------------------------------- |
5256| input | string | Der YueScript-Code. |
5257| chunkname | string | Der Name des Code-Chunks. |
5258| config | Config | [Optional] Die Compiler-Optionen. |
5259
5260**Rückgabe:**
5261
5262| Rückgabetyp | Beschreibung |
5263| --------------- | --------------------------------------------------------------------- |
5264| function \| nil | Die geladene Funktion oder `nil`, falls das Laden fehlgeschlagen ist. |
5265| string \| nil | Die Fehlermeldung oder `nil`, falls das Laden erfolgreich war. |
5266
5267### loadstring
5268
5269**Typ:** Funktion.
5270
5271**Beschreibung:**
5272
5273Lädt YueScript-Code aus einem String in eine Funktion.
5274
5275**Signatur:**
5276
5277```lua
5278loadstring: function(input: string, config?: Config):
5279 --[[loaded function]] nil | function(...: any): (any...),
5280 --[[error]] string | nil
5281```
5282
5283**Parameter:**
5284
5285| Parameter | Typ | Beschreibung |
5286| --------- | ------ | --------------------------------- |
5287| input | string | Der YueScript-Code. |
5288| config | Config | [Optional] Die Compiler-Optionen. |
5289
5290**Rückgabe:**
5291
5292| Rückgabetyp | Beschreibung |
5293| --------------- | --------------------------------------------------------------------- |
5294| function \| nil | Die geladene Funktion oder `nil`, falls das Laden fehlgeschlagen ist. |
5295| string \| nil | Die Fehlermeldung oder `nil`, falls das Laden erfolgreich war. |
5296
5297### loadfile
5298
5299**Typ:** Funktion.
5300
5301**Beschreibung:**
5302
5303Lädt YueScript-Code aus einer Datei in eine Funktion.
5304
5305**Signatur:**
5306
5307```lua
5308loadfile: function(filename: string, env: table, config?: Config):
5309 nil | function(...: any): (any...),
5310 string | nil
5311```
5312
5313**Parameter:**
5314
5315| Parameter | Typ | Beschreibung |
5316| --------- | ------ | --------------------------------- |
5317| filename | string | Der Dateiname. |
5318| env | table | Die Environment-Tabelle. |
5319| config | Config | [Optional] Die Compiler-Optionen. |
5320
5321**Rückgabe:**
5322
5323| Rückgabetyp | Beschreibung |
5324| --------------- | --------------------------------------------------------------------- |
5325| function \| nil | Die geladene Funktion oder `nil`, falls das Laden fehlgeschlagen ist. |
5326| string \| nil | Die Fehlermeldung oder `nil`, falls das Laden erfolgreich war. |
5327
5328### loadfile
5329
5330**Typ:** Funktion.
5331
5332**Beschreibung:**
5333
5334Lädt YueScript-Code aus einer Datei in eine Funktion.
5335
5336**Signatur:**
5337
5338```lua
5339loadfile: function(filename: string, config?: Config):
5340 nil | function(...: any): (any...),
5341 string | nil
5342```
5343
5344**Parameter:**
5345
5346| Parameter | Typ | Beschreibung |
5347| --------- | ------ | --------------------------------- |
5348| filename | string | Der Dateiname. |
5349| config | Config | [Optional] Die Compiler-Optionen. |
5350
5351**Rückgabe:**
5352
5353| Rückgabetyp | Beschreibung |
5354| --------------- | --------------------------------------------------------------------- |
5355| function \| nil | Die geladene Funktion oder `nil`, falls das Laden fehlgeschlagen ist. |
5356| string \| nil | Die Fehlermeldung oder `nil`, falls das Laden erfolgreich war. |
5357
5358### dofile
5359
5360**Typ:** Funktion.
5361
5362**Beschreibung:**
5363
5364Lädt YueScript-Code aus einer Datei in eine Funktion und führt sie aus.
5365
5366**Signatur:**
5367
5368```lua
5369dofile: function(filename: string, env: table, config?: Config): any...
5370```
5371
5372**Parameter:**
5373
5374| Parameter | Typ | Beschreibung |
5375| --------- | ------ | --------------------------------- |
5376| filename | string | Der Dateiname. |
5377| env | table | Die Environment-Tabelle. |
5378| config | Config | [Optional] Die Compiler-Optionen. |
5379
5380**Rückgabe:**
5381
5382| Rückgabetyp | Beschreibung |
5383| ----------- | ----------------------------------------- |
5384| any... | Die Rückgabewerte der geladenen Funktion. |
5385
5386### dofile
5387
5388**Typ:** Funktion.
5389
5390**Beschreibung:**
5391
5392Lädt YueScript-Code aus einer Datei in eine Funktion und führt sie aus.
5393
5394**Signatur:**
5395
5396```lua
5397dofile: function(filename: string, config?: Config): any...
5398```
5399
5400**Parameter:**
5401
5402| Parameter | Typ | Beschreibung |
5403| --------- | ------ | --------------------------------- |
5404| filename | string | Der Dateiname. |
5405| config | Config | [Optional] Die Compiler-Optionen. |
5406
5407**Rückgabe:**
5408
5409| Rückgabetyp | Beschreibung |
5410| ----------- | ----------------------------------------- |
5411| any... | Die Rückgabewerte der geladenen Funktion. |
5412
5413### find_modulepath
5414
5415**Typ:** Funktion.
5416
5417**Beschreibung:**
5418
5419Löst den YueScript-Modulnamen in einen Dateipfad auf.
5420
5421**Signatur:**
5422
5423```lua
5424find_modulepath: function(name: string): string
5425```
5426
5427**Parameter:**
5428
5429| Parameter | Typ | Beschreibung |
5430| --------- | ------ | -------------- |
5431| name | string | Der Modulname. |
5432
5433**Rückgabe:**
5434
5435| Rückgabetyp | Beschreibung |
5436| ----------- | -------------- |
5437| string | Der Dateipfad. |
5438
5439### pcall
5440
5441**Typ:** Funktion.
5442
5443**Beschreibung:**
5444
5445Ruft eine Funktion im geschützten Modus auf.
5446Fängt Fehler ab und gibt einen Statuscode sowie Ergebnisse oder ein Fehlerobjekt zurück.
5447Schreibt die Fehlerzeilennummer bei Fehlern auf die ursprüngliche Zeilennummer im YueScript-Code um.
5448
5449**Signatur:**
5450
5451```lua
5452pcall: function(f: function, ...: any): boolean, any...
5453```
5454
5455**Parameter:**
5456
5457| Parameter | Typ | Beschreibung |
5458| --------- | -------- | --------------------------- |
5459| f | function | Die aufzurufende Funktion. |
5460| ... | any | Argumente für die Funktion. |
5461
5462**Rückgabe:**
5463
5464| Rückgabetyp | Beschreibung |
5465| ------------ | ---------------------------------------------------- |
5466| boolean, ... | Statuscode und Funktionsresultate oder Fehlerobjekt. |
5467
5468### require
5469
5470**Typ:** Funktion.
5471
5472**Beschreibung:**
5473
5474Lädt ein Modul (Lua oder YueScript).
5475Schreibt die Fehlerzeilennummer auf die ursprüngliche Zeilennummer im YueScript-Code um, wenn das Modul ein YueScript-Modul ist und das Laden fehlschlägt.
5476
5477**Signatur:**
5478
5479```lua
5480require: function(name: string): any...
5481```
5482
5483**Parameter:**
5484
5485| Parameter | Typ | Beschreibung |
5486| --------- | ------ | -------------------------------- |
5487| modname | string | Der Name des zu ladenden Moduls. |
5488
5489**Rückgabe:**
5490
5491| Rückgabetyp | Beschreibung |
5492| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
5493| any | Der Wert in `package.loaded[modname]`, falls das Modul bereits geladen ist. Andernfalls wird ein Loader gesucht und der finale Wert von `package.loaded[modname]` sowie Loader-Daten als zweites Ergebnis zurückgegeben. |
5494
5495### p
5496
5497**Typ:** Funktion.
5498
5499**Beschreibung:**
5500
5501Inspiziert die Struktur der übergebenen Werte und gibt String-Repräsentationen aus.
5502
5503**Signatur:**
5504
5505```lua
5506p: function(...: any)
5507```
5508
5509**Parameter:**
5510
5511| Parameter | Typ | Beschreibung |
5512| --------- | --- | ---------------------------- |
5513| ... | any | Die zu inspizierenden Werte. |
5514
5515### options
5516
5517**Typ:** Feld.
5518
5519**Beschreibung:**
5520
5521Die aktuellen Compiler-Optionen.
5522
5523**Signatur:**
5524
5525```lua
5526options: Config.Options
5527```
5528
5529### traceback
5530
5531**Typ:** Funktion.
5532
5533**Beschreibung:**
5534
5535Die Traceback-Funktion, die Stacktrace-Zeilennummern auf die ursprünglichen Zeilennummern im YueScript-Code umschreibt.
5536
5537**Signatur:**
5538
5539```lua
5540traceback: function(message: string): string
5541```
5542
5543**Parameter:**
5544
5545| Parameter | Typ | Beschreibung |
5546| --------- | ------ | ------------------------ |
5547| message | string | Die Traceback-Nachricht. |
5548
5549**Rückgabe:**
5550
5551| Rückgabetyp | Beschreibung |
5552| ----------- | --------------------------------------- |
5553| string | Die umgeschriebene Traceback-Nachricht. |
5554
5555### is_ast
5556
5557**Typ:** Funktion.
5558
5559**Beschreibung:**
5560
5561Prüft, ob der Code dem angegebenen AST entspricht.
5562
5563**Signatur:**
5564
5565```lua
5566is_ast: function(astName: string, code: string): boolean
5567```
5568
5569**Parameter:**
5570
5571| Parameter | Typ | Beschreibung |
5572| --------- | ------ | ------------- |
5573| astName | string | Der AST-Name. |
5574| code | string | Der Code. |
5575
5576**Rückgabe:**
5577
5578| Rückgabetyp | Beschreibung |
5579| ----------- | ------------------------------- |
5580| boolean | Ob der Code dem AST entspricht. |
5581
5582### AST
5583
5584**Typ:** Feld.
5585
5586**Beschreibung:**
5587
5588Die AST-Typdefinition mit Name, Zeile, Spalte und Unterknoten.
5589
5590**Signatur:**
5591
5592```lua
5593type AST = {string, integer, integer, any}
5594```
5595
5596### to_ast
5597
5598**Typ:** Funktion.
5599
5600**Beschreibung:**
5601
5602Konvertiert Code in AST.
5603
5604**Signatur:**
5605
5606```lua
5607to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
5608 --[[AST]] AST | nil,
5609 --[[error]] nil | string
5610```
5611
5612**Parameter:**
5613
5614| Parameter | Typ | Beschreibung |
5615| -------------- | ------- | -------------------------------------------------------------------------------------------- |
5616| code | string | Der Code. |
5617| flattenLevel | integer | [Optional] Der Flatten-Level. Höher bedeutet mehr Flattening. Standard ist 0. Maximum ist 2. |
5618| astName | string | [Optional] Der AST-Name. Standard ist "File". |
5619| reserveComment | boolean | [Optional] Ob die ursprünglichen Kommentare beibehalten werden. Standard ist false. |
5620
5621**Rückgabe:**
5622
5623| Rückgabetyp | Beschreibung |
5624| ------------- | ---------------------------------------------------------------------- |
5625| AST \| nil | Der AST oder `nil`, falls die Konvertierung fehlgeschlagen ist. |
5626| string \| nil | Die Fehlermeldung oder `nil`, falls die Konvertierung erfolgreich war. |
5627
5628### format
5629
5630**Typ:** Funktion.
5631
5632**Beschreibung:**
5633
5634Formatiert den YueScript-Code.
5635
5636**Signatur:**
5637
5638```lua
5639format: function(code: string, tabSize?: number, reserveComment?: boolean): string
5640```
5641
5642**Parameter:**
5643
5644| Parameter | Typ | Beschreibung |
5645| -------------- | ------- | ---------------------------------------------------------------------------------- |
5646| code | string | Der Code. |
5647| tabSize | integer | [Optional] Die Tab-Größe. Standard ist 4. |
5648| reserveComment | boolean | [Optional] Ob die ursprünglichen Kommentare beibehalten werden. Standard ist true. |
5649
5650**Rückgabe:**
5651
5652| Rückgabetyp | Beschreibung |
5653| ----------- | --------------------- |
5654| string | Der formatierte Code. |
5655
5656### \_\_call
5657
5658**Typ:** Metamethod.
5659
5660**Beschreibung:**
5661
5662Required das YueScript-Modul.
5663Schreibt die Fehlerzeilennummer bei Ladefehlern auf die ursprüngliche Zeilennummer im YueScript-Code um.
5664
5665**Signatur:**
5666
5667```lua
5668metamethod __call: function(self: yue, module: string): any...
5669```
5670
5671**Parameter:**
5672
5673| Parameter | Typ | Beschreibung |
5674| --------- | ------ | -------------- |
5675| module | string | Der Modulname. |
5676
5677**Rückgabe:**
5678
5679| Rückgabetyp | Beschreibung |
5680| ----------- | -------------- |
5681| any | Der Modulwert. |
5682
5683## Config
5684
5685**Beschreibung:**
5686
5687Die Compiler-Optionen.
5688
5689### lint_global
5690
5691**Typ:** Feld.
5692
5693**Beschreibung:**
5694
5695Ob der Compiler die globalen Variablen im Code sammeln soll.
5696
5697**Signatur:**
5698
5699```lua
5700lint_global: boolean
5701```
5702
5703### implicit_return_root
5704
5705**Typ:** Feld.
5706
5707**Beschreibung:**
5708
5709Ob der Compiler für den Root-Codeblock ein implizites Return verwenden soll.
5710
5711**Signatur:**
5712
5713```lua
5714implicit_return_root: boolean
5715```
5716
5717### reserve_line_number
5718
5719**Typ:** Feld.
5720
5721**Beschreibung:**
5722
5723Ob der Compiler die ursprüngliche Zeilennummer im kompilierten Code beibehalten soll.
5724
5725**Signatur:**
5726
5727```lua
5728reserve_line_number: boolean
5729```
5730
5731### reserve_comment
5732
5733**Typ:** Feld.
5734
5735**Beschreibung:**
5736
5737Ob der Compiler die ursprünglichen Kommentare im kompilierten Code beibehalten soll.
5738
5739**Signatur:**
5740
5741```lua
5742reserve_comment: boolean
5743```
5744
5745### space_over_tab
5746
5747**Typ:** Feld.
5748
5749**Beschreibung:**
5750
5751Ob der Compiler statt Tabzeichen Leerzeichen verwenden soll.
5752
5753**Signatur:**
5754
5755```lua
5756space_over_tab: boolean
5757```
5758
5759### same_module
5760
5761**Typ:** Feld.
5762
5763**Beschreibung:**
5764
5765Ob der Compiler den zu kompilierenden Code als dasselbe aktuell kompilierte Modul behandeln soll. Nur für internen Gebrauch.
5766
5767**Signatur:**
5768
5769```lua
5770same_module: boolean
5771```
5772
5773### line_offset
5774
5775**Typ:** Feld.
5776
5777**Beschreibung:**
5778
5779Ob die Compiler-Fehlermeldung einen Zeilennummern-Offset enthalten soll. Nur für internen Gebrauch.
5780
5781**Signatur:**
5782
5783```lua
5784line_offset: integer
5785```
5786
5787### yue.Config.LuaTarget
5788
5789**Typ:** Enumeration.
5790
5791**Beschreibung:**
5792
5793Die Ziel-Lua-Version.
5794
5795**Signatur:**
5796
5797```lua
5798enum LuaTarget
5799 "5.1"
5800 "5.2"
5801 "5.3"
5802 "5.4"
5803 "5.5"
5804end
5805```
5806
5807### options
5808
5809**Typ:** Feld.
5810
5811**Beschreibung:**
5812
5813Zusätzliche Optionen für die Kompilierung.
5814
5815**Signatur:**
5816
5817```lua
5818options: Options
5819```
5820
5821## Options
5822
5823**Beschreibung:**
5824
5825Zusätzliche Compiler-Optionen.
5826
5827### target
5828
5829**Typ:** Feld.
5830
5831**Beschreibung:**
5832
5833Die Ziel-Lua-Version für die Kompilierung.
5834
5835**Signatur:**
5836
5837```lua
5838target: LuaTarget
5839```
5840
5841### path
5842
5843**Typ:** Feld.
5844
5845**Beschreibung:**
5846
5847Zusätzlicher Modul-Suchpfad.
5848
5849**Signatur:**
5850
5851```lua
5852path: string
5853```
5854
5855### dump_locals
5856
5857**Typ:** Feld.
5858
5859**Beschreibung:**
5860
5861Ob lokale Variablen in Traceback-Fehlermeldungen ausgegeben werden sollen. Standard ist false.
5862
5863**Signatur:**
5864
5865```lua
5866dump_locals: boolean
5867```
5868
5869### simplified
5870
5871**Typ:** Feld.
5872
5873**Beschreibung:**
5874
5875Ob Fehlermeldungen vereinfacht werden sollen. Standard ist true.
5876
5877**Signatur:**
5878
5879```lua
5880simplified: boolean
5881```
diff --git a/doc/yue-en.md b/doc/yue-en.md
new file mode 100644
index 0000000..a16060c
--- /dev/null
+++ b/doc/yue-en.md
@@ -0,0 +1,5895 @@
1---
2title: Reference
3---
4
5# YueScript Documentation
6
7<img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em; padding-bottom: 2em;"/>
8
9Welcome to the <b>YueScript</b> official documentation!<br/>
10Here you can find the language features, usage, reference examples and resources.<br/>
11Please select a chapter from the sidebar to start learning about YueScript.
12
13# Do
14
15When used as a statement, do works just like it does in Lua.
16
17```yuescript
18do
19 var = "hello"
20 print var
21print var -- nil here
22```
23
24<YueDisplay>
25
26```yue
27do
28 var = "hello"
29 print var
30print var -- nil here
31```
32
33</YueDisplay>
34
35YueScript's **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body.
36
37`do` expressions also support using `break` to interrupt control flow and return multiple values early:
38
39```yuescript
40status, value = do
41 n = 12
42 if n > 10
43 break "large", n
44 break "small", n
45```
46
47<YueDisplay>
48
49```yue
50status, value = do
51 n = 12
52 if n > 10
53 break "large", n
54 break "small", n
55```
56
57</YueDisplay>
58
59```yuescript
60counter = do
61 i = 0
62 ->
63 i += 1
64 i
65
66print counter!
67print counter!
68```
69
70<YueDisplay>
71
72```yue
73counter = do
74 i = 0
75 ->
76 i += 1
77 i
78
79print counter!
80print counter!
81```
82
83</YueDisplay>
84
85```yuescript
86tbl = {
87 key: do
88 print "assigning key!"
89 1234
90}
91```
92
93<YueDisplay>
94
95```yue
96tbl = {
97 key: do
98 print "assigning key!"
99 1234
100}
101```
102
103</YueDisplay>
104
105# Line Decorators
106
107For convenience, the for loop and if statement can be applied to single statements at the end of the line:
108
109```yuescript
110print "hello world" if name == "Rob"
111```
112
113<YueDisplay>
114
115```yue
116print "hello world" if name == "Rob"
117```
118
119</YueDisplay>
120
121And with basic loops:
122
123```yuescript
124print "item: ", item for item in *items
125```
126
127<YueDisplay>
128
129```yue
130print "item: ", item for item in *items
131```
132
133</YueDisplay>
134
135And with while loops:
136
137```yuescript
138game\update! while game\isRunning!
139
140reader\parse_line! until reader\eof!
141```
142
143<YueDisplay>
144
145```yue
146game\update! while game\isRunning!
147
148reader\parse_line! until reader\eof!
149```
150
151</YueDisplay>
152
153# Macro
154
155## Common Usage
156
157Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation.
158
159```yuescript
160macro PI2 = -> math.pi * 2
161area = $PI2 * 5
162
163macro HELLO = -> "'hello world'"
164print $HELLO
165
166macro config = (debugging) ->
167 global debugMode = debugging == "true"
168 ""
169
170macro asserts = (cond) ->
171 debugMode and "assert #{cond}" or ""
172
173macro assert = (cond) ->
174 debugMode and "assert #{cond}" or "#{cond}"
175
176$config true
177$asserts item ~= nil
178
179$config false
180value = $assert item
181
182-- the passed expressions are treated as strings
183macro and = (...) -> "#{ table.concat {...}, ' and ' }"
184if $and f1!, f2!, f3!
185 print "OK"
186```
187
188<YueDisplay>
189
190```yue
191macro PI2 = -> math.pi * 2
192area = $PI2 * 5
193
194macro HELLO = -> "'hello world'"
195print $HELLO
196
197macro config = (debugging) ->
198 global debugMode = debugging == "true"
199 ""
200
201macro asserts = (cond) ->
202 debugMode and "assert #{cond}" or ""
203
204macro assert = (cond) ->
205 debugMode and "assert #{cond}" or "#{cond}"
206
207$config true
208$asserts item ~= nil
209
210$config false
211value = $assert item
212
213-- the passed expressions are treated as strings
214macro and = (...) -> "#{ table.concat {...}, ' and ' }"
215if $and f1!, f2!, f3!
216 print "OK"
217```
218
219</YueDisplay>
220
221## Insert Raw Codes
222
223A macro function can either return a YueScript string or a config table containing Lua codes.
224
225```yuescript
226macro yueFunc = (var) -> "local #{var} = ->"
227$yueFunc funcA
228funcA = -> "fail to assign to the Yue macro defined variable"
229
230macro luaFunc = (var) -> {
231 code: "local function #{var}() end"
232 type: "lua"
233}
234$luaFunc funcB
235funcB = -> "fail to assign to the Lua macro defined variable"
236
237macro lua = (code) -> {
238 :code
239 type: "lua"
240}
241
242-- the raw string leading and ending symbols are auto trimed
243$lua[==[
244-- raw Lua codes insertion
245if cond then
246 print("output")
247end
248]==]
249```
250
251<YueDisplay>
252
253```yue
254macro yueFunc = (var) -> "local #{var} = ->"
255$yueFunc funcA
256funcA = -> "fail to assign to the Yue macro defined variable"
257
258macro luaFunc = (var) -> {
259 code: "local function #{var}() end"
260 type: "lua"
261}
262$luaFunc funcB
263funcB = -> "fail to assign to the Lua macro defined variable"
264
265macro lua = (code) -> {
266 :code
267 type: "lua"
268}
269
270-- the raw string leading and ending symbols are auto trimed
271$lua[==[
272-- raw Lua codes insertion
273if cond then
274 print("output")
275end
276]==]
277```
278
279</YueDisplay>
280
281## Export Macro
282
283Macro functions can be exported from a module and get imported in another module. You have to put export macro functions in a single file to be used, and only macro definition, macro importing and macro expansion in place can be put into the macro exporting module.
284
285```yuescript
286-- file: utils.yue
287export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
288export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
289export macro foreach = (items, action) -> "for _ in *#{items}
290 #{action}"
291
292-- file main.yue
293import "utils" as {
294 $, -- symbol to import all macros
295 $foreach: $each -- rename macro $foreach to $each
296}
297[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
298```
299
300<YueDisplay>
301
302```yue
303-- file: utils.yue
304export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
305export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
306export macro foreach = (items, action) -> "for _ in *#{items}
307 #{action}"
308
309-- file main.yue
310-- import function is not available in browser, try it in a real environment
311--[[
312import "utils" as {
313 $, -- symbol to import all macros
314 $foreach: $each -- rename macro $foreach to $each
315}
316[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
317]]
318```
319
320</YueDisplay>
321
322## Builtin Macro
323
324There are some builtin macros but you can override them by declaring macros with the same names.
325
326```yuescript
327print $FILE -- get string of current module name
328print $LINE -- get number 2
329```
330
331<YueDisplay>
332
333```yue
334print $FILE -- get string of current module name
335print $LINE -- get number 2
336```
337
338</YueDisplay>
339
340## Generating Macros with Macros
341
342In YueScript, macro functions allow you to generate code at compile time. By nesting macro functions, you can create more complex generation patterns. This feature enables you to define a macro function that generates another macro function, allowing for more dynamic code generation.
343
344```yuescript
345macro Enum = (...) ->
346 items = {...}
347 itemSet = {item, true for item in *items}
348 (item) ->
349 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
350 "\"#{item}\""
351
352macro BodyType = $Enum(
353 Static
354 Dynamic
355 Kinematic
356)
357
358print "Valid enum type:", $BodyType Static
359-- print "Compilation error with enum type:", $BodyType Unknown
360```
361
362<YueDisplay>
363
364```yue
365macro Enum = (...) ->
366 items = {...}
367 itemSet = {item, true for item in *items}
368 (item) ->
369 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
370 "\"#{item}\""
371
372macro BodyType = $Enum(
373 Static
374 Dynamic
375 Kinematic
376)
377
378print "Valid enum type:", $BodyType Static
379-- print "Compilation error with enum type:", $BodyType Unknown
380```
381
382</YueDisplay>
383
384## Argument Validation
385
386You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time.
387
388```yuescript
389macro printNumAndStr = (num `Num, str `String) -> |
390 print(
391 #{num}
392 #{str}
393 )
394
395$printNumAndStr 123, "hello"
396```
397
398<YueDisplay>
399
400```yue
401macro printNumAndStr = (num `Num, str `String) -> |
402 print(
403 #{num}
404 #{str}
405 )
406
407$printNumAndStr 123, "hello"
408```
409
410</YueDisplay>
411
412If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place.
413
414```yuescript
415macro printNumAndStr = (num, str) ->
416 error "expected Num as first argument" unless $is_ast Num, num
417 error "expected String as second argument" unless $is_ast String, str
418 "print(#{num}, #{str})"
419
420$printNumAndStr 123, "hello"
421```
422
423<YueDisplay>
424
425```yue
426macro printNumAndStr = (num, str) ->
427 error "expected Num as first argument" unless $is_ast Num, num
428 error "expected String as second argument" unless $is_ast String, str
429 "print(#{num}, #{str})"
430
431$printNumAndStr 123, "hello"
432```
433
434</YueDisplay>
435
436For more details about available AST nodes, please refer to the uppercased definitions in [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).
437
438# Try
439
440The syntax for Lua error handling in a common form.
441
442```yuescript
443try
444 func 1, 2, 3
445catch err
446 print yue.traceback err
447
448success, result = try
449 func 1, 2, 3
450catch err
451 yue.traceback err
452
453try func 1, 2, 3
454catch err
455 print yue.traceback err
456
457success, result = try func 1, 2, 3
458
459try
460 print "trying"
461 func 1, 2, 3
462
463-- working with if assignment pattern
464if success, result := try func 1, 2, 3
465catch err
466 print yue.traceback err
467 print result
468```
469
470<YueDisplay>
471
472```yue
473try
474 func 1, 2, 3
475catch err
476 print yue.traceback err
477
478success, result = try
479 func 1, 2, 3
480catch err
481 yue.traceback err
482
483try func 1, 2, 3
484catch err
485 print yue.traceback err
486
487success, result = try func 1, 2, 3
488
489try
490 print "trying"
491 func 1, 2, 3
492
493-- working with if assignment pattern
494if success, result := try func 1, 2, 3
495catch err
496 print yue.traceback err
497 print result
498```
499
500</YueDisplay>
501
502## Try?
503
504`try?` is a simplified use for error handling syntax that omit the boolean status from the `try` statement, and it will return the result from the try block when success, return nil instead of error object otherwise.
505
506```yuescript
507a, b, c = try? func!
508
509-- with nil coalescing operator
510a = (try? func!) ?? "default"
511
512-- as function argument
513f try? func!
514
515-- with catch block
516f try?
517 print 123
518 func!
519catch e
520 print e
521 e
522```
523
524<YueDisplay>
525
526```yue
527a, b, c = try? func!
528
529-- with nil coalescing operator
530a = (try? func!) ?? "default"
531
532-- as function argument
533f try? func!
534
535-- with catch block
536f try?
537 print 123
538 func!
539catch e
540 print e
541 e
542```
543
544</YueDisplay>
545
546# Table Literals
547
548Like in Lua, tables are delimited in curly braces.
549
550```yuescript
551some_values = [1, 2, 3, 4]
552```
553
554<YueDisplay>
555
556```yue
557some_values = [1, 2, 3, 4]
558```
559
560</YueDisplay>
561
562Unlike Lua, assigning a value to a key in a table is done with **:** (instead of **=**).
563
564```yuescript
565some_values = {
566 name: "Bill",
567 age: 200,
568 ["favorite food"]: "rice"
569}
570```
571
572<YueDisplay>
573
574```yue
575some_values = {
576 name: "Bill",
577 age: 200,
578 ["favorite food"]: "rice"
579}
580```
581
582</YueDisplay>
583
584The curly braces can be left off if a single table of key value pairs is being assigned.
585
586```yuescript
587profile =
588 height: "4 feet",
589 shoe_size: 13,
590 favorite_foods: ["ice cream", "donuts"]
591```
592
593<YueDisplay>
594
595```yue
596profile =
597 height: "4 feet",
598 shoe_size: 13,
599 favorite_foods: ["ice cream", "donuts"]
600```
601
602</YueDisplay>
603
604Newlines can be used to delimit values instead of a comma (or both):
605
606```yuescript
607values = {
608 1, 2, 3, 4
609 5, 6, 7, 8
610 name: "superman"
611 occupation: "crime fighting"
612}
613```
614
615<YueDisplay>
616
617```yue
618values = {
619 1, 2, 3, 4
620 5, 6, 7, 8
621 name: "superman"
622 occupation: "crime fighting"
623}
624```
625
626</YueDisplay>
627
628When creating a single line table literal, the curly braces can also be left off:
629
630```yuescript
631my_function dance: "Tango", partner: "none"
632
633y = type: "dog", legs: 4, tails: 1
634```
635
636<YueDisplay>
637
638```yue
639my_function dance: "Tango", partner: "none"
640
641y = type: "dog", legs: 4, tails: 1
642```
643
644</YueDisplay>
645
646The keys of a table literal can be language keywords without being escaped:
647
648```yuescript
649tbl = {
650 do: "something"
651 end: "hunger"
652}
653```
654
655<YueDisplay>
656
657```yue
658tbl = {
659 do: "something"
660 end: "hunger"
661}
662```
663
664</YueDisplay>
665
666If you are constructing a table out of variables and wish the keys to be the same as the variable names, then the **:** prefix operator can be used:
667
668```yuescript
669hair = "golden"
670height = 200
671person = { :hair, :height, shoe_size: 40 }
672
673print_table :hair, :height
674```
675
676<YueDisplay>
677
678```yue
679hair = "golden"
680height = 200
681person = { :hair, :height, shoe_size: 40 }
682
683print_table :hair, :height
684```
685
686</YueDisplay>
687
688If you want the key of a field in the table to to be result of an expression, then you can wrap it in **[ ]**, just like in Lua. You can also use a string literal directly as a key, leaving out the square brackets. This is useful if your key has any special characters.
689
690```yuescript
691t = {
692 [1 + 2]: "hello"
693 "hello world": true
694}
695```
696
697<YueDisplay>
698
699```yue
700t = {
701 [1 + 2]: "hello"
702 "hello world": true
703}
704```
705
706</YueDisplay>
707
708Lua tables have both an array part and a hash part, but sometimes you want to make a semantic distinction between array and hash usage when writing Lua tables. Then you can write Lua table with **[ ]** instead of **{ }** to represent an array table and writing any key value pair in a list table won't be allowed.
709
710```yuescript
711some_values = [1, 2, 3, 4]
712list_with_one_element = [1, ]
713```
714
715<YueDisplay>
716
717```yue
718some_values = [1, 2, 3, 4]
719list_with_one_element = [1, ]
720```
721
722</YueDisplay>
723
724# Comprehensions
725
726Comprehensions provide a convenient syntax for constructing a new table by iterating over some existing object and applying an expression to its values. There are two kinds of comprehensions: list comprehensions and table comprehensions. They both produce Lua tables; list comprehensions accumulate values into an array-like table, and table comprehensions let you set both the key and the value on each iteration.
727
728## List Comprehensions
729
730The following creates a copy of the items table but with all the values doubled.
731
732```yuescript
733items = [ 1, 2, 3, 4 ]
734doubled = [item * 2 for i, item in ipairs items]
735```
736
737<YueDisplay>
738
739```yue
740items = [ 1, 2, 3, 4 ]
741doubled = [item * 2 for i, item in ipairs items]
742```
743
744</YueDisplay>
745
746The items included in the new table can be restricted with a when clause:
747
748```yuescript
749slice = [item for i, item in ipairs items when i > 1 and i < 3]
750```
751
752<YueDisplay>
753
754```yue
755slice = [item for i, item in ipairs items when i > 1 and i < 3]
756```
757
758</YueDisplay>
759
760Because it is common to iterate over the values of a numerically indexed table, an **\*** operator is introduced. The doubled example can be rewritten as:
761
762```yuescript
763doubled = [item * 2 for item in *items]
764```
765
766<YueDisplay>
767
768```yue
769doubled = [item * 2 for item in *items]
770```
771
772</YueDisplay>
773
774In list comprehensions, you can also use the spread operator `...` to flatten nested lists, achieving a flat map effect:
775
776```yuescript
777data =
778 a: [1, 2, 3]
779 b: [4, 5, 6]
780
781flat = [...v for k,v in pairs data]
782-- flat is now [1, 2, 3, 4, 5, 6]
783```
784
785<YueDisplay>
786
787```yue
788data =
789 a: [1, 2, 3]
790 b: [4, 5, 6]
791
792flat = [...v for k,v in pairs data]
793-- flat is now [1, 2, 3, 4, 5, 6]
794```
795
796</YueDisplay>
797
798The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause.
799
800Using multiple for clauses is the same as using nested loops:
801
802```yuescript
803x_coords = [4, 5, 6, 7]
804y_coords = [9, 2, 3]
805
806points = [ [x, y] for x in *x_coords \
807for y in *y_coords]
808```
809
810<YueDisplay>
811
812```yue
813x_coords = [4, 5, 6, 7]
814y_coords = [9, 2, 3]
815
816points = [ [x, y] for x in *x_coords \
817for y in *y_coords]
818```
819
820</YueDisplay>
821
822Numeric for loops can also be used in comprehensions:
823
824```yuescript
825evens = [i for i = 1, 100 when i % 2 == 0]
826```
827
828<YueDisplay>
829
830```yue
831evens = [i for i = 1, 100 when i % 2 == 0]
832```
833
834</YueDisplay>
835
836## Table Comprehensions
837
838The syntax for table comprehensions is very similar, only differing by using **{** and **}** and taking two values from each iteration.
839
840This example makes a copy of the tablething:
841
842```yuescript
843thing = {
844 color: "red"
845 name: "fast"
846 width: 123
847}
848
849thing_copy = {k, v for k, v in pairs thing}
850```
851
852<YueDisplay>
853
854```yue
855thing = {
856 color: "red"
857 name: "fast"
858 width: 123
859}
860
861thing_copy = {k, v for k, v in pairs thing}
862```
863
864</YueDisplay>
865
866```yuescript
867no_color = {k, v for k, v in pairs thing when k != "color"}
868```
869
870<YueDisplay>
871
872```yue
873no_color = {k, v for k, v in pairs thing when k != "color"}
874```
875
876</YueDisplay>
877
878The **\*** operator is also supported. Here we create a square root look up table for a few numbers.
879
880```yuescript
881numbers = [1, 2, 3, 4]
882sqrts = {i, math.sqrt i for i in *numbers}
883```
884
885<YueDisplay>
886
887```yue
888numbers = [1, 2, 3, 4]
889sqrts = {i, math.sqrt i for i in *numbers}
890```
891
892</YueDisplay>
893
894The key-value tuple in a table comprehension can also come from a single expression, in which case the expression should return two values. The first is used as the key and the second is used as the value:
895
896In this example we convert an array of pairs to a table where the first item in the pair is the key and the second is the value.
897
898```yuescript
899tuples = [ ["hello", "world"], ["foo", "bar"]]
900tbl = {unpack tuple for tuple in *tuples}
901```
902
903<YueDisplay>
904
905```yue
906tuples = [ ["hello", "world"], ["foo", "bar"]]
907tbl = {unpack tuple for tuple in *tuples}
908```
909
910</YueDisplay>
911
912## Slicing
913
914A special syntax is provided to restrict the items that are iterated over when using the **\*** operator. This is equivalent to setting the iteration bounds and a step size in a for loop.
915
916Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive:
917
918```yuescript
919slice = [item for item in *items[1, 5]]
920```
921
922<YueDisplay>
923
924```yue
925slice = [item for item in *items[1, 5]]
926```
927
928</YueDisplay>
929
930Any of the slice arguments can be left off to use a sensible default. In this example, if the max index is left off it defaults to the length of the table. This will take everything but the first element:
931
932```yuescript
933slice = [item for item in *items[2,]]
934```
935
936<YueDisplay>
937
938```yue
939slice = [item for item in *items[2,]]
940```
941
942</YueDisplay>
943
944If the minimum bound is left out, it defaults to 1. Here we only provide a step size and leave the other bounds blank. This takes all odd indexed items: (1, 3, 5, …)
945
946```yuescript
947slice = [item for item in *items[,,2]]
948```
949
950<YueDisplay>
951
952```yue
953slice = [item for item in *items[,,2]]
954```
955
956</YueDisplay>
957
958Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table.
959
960```yuescript
961-- take the last 4 items
962slice = [item for item in *items[-4,-1]]
963```
964
965<YueDisplay>
966
967```yue
968-- take the last 4 items
969slice = [item for item in *items[-4,-1]]
970```
971
972</YueDisplay>
973
974The step size can also be negative, which means that the items are taken in reverse order.
975
976```yuescript
977reverse_slice = [item for item in *items[-1,1,-1]]
978```
979
980<YueDisplay>
981
982```yue
983reverse_slice = [item for item in *items[-1,1,-1]]
984```
985
986</YueDisplay>
987
988### Slicing Expression
989
990Slicing can also be used as an expression. This is useful for getting a sub-list of a table.
991
992```yuescript
993-- take the 2nd and 4th items as a new list
994sub_list = items[2, 4]
995
996-- take the last 4 items
997last_four_items = items[-4, -1]
998```
999
1000<YueDisplay>
1001
1002```yue
1003-- take the 2nd and 4th items as a new list
1004sub_list = items[2, 4]
1005
1006-- take the last 4 items
1007last_four_items = items[-4, -1]
1008```
1009
1010</YueDisplay>
1011
1012# Object Oriented Programming
1013
1014In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details.
1015
1016A simple class:
1017
1018```yuescript
1019class Inventory
1020 new: =>
1021 @items = {}
1022
1023 add_item: (name) =>
1024 if @items[name]
1025 @items[name] += 1
1026 else
1027 @items[name] = 1
1028```
1029
1030<YueDisplay>
1031
1032```yue
1033class Inventory
1034 new: =>
1035 @items = {}
1036
1037 add_item: (name) =>
1038 if @items[name]
1039 @items[name] += 1
1040 else
1041 @items[name] = 1
1042```
1043
1044</YueDisplay>
1045
1046A class is declared with a class statement followed by a table-like declaration where all of the methods and properties are listed.
1047
1048The new property is special in that it will become the constructor.
1049
1050Notice how all the methods in the class use the fat arrow function syntax. When calling methods on a instance, the instance itself is sent in as the first argument. The fat arrow handles the creation of a self argument.
1051
1052The @ prefix on a variable name is shorthand for self.. @items becomes self.items.
1053
1054Creating an instance of the class is done by calling the name of the class as a function.
1055
1056```yuescript
1057inv = Inventory!
1058inv\add_item "t-shirt"
1059inv\add_item "pants"
1060```
1061
1062<YueDisplay>
1063
1064```yue
1065inv = Inventory!
1066inv\add_item "t-shirt"
1067inv\add_item "pants"
1068```
1069
1070</YueDisplay>
1071
1072Because the instance of the class needs to be sent to the methods when they are called, the \ operator is used.
1073
1074All properties of a class are shared among the instances. This is fine for functions, but for other types of objects, undesired results may occur.
1075
1076Consider the example below, the clothes property is shared amongst all instances, so modifications to it in one instance will show up in another:
1077
1078```yuescript
1079class Person
1080 clothes: []
1081 give_item: (name) =>
1082 table.insert @clothes, name
1083
1084a = Person!
1085b = Person!
1086
1087a\give_item "pants"
1088b\give_item "shirt"
1089
1090-- will print both pants and shirt
1091print item for item in *a.clothes
1092```
1093
1094<YueDisplay>
1095
1096```yue
1097class Person
1098 clothes: []
1099 give_item: (name) =>
1100 table.insert @clothes, name
1101
1102a = Person!
1103b = Person!
1104
1105a\give_item "pants"
1106b\give_item "shirt"
1107
1108-- will print both pants and shirt
1109print item for item in *a.clothes
1110```
1111
1112</YueDisplay>
1113
1114The proper way to avoid this problem is to create the mutable state of the object in the constructor:
1115
1116```yuescript
1117class Person
1118 new: =>
1119 @clothes = []
1120```
1121
1122<YueDisplay>
1123
1124```yue
1125class Person
1126 new: =>
1127 @clothes = []
1128```
1129
1130</YueDisplay>
1131
1132## Inheritance
1133
1134The extends keyword can be used in a class declaration to inherit the properties and methods from another class.
1135
1136```yuescript
1137class BackPack extends Inventory
1138 size: 10
1139 add_item: (name) =>
1140 if #@items > size then error "backpack is full"
1141 super name
1142```
1143
1144<YueDisplay>
1145
1146```yue
1147class BackPack extends Inventory
1148 size: 10
1149 add_item: (name) =>
1150 if #@items > size then error "backpack is full"
1151 super name
1152```
1153
1154</YueDisplay>
1155
1156Here we extend our Inventory class, and limit the amount of items it can carry.
1157
1158In this example, we don't define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor.
1159
1160Whenever a class inherits from another, it sends a message to the parent class by calling the method \_\_inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class.
1161
1162```yuescript
1163class Shelf
1164 @__inherited: (child) =>
1165 print @__name, "was inherited by", child.__name
1166
1167-- will print: Shelf was inherited by Cupboard
1168class Cupboard extends Shelf
1169```
1170
1171<YueDisplay>
1172
1173```yue
1174class Shelf
1175 @__inherited: (child) =>
1176 print @__name, "was inherited by", child.__name
1177
1178-- will print: Shelf was inherited by Cupboard
1179class Cupboard extends Shelf
1180```
1181
1182</YueDisplay>
1183
1184## Super
1185
1186**super** is a special keyword that can be used in two different ways: It can be treated as an object, or it can be called like a function. It only has special functionality when inside a class.
1187
1188When called as a function, it will call the function of the same name in the parent class. The current self will automatically be passed as the first argument. (As seen in the inheritance example above)
1189
1190When super is used as a normal value, it is a reference to the parent class object.
1191
1192It can be accessed like any of object in order to retrieve values in the parent class that might have been shadowed by the child class.
1193
1194When the \ calling operator is used with super, self is inserted as the first argument instead of the value of super itself. When using . to retrieve a function, the raw function is returned.
1195
1196A few examples of using super in different ways:
1197
1198```yuescript
1199class MyClass extends ParentClass
1200 a_method: =>
1201 -- the following have the same effect:
1202 super "hello", "world"
1203 super\a_method "hello", "world"
1204 super.a_method self, "hello", "world"
1205
1206 -- super as a value is equal to the parent class:
1207 assert super == ParentClass
1208```
1209
1210<YueDisplay>
1211
1212```yue
1213class MyClass extends ParentClass
1214 a_method: =>
1215 -- the following have the same effect:
1216 super "hello", "world"
1217 super\a_method "hello", "world"
1218 super.a_method self, "hello", "world"
1219
1220 -- super as a value is equal to the parent class:
1221 assert super == ParentClass
1222```
1223
1224</YueDisplay>
1225
1226**super** can also be used on left side of a Function Stub. The only major difference is that instead of the resulting function being bound to the value of super, it is bound to self.
1227
1228## Types
1229
1230Every instance of a class carries its type with it. This is stored in the special \_\_class property. This property holds the class object. The class object is what we call to build a new instance. We can also index the class object to retrieve class methods and properties.
1231
1232```yuescript
1233b = BackPack!
1234assert b.__class == BackPack
1235
1236print BackPack.size -- prints 10
1237```
1238
1239<YueDisplay>
1240
1241```yue
1242b = BackPack!
1243assert b.__class == BackPack
1244
1245print BackPack.size -- prints 10
1246```
1247
1248</YueDisplay>
1249
1250## Class Objects
1251
1252The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class.
1253
1254The class object can be called like a function in order to create new instances. That's how we created instances of classes in the examples above.
1255
1256A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base.
1257
1258The class object's metatable reads properties from the base if they don't exist in the class object. This means we can access functions and properties directly from the class.
1259
1260It is important to note that assigning to the class object does not assign into the base, so it's not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the \_\_base field below.
1261
1262The class object has a couple special properties:
1263
1264The name of the class as when it was declared is stored as a string in the \_\_name field of the class object.
1265
1266```yuescript
1267print BackPack.__name -- prints Backpack
1268```
1269
1270<YueDisplay>
1271
1272```yue
1273print BackPack.__name -- prints Backpack
1274```
1275
1276</YueDisplay>
1277
1278The base object is stored in \_\_base. We can modify this table to add functionality to instances that have already been created and ones that are yet to be created.
1279
1280If the class extends from anything, the parent class object is stored in \_\_parent.
1281
1282## Class Variables
1283
1284We can create variables directly in the class object instead of in the base by using @ in the front of the property name in a class declaration.
1285
1286```yuescript
1287class Things
1288 @some_func: => print "Hello from", @__name
1289
1290Things\some_func!
1291
1292-- class variables not visible in instances
1293assert Things().some_func == nil
1294```
1295
1296<YueDisplay>
1297
1298```yue
1299class Things
1300 @some_func: => print "Hello from", @__name
1301
1302Things\some_func!
1303
1304-- class variables not visible in instances
1305assert Things().some_func == nil
1306```
1307
1308</YueDisplay>
1309
1310In expressions, we can use @@ to access a value that is stored in the **class of self. Thus, @@hello is shorthand for self.**class.hello.
1311
1312```yuescript
1313class Counter
1314 @count: 0
1315
1316 new: =>
1317 @@count += 1
1318
1319Counter!
1320Counter!
1321
1322print Counter.count -- prints 2
1323```
1324
1325<YueDisplay>
1326
1327```yue
1328class Counter
1329 @count: 0
1330
1331 new: =>
1332 @@count += 1
1333
1334Counter!
1335Counter!
1336
1337print Counter.count -- prints 2
1338```
1339
1340</YueDisplay>
1341
1342The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax.
1343
1344```yuescript
1345@@hello 1,2,3,4
1346```
1347
1348<YueDisplay>
1349
1350```yue
1351@@hello 1,2,3,4
1352```
1353
1354</YueDisplay>
1355
1356## Class Declaration Statements
1357
1358In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object.
1359
1360Here is an alternative way to create a class variable compared to what's described above:
1361
1362```yuescript
1363class Things
1364 @class_var = "hello world"
1365```
1366
1367<YueDisplay>
1368
1369```yue
1370class Things
1371 @class_var = "hello world"
1372```
1373
1374</YueDisplay>
1375
1376These expressions are executed after all the properties have been added to the base.
1377
1378All variables declared in the body of the class are local to the classes properties. This is convenient for placing private values or helper functions that only the class methods can access:
1379
1380```yuescript
1381class MoreThings
1382 secret = 123
1383 log = (msg) -> print "LOG:", msg
1384
1385 some_method: =>
1386 log "hello world: " .. secret
1387```
1388
1389<YueDisplay>
1390
1391```yue
1392class MoreThings
1393 secret = 123
1394 log = (msg) -> print "LOG:", msg
1395
1396 some_method: =>
1397 log "hello world: " .. secret
1398```
1399
1400</YueDisplay>
1401
1402## @ and @@ Values
1403
1404When @ and @@ are prefixed in front of a name they represent, respectively, that name accessed in self and self.\_\_class.
1405
1406If they are used all by themselves, they are aliases for self and self.\_\_class.
1407
1408```yuescript
1409assert @ == self
1410assert @@ == self.__class
1411```
1412
1413<YueDisplay>
1414
1415```yue
1416assert @ == self
1417assert @@ == self.__class
1418```
1419
1420</YueDisplay>
1421
1422For example, a quick way to create a new instance of the same class from an instance method using @@:
1423
1424```yuescript
1425some_instance_method = (...) => @@ ...
1426```
1427
1428<YueDisplay>
1429
1430```yue
1431some_instance_method = (...) => @@ ...
1432```
1433
1434</YueDisplay>
1435
1436## Constructor Property Promotion
1437
1438To reduce the boilerplate code for definition of simple value objects. You can write a simple class like:
1439
1440```yuescript
1441class Something
1442 new: (@foo, @bar, @@biz, @@baz) =>
1443
1444-- Which is short for
1445
1446class Something
1447 new: (foo, bar, biz, baz) =>
1448 @foo = foo
1449 @bar = bar
1450 @@biz = biz
1451 @@baz = baz
1452```
1453
1454<YueDisplay>
1455
1456```yue
1457class Something
1458 new: (@foo, @bar, @@biz, @@baz) =>
1459
1460-- Which is short for
1461
1462class Something
1463 new: (foo, bar, biz, baz) =>
1464 @foo = foo
1465 @bar = bar
1466 @@biz = biz
1467 @@baz = baz
1468```
1469
1470</YueDisplay>
1471
1472You can also use this syntax for a common function to initialize a object's fields.
1473
1474```yuescript
1475new = (@fieldA, @fieldB) => @
1476obj = new {}, 123, "abc"
1477print obj
1478```
1479
1480<YueDisplay>
1481
1482```yue
1483new = (@fieldA, @fieldB) => @
1484obj = new {}, 123, "abc"
1485print obj
1486```
1487
1488</YueDisplay>
1489
1490## Class Expressions
1491
1492The class syntax can also be used as an expression which can be assigned to a variable or explicitly returned.
1493
1494```yuescript
1495x = class Bucket
1496 drops: 0
1497 add_drop: => @drops += 1
1498```
1499
1500<YueDisplay>
1501
1502```yue
1503x = class Bucket
1504 drops: 0
1505 add_drop: => @drops += 1
1506```
1507
1508</YueDisplay>
1509
1510## Anonymous classes
1511
1512The name can be left out when declaring a class. The \_\_name attribute will be nil, unless the class expression is in an assignment. The name on the left hand side of the assignment is used instead of nil.
1513
1514```yuescript
1515BigBucket = class extends Bucket
1516 add_drop: => @drops += 10
1517
1518assert Bucket.__name == "BigBucket"
1519```
1520
1521<YueDisplay>
1522
1523```yue
1524BigBucket = class extends Bucket
1525 add_drop: => @drops += 10
1526
1527assert Bucket.__name == "BigBucket"
1528```
1529
1530</YueDisplay>
1531
1532You can even leave off the body, meaning you can write a blank anonymous class like this:
1533
1534```yuescript
1535x = class
1536```
1537
1538<YueDisplay>
1539
1540```yue
1541x = class
1542```
1543
1544</YueDisplay>
1545
1546## Class Mixing
1547
1548You can do mixing with keyword `using` to copy functions from either a plain table or a predefined class object into your new class. When doing mixing with a plain table, you can override the class indexing function (metamethod `__index`) to your customized implementation. When doing mixing with an existing class object, the class object's metamethods won't be copied.
1549
1550```yuescript
1551MyIndex = __index: var: 1
1552
1553class X using MyIndex
1554 func: =>
1555 print 123
1556
1557x = X!
1558print x.var
1559
1560class Y using X
1561
1562y = Y!
1563y\func!
1564
1565assert y.__class.__parent ~= X -- X is not parent of Y
1566```
1567
1568<YueDisplay>
1569
1570```yue
1571MyIndex = __index: var: 1
1572
1573class X using MyIndex
1574 func: =>
1575 print 123
1576
1577x = X!
1578print x.var
1579
1580class Y using X
1581
1582y = Y!
1583y\func!
1584
1585assert y.__class.__parent ~= X -- X is not parent of Y
1586```
1587
1588</YueDisplay>
1589
1590# With Statement
1591
1592A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it.
1593
1594This results in repeating the name of the object multiple times in code, adding unnecessary noise. A common solution to this is to pass a table in as an argument which contains a collection of keys and values to overwrite. The downside to this is that the constructor of this object must support this form.
1595
1596The with block helps to alleviate this. Within a with block we can use a special statements that begin with either . or \ which represent those operations applied to the object we are using with on.
1597
1598For example, we work with a newly created object:
1599
1600```yuescript
1601with Person!
1602 .name = "Oswald"
1603 \add_relative my_dad
1604 \save!
1605 print .name
1606```
1607
1608<YueDisplay>
1609
1610```yue
1611with Person!
1612 .name = "Oswald"
1613 \add_relative my_dad
1614 \save!
1615 print .name
1616```
1617
1618</YueDisplay>
1619
1620The with statement can also be used as an expression which returns the value it has been giving access to.
1621
1622```yuescript
1623file = with File "favorite_foods.txt"
1624 \set_encoding "utf8"
1625```
1626
1627<YueDisplay>
1628
1629```yue
1630file = with File "favorite_foods.txt"
1631 \set_encoding "utf8"
1632```
1633
1634</YueDisplay>
1635
1636`with` expressions support `break` with one value:
1637
1638```yuescript
1639result = with obj
1640 break .value
1641```
1642
1643<YueDisplay>
1644
1645```yue
1646result = with obj
1647 break .value
1648```
1649
1650</YueDisplay>
1651
1652After `break value` is used inside `with`, the `with` expression no longer returns its target object. Instead, it returns the value from `break`.
1653
1654```yuescript
1655a = with obj
1656 .x = 1
1657-- a is obj
1658
1659b = with obj
1660 break .x
1661-- b is .x, not obj
1662```
1663
1664<YueDisplay>
1665
1666```yue
1667a = with obj
1668 .x = 1
1669-- a is obj
1670
1671b = with obj
1672 break .x
1673-- b is .x, not obj
1674```
1675
1676</YueDisplay>
1677
1678Unlike `for` / `while` / `repeat` / `do`, `with` only supports one break value.
1679
1680Or…
1681
1682```yuescript
1683create_person = (name, relatives) ->
1684 with Person!
1685 .name = name
1686 \add_relative relative for relative in *relatives
1687
1688me = create_person "Leaf", [dad, mother, sister]
1689```
1690
1691<YueDisplay>
1692
1693```yue
1694create_person = (name, relatives) ->
1695 with Person!
1696 .name = name
1697 \add_relative relative for relative in *relatives
1698
1699me = create_person "Leaf", [dad, mother, sister]
1700```
1701
1702</YueDisplay>
1703
1704In this usage, with can be seen as a special form of the K combinator.
1705
1706The expression in the with statement can also be an assignment, if you want to give a name to the expression.
1707
1708```yuescript
1709with str := "Hello"
1710 print "original:", str
1711 print "upper:", \upper!
1712```
1713
1714<YueDisplay>
1715
1716```yue
1717with str := "Hello"
1718 print "original:", str
1719 print "upper:", \upper!
1720```
1721
1722</YueDisplay>
1723
1724You can access special keys with `[]` in a `with` statement.
1725
1726```yuescript
1727with tb
1728 [1] = 1
1729 print [2]
1730 with [abc]
1731 [3] = [2]\func!
1732 ["key-name"] = value
1733 [] = "abc" -- appending to "tb"
1734```
1735
1736<YueDisplay>
1737
1738```yue
1739with tb
1740 [1] = 1
1741 print [2]
1742 with [abc]
1743 [3] = [2]\func!
1744 ["key-name"] = value
1745 [] = "abc" -- appending to "tb"
1746```
1747
1748</YueDisplay>
1749
1750`with?` is an enhanced version of `with` syntax, which introduces an existential check to safely access objects that may be nil without explicit null checks.
1751
1752```yuescript
1753with? obj
1754 print obj.name
1755```
1756
1757<YueDisplay>
1758
1759```yue
1760with? obj
1761 print obj.name
1762```
1763
1764</YueDisplay>
1765
1766# Assignment
1767
1768The variable is dynamic typed and is defined as local by default. But you can change the scope of declaration by **local** and **global** statement.
1769
1770```yuescript
1771hello = "world"
1772a, b, c = 1, 2, 3
1773hello = 123 -- uses the existing variable
1774```
1775
1776<YueDisplay>
1777
1778```yue
1779hello = "world"
1780a, b, c = 1, 2, 3
1781hello = 123 -- uses the existing variable
1782```
1783
1784</YueDisplay>
1785
1786## Perform Update
1787
1788You can perform update assignment with many binary operators.
1789
1790```yuescript
1791x = 1
1792x += 1
1793x -= 1
1794x *= 10
1795x /= 10
1796x %= 10
1797s ..= "world" -- will add a new local if local variable is not exist
1798arg or= "default value"
1799```
1800
1801<YueDisplay>
1802
1803```yue
1804x = 1
1805x += 1
1806x -= 1
1807x *= 10
1808x /= 10
1809x %= 10
1810s ..= "world" -- will add a new local if local variable is not exist
1811arg or= "default value"
1812```
1813
1814</YueDisplay>
1815
1816## Chaining Assignment
1817
1818You can do chaining assignment to assign multiple items to hold the same value.
1819
1820```yuescript
1821a = b = c = d = e = 0
1822x = y = z = f!
1823```
1824
1825<YueDisplay>
1826
1827```yue
1828a = b = c = d = e = 0
1829x = y = z = f!
1830```
1831
1832</YueDisplay>
1833
1834## Explicit Locals
1835
1836```yuescript
1837do
1838 local a = 1
1839 local *
1840 print "forward declare all variables as locals"
1841 x = -> 1 + y + z
1842 y, z = 2, 3
1843 global instance = Item\new!
1844
1845do
1846 local X = 1
1847 local ^
1848 print "only forward declare upper case variables"
1849 a = 1
1850 B = 2
1851```
1852
1853<YueDisplay>
1854
1855```yue
1856do
1857 local a = 1
1858 local *
1859 print "forward declare all variables as locals"
1860 x = -> 1 + y + z
1861 y, z = 2, 3
1862 global instance = Item\new!
1863
1864do
1865 local X = 1
1866 local ^
1867 print "only forward declare upper case variables"
1868 a = 1
1869 B = 2
1870```
1871
1872</YueDisplay>
1873
1874## Explicit Globals
1875
1876```yuescript
1877do
1878 global a = 1
1879 global *
1880 print "declare all variables as globals"
1881 x = -> 1 + y + z
1882 y, z = 2, 3
1883
1884do
1885 global X = 1
1886 global ^
1887 print "only declare upper case variables as globals"
1888 a = 1
1889 B = 2
1890 local Temp = "a local value"
1891```
1892
1893<YueDisplay>
1894
1895```yue
1896do
1897 global a = 1
1898 global *
1899 print "declare all variables as globals"
1900 x = -> 1 + y + z
1901 y, z = 2, 3
1902
1903do
1904 global X = 1
1905 global ^
1906 print "only declare upper case variables as globals"
1907 a = 1
1908 B = 2
1909 local Temp = "a local value"
1910```
1911
1912</YueDisplay>
1913
1914# Varargs Assignment
1915
1916You can assign the results returned from a function to a varargs symbol `...`. And then access its content using the Lua way.
1917
1918```yuescript
1919list = [1, 2, 3, 4, 5]
1920fn = (ok) -> ok, table.unpack list
1921ok, ... = fn true
1922count = select '#', ...
1923first = select 1, ...
1924print ok, count, first
1925```
1926
1927<YueDisplay>
1928
1929```yue
1930list = [1, 2, 3, 4, 5]
1931fn = (ok) -> ok, table.unpack list
1932ok, ... = fn true
1933count = select '#', ...
1934first = select 1, ...
1935print ok, count, first
1936```
1937
1938</YueDisplay>
1939
1940# If Assignment
1941
1942`if` and `elseif` blocks can take an assignment in place of a conditional expression. Upon evaluating the conditional, the assignment will take place and the value that was assigned to will be used as the conditional expression. The assigned variable is only in scope for the body of the conditional, meaning it is never available if the value is not truthy. And you have to use "the walrus operator" `:=` instead of `=` to do assignment.
1943
1944```yuescript
1945if user := database.find_user "moon"
1946 print user.name
1947```
1948
1949<YueDisplay>
1950
1951```yue
1952if user := database.find_user "moon"
1953 print user.name
1954```
1955
1956</YueDisplay>
1957
1958```yuescript
1959if hello := os.getenv "hello"
1960 print "You have hello", hello
1961elseif world := os.getenv "world"
1962 print "you have world", world
1963else
1964 print "nothing :("
1965```
1966
1967<YueDisplay>
1968
1969```yue
1970if hello := os.getenv "hello"
1971 print "You have hello", hello
1972elseif world := os.getenv "world"
1973 print "you have world", world
1974else
1975 print "nothing :("
1976```
1977
1978</YueDisplay>
1979
1980If assignment with multiple return values. Only the first value is getting checked, other values are scoped.
1981
1982```yuescript
1983if success, result := pcall -> "get result without problems"
1984 print result -- variable result is scoped
1985print "OK"
1986```
1987
1988<YueDisplay>
1989
1990```yue
1991if success, result := pcall -> "get result without problems"
1992 print result -- variable result is scoped
1993print "OK"
1994```
1995
1996</YueDisplay>
1997
1998## While Assignment
1999
2000You can also use if assignment in a while loop to get the value as the loop condition.
2001
2002```yuescript
2003while byte := stream\read_one!
2004 -- do something with the byte
2005 print byte
2006```
2007
2008<YueDisplay>
2009
2010```yue
2011while byte := stream\read_one!
2012 -- do something with the byte
2013 print byte
2014```
2015
2016</YueDisplay>
2017
2018# Destructuring Assignment
2019
2020Destructuring assignment is a way to quickly extract values from a table by their name or position in array based tables.
2021
2022Typically when you see a table literal, {1,2,3}, it is on the right hand side of an assignment because it is a value. Destructuring assignment swaps the role of the table literal, and puts it on the left hand side of an assign statement.
2023
2024This is best explained with examples. Here is how you would unpack the first two values from a table:
2025
2026```yuescript
2027thing = [1, 2]
2028
2029[a, b] = thing
2030print a, b
2031```
2032
2033<YueDisplay>
2034
2035```yue
2036thing = [1, 2]
2037
2038[a, b] = thing
2039print a, b
2040```
2041
2042</YueDisplay>
2043
2044In the destructuring table literal, the key represents the key to read from the right hand side, and the value represents the name the read value will be assigned to.
2045
2046```yuescript
2047obj = {
2048 hello: "world"
2049 day: "tuesday"
2050 length: 20
2051}
2052
2053{hello: hello, day: the_day} = obj
2054print hello, the_day
2055
2056:day = obj -- OK to do simple destructuring without braces
2057```
2058
2059<YueDisplay>
2060
2061```yue
2062obj = {
2063 hello: "world"
2064 day: "tuesday"
2065 length: 20
2066}
2067
2068{hello: hello, day: the_day} = obj
2069print hello, the_day
2070
2071:day = obj -- OK to do simple destructuring without braces
2072```
2073
2074</YueDisplay>
2075
2076This also works with nested data structures as well:
2077
2078```yuescript
2079obj2 = {
2080 numbers: [1, 2, 3, 4]
2081 properties: {
2082 color: "green"
2083 height: 13.5
2084 }
2085}
2086
2087{numbers: [first, second], properties: {color: color}} = obj2
2088print first, second, color
2089```
2090
2091<YueDisplay>
2092
2093```yue
2094obj2 = {
2095 numbers: [1, 2, 3, 4]
2096 properties: {
2097 color: "green"
2098 height: 13.5
2099 }
2100}
2101
2102{numbers: [first, second], properties: {color: color}} = obj2
2103print first, second, color
2104```
2105
2106</YueDisplay>
2107
2108If the destructuring statement is complicated, feel free to spread it out over a few lines. A slightly more complicated example:
2109
2110```yuescript
2111{
2112 numbers: [first, second]
2113 properties: {
2114 color: color
2115 }
2116} = obj2
2117```
2118
2119<YueDisplay>
2120
2121```yue
2122{
2123 numbers: [first, second]
2124 properties: {
2125 color: color
2126 }
2127} = obj2
2128```
2129
2130</YueDisplay>
2131
2132It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator:
2133
2134```yuescript
2135{:concat, :insert} = table
2136```
2137
2138<YueDisplay>
2139
2140```yue
2141{:concat, :insert} = table
2142```
2143
2144</YueDisplay>
2145
2146This is effectively the same as import, but we can rename fields we want to extract by mixing the syntax:
2147
2148```yuescript
2149{:mix, :max, random: rand} = math
2150```
2151
2152<YueDisplay>
2153
2154```yue
2155{:mix, :max, random: rand} = math
2156```
2157
2158</YueDisplay>
2159
2160You can write default values while doing destructuring like:
2161
2162```yuescript
2163{:name = "nameless", :job = "jobless"} = person
2164```
2165
2166<YueDisplay>
2167
2168```yue
2169{:name = "nameless", :job = "jobless"} = person
2170```
2171
2172</YueDisplay>
2173
2174You can use `_` as placeholder when doing a list destructuring:
2175
2176```yuescript
2177[_, two, _, four] = items
2178```
2179
2180<YueDisplay>
2181
2182```yue
2183[_, two, _, four] = items
2184```
2185
2186</YueDisplay>
2187
2188## Range Destructuring
2189
2190You can use the spread operator `...` in list destructuring to capture a range of values. This is useful when you want to extract specific elements from the beginning and end of a list while collecting the rest in between.
2191
2192```yuescript
2193orders = ["first", "second", "third", "fourth", "last"]
2194[first, ...bulk, last] = orders
2195print first -- prints: first
2196print bulk -- prints: {"second", "third", "fourth"}
2197print last -- prints: last
2198```
2199
2200<YueDisplay>
2201
2202```yue
2203orders = ["first", "second", "third", "fourth", "last"]
2204[first, ...bulk, last] = orders
2205print first -- prints: first
2206print bulk -- prints: {"second", "third", "fourth"}
2207print last -- prints: last
2208```
2209
2210</YueDisplay>
2211
2212The spread operator can be used in different positions to capture different ranges, and you can use `_` as a placeholder for the values you don't want to capture:
2213
2214```yuescript
2215-- Capture everything after first element
2216[first, ...rest] = orders
2217
2218-- Capture everything before last element
2219[...start, last] = orders
2220
2221-- Capture things except the middle elements
2222[first, ..._, last] = orders
2223```
2224
2225<YueDisplay>
2226
2227```yue
2228-- Capture everything after first element
2229[first, ...rest] = orders
2230
2231-- Capture everything before last element
2232[...start, last] = orders
2233
2234-- Capture things except the middle elements
2235[first, ..._, last] = orders
2236```
2237
2238</YueDisplay>
2239
2240## Destructuring In Other Places
2241
2242Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
2243
2244```yuescript
2245tuples = [
2246 ["hello", "world"]
2247 ["egg", "head"]
2248]
2249
2250for [left, right] in *tuples
2251 print left, right
2252```
2253
2254<YueDisplay>
2255
2256```yue
2257tuples = [
2258 ["hello", "world"]
2259 ["egg", "head"]
2260]
2261
2262for [left, right] in *tuples
2263 print left, right
2264```
2265
2266</YueDisplay>
2267
2268We know each element in the array table is a two item tuple, so we can unpack it directly in the names clause of the for statement using a destructure.
2269
2270# The Using Clause; Controlling Destructive Assignment
2271
2272While lexical scoping can be a great help in reducing the complexity of the code we write, things can get unwieldy as the code size increases. Consider the following snippet:
2273
2274```yuescript
2275i = 100
2276
2277-- many lines of code...
2278
2279my_func = ->
2280 i = 10
2281 while i > 0
2282 print i
2283 i -= 1
2284
2285my_func!
2286
2287print i -- will print 0
2288```
2289
2290<YueDisplay>
2291
2292```yue
2293i = 100
2294
2295-- many lines of code...
2296
2297my_func = ->
2298 i = 10
2299 while i > 0
2300 print i
2301 i -= 1
2302
2303my_func!
2304
2305print i -- will print 0
2306```
2307
2308</YueDisplay>
2309
2310In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn't clear what names have already been declared.
2311
2312It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident.
2313
2314The using keyword lets us do that. using nil makes sure that no closed variables are overwritten in assignment. The using clause is placed after the argument list in a function, or in place of it if there are no arguments.
2315
2316```yuescript
2317i = 100
2318
2319my_func = (using nil) ->
2320 i = "hello" -- a new local variable is created here
2321
2322my_func!
2323print i -- prints 100, i is unaffected
2324```
2325
2326<YueDisplay>
2327
2328```yue
2329i = 100
2330
2331my_func = (using nil) ->
2332 i = "hello" -- a new local variable is created here
2333
2334my_func!
2335print i -- prints 100, i is unaffected
2336```
2337
2338</YueDisplay>
2339
2340Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified:
2341
2342```yuescript
2343tmp = 1213
2344i, k = 100, 50
2345
2346my_func = (add using k, i) ->
2347 tmp = tmp + add -- a new local tmp is created
2348 i += tmp
2349 k += tmp
2350
2351my_func(22)
2352print i, k -- these have been updated
2353```
2354
2355<YueDisplay>
2356
2357```yue
2358tmp = 1213
2359i, k = 100, 50
2360
2361my_func = (add using k, i) ->
2362 tmp = tmp + add -- a new local tmp is created
2363 i += tmp
2364 k += tmp
2365
2366my_func(22)
2367print i, k -- these have been updated
2368```
2369
2370</YueDisplay>
2371
2372# Usage
2373
2374## Lua Module
2375
2376Use YueScript module in Lua:
2377
2378- **Case 1**
2379
2380 Require "your_yuescript_entry.yue" in Lua.
2381
2382 ```Lua
2383 require("yue")("your_yuescript_entry")
2384 ```
2385
2386 And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly.
2387
2388- **Case 2**
2389
2390 Require YueScript module and rewite message by hand.
2391
2392 ```lua
2393 local yue = require("yue")
2394 yue.insert_loader()
2395 local success, result = xpcall(function()
2396 return require("yuescript_module_name")
2397 end, function(err)
2398 return yue.traceback(err)
2399 end)
2400 ```
2401
2402- **Case 3**
2403
2404 Use the YueScript compiler function in Lua.
2405
2406 ```lua
2407 local yue = require("yue")
2408 local codes, err, globals = yue.to_lua([[
2409 f = ->
2410 print "hello world"
2411 f!
2412 ]],{
2413 implicit_return_root = true,
2414 reserve_line_number = true,
2415 lint_global = true,
2416 space_over_tab = false,
2417 options = {
2418 target = "5.4",
2419 path = "/script"
2420 }
2421 })
2422 ```
2423
2424## YueScript Tool
2425
2426Use YueScript tool with:
2427
2428```shell
2429> yue -h
2430Usage: yue
2431 [options] [<file/directory>] ...
2432 yue -e <code_or_file> [args...]
2433 yue -w [<directory>] [options]
2434 yue -
2435
2436Notes:
2437 - '-' / '--' must be the first and only argument.
2438 - '-o/--output' can not be used with multiple input files.
2439 - '-w/--watch' can not be used with file input (directory only).
2440 - with '-e/--execute', remaining tokens are treated as script args.
2441
2442Options:
2443 -h, --help Show this help message and exit.
2444 -e <str>, --execute <str> Execute a file or raw codes
2445 -m, --minify Generate minified codes
2446 -r, --rewrite Rewrite output to match original line numbers
2447 -t <output_to>, --output-to <output_to>
2448 Specify where to place compiled files
2449 -o <file>, --output <file> Write output to file
2450 -p, --print Write output to standard out
2451 -b, --benchmark Dump compile time (doesn't write output)
2452 -g, --globals Dump global variables used in NAME LINE COLUMN
2453 -s, --spaces Use spaces in generated codes instead of tabs
2454 -l, --line-numbers Write line numbers from source codes
2455 -j, --no-implicit-return Disable implicit return at end of file
2456 -c, --reserve-comments Reserve comments before statement from source codes
2457 -w [<dir>], --watch [<dir>]
2458 Watch changes and compile every file under directory
2459 -v, --version Print version
2460 - Read from standard in, print to standard out
2461 (Must be first and only argument)
2462 -- Same as '-' (kept for backward compatibility)
2463
2464 --target <version> Specify the Lua version that codes will be generated to
2465 (version can only be 5.1 to 5.5)
2466 --path <path_str> Append an extra Lua search path string to package.path
2467 --<key>=<value> Pass compiler option in key=value form (existing behavior)
2468
2469 Execute without options to enter REPL, type symbol '$'
2470 in a single line to start/stop multi-line mode
2471```
2472
2473Use cases:
2474
2475Recursively compile every YueScript file with extension **.yue** under current path: **yue .**
2476
2477Compile and save results to a target path: **yue -t /target/path/ .**
2478
2479Compile and reserve debug info: **yue -l .**
2480
2481Compile and generate minified codes: **yue -m .**
2482
2483Execute raw codes: **yue -e 'print 123'**
2484
2485Execute a YueScript file: **yue -e main.yue**
2486
2487# Introduction
2488
2489YueScript is a dynamic language that compiles to Lua. And it's a [MoonScript](https://github.com/leafo/moonscript) dialect. The codes written in YueScript are expressive and extremely concise. And it is suitable for writing some changing application logic with more maintainable codes and runs in a Lua embeded environment such as games or website servers.
2490
2491Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ].
2492
2493## An Overview of YueScript
2494
2495```yuescript
2496-- import syntax
2497import p, to_lua from "yue"
2498
2499-- object literals
2500inventory =
2501 equipment:
2502 - "sword"
2503 - "shield"
2504 items:
2505 - name: "potion"
2506 count: 10
2507 - name: "bread"
2508 count: 3
2509
2510-- list comprehension
2511map = (arr, action) ->
2512 [action item for item in *arr]
2513
2514filter = (arr, cond) ->
2515 [item for item in *arr when cond item]
2516
2517reduce = (arr, init, action): init ->
2518 init = action init, item for item in *arr
2519
2520-- pipe operator
2521[1, 2, 3]
2522 |> map (x) -> x * 2
2523 |> filter (x) -> x > 4
2524 |> reduce 0, (a, b) -> a + b
2525 |> print
2526
2527-- metatable manipulation
2528apple =
2529 size: 15
2530 <index>:
2531 color: 0x00ffff
2532
2533with apple
2534 p .size, .color, .<index> if .<>?
2535
2536-- js-like export syntax
2537export 🌛 = "Script of Moon"
2538```
2539
2540<YueDisplay>
2541
2542```yue
2543-- import syntax
2544import p, to_lua from "yue"
2545
2546-- object literals
2547inventory =
2548 equipment:
2549 - "sword"
2550 - "shield"
2551 items:
2552 - name: "potion"
2553 count: 10
2554 - name: "bread"
2555 count: 3
2556
2557-- list comprehension
2558map = (arr, action) ->
2559 [action item for item in *arr]
2560
2561filter = (arr, cond) ->
2562 [item for item in *arr when cond item]
2563
2564reduce = (arr, init, action): init ->
2565 init = action init, item for item in *arr
2566
2567-- pipe operator
2568[1, 2, 3]
2569 |> map (x) -> x * 2
2570 |> filter (x) -> x > 4
2571 |> reduce 0, (a, b) -> a + b
2572 |> print
2573
2574-- metatable manipulation
2575apple =
2576 size: 15
2577 <index>:
2578 color: 0x00ffff
2579
2580with apple
2581 p .size, .color, .<index> if .<>?
2582
2583-- js-like export syntax
2584export 🌛 = "Script of Moon"
2585```
2586
2587</YueDisplay>
2588
2589## About Dora SSR
2590
2591YueScript is being developed and maintained alongside the open-source game engine [Dora SSR](https://github.com/Dora-SSR/Dora-SSR). It has been used to create engine tools, game demos and prototypes, validating its capabilities in real-world scenarios while enhancing the Dora SSR development experience.
2592
2593# Installation
2594
2595## Lua Module
2596
2597Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install it as a Lua module and executable with:
2598
2599```shell
2600luarocks install yuescript
2601```
2602
2603Or you can build `yue.so` file with:
2604
2605```shell
2606make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua
2607```
2608
2609Then get the binary file from path **bin/shared/yue.so**.
2610
2611## Build Binary Tool
2612
2613Clone this repo, then build and install executable with:
2614
2615```shell
2616make install
2617```
2618
2619Build YueScript tool without macro feature:
2620
2621```shell
2622make install NO_MACRO=true
2623```
2624
2625Build YueScript tool without built-in Lua binary:
2626
2627```shell
2628make install NO_LUA=true
2629```
2630
2631## Download Precompiled Binary
2632
2633You can download precompiled binary files, including binary executable files compatible with different Lua versions and library files.
2634
2635Download precompiled binary files from [here](https://github.com/IppClub/YueScript/releases).
2636
2637# Conditionals
2638
2639```yuescript
2640have_coins = false
2641if have_coins
2642 print "Got coins"
2643else
2644 print "No coins"
2645```
2646
2647<YueDisplay>
2648
2649```yue
2650have_coins = false
2651if have_coins
2652 print "Got coins"
2653else
2654 print "No coins"
2655```
2656
2657</YueDisplay>
2658
2659A short syntax for single statements can also be used:
2660
2661```yuescript
2662have_coins = false
2663if have_coins then print "Got coins" else print "No coins"
2664```
2665
2666<YueDisplay>
2667
2668```yue
2669have_coins = false
2670if have_coins then print "Got coins" else print "No coins"
2671```
2672
2673</YueDisplay>
2674
2675Because if statements can be used as expressions, this can also be written as:
2676
2677```yuescript
2678have_coins = false
2679print if have_coins then "Got coins" else "No coins"
2680```
2681
2682<YueDisplay>
2683
2684```yue
2685have_coins = false
2686print if have_coins then "Got coins" else "No coins"
2687```
2688
2689</YueDisplay>
2690
2691Conditionals can also be used in return statements and assignments:
2692
2693```yuescript
2694is_tall = (name) ->
2695 if name == "Rob"
2696 true
2697 else
2698 false
2699
2700message = if is_tall "Rob"
2701 "I am very tall"
2702else
2703 "I am not so tall"
2704
2705print message -- prints: I am very tall
2706```
2707
2708<YueDisplay>
2709
2710```yue
2711is_tall = (name) ->
2712 if name == "Rob"
2713 true
2714 else
2715 false
2716
2717message = if is_tall "Rob"
2718 "I am very tall"
2719else
2720 "I am not so tall"
2721
2722print message -- prints: I am very tall
2723```
2724
2725</YueDisplay>
2726
2727The opposite of if is unless:
2728
2729```yuescript
2730unless os.date("%A") == "Monday"
2731 print "it is not Monday!"
2732```
2733
2734<YueDisplay>
2735
2736```yue
2737unless os.date("%A") == "Monday"
2738 print "it is not Monday!"
2739```
2740
2741</YueDisplay>
2742
2743```yuescript
2744print "You're lucky!" unless math.random! > 0.1
2745```
2746
2747<YueDisplay>
2748
2749```yue
2750print "You're lucky!" unless math.random! > 0.1
2751```
2752
2753</YueDisplay>
2754
2755## In Expression
2756
2757You can write range checking code with an `in-expression`.
2758
2759```yuescript
2760a = 5
2761
2762if a in [1, 3, 5, 7]
2763 print "checking equality with discrete values"
2764
2765if a in list
2766 print "checking if `a` is in a list"
2767```
2768
2769<YueDisplay>
2770
2771```yue
2772a = 5
2773
2774if a in [1, 3, 5, 7]
2775 print "checking equality with discrete values"
2776
2777if a in list
2778 print "checking if `a` is in a list"
2779```
2780
2781</YueDisplay>
2782
2783# For Loop
2784
2785There are two for loop forms, just like in Lua. A numeric one and a generic one:
2786
2787```yuescript
2788for i = 10, 20
2789 print i
2790
2791for k = 1, 15, 2 -- an optional step provided
2792 print k
2793
2794for key, value in pairs object
2795 print key, value
2796```
2797
2798<YueDisplay>
2799
2800```yue
2801for i = 10, 20
2802 print i
2803
2804for k = 1, 15, 2 -- an optional step provided
2805 print k
2806
2807for key, value in pairs object
2808 print key, value
2809```
2810
2811</YueDisplay>
2812
2813The slicing and **\*** operators can be used, just like with comprehensions:
2814
2815```yuescript
2816for item in *items[2, 4]
2817 print item
2818```
2819
2820<YueDisplay>
2821
2822```yue
2823for item in *items[2, 4]
2824 print item
2825```
2826
2827</YueDisplay>
2828
2829A shorter syntax is also available for all variations when the body is only a single line:
2830
2831```yuescript
2832for item in *items do print item
2833
2834for j = 1, 10, 3 do print j
2835```
2836
2837<YueDisplay>
2838
2839```yue
2840for item in *items do print item
2841
2842for j = 1, 10, 3 do print j
2843```
2844
2845</YueDisplay>
2846
2847A for loop can also be used as an expression. The last statement in the body of the for loop is coerced into an expression and appended to an accumulating array table.
2848
2849Doubling every even number:
2850
2851```yuescript
2852doubled_evens = for i = 1, 20
2853 if i % 2 == 0
2854 i * 2
2855 else
2856 i
2857```
2858
2859<YueDisplay>
2860
2861```yue
2862doubled_evens = for i = 1, 20
2863 if i % 2 == 0
2864 i * 2
2865 else
2866 i
2867```
2868
2869</YueDisplay>
2870
2871In addition, for loops support break with return values, allowing the loop itself to be used as an expression that exits early with meaningful results.
2872
2873For example, to find the first number greater than 10:
2874
2875```yuescript
2876first_large = for n in *numbers
2877 break n if n > 10
2878```
2879
2880<YueDisplay>
2881
2882```yue
2883first_large = for n in *numbers
2884 break n if n > 10
2885```
2886
2887</YueDisplay>
2888
2889This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions.
2890
2891For loop expressions can break with multiple values:
2892
2893```yuescript
2894key, score = for k, v in pairs data
2895 break k, v * 10 if k == "target"
2896```
2897
2898<YueDisplay>
2899
2900```yue
2901key, score = for k, v in pairs data
2902 break k, v * 10 if k == "target"
2903```
2904
2905</YueDisplay>
2906
2907You can also filter values by combining the for loop expression with the continue statement.
2908
2909For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension.
2910
2911```yuescript
2912func_a = -> for i = 1, 10 do print i
2913func_b = -> return for i = 1, 10 do i
2914
2915print func_a! -- prints nil
2916print func_b! -- prints table object
2917```
2918
2919<YueDisplay>
2920
2921```yue
2922func_a = -> for i = 1, 10 do print i
2923func_b = -> return for i = 1, 10 do i
2924
2925print func_a! -- prints nil
2926print func_b! -- prints table object
2927```
2928
2929</YueDisplay>
2930
2931This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop.
2932
2933# Continue
2934
2935A continue statement can be used to skip the current iteration in a loop.
2936
2937```yuescript
2938i = 0
2939while i < 10
2940 i += 1
2941 continue if i % 2 == 0
2942 print i
2943```
2944
2945<YueDisplay>
2946
2947```yue
2948i = 0
2949while i < 10
2950 i += 1
2951 continue if i % 2 == 0
2952 print i
2953```
2954
2955</YueDisplay>
2956
2957continue can also be used with loop expressions to prevent that iteration from accumulating into the result. This examples filters the array table into just even numbers:
2958
2959```yuescript
2960my_numbers = [1, 2, 3, 4, 5, 6]
2961odds = for x in *my_numbers
2962 continue if x % 2 == 1
2963 x
2964```
2965
2966<YueDisplay>
2967
2968```yue
2969my_numbers = [1, 2, 3, 4, 5, 6]
2970odds = for x in *my_numbers
2971 continue if x % 2 == 1
2972 x
2973```
2974
2975</YueDisplay>
2976
2977# Switch
2978
2979The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. In switch statement, you can also use assignment expression to store temporary variable value.
2980
2981```yuescript
2982switch name := "Dan"
2983 when "Robert"
2984 print "You are Robert"
2985 when "Dan", "Daniel"
2986 print "Your name, it's Dan"
2987 else
2988 print "I don't know about you with name #{name}"
2989```
2990
2991<YueDisplay>
2992
2993```yue
2994switch name := "Dan"
2995 when "Robert"
2996 print "You are Robert"
2997 when "Dan", "Daniel"
2998 print "Your name, it's Dan"
2999 else
3000 print "I don't know about you with name #{name}"
3001```
3002
3003</YueDisplay>
3004
3005A switch when clause can match against multiple values by listing them out comma separated.
3006
3007Switches can be used as expressions as well, here we can assign the result of the switch to a variable:
3008
3009```yuescript
3010b = 1
3011next_number = switch b
3012 when 1
3013 2
3014 when 2
3015 3
3016 else
3017 error "can't count that high!"
3018```
3019
3020<YueDisplay>
3021
3022```yue
3023b = 1
3024next_number = switch b
3025 when 1
3026 2
3027 when 2
3028 3
3029 else
3030 error "can't count that high!"
3031```
3032
3033</YueDisplay>
3034
3035We can use the then keyword to write a switch's when block on a single line. No extra keyword is needed to write the else block on a single line.
3036
3037```yuescript
3038msg = switch math.random(1, 5)
3039 when 1 then "you are lucky"
3040 when 2 then "you are almost lucky"
3041 else "not so lucky"
3042```
3043
3044<YueDisplay>
3045
3046```yue
3047msg = switch math.random(1, 5)
3048 when 1 then "you are lucky"
3049 when 2 then "you are almost lucky"
3050 else "not so lucky"
3051```
3052
3053</YueDisplay>
3054
3055If you want to write code with one less indent when writing a switch statement, you can put the first when clause on the statement start line, and then all other clauses can be written with one less indent.
3056
3057```yuescript
3058switch math.random(1, 5)
3059 when 1
3060 print "you are lucky" -- two indents
3061 else
3062 print "not so lucky"
3063
3064switch math.random(1, 5) when 1
3065 print "you are lucky" -- one indent
3066else
3067 print "not so lucky"
3068```
3069
3070<YueDisplay>
3071
3072```yue
3073switch math.random(1, 5)
3074 when 1
3075 print "you are lucky" -- two indents
3076 else
3077 print "not so lucky"
3078
3079switch math.random(1, 5) when 1
3080 print "you are lucky" -- one indent
3081else
3082 print "not so lucky"
3083```
3084
3085</YueDisplay>
3086
3087It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's expression wants to overwrite how the comparison is done by defining an eq metamethod.
3088
3089## Table Matching
3090
3091You can do table matching in a switch when clause, if the table can be destructured by a specific structure and get non-nil values.
3092
3093```yuescript
3094items =
3095 * x: 100
3096 y: 200
3097 * width: 300
3098 height: 400
3099
3100for item in *items
3101 switch item
3102 when :x, :y
3103 print "Vec2 #{x}, #{y}"
3104 when :width, :height
3105 print "size #{width}, #{height}"
3106```
3107
3108<YueDisplay>
3109
3110```yue
3111items =
3112 * x: 100
3113 y: 200
3114 * width: 300
3115 height: 400
3116
3117for item in *items
3118 switch item
3119 when :x, :y
3120 print "Vec2 #{x}, #{y}"
3121 when :width, :height
3122 print "size #{width}, #{height}"
3123```
3124
3125</YueDisplay>
3126
3127You can use default values to optionally destructure the table for some fields.
3128
3129```yuescript
3130item = {}
3131
3132{pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos')
3133
3134switch item
3135 when {pos: {:x = 50, :y = 200}}
3136 print "Vec2 #{x}, #{y}" -- table destructuring will still pass
3137```
3138
3139<YueDisplay>
3140
3141```yue
3142item = {}
3143
3144{pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos')
3145
3146switch item
3147 when {pos: {:x = 50, :y = 200}}
3148 print "Vec2 #{x}, #{y}" -- table destructuring will still pass
3149```
3150
3151</YueDisplay>
3152
3153You can also match against array elements, table fields, and even nested structures with array or table literals.
3154
3155Match against array elements.
3156
3157```yuescript
3158switch tb
3159 when [1, 2, 3]
3160 print "1, 2, 3"
3161 when [1, b, 3]
3162 print "1, #{b}, 3"
3163 when [1, 2, b = 3] -- b has a default value
3164 print "1, 2, #{b}"
3165```
3166
3167<YueDisplay>
3168
3169```yue
3170switch tb
3171 when [1, 2, 3]
3172 print "1, 2, 3"
3173 when [1, b, 3]
3174 print "1, #{b}, 3"
3175 when [1, 2, b = 3] -- b has a default value
3176 print "1, 2, #{b}"
3177```
3178
3179</YueDisplay>
3180
3181Match against table fields with destructuring.
3182
3183```yuescript
3184switch tb
3185 when success: true, :result
3186 print "success", result
3187 when success: false
3188 print "failed", result
3189 else
3190 print "invalid"
3191```
3192
3193<YueDisplay>
3194
3195```yue
3196switch tb
3197 when success: true, :result
3198 print "success", result
3199 when success: false
3200 print "failed", result
3201 else
3202 print "invalid"
3203```
3204
3205</YueDisplay>
3206
3207Match against nested table structures.
3208
3209```yuescript
3210switch tb
3211 when data: {type: "success", :content}
3212 print "success", content
3213 when data: {type: "error", :content}
3214 print "failed", content
3215 else
3216 print "invalid"
3217```
3218
3219<YueDisplay>
3220
3221```yue
3222switch tb
3223 when data: {type: "success", :content}
3224 print "success", content
3225 when data: {type: "error", :content}
3226 print "failed", content
3227 else
3228 print "invalid"
3229```
3230
3231</YueDisplay>
3232
3233Match against array of tables.
3234
3235```yuescript
3236switch tb
3237 when [
3238 {a: 1, b: 2}
3239 {a: 3, b: 4}
3240 {a: 5, b: 6}
3241 fourth
3242 ]
3243 print "matched", fourth
3244```
3245
3246<YueDisplay>
3247
3248```yue
3249switch tb
3250 when [
3251 {a: 1, b: 2}
3252 {a: 3, b: 4}
3253 {a: 5, b: 6}
3254 fourth
3255 ]
3256 print "matched", fourth
3257```
3258
3259</YueDisplay>
3260
3261Match against a list and capture a range of elements.
3262
3263```yuescript
3264segments = ["admin", "users", "logs", "view"]
3265switch segments
3266 when [...groups, resource, action]
3267 print "Group:", groups -- prints: {"admin", "users"}
3268 print "Resource:", resource -- prints: "logs"
3269 print "Action:", action -- prints: "view"
3270```
3271
3272<YueDisplay>
3273
3274```yue
3275segments = ["admin", "users", "logs", "view"]
3276switch segments
3277 when [...groups, resource, action]
3278 print "Group:", groups -- prints: {"admin", "users"}
3279 print "Resource:", resource -- prints: "logs"
3280 print "Action:", action -- prints: "view"
3281```
3282
3283</YueDisplay>
3284
3285# While Loop
3286
3287The while loop also comes in four variations:
3288
3289```yuescript
3290i = 10
3291while i > 0
3292 print i
3293 i -= 1
3294
3295while running == true do my_function!
3296```
3297
3298<YueDisplay>
3299
3300```yue
3301i = 10
3302while i > 0
3303 print i
3304 i -= 1
3305
3306while running == true do my_function!
3307```
3308
3309</YueDisplay>
3310
3311```yuescript
3312i = 10
3313until i == 0
3314 print i
3315 i -= 1
3316
3317until running == false do my_function!
3318```
3319
3320<YueDisplay>
3321
3322```yue
3323i = 10
3324until i == 0
3325 print i
3326 i -= 1
3327until running == false do my_function!
3328```
3329
3330</YueDisplay>
3331
3332Like for loops, the while loop can also be used as an expression. While and until loop expressions support `break` with multiple return values.
3333
3334```yuescript
3335value, doubled = while true
3336 n = get_next!
3337 break n, n * 2 if n > 10
3338```
3339
3340<YueDisplay>
3341
3342```yue
3343value, doubled = while true
3344 n = get_next!
3345 break n, n * 2 if n > 10
3346```
3347
3348</YueDisplay>
3349
3350Additionally, for a function to return the accumulated value of a while loop, the statement must be explicitly returned.
3351
3352## Repeat Loop
3353
3354The repeat loop comes from Lua:
3355
3356```yuescript
3357i = 10
3358repeat
3359 print i
3360 i -= 1
3361until i == 0
3362```
3363
3364<YueDisplay>
3365
3366```yue
3367i = 10
3368repeat
3369 print i
3370 i -= 1
3371until i == 0
3372```
3373
3374</YueDisplay>
3375
3376Repeat loop expressions also support `break` with multiple return values:
3377
3378```yuescript
3379i = 1
3380value, scaled = repeat
3381 break i, i * 100 if i > 3
3382 i += 1
3383until false
3384```
3385
3386<YueDisplay>
3387
3388```yue
3389i = 1
3390value, scaled = repeat
3391 break i, i * 100 if i > 3
3392 i += 1
3393until false
3394```
3395
3396</YueDisplay>
3397
3398# Function Stubs
3399
3400It is common to pass a function from an object around as a value, for example, passing an instance method into a function as a callback. If the function expects the object it is operating on as the first argument then you must somehow bundle that object with the function so it can be called properly.
3401
3402The function stub syntax is a shorthand for creating a new closure function that bundles both the object and function. This new function calls the wrapped function in the correct context of the object.
3403
3404Its syntax is the same as calling an instance method with the \ operator but with no argument list provided.
3405
3406```yuescript
3407my_object = {
3408 value: 1000
3409 write: => print "the value:", @value
3410}
3411
3412run_callback = (func) ->
3413 print "running callback..."
3414 func!
3415
3416-- this will not work:
3417-- the function has to no reference to my_object
3418run_callback my_object.write
3419
3420-- function stub syntax
3421-- lets us bundle the object into a new function
3422run_callback my_object\write
3423```
3424
3425<YueDisplay>
3426
3427```yue
3428my_object = {
3429 value: 1000
3430 write: => print "the value:", @value
3431}
3432
3433run_callback = (func) ->
3434 print "running callback..."
3435 func!
3436
3437-- this will not work:
3438-- the function has to no reference to my_object
3439run_callback my_object.write
3440
3441-- function stub syntax
3442-- lets us bundle the object into a new function
3443run_callback my_object\write
3444```
3445
3446</YueDisplay>
3447
3448# Backcalls
3449
3450Backcalls are used for unnesting callbacks. They are defined using arrows pointed to the left as the last parameter by default filling in a function call. All the syntax is mostly the same as regular arrow functions except that it is just pointing the other way and the function body does not require indent.
3451
3452```yuescript
3453x <- f
3454print "hello" .. x
3455```
3456
3457<YueDisplay>
3458
3459```yue
3460x <- f
3461print "hello" .. x
3462```
3463
3464</YueDisplay>
3465
3466Fat arrow functions are also available.
3467
3468```yuescript
3469<= f
3470print @value
3471```
3472
3473<YueDisplay>
3474
3475```yue
3476<= f
3477print @value
3478```
3479
3480</YueDisplay>
3481
3482You can specify a placeholder for where you want the backcall function to go as a parameter.
3483
3484```yuescript
3485(x) <- map _, [1, 2, 3]
3486x * 2
3487```
3488
3489<YueDisplay>
3490
3491```yue
3492(x) <- map _, [1, 2, 3]
3493x * 2
3494```
3495
3496</YueDisplay>
3497
3498If you wish to have further code after your backcalls, you can set them aside with a do statement. And the parentheses can be omitted with non-fat arrow functions.
3499
3500```yuescript
3501result, msg = do
3502 data <- readAsync "filename.txt"
3503 print data
3504 info <- processAsync data
3505 check info
3506print result, msg
3507```
3508
3509<YueDisplay>
3510
3511```yue
3512result, msg = do
3513 data <- readAsync "filename.txt"
3514 print data
3515 info <- processAsync data
3516 check info
3517print result, msg
3518```
3519
3520</YueDisplay>
3521
3522# Function Literals
3523
3524All functions are created using a function expression. A simple function is denoted using the arrow: **->**.
3525
3526```yuescript
3527my_function = ->
3528my_function() -- call the empty function
3529```
3530
3531<YueDisplay>
3532
3533```yue
3534my_function = ->
3535my_function() -- call the empty function
3536```
3537
3538</YueDisplay>
3539
3540The body of the function can either be one statement placed directly after the arrow, or it can be a series of statements indented on the following lines:
3541
3542```yuescript
3543func_a = -> print "hello world"
3544
3545func_b = ->
3546 value = 100
3547 print "The value:", value
3548```
3549
3550<YueDisplay>
3551
3552```yue
3553func_a = -> print "hello world"
3554
3555func_b = ->
3556 value = 100
3557 print "The value:", value
3558```
3559
3560</YueDisplay>
3561
3562If a function has no arguments, it can be called using the ! operator, instead of empty parentheses. The ! invocation is the preferred way to call functions with no arguments.
3563
3564```yuescript
3565func_a!
3566func_b()
3567```
3568
3569<YueDisplay>
3570
3571```yue
3572func_a!
3573func_b()
3574```
3575
3576</YueDisplay>
3577
3578Functions with arguments can be created by preceding the arrow with a list of argument names in parentheses:
3579
3580```yuescript
3581sum = (x, y) -> print "sum", x + y
3582```
3583
3584<YueDisplay>
3585
3586```yue
3587sum = (x, y) -> print "sum", x + y
3588```
3589
3590</YueDisplay>
3591
3592Functions can be called by listing the arguments after the name of an expression that evaluates to a function. When chaining together function calls, the arguments are applied to the closest function to the left.
3593
3594```yuescript
3595sum 10, 20
3596print sum 10, 20
3597
3598a b c "a", "b", "c"
3599```
3600
3601<YueDisplay>
3602
3603```yue
3604sum 10, 20
3605print sum 10, 20
3606
3607a b c "a", "b", "c"
3608```
3609
3610</YueDisplay>
3611
3612In order to avoid ambiguity in when calling functions, parentheses can also be used to surround the arguments. This is required here in order to make sure the right arguments get sent to the right functions.
3613
3614```yuescript
3615print "x:", sum(10, 20), "y:", sum(30, 40)
3616```
3617
3618<YueDisplay>
3619
3620```yue
3621print "x:", sum(10, 20), "y:", sum(30, 40)
3622```
3623
3624</YueDisplay>
3625
3626There must not be any space between the opening parenthesis and the function.
3627
3628Functions will coerce the last statement in their body into a return statement, this is called implicit return:
3629
3630```yuescript
3631sum = (x, y) -> x + y
3632print "The sum is ", sum 10, 20
3633```
3634
3635<YueDisplay>
3636
3637```yue
3638sum = (x, y) -> x + y
3639print "The sum is ", sum 10, 20
3640```
3641
3642</YueDisplay>
3643
3644And if you need to explicitly return, you can use the return keyword:
3645
3646```yuescript
3647sum = (x, y) -> return x + y
3648```
3649
3650<YueDisplay>
3651
3652```yue
3653sum = (x, y) -> return x + y
3654```
3655
3656</YueDisplay>
3657
3658Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas:
3659
3660```yuescript
3661mystery = (x, y) -> x + y, x - y
3662a, b = mystery 10, 20
3663```
3664
3665<YueDisplay>
3666
3667```yue
3668mystery = (x, y) -> x + y, x - y
3669a, b = mystery 10, 20
3670```
3671
3672</YueDisplay>
3673
3674## Fat Arrows
3675
3676Because it is an idiom in Lua to send an object as the first argument when calling a method, a special syntax is provided for creating functions which automatically includes a self argument.
3677
3678```yuescript
3679func = (num) => @value + num
3680```
3681
3682<YueDisplay>
3683
3684```yue
3685func = (num) => @value + num
3686```
3687
3688</YueDisplay>
3689
3690## Argument Defaults
3691
3692It is possible to provide default values for the arguments of a function. An argument is determined to be empty if its value is nil. Any nil arguments that have a default value will be replace before the body of the function is run.
3693
3694```yuescript
3695my_function = (name = "something", height = 100) ->
3696 print "Hello I am", name
3697 print "My height is", height
3698```
3699
3700<YueDisplay>
3701
3702```yue
3703my_function = (name = "something", height = 100) ->
3704 print "Hello I am", name
3705 print "My height is", height
3706```
3707
3708</YueDisplay>
3709
3710An argument default value expression is evaluated in the body of the function in the order of the argument declarations. For this reason default values have access to previously declared arguments.
3711
3712```yuescript
3713some_args = (x = 100, y = x + 1000) ->
3714 print x + y
3715```
3716
3717<YueDisplay>
3718
3719```yue
3720some_args = (x = 100, y = x + 1000) ->
3721 print x + y
3722```
3723
3724</YueDisplay>
3725
3726## Considerations
3727
3728Because of the expressive parentheses-less way of calling functions, some restrictions must be put in place to avoid parsing ambiguity involving whitespace.
3729
3730The minus sign plays two roles, a unary negation operator and a binary subtraction operator. Consider how the following examples compile:
3731
3732```yuescript
3733a = x - 10
3734b = x-10
3735c = x -y
3736d = x- z
3737```
3738
3739<YueDisplay>
3740
3741```yue
3742a = x - 10
3743b = x-10
3744c = x -y
3745d = x- z
3746```
3747
3748</YueDisplay>
3749
3750The precedence of the first argument of a function call can be controlled using whitespace if the argument is a literal string. In Lua, it is common to leave off parentheses when calling a function with a single string or table literal.
3751
3752When there is no space between a variable and a string literal, the function call takes precedence over any following expressions. No other arguments can be passed to the function when it is called this way.
3753
3754Where there is a space following a variable and a string literal, the function call acts as show above. The string literal belongs to any following expressions (if they exist), which serves as the argument list.
3755
3756```yuescript
3757x = func"hello" + 100
3758y = func "hello" + 100
3759```
3760
3761<YueDisplay>
3762
3763```yue
3764x = func"hello" + 100
3765y = func "hello" + 100
3766```
3767
3768</YueDisplay>
3769
3770## Multi-line arguments
3771
3772When calling functions that take a large number of arguments, it is convenient to split the argument list over multiple lines. Because of the white-space sensitive nature of the language, care must be taken when splitting up the argument list.
3773
3774If an argument list is to be continued onto the next line, the current line must end in a comma. And the following line must be indented more than the current indentation. Once indented, all other argument lines must be at the same level of indentation to be part of the argument list
3775
3776```yuescript
3777my_func 5, 4, 3,
3778 8, 9, 10
3779
3780cool_func 1, 2,
3781 3, 4,
3782 5, 6,
3783 7, 8
3784```
3785
3786<YueDisplay>
3787
3788```yue
3789my_func 5, 4, 3,
3790 8, 9, 10
3791
3792cool_func 1, 2,
3793 3, 4,
3794 5, 6,
3795 7, 8
3796```
3797
3798</YueDisplay>
3799
3800This type of invocation can be nested. The level of indentation is used to determine to which function the arguments belong to.
3801
3802```yuescript
3803my_func 5, 6, 7,
3804 6, another_func 6, 7, 8,
3805 9, 1, 2,
3806 5, 4
3807```
3808
3809<YueDisplay>
3810
3811```yue
3812my_func 5, 6, 7,
3813 6, another_func 6, 7, 8,
3814 9, 1, 2,
3815 5, 4
3816```
3817
3818</YueDisplay>
3819
3820Because tables also use the comma as a delimiter, this indentation syntax is helpful for letting values be part of the argument list instead of being part of the table.
3821
3822```yuescript
3823x = [
3824 1, 2, 3, 4, a_func 4, 5,
3825 5, 6,
3826 8, 9, 10
3827]
3828```
3829
3830<YueDisplay>
3831
3832```yue
3833x = [
3834 1, 2, 3, 4, a_func 4, 5,
3835 5, 6,
3836 8, 9, 10
3837]
3838```
3839
3840</YueDisplay>
3841
3842Although uncommon, notice how we can give a deeper indentation for function arguments if we know we will be using a lower indentation further on.
3843
3844```yuescript
3845y = [ my_func 1, 2, 3,
3846 4, 5,
3847 5, 6, 7
3848]
3849```
3850
3851<YueDisplay>
3852
3853```yue
3854y = [ my_func 1, 2, 3,
3855 4, 5,
3856 5, 6, 7
3857]
3858```
3859
3860</YueDisplay>
3861
3862The same thing can be done with other block level statements like conditionals. We can use indentation level to determine what statement a value belongs to:
3863
3864```yuescript
3865if func 1, 2, 3,
3866 "hello",
3867 "world"
3868 print "hello"
3869 print "I am inside if"
3870
3871if func 1, 2, 3,
3872 "hello",
3873 "world"
3874 print "hello"
3875 print "I am inside if"
3876```
3877
3878<YueDisplay>
3879
3880```yue
3881if func 1, 2, 3,
3882 "hello",
3883 "world"
3884 print "hello"
3885 print "I am inside if"
3886
3887if func 1, 2, 3,
3888 "hello",
3889 "world"
3890 print "hello"
3891 print "I am inside if"
3892```
3893
3894</YueDisplay>
3895
3896## Parameter Destructuring
3897
3898YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available:
3899
3900- **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`).
3901
3902- **Unwrapped simple table syntax**, starting with a sequence of key-value or shorthand bindings and continuing until another expression terminates it (e.g., `:a, b: b1, :c`). This form extracts multiple fields from the same object.
3903
3904```yuescript
3905f1 = (:a, :b, :c) ->
3906 print a, b, c
3907
3908f1 a: 1, b: "2", c: {}
3909
3910f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3911 print a1, b, c
3912
3913arg1 = {a: 0}
3914f2 arg1, arg2
3915```
3916
3917<YueDisplay>
3918
3919```yue
3920f1 = (:a, :b, :c) ->
3921 print a, b, c
3922
3923f1 a: 1, b: "2", c: {}
3924
3925f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3926print a1, b, c
3927
3928arg1 = {a: 0}
3929f2 arg1, arg2
3930```
3931
3932</YueDisplay>
3933
3934## Prefixed Return Expression
3935
3936When working with deeply nested function bodies, it can be tedious to maintain readability and consistency of the return value. To address this, YueScript introduces the **Prefixed Return Expression** syntax. Its form is as follows:
3937
3938```yuescript
3939findFirstEven = (list): nil ->
3940 for item in *list
3941 if type(item) == "table"
3942 for sub in *item
3943 if sub % 2 == 0
3944 return sub
3945```
3946
3947<YueDisplay>
3948
3949```yue
3950findFirstEven = (list): nil ->
3951 for item in *list
3952 if type(item) == "table"
3953 for sub in *item
3954 if sub % 2 == 0
3955 return sub
3956```
3957
3958</YueDisplay>
3959
3960This is equivalent to:
3961
3962```yuescript
3963findFirstEven = (list) ->
3964 for item in *list
3965 if type(item) == "table"
3966 for sub in *item
3967 if sub % 2 == 0
3968 return sub
3969 nil
3970```
3971
3972<YueDisplay>
3973
3974```yue
3975findFirstEven = (list) ->
3976 for item in *list
3977 if type(item) == "table"
3978 for sub in *item
3979 if sub % 2 == 0
3980 return sub
3981 nil
3982```
3983
3984</YueDisplay>
3985
3986The only difference is that you can move the final return expression before the `->` or `=>` token to indicate the function’s implicit return value as the last statement. This way, even in functions with multiple nested loops or conditional branches, you no longer need to write a trailing return expression at the end of the function body, making the logic structure more straightforward and easier to follow.
3987
3988## Named Varargs
3989
3990You can use the `(...t) ->` syntax to automatically store varargs into a named table. This table will contain all passed arguments (including `nil` values), and the `n` field of the table will store the actual number of arguments passed (including `nil` values).
3991
3992```yuescript
3993f = (...t) ->
3994 print "argument count:", t.n
3995 print "table length:", #t
3996 for i = 1, t.n
3997 print t[i]
3998
3999f 1, 2, 3
4000f "a", "b", "c", "d"
4001f!
4002
4003-- Handling cases with nil values
4004process = (...args) ->
4005 sum = 0
4006 for i = 1, args.n
4007 if args[i] != nil and type(args[i]) == "number"
4008 sum += args[i]
4009 sum
4010
4011process 1, nil, 3, nil, 5
4012```
4013
4014<YueDisplay>
4015
4016```yue
4017f = (...t) ->
4018 print "argument count:", t.n
4019 print "table length:", #t
4020 for i = 1, t.n
4021 print t[i]
4022
4023f 1, 2, 3
4024f "a", "b", "c", "d"
4025f!
4026
4027-- Handling cases with nil values
4028process = (...args) ->
4029 sum = 0
4030 for i = 1, args.n
4031 if args[i] != nil and type(args[i]) == "number"
4032 sum += args[i]
4033 sum
4034
4035process 1, nil, 3, nil, 5
4036```
4037
4038</YueDisplay>
4039
4040# Whitespace
4041
4042YueScript is a whitespace significant language. You have to write some code block in the same indent with space **' '** or tab **'\t'** like function body, value list and some control blocks. And expressions containing different whitespaces might mean different things. Tab is treated like 4 space, but it's better not mix the use of spaces and tabs.
4043
4044## Statement Separator
4045
4046A statement normally ends at a line break. You can also use a semicolon `;` to explicitly terminate a statement, which allows writing multiple statements on the same line:
4047
4048```yuescript
4049a = 1; b = 2; print a + b
4050```
4051
4052<YueDisplay>
4053
4054```yue
4055a = 1; b = 2; print a + b
4056```
4057
4058</YueDisplay>
4059
4060## Multiline Chaining
4061
4062You can write multi-line chaining function calls with a same indent.
4063
4064```yuescript
4065Rx.Observable
4066 .fromRange 1, 8
4067 \filter (x) -> x % 2 == 0
4068 \concat Rx.Observable.of 'who do we appreciate'
4069 \map (value) -> value .. '!'
4070 \subscribe print
4071```
4072
4073<YueDisplay>
4074
4075```yue
4076Rx.Observable
4077 .fromRange 1, 8
4078 \filter (x) -> x % 2 == 0
4079 \concat Rx.Observable.of 'who do we appreciate'
4080 \map (value) -> value .. '!'
4081 \subscribe print
4082```
4083
4084</YueDisplay>
4085
4086# Comment
4087
4088```yuescript
4089-- I am a comment
4090
4091str = --[[
4092This is a multi-line comment.
4093It's OK.
4094]] strA \ -- comment 1
4095 .. strB \ -- comment 2
4096 .. strC
4097
4098func --[[port]] 3000, --[[ip]] "192.168.1.1"
4099```
4100
4101<YueDisplay>
4102
4103```yue
4104-- I am a comment
4105
4106str = --[[
4107This is a multi-line comment.
4108It's OK.
4109]] strA \ -- comment 1
4110 .. strB \ -- comment 2
4111 .. strC
4112
4113func --[[port]] 3000, --[[ip]] "192.168.1.1"
4114```
4115
4116</YueDisplay>
4117
4118# Attributes
4119
4120Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4.
4121
4122```yuescript
4123const a = 123
4124close _ = <close>: -> print "Out of scope."
4125```
4126
4127<YueDisplay>
4128
4129```yue
4130const a = 123
4131close _ = <close>: -> print "Out of scope."
4132```
4133
4134</YueDisplay>
4135
4136You can do desctructuring with variables attributed as constant.
4137
4138```yuescript
4139const {:a, :b, c, d} = tb
4140-- a = 1
4141```
4142
4143<YueDisplay>
4144
4145```yue
4146const {:a, :b, c, d} = tb
4147-- a = 1
4148```
4149
4150</YueDisplay>
4151
4152You can also declare a global variable to be `const`.
4153
4154```yuescript
4155global const Constant = 123
4156-- Constant = 1
4157```
4158
4159<YueDisplay>
4160
4161```yue
4162global const Constant = 123
4163-- Constant = 1
4164```
4165
4166</YueDisplay>
4167
4168# Operator
4169
4170All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes.
4171
4172```yuescript
4173tb\func! if tb ~= nil
4174tb::func! if tb != nil
4175```
4176
4177<YueDisplay>
4178
4179```yue
4180tb\func! if tb ~= nil
4181tb::func! if tb != nil
4182```
4183
4184</YueDisplay>
4185
4186## Chaining Comparisons
4187
4188Comparisons can be arbitrarily chained:
4189
4190```yuescript
4191print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4192-- output: true
4193
4194a = 5
4195print 1 <= a <= 10
4196-- output: true
4197```
4198
4199<YueDisplay>
4200
4201```yue
4202print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4203-- output: true
4204
4205a = 5
4206print 1 <= a <= 10
4207-- output: true
4208```
4209
4210</YueDisplay>
4211
4212Note the evaluation behavior of chained comparisons:
4213
4214```yuescript
4215v = (x) ->
4216 print x
4217 x
4218
4219print v(1) < v(2) <= v(3)
4220--[[
4221 output:
4222 2
4223 1
4224 3
4225 true
4226]]
4227
4228print v(1) > v(2) <= v(3)
4229--[[
4230 output:
4231 2
4232 1
4233 false
4234]]
4235```
4236
4237<YueDisplay>
4238
4239```yue
4240v = (x) ->
4241 print x
4242 x
4243
4244print v(1) < v(2) <= v(3)
4245--[[
4246 output:
4247 2
4248 1
4249 3
4250 true
4251]]
4252
4253print v(1) > v(2) <= v(3)
4254--[[
4255 output:
4256 2
4257 1
4258 false
4259]]
4260```
4261
4262</YueDisplay>
4263
4264The middle expression is only evaluated once, rather than twice as it would be if the expression were written as `v(1) < v(2) and v(2) <= v(3)`. However, the order of evaluations in a chained comparison is undefined. It is strongly recommended not to use expressions with side effects (such as printing) in chained comparisons. If side effects are required, the short-circuit `and` operator should be used explicitly.
4265
4266## Table Appending
4267
4268The **[] =** operator is used to append values to tables.
4269
4270```yuescript
4271tab = []
4272tab[] = "Value"
4273```
4274
4275<YueDisplay>
4276
4277```yue
4278tab = []
4279tab[] = "Value"
4280```
4281
4282</YueDisplay>
4283
4284You can also use the spread operator `...` to append all elements from one list to another:
4285
4286```yuescript
4287tbA = [1, 2, 3]
4288tbB = [4, 5, 6]
4289tbA[] = ...tbB
4290-- tbA is now [1, 2, 3, 4, 5, 6]
4291```
4292
4293<YueDisplay>
4294
4295```yue
4296tbA = [1, 2, 3]
4297tbB = [4, 5, 6]
4298tbA[] = ...tbB
4299-- tbA is now [1, 2, 3, 4, 5, 6]
4300```
4301
4302</YueDisplay>
4303
4304## Table Spreading
4305
4306You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals.
4307
4308```yuescript
4309parts =
4310 * "shoulders"
4311 * "knees"
4312lyrics =
4313 * "head"
4314 * ...parts
4315 * "and"
4316 * "toes"
4317
4318copy = {...other}
4319
4320a = {1, 2, 3, x: 1}
4321b = {4, 5, y: 1}
4322merge = {...a, ...b}
4323```
4324
4325<YueDisplay>
4326
4327```yue
4328parts =
4329 * "shoulders"
4330 * "knees"
4331lyrics =
4332 * "head"
4333 * ...parts
4334 * "and"
4335 * "toes"
4336
4337copy = {...other}
4338
4339a = {1, 2, 3, x: 1}
4340b = {4, 5, y: 1}
4341merge = {...a, ...b}
4342```
4343
4344</YueDisplay>
4345
4346## Table Reversed Indexing
4347
4348You can use the **#** operator to get the last elements of a table.
4349
4350```yuescript
4351last = data.items[#]
4352second_last = data.items[#-1]
4353data.items[#] = 1
4354```
4355
4356<YueDisplay>
4357
4358```yue
4359last = data.items[#]
4360second_last = data.items[#-1]
4361data.items[#] = 1
4362```
4363
4364</YueDisplay>
4365
4366## Metatable
4367
4368The **<>** operator can be used as a shortcut for metatable manipulation.
4369
4370### Metatable Creation
4371
4372Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**.
4373
4374```yuescript
4375mt = {}
4376add = (right) => <>: mt, value: @value + right.value
4377mt.__add = add
4378
4379a = <>: mt, value: 1
4380 -- set field with variable of the same name
4381b = :<add>, value: 2
4382c = <add>: mt.__add, value: 3
4383
4384d = a + b + c
4385print d.value
4386
4387close _ = <close>: -> print "out of scope"
4388```
4389
4390<YueDisplay>
4391
4392```yue
4393mt = {}
4394add = (right) => <>: mt, value: @value + right.value
4395mt.__add = add
4396
4397a = <>: mt, value: 1
4398 -- set field with variable of the same name
4399b = :<add>, value: 2
4400c = <add>: mt.__add, value: 3
4401
4402d = a + b + c
4403print d.value
4404
4405close _ = <close>: -> print "out of scope"
4406```
4407
4408</YueDisplay>
4409
4410### Metatable Accessing
4411
4412Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**.
4413
4414```yuescript
4415-- create with metatable containing field "value"
4416tb = <"value">: 123
4417tb.<index> = tb.<>
4418print tb.value
4419
4420tb.<> = __index: {item: "hello"}
4421print tb.item
4422```
4423
4424<YueDisplay>
4425
4426```yue
4427-- create with metatable containing field "value"
4428tb = <"value">: 123
4429tb.<index> = tb.<>
4430print tb.value
4431tb.<> = __index: {item: "hello"}
4432print tb.item
4433```
4434
4435</YueDisplay>
4436
4437### Metatable Destructure
4438
4439Destruct metatable with metamethod key surrounded by **<>**.
4440
4441```yuescript
4442{item, :new, :<close>, <index>: getter} = tb
4443print item, new, close, getter
4444```
4445
4446<YueDisplay>
4447
4448```yue
4449{item, :new, :<close>, <index>: getter} = tb
4450print item, new, close, getter
4451```
4452
4453</YueDisplay>
4454
4455## Existence
4456
4457The **?** operator can be used in a variety of contexts to check for existence.
4458
4459```yuescript
4460func?!
4461print abc?["hello world"]?.xyz
4462
4463x = tab?.value
4464len = utf8?.len or string?.len or (o) -> #o
4465
4466if print and x?
4467 print x
4468
4469with? io.open "test.txt", "w"
4470 \write "hello"
4471 \close!
4472```
4473
4474<YueDisplay>
4475
4476```yue
4477func?!
4478print abc?["hello world"]?.xyz
4479
4480x = tab?.value
4481len = utf8?.len or string?.len or (o) -> #o
4482
4483if print and x?
4484 print x
4485
4486with? io.open "test.txt", "w"
4487 \write "hello"
4488 \close!
4489```
4490
4491</YueDisplay>
4492
4493## Piping
4494
4495Instead of a series of nested function calls, you can pipe values with operator **|>**.
4496
4497```yuescript
4498"hello" |> print
44991 |> print 2 -- insert pipe item as the first argument
45002 |> print 1, _, 3 -- pipe with a placeholder
4501
4502-- pipe expression in multiline
4503readFile "example.txt"
4504 |> extract language, {}
4505 |> parse language
4506 |> emit
4507 |> render
4508 |> print
4509```
4510
4511<YueDisplay>
4512
4513```yue
4514"hello" |> print
45151 |> print 2 -- insert pipe item as the first argument
45162 |> print 1, _, 3 -- pipe with a placeholder
4517-- pipe expression in multiline
4518readFile "example.txt"
4519 |> extract language, {}
4520 |> parse language
4521 |> emit
4522 |> render
4523 |> print
4524```
4525
4526</YueDisplay>
4527
4528## Nil Coalescing
4529
4530The nil-coalescing operator **??** returns the value of its left-hand operand if it isn't **nil**; otherwise, it evaluates the right-hand operand and returns its result. The **??** operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-nil.
4531
4532```yuescript
4533local a, b, c, d
4534a = b ?? c ?? d
4535func a ?? {}
4536
4537a ??= false
4538```
4539
4540<YueDisplay>
4541
4542```yue
4543local a, b, c, d
4544a = b ?? c ?? d
4545func a ?? {}
4546a ??= false
4547```
4548
4549</YueDisplay>
4550
4551## Implicit Object
4552
4553You can write a list of implicit structures that starts with the symbol **\*** or **-** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent.
4554
4555```yuescript
4556-- assignment with implicit object
4557list =
4558 * 1
4559 * 2
4560 * 3
4561
4562-- function call with implicit object
4563func
4564 * 1
4565 * 2
4566 * 3
4567
4568-- return with implicit object
4569f = ->
4570 return
4571 * 1
4572 * 2
4573 * 3
4574
4575-- table with implicit object
4576tb =
4577 name: "abc"
4578
4579 values:
4580 - "a"
4581 - "b"
4582 - "c"
4583
4584 objects:
4585 - name: "a"
4586 value: 1
4587 func: => @value + 1
4588 tb:
4589 fieldA: 1
4590
4591 - name: "b"
4592 value: 2
4593 func: => @value + 2
4594 tb: { }
4595
4596```
4597
4598<YueDisplay>
4599
4600```yue
4601-- assignment with implicit object
4602list =
4603 * 1
4604 * 2
4605 * 3
4606
4607-- function call with implicit object
4608func
4609 * 1
4610 * 2
4611 * 3
4612
4613-- return with implicit object
4614f = ->
4615 return
4616 * 1
4617 * 2
4618 * 3
4619
4620-- table with implicit object
4621tb =
4622 name: "abc"
4623
4624 values:
4625 - "a"
4626 - "b"
4627 - "c"
4628
4629 objects:
4630 - name: "a"
4631 value: 1
4632 func: => @value + 1
4633 tb:
4634 fieldA: 1
4635
4636 - name: "b"
4637 value: 2
4638 func: => @value + 2
4639 tb: { }
4640```
4641
4642</YueDisplay>
4643
4644# Literals
4645
4646All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**.
4647
4648Unlike Lua, Line breaks are allowed inside of single and double quote strings without an escape sequence:
4649
4650```yuescript
4651some_string = "Here is a string
4652 that has a line break in it."
4653
4654-- You can mix expressions into string literals using #{} syntax.
4655-- String interpolation is only available in double quoted strings.
4656print "I am #{math.random! * 100}% sure."
4657```
4658
4659<YueDisplay>
4660
4661```yue
4662some_string = "Here is a string
4663 that has a line break in it."
4664
4665-- You can mix expressions into string literals using #{} syntax.
4666-- String interpolation is only available in double quoted strings.
4667print "I am #{math.random! * 100}% sure."
4668```
4669
4670</YueDisplay>
4671
4672## Number Literals
4673
4674You can use underscores in a number literal to increase readability.
4675
4676```yuescript
4677integer = 1_000_000
4678hex = 0xEF_BB_BF
4679binary = 0B10011
4680```
4681
4682<YueDisplay>
4683
4684```yue
4685integer = 1_000_000
4686hex = 0xEF_BB_BF
4687binary = 0B10011
4688```
4689
4690</YueDisplay>
4691
4692## YAML Multiline String
4693
4694The `|` prefix introduces a YAML-style multiline string literal:
4695
4696```yuescript
4697str = |
4698 key: value
4699 list:
4700 - item1
4701 - #{expr}
4702```
4703
4704<YueDisplay>
4705
4706```yue
4707str = |
4708 key: value
4709 list:
4710 - item1
4711 - #{expr}
4712```
4713
4714</YueDisplay>
4715
4716This allows writing structured multiline text conveniently. All line breaks and indentation are preserved relative to the first non-empty line, and expressions inside `#{...}` are interpolated automatically as `tostring(expr)`.
4717
4718YAML Multiline String automatically detects the common leading whitespace prefix (minimum indentation across all non-empty lines) and removes it from all lines. This makes it easy to indent your code visually without affecting the resulting string content.
4719
4720```yuescript
4721fn = ->
4722 str = |
4723 foo:
4724 bar: baz
4725 return str
4726```
4727
4728<YueDisplay>
4729
4730```yue
4731fn = ->
4732 str = |
4733 foo:
4734 bar: baz
4735 return str
4736```
4737
4738</YueDisplay>
4739
4740Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures.
4741
4742All special characters like quotes (`"`) and backslashes (`\`) in the YAMLMultiline block are automatically escaped so that the generated Lua string is syntactically valid and behaves as expected.
4743
4744```yuescript
4745str = |
4746 path: "C:\Program Files\App"
4747 note: 'He said: "#{Hello}!"'
4748```
4749
4750<YueDisplay>
4751
4752```yue
4753str = |
4754 path: "C:\Program Files\App"
4755 note: 'He said: "#{Hello}!"'
4756```
4757
4758</YueDisplay>
4759
4760# Module
4761
4762## Import
4763
4764The import statement is a syntax sugar for requiring a module or help extracting items from an imported module. The imported items are const by default.
4765
4766```yuescript
4767-- used as table destructuring
4768do
4769 import insert, concat from table
4770 -- report error when assigning to insert, concat
4771 import C, Ct, Cmt from require "lpeg"
4772 -- shortcut for implicit requiring
4773 import x, y, z from 'mymodule'
4774 -- import with Python style
4775 from 'module' import a, b, c
4776
4777-- shortcut for requring a module
4778do
4779 import 'module'
4780 import 'module_x'
4781 import "d-a-s-h-e-s"
4782 import "module.part"
4783
4784-- requring module with aliasing or table destructuring
4785do
4786 import "player" as PlayerModule
4787 import "lpeg" as :C, :Ct, :Cmt
4788 import "export" as {one, two, Something:{umm:{ch}}}
4789```
4790
4791<YueDisplay>
4792
4793```yue
4794-- used as table destructuring
4795do
4796 import insert, concat from table
4797 -- report error when assigning to insert, concat
4798 import C, Ct, Cmt from require "lpeg"
4799 -- shortcut for implicit requiring
4800 import x, y, z from 'mymodule'
4801 -- import with Python style
4802 from 'module' import a, b, c
4803
4804-- shortcut for requring a module
4805do
4806 import 'module'
4807 import 'module_x'
4808 import "d-a-s-h-e-s"
4809 import "module.part"
4810
4811-- requring module with aliasing or table destructuring
4812do
4813 import "player" as PlayerModule
4814 import "lpeg" as :C, :Ct, :Cmt
4815 import "export" as {one, two, Something:{umm:{ch}}}
4816```
4817
4818</YueDisplay>
4819
4820## Import Global
4821
4822You can import specific globals into local variables with `import`. When importing a chain of global variable accessings, the last field will be assigned to the local variable.
4823
4824```yuescript
4825do
4826 import tostring
4827 import table.concat
4828 print concat ["a", tostring 1]
4829```
4830
4831<YueDisplay>
4832
4833```yue
4834do
4835 import tostring
4836 import table.concat
4837 print concat ["a", tostring 1]
4838```
4839
4840</YueDisplay>
4841
4842### Automatic Global Variable Import
4843
4844You can place `import global` at the top of a block to automatically import all names that have not been explicitly declared or assigned in the current scope as globals. These implicit imports are treated as local consts that reference the corresponding globals at the position of the statement.
4845
4846Names that are explicitly declared as globals in the same scope will not be imported, so you can still assign to them.
4847
4848```yuescript
4849do
4850 import global
4851 print "hello"
4852 math.random 3
4853 -- print = nil -- error: imported globals are const
4854
4855do
4856 -- explicit global variable will not be imported
4857 import global
4858 global FLAG
4859 print FLAG
4860 FLAG = 123
4861```
4862
4863<YueDisplay>
4864
4865```yue
4866do
4867 import global
4868 print "hello"
4869 math.random 3
4870 -- print = nil -- error: imported globals are const
4871
4872do
4873 -- explicit global variable will not be imported
4874 import global
4875 global FLAG
4876 print FLAG
4877 FLAG = 123
4878```
4879
4880</YueDisplay>
4881
4882## Export
4883
4884The export statement offers a concise way to define modules.
4885
4886### Named Export
4887
4888Named export will define a local variable as well as adding a field in the exported table.
4889
4890```yuescript
4891export a, b, c = 1, 2, 3
4892export cool = "cat"
4893
4894export What = if this
4895 "abc"
4896else
4897 "def"
4898
4899export y = ->
4900 hallo = 3434
4901
4902export class Something
4903 umm: "cool"
4904```
4905
4906<YueDisplay>
4907
4908```yue
4909export a, b, c = 1, 2, 3
4910export cool = "cat"
4911
4912export What = if this
4913 "abc"
4914else
4915 "def"
4916
4917export y = ->
4918 hallo = 3434
4919
4920export class Something
4921 umm: "cool"
4922```
4923
4924</YueDisplay>
4925
4926Doing named export with destructuring.
4927
4928```yuescript
4929export :loadstring, to_lua: tolua = yue
4930export {itemA: {:fieldA = 'default'}} = tb
4931```
4932
4933<YueDisplay>
4934
4935```yue
4936export :loadstring, to_lua: tolua = yue
4937export {itemA: {:fieldA = 'default'}} = tb
4938```
4939
4940</YueDisplay>
4941
4942Export named items from module without creating local variables.
4943
4944```yuescript
4945export.itemA = tb
4946export.<index> = items
4947export["a-b-c"] = 123
4948```
4949
4950<YueDisplay>
4951
4952```yue
4953export.itemA = tb
4954export.<index> = items
4955export["a-b-c"] = 123
4956```
4957
4958</YueDisplay>
4959
4960### Unnamed Export
4961
4962Unnamed export will add the target item into the array part of the exported table.
4963
4964```yuescript
4965d, e, f = 3, 2, 1
4966export d, e, f
4967
4968export if this
4969 123
4970else
4971 456
4972
4973export with tmp
4974 j = 2000
4975```
4976
4977<YueDisplay>
4978
4979```yue
4980d, e, f = 3, 2, 1
4981export d, e, f
4982
4983export if this
4984 123
4985else
4986 456
4987
4988export with tmp
4989 j = 2000
4990```
4991
4992</YueDisplay>
4993
4994### Default Export
4995
4996Using the **default** keyword in export statement to replace the exported table with any thing.
4997
4998```yuescript
4999export default ->
5000 print "hello"
5001 123
5002```
5003
5004<YueDisplay>
5005
5006```yue
5007export default ->
5008 print "hello"
5009 123
5010```
5011
5012</YueDisplay>
5013
5014# License: MIT
5015
5016Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\>
5017
5018Permission is hereby granted, free of charge, to any person obtaining a copy
5019of this software and associated documentation files (the "Software"), to deal
5020in the Software without restriction, including without limitation the rights
5021to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5022copies of the Software, and to permit persons to whom the Software is
5023furnished to do so, subject to the following conditions:
5024
5025The above copyright notice and this permission notice shall be included in all
5026copies or substantial portions of the Software.
5027
5028THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5029IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5030FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5031AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5032LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5033OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
5034SOFTWARE.
5035
5036# The YueScript Library
5037
5038Access it by `local yue = require("yue")` in Lua.
5039
5040## yue
5041
5042**Description:**
5043
5044The YueScript language library.
5045
5046### version
5047
5048**Type:** Field.
5049
5050**Description:**
5051
5052The YueScript version.
5053
5054**Signature:**
5055
5056```lua
5057version: string
5058```
5059
5060### dirsep
5061
5062**Type:** Field.
5063
5064**Description:**
5065
5066The file separator for the current platform.
5067
5068**Signature:**
5069
5070```lua
5071dirsep: string
5072```
5073
5074### yue_compiled
5075
5076**Type:** Field.
5077
5078**Description:**
5079
5080The compiled module code cache.
5081
5082**Signature:**
5083
5084```lua
5085yue_compiled: {string: string}
5086```
5087
5088### to_lua
5089
5090**Type:** Function.
5091
5092**Description:**
5093
5094The YueScript compiling function. It compiles the YueScript code to Lua code.
5095
5096**Signature:**
5097
5098```lua
5099to_lua: function(code: string, config?: Config):
5100 --[[codes]] string | nil,
5101 --[[error]] string | nil,
5102 --[[globals]] {{string, integer, integer}} | nil
5103```
5104
5105**Parameters:**
5106
5107| Parameter | Type | Description |
5108| --------- | ------ | -------------------------------- |
5109| code | string | The YueScript code. |
5110| config | Config | [Optional] The compiler options. |
5111
5112**Returns:**
5113
5114| Return Type | Description |
5115| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
5116| string \| nil | The compiled Lua code, or nil if the compilation failed. |
5117| string \| nil | The error message, or nil if the compilation succeeded. |
5118| {{string, integer, integer}} \| nil | The global variables appearing in the code (with name, row and column), or nil if the compiler option `lint_global` is false. |
5119
5120### file_exist
5121
5122**Type:** Function.
5123
5124**Description:**
5125
5126The source file existence checking function. Can be overridden to customize the behavior.
5127
5128**Signature:**
5129
5130```lua
5131file_exist: function(filename: string): boolean
5132```
5133
5134**Parameters:**
5135
5136| Parameter | Type | Description |
5137| --------- | ------ | -------------- |
5138| filename | string | The file name. |
5139
5140**Returns:**
5141
5142| Return Type | Description |
5143| ----------- | ------------------------ |
5144| boolean | Whether the file exists. |
5145
5146### read_file
5147
5148**Type:** Function.
5149
5150**Description:**
5151
5152The source file reading function. Can be overridden to customize the behavior.
5153
5154**Signature:**
5155
5156```lua
5157read_file: function(filename: string): string
5158```
5159
5160**Parameters:**
5161
5162| Parameter | Type | Description |
5163| --------- | ------ | -------------- |
5164| filename | string | The file name. |
5165
5166**Returns:**
5167
5168| Return Type | Description |
5169| ----------- | ----------------- |
5170| string | The file content. |
5171
5172### insert_loader
5173
5174**Type:** Function.
5175
5176**Description:**
5177
5178Insert the YueScript loader to the package loaders (searchers).
5179
5180**Signature:**
5181
5182```lua
5183insert_loader: function(pos?: integer): boolean
5184```
5185
5186**Parameters:**
5187
5188| Parameter | Type | Description |
5189| --------- | ------- | ----------------------------------------------------------- |
5190| pos | integer | [Optional] The position to insert the loader. Default is 3. |
5191
5192**Returns:**
5193
5194| Return Type | Description |
5195| ----------- | -------------------------------------------------------------------------------------------- |
5196| boolean | Whether the loader is inserted successfully. It will fail if the loader is already inserted. |
5197
5198### remove_loader
5199
5200**Type:** Function.
5201
5202**Description:**
5203
5204Remove the YueScript loader from the package loaders (searchers).
5205
5206**Signature:**
5207
5208```lua
5209remove_loader: function(): boolean
5210```
5211
5212**Returns:**
5213
5214| Return Type | Description |
5215| ----------- | --------------------------------------------------------------------------------------- |
5216| boolean | Whether the loader is removed successfully. It will fail if the loader is not inserted. |
5217
5218### loadstring
5219
5220**Type:** Function.
5221
5222**Description:**
5223
5224Loads YueScript code from a string into a function.
5225
5226**Signature:**
5227
5228```lua
5229loadstring: function(input: string, chunkname: string, env: table, config?: Config):
5230 --[[loaded function]] nil | function(...: any): (any...),
5231 --[[error]] string | nil
5232```
5233
5234**Parameters:**
5235
5236| Parameter | Type | Description |
5237| --------- | ------ | -------------------------------- |
5238| input | string | The YueScript code. |
5239| chunkname | string | The name of the code chunk. |
5240| env | table | The environment table. |
5241| config | Config | [Optional] The compiler options. |
5242
5243**Returns:**
5244
5245| Return Type | Description |
5246| --------------- | --------------------------------------------------- |
5247| function \| nil | The loaded function, or nil if the loading failed. |
5248| string \| nil | The error message, or nil if the loading succeeded. |
5249
5250### loadstring
5251
5252**Type:** Function.
5253
5254**Description:**
5255
5256Loads YueScript code from a string into a function.
5257
5258**Signature:**
5259
5260```lua
5261loadstring: function(input: string, chunkname: string, config?: Config):
5262 --[[loaded function]] nil | function(...: any): (any...),
5263 --[[error]] string | nil
5264```
5265
5266**Parameters:**
5267
5268| Parameter | Type | Description |
5269| --------- | ------ | -------------------------------- |
5270| input | string | The YueScript code. |
5271| chunkname | string | The name of the code chunk. |
5272| config | Config | [Optional] The compiler options. |
5273
5274**Returns:**
5275
5276| Return Type | Description |
5277| --------------- | --------------------------------------------------- |
5278| function \| nil | The loaded function, or nil if the loading failed. |
5279| string \| nil | The error message, or nil if the loading succeeded. |
5280
5281### loadstring
5282
5283**Type:** Function.
5284
5285**Description:**
5286
5287Loads YueScript code from a string into a function.
5288
5289**Signature:**
5290
5291```lua
5292loadstring: function(input: string, config?: Config):
5293 --[[loaded function]] nil | function(...: any): (any...),
5294 --[[error]] string | nil
5295```
5296
5297**Parameters:**
5298
5299| Parameter | Type | Description |
5300| --------- | ------ | -------------------------------- |
5301| input | string | The YueScript code. |
5302| config | Config | [Optional] The compiler options. |
5303
5304**Returns:**
5305
5306| Return Type | Description |
5307| --------------- | --------------------------------------------------- |
5308| function \| nil | The loaded function, or nil if the loading failed. |
5309| string \| nil | The error message, or nil if the loading succeeded. |
5310
5311### loadfile
5312
5313**Type:** Function.
5314
5315**Description:**
5316
5317Loads YueScript code from a file into a function.
5318
5319**Signature:**
5320
5321```lua
5322loadfile: function(filename: string, env: table, config?: Config):
5323 nil | function(...: any): (any...),
5324 string | nil
5325```
5326
5327**Parameters:**
5328
5329| Parameter | Type | Description |
5330| --------- | ------ | -------------------------------- |
5331| filename | string | The file name. |
5332| env | table | The environment table. |
5333| config | Config | [Optional] The compiler options. |
5334
5335**Returns:**
5336
5337| Return Type | Description |
5338| --------------- | --------------------------------------------------- |
5339| function \| nil | The loaded function, or nil if the loading failed. |
5340| string \| nil | The error message, or nil if the loading succeeded. |
5341
5342### loadfile
5343
5344**Type:** Function.
5345
5346**Description:**
5347
5348Loads YueScript code from a file into a function.
5349
5350**Signature:**
5351
5352```lua
5353loadfile: function(filename: string, config?: Config):
5354 nil | function(...: any): (any...),
5355 string | nil
5356```
5357
5358**Parameters:**
5359
5360| Parameter | Type | Description |
5361| --------- | ------ | -------------------------------- |
5362| filename | string | The file name. |
5363| config | Config | [Optional] The compiler options. |
5364
5365**Returns:**
5366
5367| Return Type | Description |
5368| --------------- | --------------------------------------------------- |
5369| function \| nil | The loaded function, or nil if the loading failed. |
5370| string \| nil | The error message, or nil if the loading succeeded. |
5371
5372### dofile
5373
5374**Type:** Function.
5375
5376**Description:**
5377
5378Loads YueScript code from a file into a function and executes it.
5379
5380**Signature:**
5381
5382```lua
5383dofile: function(filename: string, env: table, config?: Config): any...
5384```
5385
5386**Parameters:**
5387
5388| Parameter | Type | Description |
5389| --------- | ------ | -------------------------------- |
5390| filename | string | The file name. |
5391| env | table | The environment table. |
5392| config | Config | [Optional] The compiler options. |
5393
5394**Returns:**
5395
5396| Return Type | Description |
5397| ----------- | ----------------------------------------- |
5398| any... | The return values of the loaded function. |
5399
5400### dofile
5401
5402**Type:** Function.
5403
5404**Description:**
5405
5406Loads YueScript code from a file into a function and executes it.
5407
5408**Signature:**
5409
5410```lua
5411dofile: function(filename: string, config?: Config): any...
5412```
5413
5414**Parameters:**
5415
5416| Parameter | Type | Description |
5417| --------- | ------ | -------------------------------- |
5418| filename | string | The file name. |
5419| config | Config | [Optional] The compiler options. |
5420
5421**Returns:**
5422
5423| Return Type | Description |
5424| ----------- | ----------------------------------------- |
5425| any... | The return values of the loaded function. |
5426
5427### find_modulepath
5428
5429**Type:** Function.
5430
5431**Description:**
5432
5433Resolves the YueScript module name to the file path.
5434
5435**Signature:**
5436
5437```lua
5438find_modulepath: function(name: string): string
5439```
5440
5441**Parameters:**
5442
5443| Parameter | Type | Description |
5444| --------- | ------ | ---------------- |
5445| name | string | The module name. |
5446
5447**Returns:**
5448
5449| Return Type | Description |
5450| ----------- | -------------- |
5451| string | The file path. |
5452
5453### pcall
5454
5455**Type:** Function.
5456
5457**Description:**
5458
5459Calls a function in protected mode.
5460Catches any errors and returns a status code and results or error object.
5461Rewrites the error line number to the original line number in the YueScript code when errors occur.
5462
5463**Signature:**
5464
5465```lua
5466pcall: function(f: function, ...: any): boolean, any...
5467```
5468
5469**Parameters:**
5470
5471| Parameter | Type | Description |
5472| --------- | -------- | ---------------------------------- |
5473| f | function | The function to call. |
5474| ... | any | Arguments to pass to the function. |
5475
5476**Returns:**
5477
5478| Return Type | Description |
5479| ------------ | ------------------------------------------------- |
5480| boolean, ... | Status code and function results or error object. |
5481
5482### require
5483
5484**Type:** Function.
5485
5486**Description:**
5487
5488Loads a given module. Can be either a Lua module or a YueScript module.
5489Rewrites the error line number to the original line number in the YueScript code if the module is a YueScript module and loading fails.
5490
5491**Signature:**
5492
5493```lua
5494require: function(name: string): any...
5495```
5496
5497**Parameters:**
5498
5499| Parameter | Type | Description |
5500| --------- | ------ | ------------------------------- |
5501| modname | string | The name of the module to load. |
5502
5503**Returns:**
5504
5505| Return Type | Description |
5506| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5507| any | The value stored at package.loaded[modname] if the module is already loaded.Otherwise, tries to find a loader and returns the final value of package.loaded[modname] and a loader data as a second result. |
5508
5509### p
5510
5511**Type:** Function.
5512
5513**Description:**
5514
5515Inspects the structures of the passed values and prints string representations.
5516
5517**Signature:**
5518
5519```lua
5520p: function(...: any)
5521```
5522
5523**Parameters:**
5524
5525| Parameter | Type | Description |
5526| --------- | ---- | ---------------------- |
5527| ... | any | The values to inspect. |
5528
5529### options
5530
5531**Type:** Field.
5532
5533**Description:**
5534
5535The current compiler options.
5536
5537**Signature:**
5538
5539```lua
5540options: Config.Options
5541```
5542
5543### traceback
5544
5545**Type:** Function.
5546
5547**Description:**
5548
5549The traceback function that rewrites the stack trace line numbers to the original line numbers in the YueScript code.
5550
5551**Signature:**
5552
5553```lua
5554traceback: function(message: string): string
5555```
5556
5557**Parameters:**
5558
5559| Parameter | Type | Description |
5560| --------- | ------ | ---------------------- |
5561| message | string | The traceback message. |
5562
5563**Returns:**
5564
5565| Return Type | Description |
5566| ----------- | -------------------------------- |
5567| string | The rewritten traceback message. |
5568
5569### is_ast
5570
5571**Type:** Function.
5572
5573**Description:**
5574
5575Checks whether the code matches the specified AST.
5576
5577**Signature:**
5578
5579```lua
5580is_ast: function(astName: string, code: string): boolean
5581```
5582
5583**Parameters:**
5584
5585| Parameter | Type | Description |
5586| --------- | ------ | ------------- |
5587| astName | string | The AST name. |
5588| code | string | The code. |
5589
5590**Returns:**
5591
5592| Return Type | Description |
5593| ----------- | --------------------------------- |
5594| boolean | Whether the code matches the AST. |
5595
5596### AST
5597
5598**Type:** Field.
5599
5600**Description:**
5601
5602The AST type definition with name, row, column and sub nodes.
5603
5604**Signature:**
5605
5606```lua
5607type AST = {string, integer, integer, any}
5608```
5609
5610### to_ast
5611
5612**Type:** Function.
5613
5614**Description:**
5615
5616Converts the code to the AST.
5617
5618**Signature:**
5619
5620```lua
5621to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
5622 --[[AST]] AST | nil,
5623 --[[error]] nil | string
5624```
5625
5626**Parameters:**
5627
5628| Parameter | Type | Description |
5629| -------------- | ------- | --------------------------------------------------------------------------------------------- |
5630| code | string | The code. |
5631| flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. |
5632| astName | string | [Optional] The AST name. Default is "File". |
5633| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is false. |
5634
5635**Returns:**
5636
5637| Return Type | Description |
5638| ------------- | ------------------------------------------------------ |
5639| AST \| nil | The AST, or nil if the conversion failed. |
5640| string \| nil | The error message, or nil if the conversion succeeded. |
5641
5642### format
5643
5644**Type:** Function.
5645
5646**Description:**
5647
5648Formats the YueScript code.
5649
5650**Signature:**
5651
5652```lua
5653format: function(code: string, tabSize?: number, reserveComment?: boolean): string
5654```
5655
5656**Parameters:**
5657
5658| Parameter | Type | Description |
5659| -------------- | ------- | --------------------------------------------------------------------- |
5660| code | string | The code. |
5661| tabSize | integer | [Optional] The tab size. Default is 4. |
5662| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is true. |
5663
5664**Returns:**
5665
5666| Return Type | Description |
5667| ----------- | ------------------- |
5668| string | The formatted code. |
5669
5670### \_\_call
5671
5672**Type:** Metamethod.
5673
5674**Description:**
5675
5676Requires the YueScript module.
5677Rewrites the error line number to the original line number in the YueScript code when loading fails.
5678
5679**Signature:**
5680
5681```lua
5682metamethod __call: function(self: yue, module: string): any...
5683```
5684
5685**Parameters:**
5686
5687| Parameter | Type | Description |
5688| --------- | ------ | ---------------- |
5689| module | string | The module name. |
5690
5691**Returns:**
5692
5693| Return Type | Description |
5694| ----------- | ----------------- |
5695| any | The module value. |
5696
5697## Config
5698
5699**Description:**
5700
5701The compiler compile options.
5702
5703### lint_global
5704
5705**Type:** Field.
5706
5707**Description:**
5708
5709Whether the compiler should collect the global variables appearing in the code.
5710
5711**Signature:**
5712
5713```lua
5714lint_global: boolean
5715```
5716
5717### implicit_return_root
5718
5719**Type:** Field.
5720
5721**Description:**
5722
5723Whether the compiler should do an implicit return for the root code block.
5724
5725**Signature:**
5726
5727```lua
5728implicit_return_root: boolean
5729```
5730
5731### reserve_line_number
5732
5733**Type:** Field.
5734
5735**Description:**
5736
5737Whether the compiler should reserve the original line number in the compiled code.
5738
5739**Signature:**
5740
5741```lua
5742reserve_line_number: boolean
5743```
5744
5745### reserve_comment
5746
5747**Type:** Field.
5748
5749**Description:**
5750
5751Whether the compiler should reserve the original comments in the compiled code.
5752
5753**Signature:**
5754
5755```lua
5756reserve_comment: boolean
5757```
5758
5759### space_over_tab
5760
5761**Type:** Field.
5762
5763**Description:**
5764
5765Whether the compiler should use the space character instead of the tab character in the compiled code.
5766
5767**Signature:**
5768
5769```lua
5770space_over_tab: boolean
5771```
5772
5773### same_module
5774
5775**Type:** Field.
5776
5777**Description:**
5778
5779Whether the compiler should treat the code to be compiled as the same currently being compiled module. For internal use only.
5780
5781**Signature:**
5782
5783```lua
5784same_module: boolean
5785```
5786
5787### line_offset
5788
5789**Type:** Field.
5790
5791**Description:**
5792
5793Whether the compiler error message should include the line number offset. For internal use only.
5794
5795**Signature:**
5796
5797```lua
5798line_offset: integer
5799```
5800
5801### yue.Config.LuaTarget
5802
5803**Type:** Enumeration.
5804
5805**Description:**
5806
5807The target Lua version enumeration.
5808
5809**Signature:**
5810
5811```lua
5812enum LuaTarget
5813 "5.1"
5814 "5.2"
5815 "5.3"
5816 "5.4"
5817 "5.5"
5818end
5819```
5820
5821### options
5822
5823**Type:** Field.
5824
5825**Description:**
5826
5827The extra options to be passed to the compilation function.
5828
5829**Signature:**
5830
5831```lua
5832options: Options
5833```
5834
5835## Options
5836
5837**Description:**
5838
5839The extra compiler options definition.
5840
5841### target
5842
5843**Type:** Field.
5844
5845**Description:**
5846
5847The target Lua version for the compilation.
5848
5849**Signature:**
5850
5851```lua
5852target: LuaTarget
5853```
5854
5855### path
5856
5857**Type:** Field.
5858
5859**Description:**
5860
5861The extra module search path.
5862
5863**Signature:**
5864
5865```lua
5866path: string
5867```
5868
5869### dump_locals
5870
5871**Type:** Field.
5872
5873**Description:**
5874
5875Whether to dump the local variables in the traceback error message. Default is false.
5876
5877**Signature:**
5878
5879```lua
5880dump_locals: boolean
5881```
5882
5883### simplified
5884
5885**Type:** Field.
5886
5887**Description:**
5888
5889Whether to simplify the error message. Default is true.
5890
5891**Signature:**
5892
5893```lua
5894simplified: boolean
5895```
diff --git a/doc/yue-id-id.md b/doc/yue-id-id.md
new file mode 100644
index 0000000..704ebe4
--- /dev/null
+++ b/doc/yue-id-id.md
@@ -0,0 +1,5890 @@
1---
2title: Referensi
3---
4
5# Dokumentasi YueScript
6
7<img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em; padding-bottom: 2em;"/>
8
9Selamat datang di dokumentasi resmi <b>YueScript</b>!<br/>
10Di sini Anda dapat menemukan fitur bahasa, penggunaan, contoh referensi, dan sumber daya.<br/>
11Silakan pilih bab dari sidebar untuk mulai mempelajari YueScript.
12
13# Do
14
15Saat digunakan sebagai pernyataan, `do` bekerja seperti di Lua.
16
17```yuescript
18do
19 var = "hello"
20 print var
21print var -- nil di sini
22```
23
24<YueDisplay>
25
26```yue
27do
28 var = "hello"
29 print var
30print var -- nil di sini
31```
32
33</YueDisplay>
34
35`do` di YueScript juga bisa digunakan sebagai ekspresi, memungkinkan Anda menggabungkan beberapa baris menjadi satu. Hasil ekspresi `do` adalah pernyataan terakhir di badannya. Ekspresi `do` mendukung penggunaan `break` untuk memutus alur eksekusi dan mengembalikan banyak nilai lebih awal.
36
37```yuescript
38status, value = do
39 n = 12
40 if n > 10
41 break "large", n
42 break "small", n
43```
44
45<YueDisplay>
46
47```yue
48status, value = do
49 n = 12
50 if n > 10
51 break "large", n
52 break "small", n
53```
54
55</YueDisplay>
56
57```yuescript
58counter = do
59 i = 0
60 ->
61 i += 1
62 i
63
64print counter!
65print counter!
66```
67
68<YueDisplay>
69
70```yue
71counter = do
72 i = 0
73 ->
74 i += 1
75 i
76
77print counter!
78print counter!
79```
80
81</YueDisplay>
82
83```yuescript
84tbl = {
85 key: do
86 print "assigning key!"
87 1234
88}
89```
90
91<YueDisplay>
92
93```yue
94tbl = {
95 key: do
96 print "assigning key!"
97 1234
98}
99```
100
101</YueDisplay>
102
103# Dekorator Baris
104
105Untuk kemudahan, loop for dan pernyataan if dapat diterapkan pada pernyataan tunggal di akhir baris:
106
107```yuescript
108print "hello world" if name == "Rob"
109```
110
111<YueDisplay>
112
113```yue
114print "hello world" if name == "Rob"
115```
116
117</YueDisplay>
118
119Dan dengan loop dasar:
120
121```yuescript
122print "item: ", item for item in *items
123```
124
125<YueDisplay>
126
127```yue
128print "item: ", item for item in *items
129```
130
131</YueDisplay>
132
133Dan dengan loop while:
134
135```yuescript
136game\update! while game\isRunning!
137
138reader\parse_line! until reader\eof!
139```
140
141<YueDisplay>
142
143```yue
144game\update! while game\isRunning!
145
146reader\parse_line! until reader\eof!
147```
148
149</YueDisplay>
150
151# Makro
152
153## Penggunaan Umum
154
155Fungsi macro digunakan untuk mengevaluasi string pada waktu kompilasi dan menyisipkan kode yang dihasilkan ke kompilasi akhir.
156
157```yuescript
158macro PI2 = -> math.pi * 2
159area = $PI2 * 5
160
161macro HELLO = -> "'hello world'"
162print $HELLO
163
164macro config = (debugging) ->
165 global debugMode = debugging == "true"
166 ""
167
168macro asserts = (cond) ->
169 debugMode and "assert #{cond}" or ""
170
171macro assert = (cond) ->
172 debugMode and "assert #{cond}" or "#{cond}"
173
174$config true
175$asserts item ~= nil
176
177$config false
178value = $assert item
179
180-- ekspresi yang dikirim diperlakukan sebagai string
181macro and = (...) -> "#{ table.concat {...}, ' and ' }"
182if $and f1!, f2!, f3!
183 print "OK"
184```
185
186<YueDisplay>
187
188```yue
189macro PI2 = -> math.pi * 2
190area = $PI2 * 5
191
192macro HELLO = -> "'hello world'"
193print $HELLO
194
195macro config = (debugging) ->
196 global debugMode = debugging == "true"
197 ""
198
199macro asserts = (cond) ->
200 debugMode and "assert #{cond}" or ""
201
202macro assert = (cond) ->
203 debugMode and "assert #{cond}" or "#{cond}"
204
205$config true
206$asserts item ~= nil
207
208$config false
209value = $assert item
210
211-- ekspresi yang dikirim diperlakukan sebagai string
212macro and = (...) -> "#{ table.concat {...}, ' and ' }"
213if $and f1!, f2!, f3!
214 print "OK"
215```
216
217</YueDisplay>
218
219## Menyisipkan Kode Mentah
220
221Fungsi macro bisa mengembalikan string YueScript atau tabel konfigurasi yang berisi kode Lua.
222
223```yuescript
224macro yueFunc = (var) -> "local #{var} = ->"
225$yueFunc funcA
226funcA = -> "gagal meng-assign ke variabel yang didefinisikan oleh macro Yue"
227
228macro luaFunc = (var) -> {
229 code: "local function #{var}() end"
230 type: "lua"
231}
232$luaFunc funcB
233funcB = -> "gagal meng-assign ke variabel yang didefinisikan oleh macro Lua"
234
235macro lua = (code) -> {
236 :code
237 type: "lua"
238}
239
240-- simbol awal dan akhir string mentah otomatis di-trim
241$lua[==[
242-- penyisipan kode Lua mentah
243if cond then
244 print("output")
245end
246]==]
247```
248
249<YueDisplay>
250
251```yue
252macro yueFunc = (var) -> "local #{var} = ->"
253$yueFunc funcA
254funcA = -> "gagal meng-assign ke variabel yang didefinisikan oleh macro Yue"
255
256macro luaFunc = (var) -> {
257 code: "local function #{var}() end"
258 type: "lua"
259}
260$luaFunc funcB
261funcB = -> "gagal meng-assign ke variabel yang didefinisikan oleh macro Lua"
262
263macro lua = (code) -> {
264 :code
265 type: "lua"
266}
267
268-- simbol awal dan akhir string mentah otomatis di-trim
269$lua[==[
270-- penyisipan kode Lua mentah
271if cond then
272 print("output")
273end
274]==]
275```
276
277</YueDisplay>
278
279## Export Macro
280
281Fungsi macro dapat diekspor dari modul dan diimpor di modul lain. Anda harus menaruh fungsi macro export dalam satu file agar dapat digunakan, dan hanya definisi macro, impor macro, dan ekspansi macro yang boleh ada di modul export macro.
282
283```yuescript
284-- file: utils.yue
285export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
286export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
287export macro foreach = (items, action) -> "for _ in *#{items}
288 #{action}"
289
290-- file main.yue
291import "utils" as {
292 $, -- simbol untuk mengimpor semua macro
293 $foreach: $each -- ganti nama macro $foreach menjadi $each
294}
295[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
296```
297
298<YueDisplay>
299
300```yue
301-- file: utils.yue
302export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
303export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
304export macro foreach = (items, action) -> "for _ in *#{items}
305 #{action}"
306
307-- file main.yue
308-- fungsi import tidak tersedia di browser, coba di lingkungan nyata
309--[[
310import "utils" as {
311 $, -- simbol untuk mengimpor semua macro
312 $foreach: $each -- ganti nama macro $foreach menjadi $each
313}
314[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
315]]
316```
317
318</YueDisplay>
319
320## Macro Bawaan
321
322Ada beberapa macro bawaan tetapi Anda bisa menimpanya dengan mendeklarasikan macro dengan nama yang sama.
323
324```yuescript
325print $FILE -- mendapatkan string nama modul saat ini
326print $LINE -- mendapatkan angka 2
327```
328
329<YueDisplay>
330
331```yue
332print $FILE -- mendapatkan string nama modul saat ini
333print $LINE -- mendapatkan angka 2
334```
335
336</YueDisplay>
337
338## Menghasilkan Macro dengan Macro
339
340Di YueScript, fungsi macro memungkinkan Anda menghasilkan kode pada waktu kompilasi. Dengan menumpuk fungsi macro, Anda dapat membuat pola generasi yang lebih kompleks. Fitur ini memungkinkan Anda mendefinisikan fungsi macro yang menghasilkan fungsi macro lain, sehingga menghasilkan kode yang lebih dinamis.
341
342```yuescript
343macro Enum = (...) ->
344 items = {...}
345 itemSet = {item, true for item in *items}
346 (item) ->
347 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
348 "\"#{item}\""
349
350macro BodyType = $Enum(
351 Static
352 Dynamic
353 Kinematic
354)
355
356print "Valid enum type:", $BodyType Static
357-- print "Compilation error with enum type:", $BodyType Unknown
358```
359
360<YueDisplay>
361
362```yue
363macro Enum = (...) ->
364 items = {...}
365 itemSet = {item, true for item in *items}
366 (item) ->
367 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
368 "\"#{item}\""
369
370macro BodyType = $Enum(
371 Static
372 Dynamic
373 Kinematic
374)
375
376print "Valid enum type:", $BodyType Static
377-- print "Compilation error with enum type:", $BodyType Unknown
378```
379
380</YueDisplay>
381
382## Validasi Argumen
383
384Anda dapat mendeklarasikan tipe node AST yang diharapkan dalam daftar argumen, dan memeriksa apakah argumen macro yang masuk memenuhi harapan pada waktu kompilasi.
385
386```yuescript
387macro printNumAndStr = (num `Num, str `String) -> |
388 print(
389 #{num}
390 #{str}
391 )
392
393$printNumAndStr 123, "hello"
394```
395
396<YueDisplay>
397
398```yue
399macro printNumAndStr = (num `Num, str `String) -> |
400 print(
401 #{num}
402 #{str}
403 )
404
405$printNumAndStr 123, "hello"
406```
407
408</YueDisplay>
409
410Jika Anda membutuhkan pengecekan argumen yang lebih fleksibel, Anda dapat menggunakan fungsi macro bawaan `$is_ast` untuk memeriksa secara manual pada tempat yang tepat.
411
412```yuescript
413macro printNumAndStr = (num, str) ->
414 error "expected Num as first argument" unless $is_ast Num, num
415 error "expected String as second argument" unless $is_ast String, str
416 "print(#{num}, #{str})"
417
418$printNumAndStr 123, "hello"
419```
420
421<YueDisplay>
422
423```yue
424macro printNumAndStr = (num, str) ->
425 error "expected Num as first argument" unless $is_ast Num, num
426 error "expected String as second argument" unless $is_ast String, str
427 "print(#{num}, #{str})"
428
429$printNumAndStr 123, "hello"
430```
431
432</YueDisplay>
433
434Untuk detail lebih lanjut tentang node AST yang tersedia, silakan lihat definisi huruf besar di [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).
435
436# Try
437
438Sintaks untuk penanganan error Lua dalam bentuk umum.
439
440```yuescript
441try
442 func 1, 2, 3
443catch err
444 print yue.traceback err
445
446success, result = try
447 func 1, 2, 3
448catch err
449 yue.traceback err
450
451try func 1, 2, 3
452catch err
453 print yue.traceback err
454
455success, result = try func 1, 2, 3
456
457try
458 print "trying"
459 func 1, 2, 3
460
461-- bekerja dengan pola if assignment
462if success, result := try func 1, 2, 3
463catch err
464 print yue.traceback err
465 print result
466```
467
468<YueDisplay>
469
470```yue
471try
472 func 1, 2, 3
473catch err
474 print yue.traceback err
475
476success, result = try
477 func 1, 2, 3
478catch err
479 yue.traceback err
480
481try func 1, 2, 3
482catch err
483 print yue.traceback err
484
485success, result = try func 1, 2, 3
486
487try
488 print "trying"
489 func 1, 2, 3
490
491-- bekerja dengan pola if assignment
492if success, result := try func 1, 2, 3
493catch err
494 print yue.traceback err
495 print result
496```
497
498</YueDisplay>
499
500## Try?
501
502`try?` adalah bentuk sederhana untuk penanganan error yang menghilangkan status boolean dari pernyataan `try`, dan akan mengembalikan hasil dari blok try ketika berhasil, atau mengembalikan nil alih-alih objek error bila gagal.
503
504```yuescript
505a, b, c = try? func!
506
507-- dengan operator nil coalescing
508a = (try? func!) ?? "default"
509
510-- sebagai argumen fungsi
511f try? func!
512
513-- dengan blok catch
514f try?
515 print 123
516 func!
517catch e
518 print e
519 e
520```
521
522<YueDisplay>
523
524```yue
525a, b, c = try? func!
526
527-- dengan operator nil coalescing
528a = (try? func!) ?? "default"
529
530-- sebagai argumen fungsi
531f try? func!
532
533-- dengan blok catch
534f try?
535 print 123
536 func!
537catch e
538 print e
539 e
540```
541
542</YueDisplay>
543
544# Literal Tabel
545
546Seperti di Lua, tabel dibatasi dengan kurung kurawal.
547
548```yuescript
549some_values = [1, 2, 3, 4]
550```
551
552<YueDisplay>
553
554```yue
555some_values = [1, 2, 3, 4]
556```
557
558</YueDisplay>
559
560Berbeda dengan Lua, assignment nilai ke sebuah kunci di tabel dilakukan dengan **:** (bukan **=**).
561
562```yuescript
563some_values = {
564 name: "Bill",
565 age: 200,
566 ["favorite food"]: "rice"
567}
568```
569
570<YueDisplay>
571
572```yue
573some_values = {
574 name: "Bill",
575 age: 200,
576 ["favorite food"]: "rice"
577}
578```
579
580</YueDisplay>
581
582Kurung kurawal dapat dihilangkan jika hanya satu tabel pasangan key-value yang di-assign.
583
584```yuescript
585profile =
586 height: "4 feet",
587 shoe_size: 13,
588 favorite_foods: ["ice cream", "donuts"]
589```
590
591<YueDisplay>
592
593```yue
594profile =
595 height: "4 feet",
596 shoe_size: 13,
597 favorite_foods: ["ice cream", "donuts"]
598```
599
600</YueDisplay>
601
602Baris baru dapat digunakan untuk memisahkan nilai sebagai ganti koma (atau keduanya):
603
604```yuescript
605values = {
606 1, 2, 3, 4
607 5, 6, 7, 8
608 name: "superman"
609 occupation: "crime fighting"
610}
611```
612
613<YueDisplay>
614
615```yue
616values = {
617 1, 2, 3, 4
618 5, 6, 7, 8
619 name: "superman"
620 occupation: "crime fighting"
621}
622```
623
624</YueDisplay>
625
626Saat membuat literal tabel satu baris, kurung kurawal juga bisa dihilangkan:
627
628```yuescript
629my_function dance: "Tango", partner: "none"
630
631y = type: "dog", legs: 4, tails: 1
632```
633
634<YueDisplay>
635
636```yue
637my_function dance: "Tango", partner: "none"
638
639y = type: "dog", legs: 4, tails: 1
640```
641
642</YueDisplay>
643
644Kunci literal tabel dapat berupa kata kunci bahasa tanpa perlu di-escape:
645
646```yuescript
647tbl = {
648 do: "something"
649 end: "hunger"
650}
651```
652
653<YueDisplay>
654
655```yue
656tbl = {
657 do: "something"
658 end: "hunger"
659}
660```
661
662</YueDisplay>
663
664Jika Anda membangun tabel dari variabel dan ingin kunci sama dengan nama variabel, maka operator prefiks **:** dapat digunakan:
665
666```yuescript
667hair = "golden"
668height = 200
669person = { :hair, :height, shoe_size: 40 }
670
671print_table :hair, :height
672```
673
674<YueDisplay>
675
676```yue
677hair = "golden"
678height = 200
679person = { :hair, :height, shoe_size: 40 }
680
681print_table :hair, :height
682```
683
684</YueDisplay>
685
686Jika Anda ingin kunci field dalam tabel menjadi hasil suatu ekspresi, Anda dapat membungkusnya dengan **[ ]**, seperti di Lua. Anda juga bisa menggunakan literal string langsung sebagai kunci tanpa tanda kurung siku. Ini berguna jika kunci memiliki karakter khusus.
687
688```yuescript
689t = {
690 [1 + 2]: "hello"
691 "hello world": true
692}
693```
694
695<YueDisplay>
696
697```yue
698t = {
699 [1 + 2]: "hello"
700 "hello world": true
701}
702```
703
704</YueDisplay>
705
706Tabel Lua memiliki bagian array dan bagian hash, tetapi terkadang Anda ingin membedakan penggunaan array dan hash secara semantik saat menulis tabel Lua. Maka Anda bisa menulis tabel Lua dengan **[ ]** alih-alih **{ }** untuk merepresentasikan tabel array, dan menuliskan pasangan key-value di tabel list tidak akan diizinkan.
707
708```yuescript
709some_values = [1, 2, 3, 4]
710list_with_one_element = [1, ]
711```
712
713<YueDisplay>
714
715```yue
716some_values = [1, 2, 3, 4]
717list_with_one_element = [1, ]
718```
719
720</YueDisplay>
721
722# Komprehensi
723
724Komprehensi menyediakan sintaks yang nyaman untuk membangun tabel baru dengan mengiterasi objek yang ada dan menerapkan ekspresi pada nilainya. Ada dua jenis komprehensi: komprehensi list dan komprehensi tabel. Keduanya menghasilkan tabel Lua; komprehensi list mengakumulasi nilai ke tabel mirip array, dan komprehensi tabel memungkinkan Anda menetapkan kunci dan nilai pada setiap iterasi.
725
726## Komprehensi List
727
728Berikut membuat salinan tabel `items` tetapi semua nilainya digandakan.
729
730```yuescript
731items = [ 1, 2, 3, 4 ]
732doubled = [item * 2 for i, item in ipairs items]
733```
734
735<YueDisplay>
736
737```yue
738items = [ 1, 2, 3, 4 ]
739doubled = [item * 2 for i, item in ipairs items]
740```
741
742</YueDisplay>
743
744Item yang disertakan dalam tabel baru bisa dibatasi dengan klausa `when`:
745
746```yuescript
747slice = [item for i, item in ipairs items when i > 1 and i < 3]
748```
749
750<YueDisplay>
751
752```yue
753slice = [item for i, item in ipairs items when i > 1 and i < 3]
754```
755
756</YueDisplay>
757
758Karena umum untuk mengiterasi nilai dari tabel berindeks numerik, operator **\*** diperkenalkan. Contoh `doubled` bisa ditulis ulang sebagai:
759
760```yuescript
761doubled = [item * 2 for item in *items]
762```
763
764<YueDisplay>
765
766```yue
767doubled = [item * 2 for item in *items]
768```
769
770</YueDisplay>
771
772Dalam komprehensi list, Anda juga bisa menggunakan operator spread `...` untuk meratakan list bertingkat, menghasilkan efek flat map:
773
774```yuescript
775data =
776 a: [1, 2, 3]
777 b: [4, 5, 6]
778
779flat = [...v for k,v in pairs data]
780-- flat sekarang [1, 2, 3, 4, 5, 6]
781```
782
783<YueDisplay>
784
785```yue
786data =
787 a: [1, 2, 3]
788 b: [4, 5, 6]
789
790flat = [...v for k,v in pairs data]
791-- flat sekarang [1, 2, 3, 4, 5, 6]
792```
793
794</YueDisplay>
795
796Klausa `for` dan `when` dapat dirantai sebanyak yang diinginkan. Satu-satunya syarat adalah komprehensi memiliki setidaknya satu klausa `for`.
797
798Menggunakan beberapa klausa `for` sama seperti menggunakan loop bertingkat:
799
800```yuescript
801x_coords = [4, 5, 6, 7]
802y_coords = [9, 2, 3]
803
804points = [ [x, y] for x in *x_coords \
805for y in *y_coords]
806```
807
808<YueDisplay>
809
810```yue
811x_coords = [4, 5, 6, 7]
812y_coords = [9, 2, 3]
813
814points = [ [x, y] for x in *x_coords \
815for y in *y_coords]
816```
817
818</YueDisplay>
819
820Perulangan for numerik juga bisa digunakan dalam komprehensi:
821
822```yuescript
823evens = [i for i = 1, 100 when i % 2 == 0]
824```
825
826<YueDisplay>
827
828```yue
829evens = [i for i = 1, 100 when i % 2 == 0]
830```
831
832</YueDisplay>
833
834## Komprehensi Tabel
835
836Sintaks untuk komprehensi tabel sangat mirip, hanya berbeda dengan penggunaan **{** dan **}** serta mengambil dua nilai dari setiap iterasi.
837
838Contoh ini membuat salinan tabel `thing`:
839
840```yuescript
841thing = {
842 color: "red"
843 name: "fast"
844 width: 123
845}
846
847thing_copy = {k, v for k, v in pairs thing}
848```
849
850<YueDisplay>
851
852```yue
853thing = {
854 color: "red"
855 name: "fast"
856 width: 123
857}
858
859thing_copy = {k, v for k, v in pairs thing}
860```
861
862</YueDisplay>
863
864```yuescript
865no_color = {k, v for k, v in pairs thing when k != "color"}
866```
867
868<YueDisplay>
869
870```yue
871no_color = {k, v for k, v in pairs thing when k != "color"}
872```
873
874</YueDisplay>
875
876Operator **\*** juga didukung. Di sini kita membuat tabel lookup akar kuadrat untuk beberapa angka.
877
878```yuescript
879numbers = [1, 2, 3, 4]
880sqrts = {i, math.sqrt i for i in *numbers}
881```
882
883<YueDisplay>
884
885```yue
886numbers = [1, 2, 3, 4]
887sqrts = {i, math.sqrt i for i in *numbers}
888```
889
890</YueDisplay>
891
892Tuple key-value dalam komprehensi tabel juga bisa berasal dari satu ekspresi, yang berarti ekspresi tersebut harus mengembalikan dua nilai. Nilai pertama digunakan sebagai kunci dan nilai kedua digunakan sebagai nilai:
893
894Dalam contoh ini kita mengonversi array pasangan menjadi tabel di mana item pertama dalam pasangan menjadi kunci dan item kedua menjadi nilai.
895
896```yuescript
897tuples = [ ["hello", "world"], ["foo", "bar"]]
898tbl = {unpack tuple for tuple in *tuples}
899```
900
901<YueDisplay>
902
903```yue
904tuples = [ ["hello", "world"], ["foo", "bar"]]
905tbl = {unpack tuple for tuple in *tuples}
906```
907
908</YueDisplay>
909
910## Slicing
911
912Sintaks khusus disediakan untuk membatasi item yang diiterasi saat menggunakan operator **\***. Ini setara dengan mengatur batas iterasi dan ukuran langkah pada loop for.
913
914Di sini kita bisa menetapkan batas minimum dan maksimum, mengambil semua item dengan indeks antara 1 dan 5 (inklusif):
915
916```yuescript
917slice = [item for item in *items[1, 5]]
918```
919
920<YueDisplay>
921
922```yue
923slice = [item for item in *items[1, 5]]
924```
925
926</YueDisplay>
927
928Salah satu argumen slice boleh dikosongkan untuk menggunakan default yang masuk akal. Pada contoh ini, jika indeks maksimum dikosongkan, defaultnya adalah panjang tabel. Ini akan mengambil semua item kecuali elemen pertama:
929
930```yuescript
931slice = [item for item in *items[2,]]
932```
933
934<YueDisplay>
935
936```yue
937slice = [item for item in *items[2,]]
938```
939
940</YueDisplay>
941
942Jika batas minimum dikosongkan, defaultnya adalah 1. Di sini kita hanya memberikan ukuran langkah dan membiarkan batas lainnya kosong. Ini akan mengambil semua item berindeks ganjil: (1, 3, 5, …)
943
944```yuescript
945slice = [item for item in *items[,,2]]
946```
947
948<YueDisplay>
949
950```yue
951slice = [item for item in *items[,,2]]
952```
953
954</YueDisplay>
955
956Batas minimum dan maksimum bisa bernilai negatif, yang berarti batas dihitung dari akhir tabel.
957
958```yuescript
959-- ambil 4 item terakhir
960slice = [item for item in *items[-4,-1]]
961```
962
963<YueDisplay>
964
965```yue
966-- ambil 4 item terakhir
967slice = [item for item in *items[-4,-1]]
968```
969
970</YueDisplay>
971
972Ukuran langkah juga bisa negatif, yang berarti item diambil dalam urutan terbalik.
973
974```yuescript
975reverse_slice = [item for item in *items[-1,1,-1]]
976```
977
978<YueDisplay>
979
980```yue
981reverse_slice = [item for item in *items[-1,1,-1]]
982```
983
984</YueDisplay>
985
986### Ekspresi Slicing
987
988Slicing juga bisa digunakan sebagai ekspresi. Ini berguna untuk mendapatkan sub-list dari sebuah tabel.
989
990```yuescript
991-- ambil item ke-2 dan ke-4 sebagai list baru
992sub_list = items[2, 4]
993
994-- ambil 4 item terakhir
995last_four_items = items[-4, -1]
996```
997
998<YueDisplay>
999
1000```yue
1001-- ambil item ke-2 dan ke-4 sebagai list baru
1002sub_list = items[2, 4]
1003
1004-- ambil 4 item terakhir
1005last_four_items = items[-4, -1]
1006```
1007
1008</YueDisplay>
1009
1010# Pemrograman Berorientasi Objek
1011
1012Dalam contoh-contoh ini, kode Lua yang dihasilkan mungkin tampak berat. Sebaiknya fokus dulu pada makna kode YueScript, lalu lihat kode Lua jika Anda ingin mengetahui detail implementasinya.
1013
1014Kelas sederhana:
1015
1016```yuescript
1017class Inventory
1018 new: =>
1019 @items = {}
1020
1021 add_item: (name) =>
1022 if @items[name]
1023 @items[name] += 1
1024 else
1025 @items[name] = 1
1026```
1027
1028<YueDisplay>
1029
1030```yue
1031class Inventory
1032 new: =>
1033 @items = {}
1034
1035 add_item: (name) =>
1036 if @items[name]
1037 @items[name] += 1
1038 else
1039 @items[name] = 1
1040```
1041
1042</YueDisplay>
1043
1044Kelas dideklarasikan dengan pernyataan `class` diikuti deklarasi mirip tabel di mana semua method dan properti dicantumkan.
1045
1046Properti `new` bersifat khusus karena akan menjadi konstruktor.
1047
1048Perhatikan bahwa semua method di kelas menggunakan sintaks fungsi panah tebal. Saat memanggil method pada instance, instance itu sendiri dikirim sebagai argumen pertama. Panah tebal menangani pembuatan argumen `self`.
1049
1050Prefiks `@` pada nama variabel adalah singkatan untuk `self.`. `@items` menjadi `self.items`.
1051
1052Membuat instance kelas dilakukan dengan memanggil nama kelas sebagai fungsi.
1053
1054```yuescript
1055inv = Inventory!
1056inv\add_item "t-shirt"
1057inv\add_item "pants"
1058```
1059
1060<YueDisplay>
1061
1062```yue
1063inv = Inventory!
1064inv\add_item "t-shirt"
1065inv\add_item "pants"
1066```
1067
1068</YueDisplay>
1069
1070Karena instance kelas perlu dikirim ke method saat dipanggil, operator `\` digunakan.
1071
1072Semua properti kelas dibagikan di antara instance. Ini baik untuk fungsi, tetapi untuk jenis objek lain dapat menimbulkan hasil yang tidak diinginkan.
1073
1074Pertimbangkan contoh di bawah ini, properti `clothes` dibagikan di antara semua instance, sehingga perubahan di satu instance akan terlihat di instance lainnya:
1075
1076```yuescript
1077class Person
1078 clothes: []
1079 give_item: (name) =>
1080 table.insert @clothes, name
1081
1082a = Person!
1083b = Person!
1084
1085a\give_item "pants"
1086b\give_item "shirt"
1087
1088-- akan mencetak pants dan shirt
1089print item for item in *a.clothes
1090```
1091
1092<YueDisplay>
1093
1094```yue
1095class Person
1096 clothes: []
1097 give_item: (name) =>
1098 table.insert @clothes, name
1099
1100a = Person!
1101b = Person!
1102
1103a\give_item "pants"
1104b\give_item "shirt"
1105
1106-- akan mencetak pants dan shirt
1107print item for item in *a.clothes
1108```
1109
1110</YueDisplay>
1111
1112Cara yang benar untuk menghindari masalah ini adalah membuat state yang dapat berubah di konstruktor:
1113
1114```yuescript
1115class Person
1116 new: =>
1117 @clothes = []
1118```
1119
1120<YueDisplay>
1121
1122```yue
1123class Person
1124 new: =>
1125 @clothes = []
1126```
1127
1128</YueDisplay>
1129
1130## Pewarisan
1131
1132Kata kunci `extends` dapat digunakan dalam deklarasi kelas untuk mewarisi properti dan method dari kelas lain.
1133
1134```yuescript
1135class BackPack extends Inventory
1136 size: 10
1137 add_item: (name) =>
1138 if #@items > size then error "backpack is full"
1139 super name
1140```
1141
1142<YueDisplay>
1143
1144```yue
1145class BackPack extends Inventory
1146 size: 10
1147 add_item: (name) =>
1148 if #@items > size then error "backpack is full"
1149 super name
1150```
1151
1152</YueDisplay>
1153
1154Di sini kita memperluas kelas Inventory, dan membatasi jumlah item yang bisa dibawa.
1155
1156Dalam contoh ini, kita tidak mendefinisikan konstruktor pada subclass, sehingga konstruktor kelas induk dipanggil ketika membuat instance baru. Jika kita mendefinisikan konstruktor, kita bisa menggunakan method `super` untuk memanggil konstruktor induk.
1157
1158Setiap kali sebuah kelas mewarisi dari kelas lain, ia mengirim pesan ke kelas induk dengan memanggil method `__inherited` pada kelas induk jika ada. Fungsi menerima dua argumen, kelas yang diwarisi dan kelas anak.
1159
1160```yuescript
1161class Shelf
1162 @__inherited: (child) =>
1163 print @__name, "was inherited by", child.__name
1164
1165-- akan mencetak: Shelf was inherited by Cupboard
1166class Cupboard extends Shelf
1167```
1168
1169<YueDisplay>
1170
1171```yue
1172class Shelf
1173 @__inherited: (child) =>
1174 print @__name, "was inherited by", child.__name
1175
1176-- akan mencetak: Shelf was inherited by Cupboard
1177class Cupboard extends Shelf
1178```
1179
1180</YueDisplay>
1181
1182## Super
1183
1184**super** adalah kata kunci khusus yang dapat digunakan dengan dua cara: sebagai objek, atau dipanggil seperti fungsi. Ia hanya memiliki fungsi khusus ketika berada di dalam kelas.
1185
1186Ketika dipanggil sebagai fungsi, ia akan memanggil fungsi dengan nama yang sama di kelas induk. `self` saat ini akan otomatis dikirim sebagai argumen pertama. (Seperti pada contoh pewarisan di atas)
1187
1188Ketika `super` digunakan sebagai nilai normal, ia merupakan referensi ke objek kelas induk.
1189
1190Ia dapat diakses seperti objek biasa untuk mengambil nilai di kelas induk yang mungkin tertutup oleh kelas anak.
1191
1192Ketika operator pemanggilan `\` digunakan dengan `super`, `self` disisipkan sebagai argumen pertama alih-alih nilai `super` itu sendiri. Saat menggunakan `.` untuk mengambil fungsi, fungsi mentah dikembalikan.
1193
1194Beberapa contoh penggunaan `super` dengan cara berbeda:
1195
1196```yuescript
1197class MyClass extends ParentClass
1198 a_method: =>
1199 -- berikut memiliki efek yang sama:
1200 super "hello", "world"
1201 super\a_method "hello", "world"
1202 super.a_method self, "hello", "world"
1203
1204 -- super sebagai nilai sama dengan kelas induk:
1205 assert super == ParentClass
1206```
1207
1208<YueDisplay>
1209
1210```yue
1211class MyClass extends ParentClass
1212 a_method: =>
1213 -- berikut memiliki efek yang sama:
1214 super "hello", "world"
1215 super\a_method "hello", "world"
1216 super.a_method self, "hello", "world"
1217
1218 -- super sebagai nilai sama dengan kelas induk:
1219 assert super == ParentClass
1220```
1221
1222</YueDisplay>
1223
1224**super** juga dapat digunakan di sisi kiri Function Stub. Perbedaan utamanya adalah, alih-alih fungsi hasil terikat pada nilai `super`, fungsi terikat pada `self`.
1225
1226## Tipe
1227
1228Setiap instance kelas membawa tipenya sendiri. Ini disimpan di properti khusus `__class`. Properti ini memuat objek kelas. Objek kelas adalah yang kita panggil untuk membuat instance baru. Kita juga dapat mengindeks objek kelas untuk mengambil method dan properti kelas.
1229
1230```yuescript
1231b = BackPack!
1232assert b.__class == BackPack
1233
1234print BackPack.size -- mencetak 10
1235```
1236
1237<YueDisplay>
1238
1239```yue
1240b = BackPack!
1241assert b.__class == BackPack
1242
1243print BackPack.size -- mencetak 10
1244```
1245
1246</YueDisplay>
1247
1248## Objek Kelas
1249
1250Objek kelas adalah yang kita buat saat menggunakan pernyataan `class`. Objek kelas disimpan dalam variabel dengan nama yang sama dengan kelas.
1251
1252Objek kelas dapat dipanggil seperti fungsi untuk membuat instance baru. Begitulah cara kita membuat instance kelas pada contoh di atas.
1253
1254Sebuah kelas terdiri dari dua tabel: tabel kelas itu sendiri dan tabel base. Base digunakan sebagai metatable untuk semua instance. Semua properti yang dicantumkan dalam deklarasi kelas ditempatkan di base.
1255
1256Metatable objek kelas membaca properti dari base jika tidak ada di objek kelas. Ini berarti kita dapat mengakses fungsi dan properti langsung dari kelas.
1257
1258Penting untuk dicatat bahwa assignment ke objek kelas tidak meng-assign ke base, sehingga itu bukan cara yang valid untuk menambahkan method baru ke instance. Sebagai gantinya, base harus diubah secara eksplisit. Lihat field `__base` di bawah.
1259
1260Objek kelas memiliki beberapa properti khusus:
1261
1262Nama kelas saat dideklarasikan disimpan sebagai string di field `__name` pada objek kelas.
1263
1264```yuescript
1265print BackPack.__name -- mencetak Backpack
1266```
1267
1268<YueDisplay>
1269
1270```yue
1271print BackPack.__name -- mencetak Backpack
1272```
1273
1274</YueDisplay>
1275
1276Objek base disimpan di `__base`. Kita dapat memodifikasi tabel ini untuk menambahkan fungsionalitas ke instance yang sudah dibuat maupun yang akan dibuat.
1277
1278Jika kelas memperluas kelas lain, objek kelas induk disimpan di `__parent`.
1279
1280## Variabel Kelas
1281
1282Kita dapat membuat variabel langsung di objek kelas alih-alih di base dengan menggunakan `@` di depan nama properti pada deklarasi kelas.
1283
1284```yuescript
1285class Things
1286 @some_func: => print "Hello from", @__name
1287
1288Things\some_func!
1289
1290-- variabel kelas tidak terlihat pada instance
1291assert Things().some_func == nil
1292```
1293
1294<YueDisplay>
1295
1296```yue
1297class Things
1298 @some_func: => print "Hello from", @__name
1299
1300Things\some_func!
1301
1302-- variabel kelas tidak terlihat pada instance
1303assert Things().some_func == nil
1304```
1305
1306</YueDisplay>
1307
1308Dalam ekspresi, kita dapat menggunakan `@@` untuk mengakses nilai yang disimpan di `__class` milik `self`. Jadi, `@@hello` adalah singkatan dari `self.__class.hello`.
1309
1310```yuescript
1311class Counter
1312 @count: 0
1313
1314 new: =>
1315 @@count += 1
1316
1317Counter!
1318Counter!
1319
1320print Counter.count -- mencetak 2
1321```
1322
1323<YueDisplay>
1324
1325```yue
1326class Counter
1327 @count: 0
1328
1329 new: =>
1330 @@count += 1
1331
1332Counter!
1333Counter!
1334
1335print Counter.count -- mencetak 2
1336```
1337
1338</YueDisplay>
1339
1340Semantik pemanggilan `@@` mirip dengan `@`. Memanggil nama `@@` akan meneruskan kelas sebagai argumen pertama menggunakan sintaks kolon Lua.
1341
1342```yuescript
1343@@hello 1,2,3,4
1344```
1345
1346<YueDisplay>
1347
1348```yue
1349@@hello 1,2,3,4
1350```
1351
1352</YueDisplay>
1353
1354## Pernyataan Deklarasi Kelas
1355
1356Di dalam badan deklarasi kelas, kita bisa memiliki ekspresi normal selain pasangan key/value. Dalam konteks ini, `self` sama dengan objek kelas.
1357
1358Berikut cara alternatif untuk membuat variabel kelas dibandingkan yang dijelaskan di atas:
1359
1360```yuescript
1361class Things
1362 @class_var = "hello world"
1363```
1364
1365<YueDisplay>
1366
1367```yue
1368class Things
1369 @class_var = "hello world"
1370```
1371
1372</YueDisplay>
1373
1374Ekspresi ini dieksekusi setelah semua properti ditambahkan ke base.
1375
1376Semua variabel yang dideklarasikan di badan kelas bersifat lokal terhadap properti kelas. Ini berguna untuk menempatkan nilai privat atau fungsi pembantu yang hanya dapat diakses oleh method kelas:
1377
1378```yuescript
1379class MoreThings
1380 secret = 123
1381 log = (msg) -> print "LOG:", msg
1382
1383 some_method: =>
1384 log "hello world: " .. secret
1385```
1386
1387<YueDisplay>
1388
1389```yue
1390class MoreThings
1391 secret = 123
1392 log = (msg) -> print "LOG:", msg
1393
1394 some_method: =>
1395 log "hello world: " .. secret
1396```
1397
1398</YueDisplay>
1399
1400## Nilai @ dan @@
1401
1402Ketika `@` dan `@@` diprefiks di depan sebuah nama, masing-masing merepresentasikan nama tersebut yang diakses di `self` dan `self.__class`.
1403
1404Jika digunakan sendirian, keduanya adalah alias untuk `self` dan `self.__class`.
1405
1406```yuescript
1407assert @ == self
1408assert @@ == self.__class
1409```
1410
1411<YueDisplay>
1412
1413```yue
1414assert @ == self
1415assert @@ == self.__class
1416```
1417
1418</YueDisplay>
1419
1420Contohnya, cara cepat untuk membuat instance baru dari kelas yang sama dari method instance menggunakan `@@`:
1421
1422```yuescript
1423some_instance_method = (...) => @@ ...
1424```
1425
1426<YueDisplay>
1427
1428```yue
1429some_instance_method = (...) => @@ ...
1430```
1431
1432</YueDisplay>
1433
1434## Promosi Properti Konstruktor
1435
1436Untuk mengurangi boilerplate saat mendefinisikan objek nilai sederhana, Anda dapat menulis kelas sederhana seperti:
1437
1438```yuescript
1439class Something
1440 new: (@foo, @bar, @@biz, @@baz) =>
1441
1442-- Yang merupakan singkatan dari
1443
1444class Something
1445 new: (foo, bar, biz, baz) =>
1446 @foo = foo
1447 @bar = bar
1448 @@biz = biz
1449 @@baz = baz
1450```
1451
1452<YueDisplay>
1453
1454```yue
1455class Something
1456 new: (@foo, @bar, @@biz, @@baz) =>
1457
1458-- Yang merupakan singkatan dari
1459
1460class Something
1461 new: (foo, bar, biz, baz) =>
1462 @foo = foo
1463 @bar = bar
1464 @@biz = biz
1465 @@baz = baz
1466```
1467
1468</YueDisplay>
1469
1470Anda juga bisa menggunakan sintaks ini untuk fungsi umum guna menginisialisasi field objek.
1471
1472```yuescript
1473new = (@fieldA, @fieldB) => @
1474obj = new {}, 123, "abc"
1475print obj
1476```
1477
1478<YueDisplay>
1479
1480```yue
1481new = (@fieldA, @fieldB) => @
1482obj = new {}, 123, "abc"
1483print obj
1484```
1485
1486</YueDisplay>
1487
1488## Ekspresi Kelas
1489
1490Sintaks kelas juga bisa digunakan sebagai ekspresi yang dapat di-assign ke variabel atau di-return secara eksplisit.
1491
1492```yuescript
1493x = class Bucket
1494 drops: 0
1495 add_drop: => @drops += 1
1496```
1497
1498<YueDisplay>
1499
1500```yue
1501x = class Bucket
1502 drops: 0
1503 add_drop: => @drops += 1
1504```
1505
1506</YueDisplay>
1507
1508## Kelas Anonim
1509
1510Nama bisa dihilangkan saat mendeklarasikan kelas. Atribut `__name` akan bernilai nil, kecuali ekspresi kelas berada dalam assignment. Nama di sisi kiri assignment digunakan sebagai ganti nil.
1511
1512```yuescript
1513BigBucket = class extends Bucket
1514 add_drop: => @drops += 10
1515
1516assert Bucket.__name == "BigBucket"
1517```
1518
1519<YueDisplay>
1520
1521```yue
1522BigBucket = class extends Bucket
1523 add_drop: => @drops += 10
1524
1525assert Bucket.__name == "BigBucket"
1526```
1527
1528</YueDisplay>
1529
1530Anda bahkan bisa menghilangkan badan kelas, artinya Anda bisa menulis kelas anonim kosong seperti ini:
1531
1532```yuescript
1533x = class
1534```
1535
1536<YueDisplay>
1537
1538```yue
1539x = class
1540```
1541
1542</YueDisplay>
1543
1544## Pencampuran Kelas
1545
1546Anda bisa melakukan mixing dengan kata kunci `using` untuk menyalin fungsi dari tabel biasa atau objek kelas yang sudah didefinisikan ke kelas baru Anda. Saat mixing dengan tabel biasa, Anda dapat mengganti fungsi pengindeksan kelas (metamethod `__index`) dengan implementasi kustom. Saat mixing dengan objek kelas yang sudah ada, metamethod objek kelas tidak akan disalin.
1547
1548```yuescript
1549MyIndex = __index: var: 1
1550
1551class X using MyIndex
1552 func: =>
1553 print 123
1554
1555x = X!
1556print x.var
1557
1558class Y using X
1559
1560y = Y!
1561y\func!
1562
1563assert y.__class.__parent ~= X -- X bukan parent dari Y
1564```
1565
1566<YueDisplay>
1567
1568```yue
1569MyIndex = __index: var: 1
1570
1571class X using MyIndex
1572 func: =>
1573 print 123
1574
1575x = X!
1576print x.var
1577
1578class Y using X
1579
1580y = Y!
1581y\func!
1582
1583assert y.__class.__parent ~= X -- X bukan parent dari Y
1584```
1585
1586</YueDisplay>
1587
1588# Pernyataan With
1589
1590Pola umum saat membuat objek adalah memanggil serangkaian fungsi dan mengatur serangkaian properti segera setelah objek dibuat.
1591
1592Hal ini menyebabkan nama objek diulang berkali-kali di kode, menambah noise yang tidak perlu. Solusi umum untuk ini adalah meneruskan tabel sebagai argumen yang berisi kumpulan kunci dan nilai untuk ditimpa. Kekurangannya adalah konstruktor objek harus mendukung bentuk ini.
1593
1594Blok `with` membantu mengatasi hal ini. Di dalam blok `with`, kita bisa menggunakan pernyataan khusus yang diawali dengan `.` atau `\` yang merepresentasikan operasi tersebut diterapkan pada objek yang sedang dipakai.
1595
1596Sebagai contoh, kita bekerja dengan objek yang baru dibuat:
1597
1598```yuescript
1599with Person!
1600 .name = "Oswald"
1601 \add_relative my_dad
1602 \save!
1603 print .name
1604```
1605
1606<YueDisplay>
1607
1608```yue
1609with Person!
1610 .name = "Oswald"
1611 \add_relative my_dad
1612 \save!
1613 print .name
1614```
1615
1616</YueDisplay>
1617
1618Pernyataan `with` juga bisa digunakan sebagai ekspresi yang mengembalikan nilai yang diberi akses.
1619
1620```yuescript
1621file = with File "favorite_foods.txt"
1622 \set_encoding "utf8"
1623```
1624
1625<YueDisplay>
1626
1627```yue
1628file = with File "favorite_foods.txt"
1629 \set_encoding "utf8"
1630```
1631
1632</YueDisplay>
1633
1634Ekspresi `with` mendukung `break` dengan satu nilai:
1635
1636```yuescript
1637result = with obj
1638 break .value
1639```
1640
1641<YueDisplay>
1642
1643```yue
1644result = with obj
1645 break .value
1646```
1647
1648</YueDisplay>
1649
1650Setelah `break value` digunakan di dalam `with`, ekspresi `with` tidak lagi mengembalikan objek targetnya, melainkan mengembalikan nilai dari `break`.
1651
1652```yuescript
1653a = with obj
1654 .x = 1
1655-- a adalah obj
1656
1657b = with obj
1658 break .x
1659-- b adalah .x, bukan obj
1660```
1661
1662<YueDisplay>
1663
1664```yue
1665a = with obj
1666 .x = 1
1667-- a adalah obj
1668
1669b = with obj
1670 break .x
1671-- b adalah .x, bukan obj
1672```
1673
1674</YueDisplay>
1675
1676Berbeda dari `for` / `while` / `repeat` / `do`, `with` hanya mendukung satu nilai `break`.
1677
1678Atau…
1679
1680```yuescript
1681create_person = (name, relatives) ->
1682 with Person!
1683 .name = name
1684 \add_relative relative for relative in *relatives
1685
1686me = create_person "Leaf", [dad, mother, sister]
1687```
1688
1689<YueDisplay>
1690
1691```yue
1692create_person = (name, relatives) ->
1693 with Person!
1694 .name = name
1695 \add_relative relative for relative in *relatives
1696
1697me = create_person "Leaf", [dad, mother, sister]
1698```
1699
1700</YueDisplay>
1701
1702Dalam penggunaan ini, `with` dapat dilihat sebagai bentuk khusus dari kombinator K.
1703
1704Ekspresi pada pernyataan `with` juga bisa berupa assignment jika Anda ingin memberi nama pada ekspresi tersebut.
1705
1706```yuescript
1707with str := "Hello"
1708 print "original:", str
1709 print "upper:", \upper!
1710```
1711
1712<YueDisplay>
1713
1714```yue
1715with str := "Hello"
1716 print "original:", str
1717 print "upper:", \upper!
1718```
1719
1720</YueDisplay>
1721
1722Anda bisa mengakses kunci khusus dengan `[]` di dalam pernyataan `with`.
1723
1724```yuescript
1725with tb
1726 [1] = 1
1727 print [2]
1728 with [abc]
1729 [3] = [2]\func!
1730 ["key-name"] = value
1731 [] = "abc" -- menambahkan ke "tb"
1732```
1733
1734<YueDisplay>
1735
1736```yue
1737with tb
1738 [1] = 1
1739 print [2]
1740 with [abc]
1741 [3] = [2]\func!
1742 ["key-name"] = value
1743 [] = "abc" -- menambahkan ke "tb"
1744```
1745
1746</YueDisplay>
1747
1748`with?` adalah versi yang ditingkatkan dari sintaks `with`, yang memperkenalkan pengecekan keberadaan untuk mengakses objek yang mungkin nil secara aman tanpa pemeriksaan null eksplisit.
1749
1750```yuescript
1751with? obj
1752 print obj.name
1753```
1754
1755<YueDisplay>
1756
1757```yue
1758with? obj
1759 print obj.name
1760```
1761
1762</YueDisplay>
1763
1764# Penugasan
1765
1766Variabel bersifat bertipe dinamis dan secara default dideklarasikan sebagai local. Namun Anda dapat mengubah cakupan deklarasi dengan pernyataan **local** dan **global**.
1767
1768```yuescript
1769hello = "world"
1770a, b, c = 1, 2, 3
1771hello = 123 -- menggunakan variabel yang sudah ada
1772```
1773
1774<YueDisplay>
1775
1776```yue
1777hello = "world"
1778a, b, c = 1, 2, 3
1779hello = 123 -- menggunakan variabel yang sudah ada
1780```
1781
1782</YueDisplay>
1783
1784## Pembaruan Nilai
1785
1786Anda dapat melakukan assignment pembaruan dengan banyak operator biner.
1787
1788```yuescript
1789x = 1
1790x += 1
1791x -= 1
1792x *= 10
1793x /= 10
1794x %= 10
1795s ..= "world" -- akan menambah local baru jika variabel local belum ada
1796arg or= "default value"
1797```
1798
1799<YueDisplay>
1800
1801```yue
1802x = 1
1803x += 1
1804x -= 1
1805x *= 10
1806x /= 10
1807x %= 10
1808s ..= "world" -- akan menambah local baru jika variabel local belum ada
1809arg or= "default value"
1810```
1811
1812</YueDisplay>
1813
1814## Assignment Berantai
1815
1816Anda bisa melakukan assignment berantai untuk menetapkan beberapa item ke nilai yang sama.
1817
1818```yuescript
1819a = b = c = d = e = 0
1820x = y = z = f!
1821```
1822
1823<YueDisplay>
1824
1825```yue
1826a = b = c = d = e = 0
1827x = y = z = f!
1828```
1829
1830</YueDisplay>
1831
1832## Local Eksplisit
1833
1834```yuescript
1835do
1836 local a = 1
1837 local *
1838 print "deklarasikan semua variabel sebagai local di awal"
1839 x = -> 1 + y + z
1840 y, z = 2, 3
1841 global instance = Item\new!
1842
1843do
1844 local X = 1
1845 local ^
1846 print "hanya deklarasikan variabel huruf besar sebagai local di awal"
1847 a = 1
1848 B = 2
1849```
1850
1851<YueDisplay>
1852
1853```yue
1854do
1855 local a = 1
1856 local *
1857 print "deklarasikan semua variabel sebagai local di awal"
1858 x = -> 1 + y + z
1859 y, z = 2, 3
1860 global instance = Item\new!
1861
1862do
1863 local X = 1
1864 local ^
1865 print "hanya deklarasikan variabel huruf besar sebagai local di awal"
1866 a = 1
1867 B = 2
1868```
1869
1870</YueDisplay>
1871
1872## Global Eksplisit
1873
1874```yuescript
1875do
1876 global a = 1
1877 global *
1878 print "deklarasikan semua variabel sebagai global"
1879 x = -> 1 + y + z
1880 y, z = 2, 3
1881
1882do
1883 global X = 1
1884 global ^
1885 print "hanya deklarasikan variabel huruf besar sebagai global"
1886 a = 1
1887 B = 2
1888 local Temp = "a local value"
1889```
1890
1891<YueDisplay>
1892
1893```yue
1894do
1895 global a = 1
1896 global *
1897 print "deklarasikan semua variabel sebagai global"
1898 x = -> 1 + y + z
1899 y, z = 2, 3
1900
1901do
1902 global X = 1
1903 global ^
1904 print "hanya deklarasikan variabel huruf besar sebagai global"
1905 a = 1
1906 B = 2
1907 local Temp = "a local value"
1908```
1909
1910</YueDisplay>
1911
1912# Penugasan Varargs
1913
1914Anda dapat meng-assign hasil yang dikembalikan dari sebuah fungsi ke simbol varargs `...`. Lalu akses isinya menggunakan cara Lua.
1915
1916```yuescript
1917list = [1, 2, 3, 4, 5]
1918fn = (ok) -> ok, table.unpack list
1919ok, ... = fn true
1920count = select '#', ...
1921first = select 1, ...
1922print ok, count, first
1923```
1924
1925<YueDisplay>
1926
1927```yue
1928list = [1, 2, 3, 4, 5]
1929fn = (ok) -> ok, table.unpack list
1930ok, ... = fn true
1931count = select '#', ...
1932first = select 1, ...
1933print ok, count, first
1934```
1935
1936</YueDisplay>
1937
1938# Penugasan pada If
1939
1940Blok `if` dan `elseif` dapat menerima assignment sebagai ganti ekspresi kondisional. Saat kondisi dievaluasi, assignment akan dilakukan dan nilai yang di-assign akan digunakan sebagai ekspresi kondisional. Variabel yang di-assign hanya berada dalam scope badan kondisional, artinya tidak pernah tersedia jika nilai tidak truthy. Dan Anda harus menggunakan "walrus operator" `:=` sebagai ganti `=` untuk melakukan assignment.
1941
1942```yuescript
1943if user := database.find_user "moon"
1944 print user.name
1945```
1946
1947<YueDisplay>
1948
1949```yue
1950if user := database.find_user "moon"
1951 print user.name
1952```
1953
1954</YueDisplay>
1955
1956```yuescript
1957if hello := os.getenv "hello"
1958 print "You have hello", hello
1959elseif world := os.getenv "world"
1960 print "you have world", world
1961else
1962 print "nothing :("
1963```
1964
1965<YueDisplay>
1966
1967```yue
1968if hello := os.getenv "hello"
1969 print "You have hello", hello
1970elseif world := os.getenv "world"
1971 print "you have world", world
1972else
1973 print "nothing :("
1974```
1975
1976</YueDisplay>
1977
1978Assignment if dengan beberapa nilai return. Hanya nilai pertama yang dicek, nilai lainnya tetap berada dalam scope.
1979
1980```yuescript
1981if success, result := pcall -> "get result without problems"
1982 print result -- variabel result berada dalam scope
1983print "OK"
1984```
1985
1986<YueDisplay>
1987
1988```yue
1989if success, result := pcall -> "get result without problems"
1990 print result -- variabel result berada dalam scope
1991print "OK"
1992```
1993
1994</YueDisplay>
1995
1996## Assignment pada While
1997
1998Anda juga bisa menggunakan assignment if di loop while untuk mendapatkan nilai sebagai kondisi loop.
1999
2000```yuescript
2001while byte := stream\read_one!
2002 -- lakukan sesuatu dengan byte
2003 print byte
2004```
2005
2006<YueDisplay>
2007
2008```yue
2009while byte := stream\read_one!
2010 -- lakukan sesuatu dengan byte
2011 print byte
2012```
2013
2014</YueDisplay>
2015
2016# Penugasan Destrukturisasi
2017
2018Assignment destrukturisasi adalah cara cepat untuk mengekstrak nilai dari sebuah tabel berdasarkan nama kunci atau posisinya pada tabel berbasis array.
2019
2020Biasanya ketika Anda melihat literal tabel, `{1,2,3}`, ia berada di sisi kanan assignment karena merupakan nilai. Assignment destrukturisasi menukar peran literal tabel dan menaruhnya di sisi kiri pernyataan assignment.
2021
2022Ini paling mudah dijelaskan dengan contoh. Berikut cara membongkar dua nilai pertama dari sebuah tabel:
2023
2024```yuescript
2025thing = [1, 2]
2026
2027[a, b] = thing
2028print a, b
2029```
2030
2031<YueDisplay>
2032
2033```yue
2034thing = [1, 2]
2035
2036[a, b] = thing
2037print a, b
2038```
2039
2040</YueDisplay>
2041
2042Di literal tabel destrukturisasi, kunci mewakili kunci yang dibaca dari sisi kanan, dan nilai mewakili nama yang akan menerima nilai tersebut.
2043
2044```yuescript
2045obj = {
2046 hello: "world"
2047 day: "tuesday"
2048 length: 20
2049}
2050
2051{hello: hello, day: the_day} = obj
2052print hello, the_day
2053
2054:day = obj -- OK untuk destrukturisasi sederhana tanpa kurung
2055```
2056
2057<YueDisplay>
2058
2059```yue
2060obj = {
2061 hello: "world"
2062 day: "tuesday"
2063 length: 20
2064}
2065
2066{hello: hello, day: the_day} = obj
2067print hello, the_day
2068
2069:day = obj -- OK untuk destrukturisasi sederhana tanpa kurung
2070```
2071
2072</YueDisplay>
2073
2074Ini juga bekerja pada struktur data bertingkat:
2075
2076```yuescript
2077obj2 = {
2078 numbers: [1, 2, 3, 4]
2079 properties: {
2080 color: "green"
2081 height: 13.5
2082 }
2083}
2084
2085{numbers: [first, second], properties: {color: color}} = obj2
2086print first, second, color
2087```
2088
2089<YueDisplay>
2090
2091```yue
2092obj2 = {
2093 numbers: [1, 2, 3, 4]
2094 properties: {
2095 color: "green"
2096 height: 13.5
2097 }
2098}
2099
2100{numbers: [first, second], properties: {color: color}} = obj2
2101print first, second, color
2102```
2103
2104</YueDisplay>
2105
2106Jika pernyataan destrukturisasi kompleks, Anda bisa memecahnya ke beberapa baris. Contoh yang sedikit lebih rumit:
2107
2108```yuescript
2109{
2110 numbers: [first, second]
2111 properties: {
2112 color: color
2113 }
2114} = obj2
2115```
2116
2117<YueDisplay>
2118
2119```yue
2120{
2121 numbers: [first, second]
2122 properties: {
2123 color: color
2124 }
2125} = obj2
2126```
2127
2128</YueDisplay>
2129
2130Umumnya mengekstrak nilai dari tabel lalu menugaskannya ke variabel local dengan nama yang sama dengan kuncinya. Untuk menghindari pengulangan, kita bisa menggunakan operator prefiks **:**:
2131
2132```yuescript
2133{:concat, :insert} = table
2134```
2135
2136<YueDisplay>
2137
2138```yue
2139{:concat, :insert} = table
2140```
2141
2142</YueDisplay>
2143
2144Ini secara efektif sama seperti import, tetapi kita dapat mengganti nama field yang ingin diekstrak dengan menggabungkan sintaks:
2145
2146```yuescript
2147{:mix, :max, random: rand} = math
2148```
2149
2150<YueDisplay>
2151
2152```yue
2153{:mix, :max, random: rand} = math
2154```
2155
2156</YueDisplay>
2157
2158Anda bisa menulis nilai default saat destrukturisasi seperti:
2159
2160```yuescript
2161{:name = "nameless", :job = "jobless"} = person
2162```
2163
2164<YueDisplay>
2165
2166```yue
2167{:name = "nameless", :job = "jobless"} = person
2168```
2169
2170</YueDisplay>
2171
2172Anda dapat menggunakan `_` sebagai placeholder saat destrukturisasi list:
2173
2174```yuescript
2175[_, two, _, four] = items
2176```
2177
2178<YueDisplay>
2179
2180```yue
2181[_, two, _, four] = items
2182```
2183
2184</YueDisplay>
2185
2186## Destrukturisasi Rentang
2187
2188Anda dapat menggunakan operator spread `...` pada destrukturisasi list untuk menangkap rentang nilai. Ini berguna ketika Anda ingin mengekstrak elemen tertentu dari awal dan akhir list sambil mengumpulkan sisanya di tengah.
2189
2190```yuescript
2191orders = ["first", "second", "third", "fourth", "last"]
2192[first, ...bulk, last] = orders
2193print first -- prints: first
2194print bulk -- prints: {"second", "third", "fourth"}
2195print last -- prints: last
2196```
2197
2198<YueDisplay>
2199
2200```yue
2201orders = ["first", "second", "third", "fourth", "last"]
2202[first, ...bulk, last] = orders
2203print first -- prints: first
2204print bulk -- prints: {"second", "third", "fourth"}
2205print last -- prints: last
2206```
2207
2208</YueDisplay>
2209
2210Operator spread dapat digunakan pada posisi berbeda untuk menangkap rentang yang berbeda, dan Anda bisa memakai `_` sebagai placeholder untuk nilai yang tidak ingin ditangkap:
2211
2212```yuescript
2213-- Tangkap semuanya setelah elemen pertama
2214[first, ...rest] = orders
2215
2216-- Tangkap semuanya sebelum elemen terakhir
2217[...start, last] = orders
2218
2219-- Tangkap semuanya kecuali elemen tengah
2220[first, ..._, last] = orders
2221```
2222
2223<YueDisplay>
2224
2225```yue
2226-- Tangkap semuanya setelah elemen pertama
2227[first, ...rest] = orders
2228
2229-- Tangkap semuanya sebelum elemen terakhir
2230[...start, last] = orders
2231
2232-- Tangkap semuanya kecuali elemen tengah
2233[first, ..._, last] = orders
2234```
2235
2236</YueDisplay>
2237
2238## Destrukturisasi di Tempat Lain
2239
2240Destrukturisasi juga dapat muncul di tempat-tempat di mana assignment terjadi secara implisit. Contohnya adalah perulangan for:
2241
2242```yuescript
2243tuples = [
2244 ["hello", "world"]
2245 ["egg", "head"]
2246]
2247
2248for [left, right] in *tuples
2249 print left, right
2250```
2251
2252<YueDisplay>
2253
2254```yue
2255tuples = [
2256 ["hello", "world"]
2257 ["egg", "head"]
2258]
2259
2260for [left, right] in *tuples
2261 print left, right
2262```
2263
2264</YueDisplay>
2265
2266Kita tahu setiap elemen pada tabel array adalah tuple dua item, sehingga kita dapat membongkarnya langsung di klausa nama pada pernyataan for menggunakan destrukturisasi.
2267
2268# Klausa Using; Mengendalikan Penugasan Destruktif
2269
2270Meskipun scope leksikal sangat membantu mengurangi kompleksitas kode yang kita tulis, hal ini bisa menjadi sulit ketika ukuran kode membesar. Pertimbangkan cuplikan berikut:
2271
2272```yuescript
2273i = 100
2274
2275-- banyak baris kode...
2276
2277my_func = ->
2278 i = 10
2279 while i > 0
2280 print i
2281 i -= 1
2282
2283my_func!
2284
2285print i -- akan mencetak 0
2286```
2287
2288<YueDisplay>
2289
2290```yue
2291i = 100
2292
2293-- banyak baris kode...
2294
2295my_func = ->
2296 i = 10
2297 while i > 0
2298 print i
2299 i -= 1
2300
2301my_func!
2302
2303print i -- akan mencetak 0
2304```
2305
2306</YueDisplay>
2307
2308Di `my_func`, kita tanpa sengaja menimpa nilai `i`. Dalam contoh ini halnya cukup jelas, tetapi bayangkan kode besar atau basis kode asing di mana tidak jelas nama apa saja yang sudah dideklarasikan.
2309
2310Akan sangat membantu jika kita dapat menyatakan variabel mana dari scope luar yang memang ingin kita ubah, agar mencegah mengubah yang lain secara tidak sengaja.
2311
2312Kata kunci `using` memungkinkan kita melakukan itu. `using nil` memastikan bahwa tidak ada variabel tertutup yang ditimpa dalam assignment. Klausa `using` ditempatkan setelah daftar argumen pada fungsi, atau menggantikannya jika tidak ada argumen.
2313
2314```yuescript
2315i = 100
2316
2317my_func = (using nil) ->
2318 i = "hello" -- variabel local baru dibuat di sini
2319
2320my_func!
2321print i -- mencetak 100, i tidak terpengaruh
2322```
2323
2324<YueDisplay>
2325
2326```yue
2327i = 100
2328
2329my_func = (using nil) ->
2330 i = "hello" -- variabel local baru dibuat di sini
2331
2332my_func!
2333print i -- mencetak 100, i tidak terpengaruh
2334```
2335
2336</YueDisplay>
2337
2338Beberapa nama dapat dipisahkan dengan koma. Nilai closure tetap bisa diakses, hanya saja tidak dapat dimodifikasi:
2339
2340```yuescript
2341tmp = 1213
2342i, k = 100, 50
2343
2344my_func = (add using k, i) ->
2345 tmp = tmp + add -- tmp local baru dibuat
2346 i += tmp
2347 k += tmp
2348
2349my_func(22)
2350print i, k -- ini telah diperbarui
2351```
2352
2353<YueDisplay>
2354
2355```yue
2356tmp = 1213
2357i, k = 100, 50
2358
2359my_func = (add using k, i) ->
2360 tmp = tmp + add -- tmp local baru dibuat
2361 i += tmp
2362 k += tmp
2363
2364my_func(22)
2365print i, k -- ini telah diperbarui
2366```
2367
2368</YueDisplay>
2369
2370# Penggunaan
2371
2372## Modul Lua
2373
2374Gunakan modul YueScript di Lua:
2375
2376- **Kasus 1**
2377
2378 Require "your_yuescript_entry.yue" di Lua.
2379
2380 ```Lua
2381 require("yue")("your_yuescript_entry")
2382 ```
2383
2384 Dan kode ini tetap bekerja ketika Anda mengompilasi "your_yuescript_entry.yue" menjadi "your_yuescript_entry.lua" di path yang sama. Pada file YueScript lainnya cukup gunakan **require** atau **import** biasa. Nomor baris pada pesan error juga akan ditangani dengan benar.
2385
2386- **Kasus 2**
2387
2388 Require modul YueScript dan tulis ulang pesan secara manual.
2389
2390 ```lua
2391 local yue = require("yue")
2392 yue.insert_loader()
2393 local success, result = xpcall(function()
2394 return require("yuescript_module_name")
2395 end, function(err)
2396 return yue.traceback(err)
2397 end)
2398 ```
2399
2400- **Kasus 3**
2401
2402 Gunakan fungsi kompiler YueScript di Lua.
2403
2404 ```lua
2405 local yue = require("yue")
2406 local codes, err, globals = yue.to_lua([[
2407 f = ->
2408 print "hello world"
2409 f!
2410 ]],{
2411 implicit_return_root = true,
2412 reserve_line_number = true,
2413 lint_global = true,
2414 space_over_tab = false,
2415 options = {
2416 target = "5.4",
2417 path = "/script"
2418 }
2419 })
2420 ```
2421
2422## Tool YueScript
2423
2424Gunakan tool YueScript dengan:
2425
2426```shell
2427> yue -h
2428Penggunaan: yue
2429 [opsi] [<file/direktori>] ...
2430 yue -e <kode_atau_file> [argumen...]
2431 yue -w [<direktori>] [opsi]
2432 yue -
2433
2434Catatan:
2435 - '-' / '--' harus menjadi argumen pertama dan satu-satunya.
2436 - '-o/--output' tidak dapat digunakan dengan beberapa file input.
2437 - '-w/--watch' tidak dapat digunakan dengan file input (khusus direktori).
2438 - dengan '-e/--execute', token sisanya dianggap sebagai argumen skrip.
2439
2440Opsi:
2441 -h, --help Tampilkan pesan bantuan ini dan keluar.
2442 -e <str>, --execute <str> Eksekusi file atau kode mentah
2443 -m, --minify Menghasilkan kode yang sudah diminimasi
2444 -r, --rewrite Tulis ulang output agar sesuai dengan nomor baris asal
2445 -t <output_to>, --output-to <output_to>
2446 Tentukan lokasi untuk menaruh file hasil kompilasi
2447 -o <file>, --output <file> Tulis output ke file
2448 -p, --print Tulis output ke standar output
2449 -b, --benchmark Tampilkan waktu kompilasi (tanpa menulis output)
2450 -g, --globals Tampilkan variabel global yang digunakan dalam FORMAT NAMA BARIS KOLOM
2451 -s, --spaces Pakai spasi di kode hasil kompilasi (bukan tab)
2452 -l, --line-numbers Tulis nomor baris dari kode sumber
2453 -j, --no-implicit-return Nonaktifkan return implisit di akhir file
2454 -c, --reserve-comments Pertahankan komentar sebelum pernyataan dari kode sumber
2455 -w [<dir>], --watch [<dir>]
2456 Pantau perubahan dan kompilasi setiap file di bawah direktori
2457 -v, --version Tampilkan versi
2458 - Baca dari standar input, tulis ke standar output
2459 (harus menjadi argumen pertama dan satu-satunya)
2460 -- Sama dengan '-', dipertahankan untuk kompatibilitas lama
2461
2462 --target <versi> Tentukan versi Lua yang akan dihasilkan kodenya
2463 (versi hanya bisa dari 5.1 sampai 5.5)
2464 --path <path_str> Tambahkan path pencarian Lua tambahan ke package.path
2465 --<key>=<value> Kirim opsi kompilasi dalam bentuk key=value (perilaku standar)
2466
2467 Jalankan tanpa opsi untuk masuk ke REPL, ketik simbol '$'
2468 dalam satu baris untuk memulai/mengakhiri mode multi-baris
2469```
2470
2471Gunakan kasus:
2472
2473Kompilasi semua file YueScript dengan ekstensi **.yue** secara rekursif di bawah path saat ini: **yue .**
2474
2475Kompilasi dan simpan hasil ke path target: **yue -t /target/path/ .**
2476
2477Kompilasi dan pertahankan info debug: **yue -l .**
2478
2479Kompilasi dan hasilkan kode yang diminisasi: **yue -m .**
2480
2481Eksekusi kode mentah: **yue -e 'print 123'**
2482
2483Eksekusi file YueScript: **yue -e main.yue**
2484
2485# Pendahuluan
2486
2487YueScript adalah bahasa dinamis yang dikompilasi ke Lua, dan merupakan dialek [MoonScript](https://github.com/leafo/moonscript). Kode yang ditulis dengan YueScript ekspresif dan sangat ringkas. YueScript cocok untuk menulis logika aplikasi yang sering berubah dengan kode yang lebih mudah dipelihara, serta berjalan di lingkungan embed Lua seperti game atau server situs web.
2488
2489Yue (月) adalah kata untuk bulan dalam bahasa Tionghoa dan diucapkan sebagai [jyɛ].
2490
2491## Ikhtisar YueScript
2492
2493```yuescript
2494-- import syntax
2495import p, to_lua from "yue"
2496
2497-- object literals
2498inventory =
2499 equipment:
2500 - "sword"
2501 - "shield"
2502 items:
2503 - name: "potion"
2504 count: 10
2505 - name: "bread"
2506 count: 3
2507
2508-- list comprehension
2509map = (arr, action) ->
2510 [action item for item in *arr]
2511
2512filter = (arr, cond) ->
2513 [item for item in *arr when cond item]
2514
2515reduce = (arr, init, action): init ->
2516 init = action init, item for item in *arr
2517
2518-- pipe operator
2519[1, 2, 3]
2520 |> map (x) -> x * 2
2521 |> filter (x) -> x > 4
2522 |> reduce 0, (a, b) -> a + b
2523 |> print
2524
2525-- metatable manipulation
2526apple =
2527 size: 15
2528 <index>:
2529 color: 0x00ffff
2530
2531with apple
2532 p .size, .color, .<index> if .<>?
2533
2534-- js-like export syntax
2535export 🌛 = "Skrip Bulan"
2536```
2537
2538<YueDisplay>
2539
2540```yue
2541-- import syntax
2542import p, to_lua from "yue"
2543
2544-- object literals
2545inventory =
2546 equipment:
2547 - "sword"
2548 - "shield"
2549 items:
2550 - name: "potion"
2551 count: 10
2552 - name: "bread"
2553 count: 3
2554
2555-- list comprehension
2556map = (arr, action) ->
2557 [action item for item in *arr]
2558
2559filter = (arr, cond) ->
2560 [item for item in *arr when cond item]
2561
2562reduce = (arr, init, action): init ->
2563 init = action init, item for item in *arr
2564
2565-- pipe operator
2566[1, 2, 3]
2567 |> map (x) -> x * 2
2568 |> filter (x) -> x > 4
2569 |> reduce 0, (a, b) -> a + b
2570 |> print
2571
2572-- metatable manipulation
2573apple =
2574 size: 15
2575 <index>:
2576 color: 0x00ffff
2577
2578with apple
2579 p .size, .color, .<index> if .<>?
2580
2581-- js-like export syntax
2582export 🌛 = "Skrip Bulan"
2583```
2584
2585</YueDisplay>
2586
2587## Tentang Dora SSR
2588
2589YueScript dikembangkan dan dipelihara bersama mesin game open-source [Dora SSR](https://github.com/Dora-SSR/Dora-SSR). YueScript telah digunakan untuk membuat alat mesin, demo game, dan prototipe, membuktikan kemampuannya dalam skenario dunia nyata sekaligus meningkatkan pengalaman pengembangan Dora SSR.
2590
2591# Instalasi
2592
2593## Modul Lua
2594
2595Instal [luarocks](https://luarocks.org), manajer paket untuk modul Lua. Lalu instal sebagai modul Lua dan executable dengan:
2596
2597```shell
2598luarocks install yuescript
2599```
2600
2601Atau Anda dapat membangun file `yue.so` dengan:
2602
2603```shell
2604make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua
2605```
2606
2607Lalu ambil file biner dari path **bin/shared/yue.so**.
2608
2609## Membangun Tool Biner
2610
2611Klon repo ini, lalu bangun dan instal executable dengan:
2612
2613```shell
2614make install
2615```
2616
2617Bangun tool YueScript tanpa fitur macro:
2618
2619```shell
2620make install NO_MACRO=true
2621```
2622
2623Bangun tool YueScript tanpa biner Lua bawaan:
2624
2625```shell
2626make install NO_LUA=true
2627```
2628
2629## Unduh Biner Pra-kompilasi
2630
2631Anda dapat mengunduh file biner pra-kompilasi, termasuk file executable biner yang kompatibel dengan berbagai versi Lua dan file library.
2632
2633Unduh file biner pra-kompilasi dari [sini](https://github.com/IppClub/YueScript/releases).
2634
2635# Kondisional
2636
2637```yuescript
2638have_coins = false
2639if have_coins
2640 print "Dapat koin"
2641else
2642 print "Tidak ada koin"
2643```
2644
2645<YueDisplay>
2646
2647```yue
2648have_coins = false
2649if have_coins
2650 print "Dapat koin"
2651else
2652 print "Tidak ada koin"
2653```
2654
2655</YueDisplay>
2656
2657Sintaks pendek untuk pernyataan tunggal juga bisa digunakan:
2658
2659```yuescript
2660have_coins = false
2661if have_coins then print "Dapat koin" else print "Tidak ada koin"
2662```
2663
2664<YueDisplay>
2665
2666```yue
2667have_coins = false
2668if have_coins then print "Dapat koin" else print "Tidak ada koin"
2669```
2670
2671</YueDisplay>
2672
2673Karena pernyataan if dapat digunakan sebagai ekspresi, ini juga bisa ditulis sebagai:
2674
2675```yuescript
2676have_coins = false
2677print if have_coins then "Dapat koin" else "Tidak ada koin"
2678```
2679
2680<YueDisplay>
2681
2682```yue
2683have_coins = false
2684print if have_coins then "Dapat koin" else "Tidak ada koin"
2685```
2686
2687</YueDisplay>
2688
2689Kondisional juga bisa digunakan di pernyataan return dan assignment:
2690
2691```yuescript
2692is_tall = (name) ->
2693 if name == "Rob"
2694 true
2695 else
2696 false
2697
2698message = if is_tall "Rob"
2699 "Saya sangat tinggi"
2700else
2701 "Saya tidak terlalu tinggi"
2702
2703print message -- prints: Saya sangat tinggi
2704```
2705
2706<YueDisplay>
2707
2708```yue
2709is_tall = (name) ->
2710 if name == "Rob"
2711 true
2712 else
2713 false
2714
2715message = if is_tall "Rob"
2716 "Saya sangat tinggi"
2717else
2718 "Saya tidak terlalu tinggi"
2719
2720print message -- prints: Saya sangat tinggi
2721```
2722
2723</YueDisplay>
2724
2725Kebalikan dari if adalah unless:
2726
2727```yuescript
2728unless os.date("%A") == "Monday"
2729 print "hari ini bukan Senin!"
2730```
2731
2732<YueDisplay>
2733
2734```yue
2735unless os.date("%A") == "Monday"
2736 print "hari ini bukan Senin!"
2737```
2738
2739</YueDisplay>
2740
2741```yuescript
2742print "Kamu beruntung!" unless math.random! > 0.1
2743```
2744
2745<YueDisplay>
2746
2747```yue
2748print "Kamu beruntung!" unless math.random! > 0.1
2749```
2750
2751</YueDisplay>
2752
2753## Ekspresi In
2754
2755Anda dapat menulis kode pengecekan rentang dengan `ekspresi in`.
2756
2757```yuescript
2758a = 5
2759
2760if a in [1, 3, 5, 7]
2761 print "memeriksa kesamaan dengan nilai-nilai diskrit"
2762
2763if a in list
2764 print "memeriksa apakah `a` ada di dalam daftar"
2765```
2766
2767<YueDisplay>
2768
2769```yue
2770a = 5
2771
2772if a in [1, 3, 5, 7]
2773 print "memeriksa kesamaan dengan nilai-nilai diskrit"
2774
2775if a in list
2776 print "memeriksa apakah `a` ada di dalam daftar"
2777```
2778
2779</YueDisplay>
2780
2781# Perulangan For
2782
2783Ada dua bentuk perulangan for, seperti di Lua. Satu numerik dan satu generik:
2784
2785```yuescript
2786for i = 10, 20
2787 print i
2788
2789for k = 1, 15, 2 -- an optional step provided
2790 print k
2791
2792for key, value in pairs object
2793 print key, value
2794```
2795
2796<YueDisplay>
2797
2798```yue
2799for i = 10, 20
2800 print i
2801
2802for k = 1, 15, 2 -- an optional step provided
2803 print k
2804
2805for key, value in pairs object
2806 print key, value
2807```
2808
2809</YueDisplay>
2810
2811Operator slicing dan **\*** dapat digunakan, seperti pada comprehension:
2812
2813```yuescript
2814for item in *items[2, 4]
2815 print item
2816```
2817
2818<YueDisplay>
2819
2820```yue
2821for item in *items[2, 4]
2822 print item
2823```
2824
2825</YueDisplay>
2826
2827Sintaks yang lebih singkat juga tersedia untuk semua variasi ketika badan hanya satu baris:
2828
2829```yuescript
2830for item in *items do print item
2831
2832for j = 1, 10, 3 do print j
2833```
2834
2835<YueDisplay>
2836
2837```yue
2838for item in *items do print item
2839
2840for j = 1, 10, 3 do print j
2841```
2842
2843</YueDisplay>
2844
2845Perulangan for juga bisa digunakan sebagai ekspresi. Pernyataan terakhir di badan for dipaksa menjadi ekspresi dan ditambahkan ke tabel array yang terakumulasi.
2846
2847Menggandakan setiap bilangan genap:
2848
2849```yuescript
2850doubled_evens = for i = 1, 20
2851 if i % 2 == 0
2852 i * 2
2853 else
2854 i
2855```
2856
2857<YueDisplay>
2858
2859```yue
2860doubled_evens = for i = 1, 20
2861 if i % 2 == 0
2862 i * 2
2863 else
2864 i
2865```
2866
2867</YueDisplay>
2868
2869Selain itu, loop for mendukung break dengan nilai kembalian, sehingga loop itu sendiri bisa dipakai sebagai ekspresi yang keluar lebih awal dengan hasil bermakna. Ekspresi `for` mendukung `break` dengan banyak nilai.
2870
2871Contohnya, untuk menemukan angka pertama yang lebih besar dari 10:
2872
2873```yuescript
2874first_large = for n in *numbers
2875 break n if n > 10
2876```
2877
2878<YueDisplay>
2879
2880```yue
2881first_large = for n in *numbers
2882 break n if n > 10
2883```
2884
2885</YueDisplay>
2886
2887Sintaks break-dengan-nilai ini memungkinkan pola pencarian atau keluar-lebih-awal yang ringkas langsung di dalam ekspresi loop.
2888
2889```yuescript
2890key, score = for k, v in pairs data
2891 break k, v * 10 if k == "target"
2892```
2893
2894<YueDisplay>
2895
2896```yue
2897key, score = for k, v in pairs data
2898 break k, v * 10 if k == "target"
2899```
2900
2901</YueDisplay>
2902
2903Anda juga bisa memfilter nilai dengan menggabungkan ekspresi for dengan pernyataan continue.
2904
2905Loop for di akhir badan fungsi tidak diakumulasikan menjadi tabel untuk nilai kembalian (sebaliknya fungsi akan mengembalikan nil). Gunakan pernyataan return eksplisit, atau ubah loop menjadi list comprehension.
2906
2907```yuescript
2908func_a = -> for i = 1, 10 do print i
2909func_b = -> return for i = 1, 10 do i
2910
2911print func_a! -- prints nil
2912print func_b! -- prints table object
2913```
2914
2915<YueDisplay>
2916
2917```yue
2918func_a = -> for i = 1, 10 do print i
2919func_b = -> return for i = 1, 10 do i
2920
2921print func_a! -- prints nil
2922print func_b! -- prints table object
2923```
2924
2925</YueDisplay>
2926
2927# Pernyataan Continue
2928
2929Pernyataan continue dapat digunakan untuk melewati iterasi saat ini di dalam loop.
2930
2931```yuescript
2932i = 0
2933while i < 10
2934 i += 1
2935 continue if i % 2 == 0
2936 print i
2937```
2938
2939<YueDisplay>
2940
2941```yue
2942i = 0
2943while i < 10
2944 i += 1
2945 continue if i % 2 == 0
2946 print i
2947```
2948
2949</YueDisplay>
2950
2951continue juga bisa digunakan bersama ekspresi loop untuk mencegah iterasi tersebut diakumulasikan ke hasil. Contoh ini memfilter tabel array menjadi hanya angka genap:
2952
2953```yuescript
2954my_numbers = [1, 2, 3, 4, 5, 6]
2955odds = for x in *my_numbers
2956 continue if x % 2 == 1
2957 x
2958```
2959
2960<YueDisplay>
2961
2962```yue
2963my_numbers = [1, 2, 3, 4, 5, 6]
2964odds = for x in *my_numbers
2965 continue if x % 2 == 1
2966 x
2967```
2968
2969</YueDisplay>
2970
2971# Pernyataan Switch
2972
2973Pernyataan switch adalah bentuk singkat untuk menulis serangkaian if yang membandingkan nilai yang sama. Perhatikan bahwa nilainya hanya dievaluasi sekali. Seperti if, switch bisa memiliki blok else untuk menangani tidak ada yang cocok. Perbandingan dilakukan dengan operator `==`. Di dalam switch, Anda juga bisa memakai ekspresi assignment untuk menyimpan nilai variabel sementara.
2974
2975```yuescript
2976switch name := "Dan"
2977 when "Robert"
2978 print "You are Robert"
2979 when "Dan", "Daniel"
2980 print "Your name, it's Dan"
2981 else
2982 print "I don't know about you with name #{name}"
2983```
2984
2985<YueDisplay>
2986
2987```yue
2988switch name := "Dan"
2989 when "Robert"
2990 print "You are Robert"
2991 when "Dan", "Daniel"
2992 print "Your name, it's Dan"
2993 else
2994 print "I don't know about you with name #{name}"
2995```
2996
2997</YueDisplay>
2998
2999Klausa when pada switch bisa mencocokkan beberapa nilai dengan menuliskannya dipisah koma.
3000
3001Switch juga bisa dipakai sebagai ekspresi; di sini kita dapat menetapkan hasil switch ke sebuah variabel:
3002
3003```yuescript
3004b = 1
3005next_number = switch b
3006 when 1
3007 2
3008 when 2
3009 3
3010 else
3011 error "can't count that high!"
3012```
3013
3014<YueDisplay>
3015
3016```yue
3017b = 1
3018next_number = switch b
3019 when 1
3020 2
3021 when 2
3022 3
3023 else
3024 error "can't count that high!"
3025```
3026
3027</YueDisplay>
3028
3029Kita bisa memakai kata kunci `then` untuk menulis blok when switch pada satu baris. Tidak ada kata kunci tambahan yang dibutuhkan untuk menulis blok else pada satu baris.
3030
3031```yuescript
3032msg = switch math.random(1, 5)
3033 when 1 then "you are lucky"
3034 when 2 then "you are almost lucky"
3035 else "not so lucky"
3036```
3037
3038<YueDisplay>
3039
3040```yue
3041msg = switch math.random(1, 5)
3042 when 1 then "you are lucky"
3043 when 2 then "you are almost lucky"
3044 else "not so lucky"
3045```
3046
3047</YueDisplay>
3048
3049Jika Anda ingin menulis kode dengan satu indentasi lebih sedikit saat menulis switch, Anda bisa menaruh klausa when pertama pada baris awal pernyataan, lalu semua klausa lain dapat ditulis dengan satu indentasi lebih sedikit.
3050
3051```yuescript
3052switch math.random(1, 5)
3053 when 1
3054 print "you are lucky" -- two indents
3055 else
3056 print "not so lucky"
3057
3058switch math.random(1, 5) when 1
3059 print "you are lucky" -- one indent
3060else
3061 print "not so lucky"
3062```
3063
3064<YueDisplay>
3065
3066```yue
3067switch math.random(1, 5)
3068 when 1
3069 print "you are lucky" -- two indents
3070 else
3071 print "not so lucky"
3072
3073switch math.random(1, 5) when 1
3074 print "you are lucky" -- one indent
3075else
3076 print "not so lucky"
3077```
3078
3079</YueDisplay>
3080
3081Perlu dicatat urutan ekspresi perbandingan kasus. Ekspresi kasus berada di sisi kiri. Ini bisa berguna jika ekspresi kasus ingin mengganti cara perbandingan dengan mendefinisikan metamethod `eq`.
3082
3083## Pencocokan Tabel
3084
3085Anda bisa melakukan pencocokan tabel dalam klausa when switch, jika tabel dapat didestrukturisasi oleh struktur tertentu dan mendapatkan nilai non-nil.
3086
3087```yuescript
3088items =
3089 * x: 100
3090 y: 200
3091 * width: 300
3092 height: 400
3093
3094for item in *items
3095 switch item
3096 when :x, :y
3097 print "Vec2 #{x}, #{y}"
3098 when :width, :height
3099 print "size #{width}, #{height}"
3100```
3101
3102<YueDisplay>
3103
3104```yue
3105items =
3106 * x: 100
3107 y: 200
3108 * width: 300
3109 height: 400
3110
3111for item in *items
3112 switch item
3113 when :x, :y
3114 print "Vec2 #{x}, #{y}"
3115 when :width, :height
3116 print "size #{width}, #{height}"
3117```
3118
3119</YueDisplay>
3120
3121Anda dapat menggunakan nilai default untuk mendestrukturisasi tabel secara opsional pada beberapa field.
3122
3123```yuescript
3124item = {}
3125
3126{pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos')
3127
3128switch item
3129 when {pos: {:x = 50, :y = 200}}
3130 print "Vec2 #{x}, #{y}" -- table destructuring will still pass
3131```
3132
3133<YueDisplay>
3134
3135```yue
3136item = {}
3137
3138{pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos')
3139
3140switch item
3141 when {pos: {:x = 50, :y = 200}}
3142 print "Vec2 #{x}, #{y}" -- table destructuring will still pass
3143```
3144
3145</YueDisplay>
3146
3147Anda juga bisa mencocokkan elemen array, field tabel, dan bahkan struktur bertingkat dengan literal array atau tabel.
3148
3149Cocokkan terhadap elemen array.
3150
3151```yuescript
3152switch tb
3153 when [1, 2, 3]
3154 print "1, 2, 3"
3155 when [1, b, 3]
3156 print "1, #{b}, 3"
3157 when [1, 2, b = 3] -- b has a default value
3158 print "1, 2, #{b}"
3159```
3160
3161<YueDisplay>
3162
3163```yue
3164switch tb
3165 when [1, 2, 3]
3166 print "1, 2, 3"
3167 when [1, b, 3]
3168 print "1, #{b}, 3"
3169 when [1, 2, b = 3] -- b has a default value
3170 print "1, 2, #{b}"
3171```
3172
3173</YueDisplay>
3174
3175Cocokkan terhadap field tabel dengan destrukturisasi.
3176
3177```yuescript
3178switch tb
3179 when success: true, :result
3180 print "success", result
3181 when success: false
3182 print "failed", result
3183 else
3184 print "invalid"
3185```
3186
3187<YueDisplay>
3188
3189```yue
3190switch tb
3191 when success: true, :result
3192 print "success", result
3193 when success: false
3194 print "failed", result
3195 else
3196 print "invalid"
3197```
3198
3199</YueDisplay>
3200
3201Cocokkan terhadap struktur tabel bertingkat.
3202
3203```yuescript
3204switch tb
3205 when data: {type: "success", :content}
3206 print "success", content
3207 when data: {type: "error", :content}
3208 print "failed", content
3209 else
3210 print "invalid"
3211```
3212
3213<YueDisplay>
3214
3215```yue
3216switch tb
3217 when data: {type: "success", :content}
3218 print "success", content
3219 when data: {type: "error", :content}
3220 print "failed", content
3221 else
3222 print "invalid"
3223```
3224
3225</YueDisplay>
3226
3227Cocokkan terhadap array dari tabel.
3228
3229```yuescript
3230switch tb
3231 when [
3232 {a: 1, b: 2}
3233 {a: 3, b: 4}
3234 {a: 5, b: 6}
3235 fourth
3236 ]
3237 print "matched", fourth
3238```
3239
3240<YueDisplay>
3241
3242```yue
3243switch tb
3244 when [
3245 {a: 1, b: 2}
3246 {a: 3, b: 4}
3247 {a: 5, b: 6}
3248 fourth
3249 ]
3250 print "matched", fourth
3251```
3252
3253</YueDisplay>
3254
3255Cocokkan terhadap daftar dan tangkap rentang elemen.
3256
3257```yuescript
3258segments = ["admin", "users", "logs", "view"]
3259switch segments
3260 when [...groups, resource, action]
3261 print "Group:", groups -- prints: {"admin", "users"}
3262 print "Resource:", resource -- prints: "logs"
3263 print "Action:", action -- prints: "view"
3264```
3265
3266<YueDisplay>
3267
3268```yue
3269segments = ["admin", "users", "logs", "view"]
3270switch segments
3271 when [...groups, resource, action]
3272 print "Group:", groups -- prints: {"admin", "users"}
3273 print "Resource:", resource -- prints: "logs"
3274 print "Action:", action -- prints: "view"
3275```
3276
3277</YueDisplay>
3278
3279# Perulangan While
3280
3281Perulangan while juga memiliki empat variasi:
3282
3283```yuescript
3284i = 10
3285while i > 0
3286 print i
3287 i -= 1
3288
3289while running == true do my_function!
3290```
3291
3292<YueDisplay>
3293
3294```yue
3295i = 10
3296while i > 0
3297 print i
3298 i -= 1
3299
3300while running == true do my_function!
3301```
3302
3303</YueDisplay>
3304
3305```yuescript
3306i = 10
3307until i == 0
3308 print i
3309 i -= 1
3310
3311until running == false do my_function!
3312```
3313
3314<YueDisplay>
3315
3316```yue
3317i = 10
3318until i == 0
3319 print i
3320 i -= 1
3321until running == false do my_function!
3322```
3323
3324</YueDisplay>
3325
3326Seperti loop for, loop while juga bisa digunakan sebagai ekspresi. Ekspresi `while` dan `until` mendukung `break` dengan banyak nilai.
3327
3328```yuescript
3329value, doubled = while true
3330 n = get_next!
3331 break n, n * 2 if n > 10
3332```
3333
3334<YueDisplay>
3335
3336```yue
3337value, doubled = while true
3338 n = get_next!
3339 break n, n * 2 if n > 10
3340```
3341
3342</YueDisplay>
3343
3344Selain itu, agar sebuah fungsi mengembalikan nilai akumulasi dari loop while, pernyataannya harus di-return secara eksplisit.
3345
3346## Repeat Loop
3347
3348Loop repeat berasal dari Lua:
3349
3350```yuescript
3351i = 10
3352repeat
3353 print i
3354 i -= 1
3355until i == 0
3356```
3357
3358<YueDisplay>
3359
3360```yue
3361i = 10
3362repeat
3363 print i
3364 i -= 1
3365until i == 0
3366```
3367
3368</YueDisplay>
3369
3370Ekspresi `repeat` juga mendukung `break` dengan banyak nilai:
3371
3372```yuescript
3373i = 1
3374value, scaled = repeat
3375 break i, i * 100 if i > 3
3376 i += 1
3377until false
3378```
3379
3380<YueDisplay>
3381
3382```yue
3383i = 1
3384value, scaled = repeat
3385 break i, i * 100 if i > 3
3386 i += 1
3387until false
3388```
3389
3390</YueDisplay>
3391
3392# Stub Fungsi
3393
3394Sering kali fungsi dari sebuah objek diteruskan sebagai nilai, misalnya meneruskan method instance ke fungsi lain sebagai callback. Jika fungsi mengharapkan objek yang dioperasikan sebagai argumen pertama, maka Anda harus menggabungkan objek tersebut dengan fungsi agar dapat dipanggil dengan benar.
3395
3396Sintaks stub fungsi adalah singkatan untuk membuat fungsi closure baru yang menggabungkan objek dan fungsi. Fungsi baru ini memanggil fungsi yang dibungkus dalam konteks objek yang benar.
3397
3398Sintaksnya sama seperti memanggil method instance dengan operator `\`, tetapi tanpa menyediakan daftar argumen.
3399
3400```yuescript
3401my_object = {
3402 value: 1000
3403 write: => print "the value:", @value
3404}
3405
3406run_callback = (func) ->
3407 print "running callback..."
3408 func!
3409
3410-- ini tidak akan berfungsi:
3411-- fungsi tidak memiliki referensi ke my_object
3412run_callback my_object.write
3413
3414-- sintaks stub fungsi
3415-- memungkinkan kita membundel objek ke fungsi baru
3416run_callback my_object\write
3417```
3418
3419<YueDisplay>
3420
3421```yue
3422my_object = {
3423 value: 1000
3424 write: => print "the value:", @value
3425}
3426
3427run_callback = (func) ->
3428 print "running callback..."
3429 func!
3430
3431-- ini tidak akan berfungsi:
3432-- fungsi tidak memiliki referensi ke my_object
3433run_callback my_object.write
3434
3435-- sintaks stub fungsi
3436-- memungkinkan kita membundel objek ke fungsi baru
3437run_callback my_object\write
3438```
3439
3440</YueDisplay>
3441
3442# Backcall
3443
3444Backcall digunakan untuk meratakan callback yang bersarang. Backcall didefinisikan menggunakan panah yang mengarah ke kiri sebagai parameter terakhir secara default yang akan mengisi pemanggilan fungsi. Semua sintaks pada dasarnya sama seperti fungsi panah biasa, kecuali arahnya berlawanan dan badan fungsi tidak memerlukan indentasi.
3445
3446```yuescript
3447x <- f
3448print "hello" .. x
3449```
3450
3451<YueDisplay>
3452
3453```yue
3454x <- f
3455print "hello" .. x
3456```
3457
3458</YueDisplay>
3459
3460Fungsi panah tebal juga tersedia.
3461
3462```yuescript
3463<= f
3464print @value
3465```
3466
3467<YueDisplay>
3468
3469```yue
3470<= f
3471print @value
3472```
3473
3474</YueDisplay>
3475
3476Anda dapat menentukan placeholder untuk posisi fungsi backcall sebagai parameter.
3477
3478```yuescript
3479(x) <- map _, [1, 2, 3]
3480x * 2
3481```
3482
3483<YueDisplay>
3484
3485```yue
3486(x) <- map _, [1, 2, 3]
3487x * 2
3488```
3489
3490</YueDisplay>
3491
3492Jika Anda ingin menulis kode lanjutan setelah backcall, Anda dapat memisahkannya dengan pernyataan `do`. Tanda kurung dapat dihilangkan untuk fungsi panah non-tebal.
3493
3494```yuescript
3495result, msg = do
3496 data <- readAsync "filename.txt"
3497 print data
3498 info <- processAsync data
3499 check info
3500print result, msg
3501```
3502
3503<YueDisplay>
3504
3505```yue
3506result, msg = do
3507 data <- readAsync "filename.txt"
3508 print data
3509 info <- processAsync data
3510 check info
3511print result, msg
3512```
3513
3514</YueDisplay>
3515
3516# Literal Fungsi
3517
3518Semua fungsi dibuat menggunakan ekspresi fungsi. Fungsi sederhana ditandai dengan panah: **->**.
3519
3520```yuescript
3521my_function = ->
3522my_function() -- memanggil fungsi kosong
3523```
3524
3525<YueDisplay>
3526
3527```yue
3528my_function = ->
3529my_function() -- memanggil fungsi kosong
3530```
3531
3532</YueDisplay>
3533
3534Badan fungsi bisa berupa satu pernyataan yang ditulis langsung setelah panah, atau berupa serangkaian pernyataan yang diindentasi di baris berikutnya:
3535
3536```yuescript
3537func_a = -> print "hello world"
3538
3539func_b = ->
3540 value = 100
3541 print "The value:", value
3542```
3543
3544<YueDisplay>
3545
3546```yue
3547func_a = -> print "hello world"
3548
3549func_b = ->
3550 value = 100
3551 print "The value:", value
3552```
3553
3554</YueDisplay>
3555
3556Jika fungsi tidak memiliki argumen, ia dapat dipanggil menggunakan operator `!`, sebagai ganti tanda kurung kosong. Pemanggilan `!` adalah cara yang disarankan untuk memanggil fungsi tanpa argumen.
3557
3558```yuescript
3559func_a!
3560func_b()
3561```
3562
3563<YueDisplay>
3564
3565```yue
3566func_a!
3567func_b()
3568```
3569
3570</YueDisplay>
3571
3572Fungsi dengan argumen dapat dibuat dengan menaruh daftar nama argumen dalam tanda kurung sebelum panah:
3573
3574```yuescript
3575sum = (x, y) -> print "sum", x + y
3576```
3577
3578<YueDisplay>
3579
3580```yue
3581sum = (x, y) -> print "sum", x + y
3582```
3583
3584</YueDisplay>
3585
3586Fungsi dapat dipanggil dengan menuliskan argumen setelah nama ekspresi yang mengevaluasi ke fungsi. Saat merangkai pemanggilan fungsi, argumen diterapkan ke fungsi terdekat di sebelah kiri.
3587
3588```yuescript
3589sum 10, 20
3590print sum 10, 20
3591
3592a b c "a", "b", "c"
3593```
3594
3595<YueDisplay>
3596
3597```yue
3598sum 10, 20
3599print sum 10, 20
3600
3601a b c "a", "b", "c"
3602```
3603
3604</YueDisplay>
3605
3606Untuk menghindari ambiguitas saat memanggil fungsi, tanda kurung juga bisa digunakan untuk mengelilingi argumen. Ini diperlukan di sini agar argumen yang tepat dikirim ke fungsi yang tepat.
3607
3608```yuescript
3609print "x:", sum(10, 20), "y:", sum(30, 40)
3610```
3611
3612<YueDisplay>
3613
3614```yue
3615print "x:", sum(10, 20), "y:", sum(30, 40)
3616```
3617
3618</YueDisplay>
3619
3620Tidak boleh ada spasi antara tanda kurung buka dan nama fungsi.
3621
3622Fungsi akan memaksa pernyataan terakhir di badannya menjadi pernyataan return, ini disebut return implisit:
3623
3624```yuescript
3625sum = (x, y) -> x + y
3626print "The sum is ", sum 10, 20
3627```
3628
3629<YueDisplay>
3630
3631```yue
3632sum = (x, y) -> x + y
3633print "The sum is ", sum 10, 20
3634```
3635
3636</YueDisplay>
3637
3638Dan jika Anda perlu return secara eksplisit, Anda bisa menggunakan kata kunci `return`:
3639
3640```yuescript
3641sum = (x, y) -> return x + y
3642```
3643
3644<YueDisplay>
3645
3646```yue
3647sum = (x, y) -> return x + y
3648```
3649
3650</YueDisplay>
3651
3652Seperti di Lua, fungsi dapat mengembalikan beberapa nilai. Pernyataan terakhir harus berupa daftar nilai yang dipisahkan koma:
3653
3654```yuescript
3655mystery = (x, y) -> x + y, x - y
3656a, b = mystery 10, 20
3657```
3658
3659<YueDisplay>
3660
3661```yue
3662mystery = (x, y) -> x + y, x - y
3663a, b = mystery 10, 20
3664```
3665
3666</YueDisplay>
3667
3668## Panah Tebal
3669
3670Karena sudah menjadi idiom di Lua untuk mengirim objek sebagai argumen pertama saat memanggil method, disediakan sintaks khusus untuk membuat fungsi yang otomatis menyertakan argumen `self`.
3671
3672```yuescript
3673func = (num) => @value + num
3674```
3675
3676<YueDisplay>
3677
3678```yue
3679func = (num) => @value + num
3680```
3681
3682</YueDisplay>
3683
3684## Nilai Default Argumen
3685
3686Dimungkinkan untuk menyediakan nilai default bagi argumen fungsi. Argumen dianggap kosong jika nilainya nil. Argumen nil yang memiliki nilai default akan diganti sebelum badan fungsi dijalankan.
3687
3688```yuescript
3689my_function = (name = "something", height = 100) ->
3690 print "Hello I am", name
3691 print "My height is", height
3692```
3693
3694<YueDisplay>
3695
3696```yue
3697my_function = (name = "something", height = 100) ->
3698 print "Hello I am", name
3699 print "My height is", height
3700```
3701
3702</YueDisplay>
3703
3704Ekspresi nilai default argumen dievaluasi di dalam badan fungsi sesuai urutan deklarasi argumen. Karena itu, nilai default dapat mengakses argumen yang dideklarasikan sebelumnya.
3705
3706```yuescript
3707some_args = (x = 100, y = x + 1000) ->
3708 print x + y
3709```
3710
3711<YueDisplay>
3712
3713```yue
3714some_args = (x = 100, y = x + 1000) ->
3715 print x + y
3716```
3717
3718</YueDisplay>
3719
3720## Pertimbangan
3721
3722Karena cara pemanggilan fungsi tanpa tanda kurung yang ekspresif, beberapa pembatasan harus diterapkan untuk menghindari ambiguitas parsing yang melibatkan spasi.
3723
3724Tanda minus memiliki dua peran, operator negasi unari dan operator pengurangan biner. Perhatikan bagaimana contoh berikut dikompilasi:
3725
3726```yuescript
3727a = x - 10
3728b = x-10
3729c = x -y
3730d = x- z
3731```
3732
3733<YueDisplay>
3734
3735```yue
3736a = x - 10
3737b = x-10
3738c = x -y
3739d = x- z
3740```
3741
3742</YueDisplay>
3743
3744Prioritas argumen pertama pada pemanggilan fungsi dapat dikendalikan menggunakan spasi jika argumennya adalah literal string. Di Lua, sudah umum untuk menghilangkan tanda kurung saat memanggil fungsi dengan satu literal string atau tabel.
3745
3746Ketika tidak ada spasi antara variabel dan literal string, pemanggilan fungsi akan memiliki prioritas atas ekspresi yang mengikuti. Tidak ada argumen lain yang dapat diberikan pada fungsi ketika dipanggil dengan cara ini.
3747
3748Ketika ada spasi setelah variabel dan literal string, pemanggilan fungsi bertindak seperti yang dijelaskan di atas. Literal string menjadi milik ekspresi berikutnya (jika ada), yang berfungsi sebagai daftar argumen.
3749
3750```yuescript
3751x = func"hello" + 100
3752y = func "hello" + 100
3753```
3754
3755<YueDisplay>
3756
3757```yue
3758x = func"hello" + 100
3759y = func "hello" + 100
3760```
3761
3762</YueDisplay>
3763
3764## Argumen Multi-baris
3765
3766Saat memanggil fungsi yang menerima banyak argumen, akan lebih nyaman untuk memecah daftar argumen menjadi beberapa baris. Karena sifat bahasa yang peka terhadap spasi, perlu hati-hati saat memecah daftar argumen.
3767
3768Jika daftar argumen akan dilanjutkan ke baris berikutnya, baris saat ini harus diakhiri dengan koma. Dan baris berikutnya harus lebih terindentasi daripada indentasi saat ini. Setelah diindentasi, semua baris argumen lainnya harus berada pada tingkat indentasi yang sama agar menjadi bagian dari daftar argumen.
3769
3770```yuescript
3771my_func 5, 4, 3,
3772 8, 9, 10
3773
3774cool_func 1, 2,
3775 3, 4,
3776 5, 6,
3777 7, 8
3778```
3779
3780<YueDisplay>
3781
3782```yue
3783my_func 5, 4, 3,
3784 8, 9, 10
3785
3786cool_func 1, 2,
3787 3, 4,
3788 5, 6,
3789 7, 8
3790```
3791
3792</YueDisplay>
3793
3794Jenis pemanggilan ini dapat dinest. Tingkat indentasi digunakan untuk menentukan argumen milik fungsi yang mana.
3795
3796```yuescript
3797my_func 5, 6, 7,
3798 6, another_func 6, 7, 8,
3799 9, 1, 2,
3800 5, 4
3801```
3802
3803<YueDisplay>
3804
3805```yue
3806my_func 5, 6, 7,
3807 6, another_func 6, 7, 8,
3808 9, 1, 2,
3809 5, 4
3810```
3811
3812</YueDisplay>
3813
3814Karena tabel juga menggunakan koma sebagai pemisah, sintaks indentasi ini membantu agar nilai menjadi bagian dari daftar argumen, bukan bagian dari tabel.
3815
3816```yuescript
3817x = [
3818 1, 2, 3, 4, a_func 4, 5,
3819 5, 6,
3820 8, 9, 10
3821]
3822```
3823
3824<YueDisplay>
3825
3826```yue
3827x = [
3828 1, 2, 3, 4, a_func 4, 5,
3829 5, 6,
3830 8, 9, 10
3831]
3832```
3833
3834</YueDisplay>
3835
3836Meskipun jarang, perhatikan bahwa kita bisa memberikan indentasi yang lebih dalam untuk argumen fungsi jika kita tahu akan menggunakan indentasi yang lebih dangkal di bagian selanjutnya.
3837
3838```yuescript
3839y = [ my_func 1, 2, 3,
3840 4, 5,
3841 5, 6, 7
3842]
3843```
3844
3845<YueDisplay>
3846
3847```yue
3848y = [ my_func 1, 2, 3,
3849 4, 5,
3850 5, 6, 7
3851]
3852```
3853
3854</YueDisplay>
3855
3856Hal yang sama juga dapat dilakukan pada pernyataan tingkat blok lainnya seperti kondisional. Kita bisa menggunakan tingkat indentasi untuk menentukan nilai milik pernyataan apa:
3857
3858```yuescript
3859if func 1, 2, 3,
3860 "hello",
3861 "world"
3862 print "hello"
3863 print "I am inside if"
3864
3865if func 1, 2, 3,
3866 "hello",
3867 "world"
3868 print "hello"
3869 print "I am inside if"
3870```
3871
3872<YueDisplay>
3873
3874```yue
3875if func 1, 2, 3,
3876 "hello",
3877 "world"
3878 print "hello"
3879 print "I am inside if"
3880
3881if func 1, 2, 3,
3882 "hello",
3883 "world"
3884 print "hello"
3885 print "I am inside if"
3886```
3887
3888</YueDisplay>
3889
3890## Destrukturisasi Parameter
3891
3892YueScript kini mendukung destrukturisasi parameter fungsi ketika argumen berupa objek. Dua bentuk destrukturisasi literal tabel tersedia:
3893
3894- **Literal berkurung kurawal/parameter objek**, memungkinkan nilai default opsional ketika field hilang (misalnya, `{:a, :b}`, `{a: a1 = 123}`).
3895
3896- **Sintaks tabel sederhana tanpa pembungkus**, dimulai dengan urutan key-value atau binding singkat dan berlanjut sampai ekspresi lain menghentikannya (misalnya, `:a, b: b1, :c`). Bentuk ini mengekstrak beberapa field dari objek yang sama.
3897
3898```yuescript
3899f1 = (:a, :b, :c) ->
3900 print a, b, c
3901
3902f1 a: 1, b: "2", c: {}
3903
3904f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3905 print a1, b, c
3906
3907arg1 = {a: 0}
3908f2 arg1, arg2
3909```
3910
3911<YueDisplay>
3912
3913```yue
3914f1 = (:a, :b, :c) ->
3915 print a, b, c
3916
3917f1 a: 1, b: "2", c: {}
3918
3919f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3920print a1, b, c
3921
3922arg1 = {a: 0}
3923f2 arg1, arg2
3924```
3925
3926</YueDisplay>
3927
3928## Ekspresi Return Berawalan
3929
3930Saat bekerja dengan badan fungsi yang sangat bertingkat, menjaga keterbacaan dan konsistensi nilai return bisa terasa melelahkan. Untuk mengatasinya, YueScript memperkenalkan sintaks **Ekspresi Return Berawalan**. Bentuknya sebagai berikut:
3931
3932```yuescript
3933findFirstEven = (list): nil ->
3934 for item in *list
3935 if type(item) == "table"
3936 for sub in *item
3937 if sub % 2 == 0
3938 return sub
3939```
3940
3941<YueDisplay>
3942
3943```yue
3944findFirstEven = (list): nil ->
3945 for item in *list
3946 if type(item) == "table"
3947 for sub in *item
3948 if sub % 2 == 0
3949 return sub
3950```
3951
3952</YueDisplay>
3953
3954Ini setara dengan:
3955
3956```yuescript
3957findFirstEven = (list) ->
3958 for item in *list
3959 if type(item) == "table"
3960 for sub in *item
3961 if sub % 2 == 0
3962 return sub
3963 nil
3964```
3965
3966<YueDisplay>
3967
3968```yue
3969findFirstEven = (list) ->
3970 for item in *list
3971 if type(item) == "table"
3972 for sub in *item
3973 if sub % 2 == 0
3974 return sub
3975 nil
3976```
3977
3978</YueDisplay>
3979
3980Satu-satunya perbedaan adalah Anda dapat memindahkan ekspresi return terakhir sebelum token `->` atau `=>` untuk menunjukkan nilai return implisit fungsi sebagai pernyataan terakhir. Dengan cara ini, bahkan pada fungsi dengan banyak loop bertingkat atau cabang kondisional, Anda tidak lagi perlu menulis ekspresi return di akhir badan fungsi, sehingga struktur logika menjadi lebih lurus dan mudah diikuti.
3981
3982## Varargs Bernama
3983
3984Anda dapat menggunakan sintaks `(...t) ->` untuk otomatis menyimpan varargs ke tabel bernama. Tabel ini berisi semua argumen yang diteruskan (termasuk nilai `nil`), dan field `n` pada tabel menyimpan jumlah argumen yang benar-benar diteruskan (termasuk nilai `nil`).
3985
3986```yuescript
3987f = (...t) ->
3988 print "argument count:", t.n
3989 print "table length:", #t
3990 for i = 1, t.n
3991 print t[i]
3992
3993f 1, 2, 3
3994f "a", "b", "c", "d"
3995f!
3996
3997-- Menangani kasus dengan nilai nil
3998process = (...args) ->
3999 sum = 0
4000 for i = 1, args.n
4001 if args[i] != nil and type(args[i]) == "number"
4002 sum += args[i]
4003 sum
4004
4005process 1, nil, 3, nil, 5
4006```
4007
4008<YueDisplay>
4009
4010```yue
4011f = (...t) ->
4012 print "argument count:", t.n
4013 print "table length:", #t
4014 for i = 1, t.n
4015 print t[i]
4016
4017f 1, 2, 3
4018f "a", "b", "c", "d"
4019f!
4020
4021-- Menangani kasus dengan nilai nil
4022process = (...args) ->
4023 sum = 0
4024 for i = 1, args.n
4025 if args[i] != nil and type(args[i]) == "number"
4026 sum += args[i]
4027 sum
4028
4029process 1, nil, 3, nil, 5
4030```
4031
4032</YueDisplay>
4033
4034# Spasi Kosong
4035
4036YueScript adalah bahasa yang peka terhadap spasi. Anda harus menulis beberapa blok kode dengan indentasi yang sama menggunakan spasi **' '** atau tab **'\t'** seperti badan fungsi, daftar nilai, dan beberapa blok kontrol. Ekspresi yang mengandung spasi berbeda dapat bermakna berbeda. Tab diperlakukan seperti 4 spasi, tetapi sebaiknya jangan mencampur penggunaan spasi dan tab.
4037
4038## Pemisah Pernyataan
4039
4040Sebuah pernyataan biasanya berakhir pada pergantian baris. Anda juga bisa memakai titik koma `;` untuk mengakhiri pernyataan secara eksplisit, yang memungkinkan menulis beberapa pernyataan pada satu baris:
4041
4042```yuescript
4043a = 1; b = 2; print a + b
4044```
4045
4046<YueDisplay>
4047
4048```yue
4049a = 1; b = 2; print a + b
4050```
4051
4052</YueDisplay>
4053
4054## Rantai Multibaris
4055
4056Anda bisa menulis pemanggilan fungsi berantai multi-baris dengan indentasi yang sama.
4057
4058```yuescript
4059Rx.Observable
4060 .fromRange 1, 8
4061 \filter (x) -> x % 2 == 0
4062 \concat Rx.Observable.of 'who do we appreciate'
4063 \map (value) -> value .. '!'
4064 \subscribe print
4065```
4066
4067<YueDisplay>
4068
4069```yue
4070Rx.Observable
4071 .fromRange 1, 8
4072 \filter (x) -> x % 2 == 0
4073 \concat Rx.Observable.of 'who do we appreciate'
4074 \map (value) -> value .. '!'
4075 \subscribe print
4076```
4077
4078</YueDisplay>
4079
4080# Komentar
4081
4082```yuescript
4083-- Saya adalah komentar
4084
4085str = --[[
4086Ini komentar multi-baris.
4087Tidak masalah.
4088]] strA \ -- komentar 1
4089 .. strB \ -- komentar 2
4090 .. strC
4091
4092func --[[port]] 3000, --[[ip]] "192.168.1.1"
4093```
4094
4095<YueDisplay>
4096
4097```yue
4098-- Saya adalah komentar
4099
4100str = --[[
4101Ini komentar multi-baris.
4102Tidak masalah.
4103]] strA \ -- komentar 1
4104 .. strB \ -- komentar 2
4105 .. strC
4106
4107func --[[port]] 3000, --[[ip]] "192.168.1.1"
4108```
4109
4110</YueDisplay>
4111
4112# Atribut
4113
4114Dukungan sintaks untuk atribut Lua 5.4. Anda juga masih bisa menggunakan deklarasi `const` dan `close` dan mendapatkan pemeriksaan konstanta serta callback berbatas-scope ketika menargetkan versi Lua di bawah 5.4.
4115
4116```yuescript
4117const a = 123
4118close _ = <close>: -> print "Out of scope."
4119```
4120
4121<YueDisplay>
4122
4123```yue
4124const a = 123
4125close _ = <close>: -> print "Out of scope."
4126```
4127
4128</YueDisplay>
4129
4130Anda dapat melakukan destrukturisasi dengan variabel yang diberi atribut sebagai konstanta.
4131
4132```yuescript
4133const {:a, :b, c, d} = tb
4134-- a = 1
4135```
4136
4137<YueDisplay>
4138
4139```yue
4140const {:a, :b, c, d} = tb
4141-- a = 1
4142```
4143
4144</YueDisplay>
4145
4146Anda juga bisa mendeklarasikan variabel global sebagai `const`.
4147
4148```yuescript
4149global const Constant = 123
4150-- Constant = 1
4151```
4152
4153<YueDisplay>
4154
4155```yue
4156global const Constant = 123
4157-- Constant = 1
4158```
4159
4160</YueDisplay>
4161
4162# Operator
4163
4164Semua operator biner dan unari Lua tersedia. Selain itu **!=** adalah alias untuk **~=**, dan **\\** atau **::** bisa digunakan untuk menulis pemanggilan fungsi berantai seperti `tb\func!` atau `tb::func!`. YueScript juga menawarkan beberapa operator khusus lain untuk menulis kode yang lebih ekspresif.
4165
4166```yuescript
4167tb\func! if tb ~= nil
4168tb::func! if tb != nil
4169```
4170
4171<YueDisplay>
4172
4173```yue
4174tb\func! if tb ~= nil
4175tb::func! if tb != nil
4176```
4177
4178</YueDisplay>
4179
4180## Perbandingan Berantai
4181
4182Perbandingan bisa dirantai secara bebas:
4183
4184```yuescript
4185print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4186-- output: true
4187
4188a = 5
4189print 1 <= a <= 10
4190-- output: true
4191```
4192
4193<YueDisplay>
4194
4195```yue
4196print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4197-- output: true
4198
4199a = 5
4200print 1 <= a <= 10
4201-- output: true
4202```
4203
4204</YueDisplay>
4205
4206Perhatikan perilaku evaluasi perbandingan berantai:
4207
4208```yuescript
4209v = (x) ->
4210 print x
4211 x
4212
4213print v(1) < v(2) <= v(3)
4214--[[
4215 output:
4216 2
4217 1
4218 3
4219 true
4220]]
4221
4222print v(1) > v(2) <= v(3)
4223--[[
4224 output:
4225 2
4226 1
4227 false
4228]]
4229```
4230
4231<YueDisplay>
4232
4233```yue
4234v = (x) ->
4235 print x
4236 x
4237
4238print v(1) < v(2) <= v(3)
4239--[[
4240 output:
4241 2
4242 1
4243 3
4244 true
4245]]
4246
4247print v(1) > v(2) <= v(3)
4248--[[
4249 output:
4250 2
4251 1
4252 false
4253]]
4254```
4255
4256</YueDisplay>
4257
4258Ekspresi tengah hanya dievaluasi sekali, bukan dua kali seperti jika ekspresi ditulis sebagai `v(1) < v(2) and v(2) <= v(3)`. Namun, urutan evaluasi pada perbandingan berantai tidak didefinisikan. Sangat disarankan untuk tidak menggunakan ekspresi dengan efek samping (seperti `print`) di perbandingan berantai. Jika efek samping diperlukan, operator short-circuit `and` sebaiknya digunakan secara eksplisit.
4259
4260## Menambahkan ke Tabel
4261
4262Operator **[] =** digunakan untuk menambahkan nilai ke tabel.
4263
4264```yuescript
4265tab = []
4266tab[] = "Value"
4267```
4268
4269<YueDisplay>
4270
4271```yue
4272tab = []
4273tab[] = "Value"
4274```
4275
4276</YueDisplay>
4277
4278Anda juga bisa memakai operator spread `...` untuk menambahkan semua elemen dari satu list ke list lain:
4279
4280```yuescript
4281tbA = [1, 2, 3]
4282tbB = [4, 5, 6]
4283tbA[] = ...tbB
4284-- tbA sekarang [1, 2, 3, 4, 5, 6]
4285```
4286
4287<YueDisplay>
4288
4289```yue
4290tbA = [1, 2, 3]
4291tbB = [4, 5, 6]
4292tbA[] = ...tbB
4293-- tbA sekarang [1, 2, 3, 4, 5, 6]
4294```
4295
4296</YueDisplay>
4297
4298## Penyebaran Tabel
4299
4300Anda bisa menggabungkan tabel array atau tabel hash menggunakan operator spread `...` sebelum ekspresi di literal tabel.
4301
4302```yuescript
4303parts =
4304 * "shoulders"
4305 * "knees"
4306lyrics =
4307 * "head"
4308 * ...parts
4309 * "and"
4310 * "toes"
4311
4312copy = {...other}
4313
4314a = {1, 2, 3, x: 1}
4315b = {4, 5, y: 1}
4316merge = {...a, ...b}
4317```
4318
4319<YueDisplay>
4320
4321```yue
4322parts =
4323 * "shoulders"
4324 * "knees"
4325lyrics =
4326 * "head"
4327 * ...parts
4328 * "and"
4329 * "toes"
4330
4331copy = {...other}
4332
4333a = {1, 2, 3, x: 1}
4334b = {4, 5, y: 1}
4335merge = {...a, ...b}
4336```
4337
4338</YueDisplay>
4339
4340## Indeks Balik Tabel
4341
4342Anda dapat menggunakan operator **#** untuk mendapatkan elemen terakhir dari tabel.
4343
4344```yuescript
4345last = data.items[#]
4346second_last = data.items[#-1]
4347data.items[#] = 1
4348```
4349
4350<YueDisplay>
4351
4352```yue
4353last = data.items[#]
4354second_last = data.items[#-1]
4355data.items[#] = 1
4356```
4357
4358</YueDisplay>
4359
4360## Metatable
4361
4362Operator **<>** dapat digunakan sebagai pintasan untuk manipulasi metatable.
4363
4364### Pembuatan Metatable
4365
4366Buat tabel normal dengan tanda kurung siku kosong **<>** atau kunci metamethod yang dikelilingi oleh **<>**.
4367
4368```yuescript
4369mt = {}
4370add = (right) => <>: mt, value: @value + right.value
4371mt.__add = add
4372
4373a = <>: mt, value: 1
4374 -- set field dengan variabel bernama sama
4375b = :<add>, value: 2
4376c = <add>: mt.__add, value: 3
4377
4378d = a + b + c
4379print d.value
4380
4381close _ = <close>: -> print "out of scope"
4382```
4383
4384<YueDisplay>
4385
4386```yue
4387mt = {}
4388add = (right) => <>: mt, value: @value + right.value
4389mt.__add = add
4390
4391a = <>: mt, value: 1
4392 -- set field dengan variabel bernama sama
4393b = :<add>, value: 2
4394c = <add>: mt.__add, value: 3
4395
4396d = a + b + c
4397print d.value
4398
4399close _ = <close>: -> print "out of scope"
4400```
4401
4402</YueDisplay>
4403
4404### Mengakses Metatable
4405
4406Akses metatable dengan **<>**, nama metamethod yang dikelilingi **<>**, atau menulis ekspresi di dalam **<>**.
4407
4408```yuescript
4409-- dibuat dengan metatable yang berisi field "value"
4410tb = <"value">: 123
4411tb.<index> = tb.<>
4412print tb.value
4413
4414tb.<> = __index: {item: "hello"}
4415print tb.item
4416```
4417
4418<YueDisplay>
4419
4420```yue
4421-- dibuat dengan metatable yang berisi field "value"
4422tb = <"value">: 123
4423tb.<index> = tb.<>
4424print tb.value
4425tb.<> = __index: {item: "hello"}
4426print tb.item
4427```
4428
4429</YueDisplay>
4430
4431### Destrukturisasi Metatable
4432
4433Destrukturisasi metatable dengan kunci metamethod yang dikelilingi **<>**.
4434
4435```yuescript
4436{item, :new, :<close>, <index>: getter} = tb
4437print item, new, close, getter
4438```
4439
4440<YueDisplay>
4441
4442```yue
4443{item, :new, :<close>, <index>: getter} = tb
4444print item, new, close, getter
4445```
4446
4447</YueDisplay>
4448
4449## Keberadaan
4450
4451Operator **?** dapat digunakan dalam berbagai konteks untuk memeriksa keberadaan.
4452
4453```yuescript
4454func?!
4455print abc?["hello world"]?.xyz
4456
4457x = tab?.value
4458len = utf8?.len or string?.len or (o) -> #o
4459
4460if print and x?
4461 print x
4462
4463with? io.open "test.txt", "w"
4464 \write "hello"
4465 \close!
4466```
4467
4468<YueDisplay>
4469
4470```yue
4471func?!
4472print abc?["hello world"]?.xyz
4473
4474x = tab?.value
4475len = utf8?.len or string?.len or (o) -> #o
4476
4477if print and x?
4478 print x
4479
4480with? io.open "test.txt", "w"
4481 \write "hello"
4482 \close!
4483```
4484
4485</YueDisplay>
4486
4487## Piping
4488
4489Sebagai ganti serangkaian pemanggilan fungsi bersarang, Anda bisa mengalirkan nilai dengan operator **|>**.
4490
4491```yuescript
4492"hello" |> print
44931 |> print 2 -- sisipkan nilai pipe sebagai argumen pertama
44942 |> print 1, _, 3 -- pipe dengan placeholder
4495
4496-- ekspresi pipe multi-baris
4497readFile "example.txt"
4498 |> extract language, {}
4499 |> parse language
4500 |> emit
4501 |> render
4502 |> print
4503```
4504
4505<YueDisplay>
4506
4507```yue
4508"hello" |> print
45091 |> print 2 -- sisipkan nilai pipe sebagai argumen pertama
45102 |> print 1, _, 3 -- pipe dengan placeholder
4511-- ekspresi pipe multi-baris
4512readFile "example.txt"
4513 |> extract language, {}
4514 |> parse language
4515 |> emit
4516 |> render
4517 |> print
4518```
4519
4520</YueDisplay>
4521
4522## Nil Coalescing
4523
4524Operator nil-coalescing **??** mengembalikan nilai dari operan kiri jika bukan **nil**; jika tidak, operator mengevaluasi operan kanan dan mengembalikan hasilnya. Operator **??** tidak mengevaluasi operan kanan jika operan kiri bernilai non-nil.
4525
4526```yuescript
4527local a, b, c, d
4528a = b ?? c ?? d
4529func a ?? {}
4530
4531a ??= false
4532```
4533
4534<YueDisplay>
4535
4536```yue
4537local a, b, c, d
4538a = b ?? c ?? d
4539func a ?? {}
4540a ??= false
4541```
4542
4543</YueDisplay>
4544
4545## Objek Implisit
4546
4547Anda dapat menulis daftar struktur implisit yang diawali simbol **\*** atau **-** di dalam blok tabel. Jika Anda membuat objek implisit, field objek harus berada pada indentasi yang sama.
4548
4549```yuescript
4550-- assignment dengan objek implisit
4551list =
4552 * 1
4553 * 2
4554 * 3
4555
4556-- pemanggilan fungsi dengan objek implisit
4557func
4558 * 1
4559 * 2
4560 * 3
4561
4562-- return dengan objek implisit
4563f = ->
4564 return
4565 * 1
4566 * 2
4567 * 3
4568
4569-- tabel dengan objek implisit
4570tb =
4571 name: "abc"
4572
4573 values:
4574 - "a"
4575 - "b"
4576 - "c"
4577
4578 objects:
4579 - name: "a"
4580 value: 1
4581 func: => @value + 1
4582 tb:
4583 fieldA: 1
4584
4585 - name: "b"
4586 value: 2
4587 func: => @value + 2
4588 tb: { }
4589
4590```
4591
4592<YueDisplay>
4593
4594```yue
4595-- assignment dengan objek implisit
4596list =
4597 * 1
4598 * 2
4599 * 3
4600
4601-- pemanggilan fungsi dengan objek implisit
4602func
4603 * 1
4604 * 2
4605 * 3
4606
4607-- return dengan objek implisit
4608f = ->
4609 return
4610 * 1
4611 * 2
4612 * 3
4613
4614-- tabel dengan objek implisit
4615tb =
4616 name: "abc"
4617
4618 values:
4619 - "a"
4620 - "b"
4621 - "c"
4622
4623 objects:
4624 - name: "a"
4625 value: 1
4626 func: => @value + 1
4627 tb:
4628 fieldA: 1
4629
4630 - name: "b"
4631 value: 2
4632 func: => @value + 2
4633 tb: { }
4634```
4635
4636</YueDisplay>
4637
4638# Literal
4639
4640Semua literal primitif di Lua dapat digunakan. Ini berlaku untuk angka, string, boolean, dan **nil**.
4641
4642Berbeda dengan Lua, pemisah baris diizinkan di dalam string bertanda kutip tunggal maupun ganda tanpa urutan escape:
4643
4644```yuescript
4645some_string = "Here is a string
4646 that has a line break in it."
4647
4648-- Anda dapat mencampur ekspresi ke dalam literal string dengan sintaks #{}.
4649-- Interpolasi string hanya tersedia pada string dengan tanda kutip ganda.
4650print "I am #{math.random! * 100}% sure."
4651```
4652
4653<YueDisplay>
4654
4655```yue
4656some_string = "Here is a string
4657 that has a line break in it."
4658
4659-- Anda dapat mencampur ekspresi ke dalam literal string dengan sintaks #{}.
4660-- Interpolasi string hanya tersedia pada string dengan tanda kutip ganda.
4661print "I am #{math.random! * 100}% sure."
4662```
4663
4664</YueDisplay>
4665
4666## Literal Angka
4667
4668Anda bisa menggunakan garis bawah pada literal angka untuk meningkatkan keterbacaan.
4669
4670```yuescript
4671integer = 1_000_000
4672hex = 0xEF_BB_BF
4673binary = 0B10011
4674```
4675
4676<YueDisplay>
4677
4678```yue
4679integer = 1_000_000
4680hex = 0xEF_BB_BF
4681binary = 0B10011
4682```
4683
4684</YueDisplay>
4685
4686## String Multibaris YAML
4687
4688Prefiks `|` memperkenalkan literal string multibaris bergaya YAML:
4689
4690```yuescript
4691str = |
4692 key: value
4693 list:
4694 - item1
4695 - #{expr}
4696```
4697
4698<YueDisplay>
4699
4700```yue
4701str = |
4702 key: value
4703 list:
4704 - item1
4705 - #{expr}
4706```
4707
4708</YueDisplay>
4709
4710Ini memungkinkan penulisan teks multibaris terstruktur dengan mudah. Semua pemisah baris dan indentasi dipertahankan relatif terhadap baris non-kosong pertama, dan ekspresi di dalam `#{...}` diinterpolasi otomatis sebagai `tostring(expr)`.
4711
4712String Multibaris YAML secara otomatis mendeteksi prefiks spasi awal yang sama (indentasi minimum di seluruh baris non-kosong) dan menghapusnya dari semua baris. Ini memudahkan untuk mengindentasi kode secara visual tanpa memengaruhi isi string yang dihasilkan.
4713
4714```yuescript
4715fn = ->
4716 str = |
4717 foo:
4718 bar: baz
4719 return str
4720```
4721
4722<YueDisplay>
4723
4724```yue
4725fn = ->
4726 str = |
4727 foo:
4728 bar: baz
4729 return str
4730```
4731
4732</YueDisplay>
4733
4734Indentasi internal dipertahankan relatif terhadap prefiks umum yang dihapus, sehingga struktur bertingkat tetap rapi.
4735
4736Semua karakter khusus seperti tanda kutip (`"`) dan backslash (`\`) di dalam blok YAMLMultiline di-escape secara otomatis agar string Lua yang dihasilkan valid secara sintaks dan berperilaku sebagaimana mestinya.
4737
4738```yuescript
4739str = |
4740 path: "C:\Program Files\App"
4741 note: 'He said: "#{Hello}!"'
4742```
4743
4744<YueDisplay>
4745
4746```yue
4747str = |
4748 path: "C:\Program Files\App"
4749 note: 'He said: "#{Hello}!"'
4750```
4751
4752</YueDisplay>
4753
4754# Modul
4755
4756## Import
4757
4758Pernyataan `import` adalah sintaks sugar untuk me-require modul atau membantu mengekstrak item dari modul yang diimpor. Item yang diimpor bersifat `const` secara default.
4759
4760```yuescript
4761-- digunakan sebagai destrukturisasi tabel
4762do
4763 import insert, concat from table
4764 -- akan error saat meng-assign ke insert, concat
4765 import C, Ct, Cmt from require "lpeg"
4766 -- shortcut untuk require implisit
4767 import x, y, z from 'mymodule'
4768 -- import gaya Python
4769 from 'module' import a, b, c
4770
4771-- shortcut untuk require modul
4772do
4773 import 'module'
4774 import 'module_x'
4775 import "d-a-s-h-e-s"
4776 import "module.part"
4777
4778-- require modul dengan aliasing atau destrukturisasi tabel
4779do
4780 import "player" as PlayerModule
4781 import "lpeg" as :C, :Ct, :Cmt
4782 import "export" as {one, two, Something:{umm:{ch}}}
4783```
4784
4785<YueDisplay>
4786
4787```yue
4788-- digunakan sebagai destrukturisasi tabel
4789do
4790 import insert, concat from table
4791 -- akan error saat meng-assign ke insert, concat
4792 import C, Ct, Cmt from require "lpeg"
4793 -- shortcut untuk require implisit
4794 import x, y, z from 'mymodule'
4795 -- import gaya Python
4796 from 'module' import a, b, c
4797
4798-- shortcut untuk require modul
4799do
4800 import 'module'
4801 import 'module_x'
4802 import "d-a-s-h-e-s"
4803 import "module.part"
4804
4805-- require modul dengan aliasing atau destrukturisasi tabel
4806do
4807 import "player" as PlayerModule
4808 import "lpeg" as :C, :Ct, :Cmt
4809 import "export" as {one, two, Something:{umm:{ch}}}
4810```
4811
4812</YueDisplay>
4813
4814## Import Global
4815
4816Anda dapat mengimpor global tertentu ke variabel local dengan `import`. Saat mengimpor rangkaian akses variabel global, field terakhir akan di-assign ke variabel local.
4817
4818```yuescript
4819do
4820 import tostring
4821 import table.concat
4822 print concat ["a", tostring 1]
4823```
4824
4825<YueDisplay>
4826
4827```yue
4828do
4829 import tostring
4830 import table.concat
4831 print concat ["a", tostring 1]
4832```
4833
4834</YueDisplay>
4835
4836### Import Variabel Global Otomatis
4837
4838Anda dapat menempatkan `import global` di awal blok untuk mengimpor secara otomatis semua nama yang belum dideklarasikan atau di-assign secara eksplisit di scope saat ini sebagai global. Import implisit ini diperlakukan sebagai local const yang mereferensikan global terkait pada posisi pernyataan tersebut.
4839
4840Nama yang secara eksplisit dideklarasikan sebagai global di scope yang sama tidak akan diimpor, sehingga Anda masih bisa meng-assign ke mereka.
4841
4842```yuescript
4843do
4844 import global
4845 print "hello"
4846 math.random 3
4847 -- print = nil -- error: imported globals are const
4848
4849do
4850 -- variabel global eksplisit tidak akan diimpor
4851 import global
4852 global FLAG
4853 print FLAG
4854 FLAG = 123
4855```
4856
4857<YueDisplay>
4858
4859```yue
4860do
4861 import global
4862 print "hello"
4863 math.random 3
4864 -- print = nil -- error: imported globals are const
4865
4866do
4867 -- variabel global eksplisit tidak akan diimpor
4868 import global
4869 global FLAG
4870 print FLAG
4871 FLAG = 123
4872```
4873
4874</YueDisplay>
4875
4876## Export
4877
4878Pernyataan `export` menawarkan cara ringkas untuk mendefinisikan modul.
4879
4880### Export Bernama
4881
4882Export bernama akan mendefinisikan variabel local sekaligus menambahkan field di tabel export.
4883
4884```yuescript
4885export a, b, c = 1, 2, 3
4886export cool = "cat"
4887
4888export What = if this
4889 "abc"
4890else
4891 "def"
4892
4893export y = ->
4894 hallo = 3434
4895
4896export class Something
4897 umm: "cool"
4898```
4899
4900<YueDisplay>
4901
4902```yue
4903export a, b, c = 1, 2, 3
4904export cool = "cat"
4905
4906export What = if this
4907 "abc"
4908else
4909 "def"
4910
4911export y = ->
4912 hallo = 3434
4913
4914export class Something
4915 umm: "cool"
4916```
4917
4918</YueDisplay>
4919
4920Melakukan export bernama dengan destrukturisasi.
4921
4922```yuescript
4923export :loadstring, to_lua: tolua = yue
4924export {itemA: {:fieldA = 'default'}} = tb
4925```
4926
4927<YueDisplay>
4928
4929```yue
4930export :loadstring, to_lua: tolua = yue
4931export {itemA: {:fieldA = 'default'}} = tb
4932```
4933
4934</YueDisplay>
4935
4936Export item bernama dari modul tanpa membuat variabel local.
4937
4938```yuescript
4939export.itemA = tb
4940export.<index> = items
4941export["a-b-c"] = 123
4942```
4943
4944<YueDisplay>
4945
4946```yue
4947export.itemA = tb
4948export.<index> = items
4949export["a-b-c"] = 123
4950```
4951
4952</YueDisplay>
4953
4954### Export Tanpa Nama
4955
4956Export tanpa nama akan menambahkan item target ke bagian array dari tabel export.
4957
4958```yuescript
4959d, e, f = 3, 2, 1
4960export d, e, f
4961
4962export if this
4963 123
4964else
4965 456
4966
4967export with tmp
4968 j = 2000
4969```
4970
4971<YueDisplay>
4972
4973```yue
4974d, e, f = 3, 2, 1
4975export d, e, f
4976
4977export if this
4978 123
4979else
4980 456
4981
4982export with tmp
4983 j = 2000
4984```
4985
4986</YueDisplay>
4987
4988### Export Default
4989
4990Gunakan kata kunci **default** dalam pernyataan export untuk mengganti tabel export dengan apa pun.
4991
4992```yuescript
4993export default ->
4994 print "hello"
4995 123
4996```
4997
4998<YueDisplay>
4999
5000```yue
5001export default ->
5002 print "hello"
5003 123
5004```
5005
5006</YueDisplay>
5007
5008# Lisensi: MIT
5009
5010Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
5011
5012Izin dengan ini diberikan, tanpa biaya, kepada siapa pun yang memperoleh salinan
5013perangkat lunak ini beserta file dokumentasi terkait ("Perangkat Lunak"), untuk
5014berurusan dengan Perangkat Lunak tanpa pembatasan, termasuk tanpa batasan hak
5015untuk menggunakan, menyalin, memodifikasi, menggabungkan, menerbitkan,
5016mendistribusikan, mensublisensikan, dan/atau menjual salinan Perangkat Lunak,
5017dan untuk mengizinkan orang yang menerima Perangkat Lunak untuk melakukannya,
5018dengan syarat-syarat berikut:
5019
5020Pemberitahuan hak cipta di atas dan pemberitahuan izin ini harus disertakan dalam
5021semua salinan atau bagian substansial dari Perangkat Lunak.
5022
5023PERANGKAT LUNAK DISEDIAKAN "APA ADANYA", TANPA JAMINAN APA PUN, BAIK TERSURAT
5024MAUPUN TERSIRAT, TERMASUK NAMUN TIDAK TERBATAS PADA JAMINAN KELAYAKAN
5025DIPERDAGANGKAN, KESESUAIAN UNTUK TUJUAN TERTENTU, DAN TIDAK MELANGGAR HAK.
5026DALAM KEADAAN APA PUN, PENULIS ATAU PEMEGANG HAK CIPTA TIDAK BERTANGGUNG JAWAB
5027ATAS KLAIM, KERUSAKAN, ATAU KEWAJIBAN LAINNYA, BAIK DALAM TINDAKAN KONTRAK,
5028PERBUATAN MELAWAN HUKUM, ATAU LAINNYA, YANG TIMBUL DARI, DI LUAR, ATAU TERKAIT
5029DENGAN PERANGKAT LUNAK ATAU PENGGUNAAN ATAU URUSAN LAIN DALAM PERANGKAT LUNAK.
5030
5031# Pustaka YueScript
5032
5033Akses dengan `local yue = require("yue")` di Lua.
5034
5035## yue
5036
5037**Deskripsi:**
5038
5039Pustaka bahasa YueScript.
5040
5041### version
5042
5043**Tipe:** Field.
5044
5045**Deskripsi:**
5046
5047Versi YueScript.
5048
5049**Signature:**
5050
5051```lua
5052version: string
5053```
5054
5055### dirsep
5056
5057**Tipe:** Field.
5058
5059**Deskripsi:**
5060
5061Pemisah file untuk platform saat ini.
5062
5063**Signature:**
5064
5065```lua
5066dirsep: string
5067```
5068
5069### yue_compiled
5070
5071**Tipe:** Field.
5072
5073**Deskripsi:**
5074
5075Cache kode modul yang telah dikompilasi.
5076
5077**Signature:**
5078
5079```lua
5080yue_compiled: {string: string}
5081```
5082
5083### to_lua
5084
5085**Tipe:** Function.
5086
5087**Deskripsi:**
5088
5089Fungsi kompilasi YueScript. Mengompilasi kode YueScript menjadi kode Lua.
5090
5091**Signature:**
5092
5093```lua
5094to_lua: function(code: string, config?: Config):
5095 --[[codes]] string | nil,
5096 --[[error]] string | nil,
5097 --[[globals]] {{string, integer, integer}} | nil
5098```
5099
5100**Parameter:**
5101
5102| Parameter | Tipe | Deskripsi |
5103| --------- | ------ | ------------------------- |
5104| code | string | Kode YueScript. |
5105| config | Config | [Opsional] Opsi kompiler. |
5106
5107**Return:**
5108
5109| Tipe Return | Deskripsi |
5110| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
5111| string \| nil | Kode Lua hasil kompilasi, atau nil jika kompilasi gagal. |
5112| string \| nil | Pesan error, atau nil jika kompilasi berhasil. |
5113| {{string, integer, integer}} \| nil | Variabel global yang muncul dalam kode (dengan nama, baris, dan kolom), atau nil jika opsi kompiler `lint_global` bernilai false. |
5114
5115### file_exist
5116
5117**Tipe:** Function.
5118
5119**Deskripsi:**
5120
5121Fungsi untuk memeriksa keberadaan file sumber. Dapat ditimpa untuk menyesuaikan perilaku.
5122
5123**Signature:**
5124
5125```lua
5126file_exist: function(filename: string): boolean
5127```
5128
5129**Parameter:**
5130
5131| Parameter | Tipe | Deskripsi |
5132| --------- | ------ | ---------- |
5133| filename | string | Nama file. |
5134
5135**Return:**
5136
5137| Tipe Return | Deskripsi |
5138| ----------- | ---------------- |
5139| boolean | Apakah file ada. |
5140
5141### read_file
5142
5143**Tipe:** Function.
5144
5145**Deskripsi:**
5146
5147Fungsi untuk membaca file sumber. Dapat ditimpa untuk menyesuaikan perilaku.
5148
5149**Signature:**
5150
5151```lua
5152read_file: function(filename: string): string
5153```
5154
5155**Parameter:**
5156
5157| Parameter | Tipe | Deskripsi |
5158| --------- | ------ | ---------- |
5159| filename | string | Nama file. |
5160
5161**Return:**
5162
5163| Tipe Return | Deskripsi |
5164| ----------- | --------- |
5165| string | Isi file. |
5166
5167### insert_loader
5168
5169**Tipe:** Function.
5170
5171**Deskripsi:**
5172
5173Menyisipkan loader YueScript ke package loaders (searchers).
5174
5175**Signature:**
5176
5177```lua
5178insert_loader: function(pos?: integer): boolean
5179```
5180
5181**Parameter:**
5182
5183| Parameter | Tipe | Deskripsi |
5184| --------- | ------- | ------------------------------------------------------------- |
5185| pos | integer | [Opsional] Posisi untuk menyisipkan loader. Default adalah 3. |
5186
5187**Return:**
5188
5189| Tipe Return | Deskripsi |
5190| ----------- | --------------------------------------------------------------------------- |
5191| boolean | Apakah loader berhasil disisipkan. Akan gagal jika loader sudah disisipkan. |
5192
5193### remove_loader
5194
5195**Tipe:** Function.
5196
5197**Deskripsi:**
5198
5199Menghapus loader YueScript dari package loaders (searchers).
5200
5201**Signature:**
5202
5203```lua
5204remove_loader: function(): boolean
5205```
5206
5207**Return:**
5208
5209| Tipe Return | Deskripsi |
5210| ----------- | ------------------------------------------------------------------------ |
5211| boolean | Apakah loader berhasil dihapus. Akan gagal jika loader belum disisipkan. |
5212
5213### loadstring
5214
5215**Tipe:** Function.
5216
5217**Deskripsi:**
5218
5219Memuat kode YueScript dari string menjadi fungsi.
5220
5221**Signature:**
5222
5223```lua
5224loadstring: function(input: string, chunkname: string, env: table, config?: Config):
5225 --[[loaded function]] nil | function(...: any): (any...),
5226 --[[error]] string | nil
5227```
5228
5229**Parameter:**
5230
5231| Parameter | Tipe | Deskripsi |
5232| --------- | ------ | ------------------------- |
5233| input | string | Kode YueScript. |
5234| chunkname | string | Nama chunk kode. |
5235| env | table | Tabel environment. |
5236| config | Config | [Opsional] Opsi kompiler. |
5237
5238**Return:**
5239
5240| Tipe Return | Deskripsi |
5241| --------------- | ------------------------------------------------- |
5242| function \| nil | Fungsi yang dimuat, atau nil jika pemuatan gagal. |
5243| string \| nil | Pesan error, atau nil jika pemuatan berhasil. |
5244
5245### loadstring
5246
5247**Tipe:** Function.
5248
5249**Deskripsi:**
5250
5251Memuat kode YueScript dari string menjadi fungsi.
5252
5253**Signature:**
5254
5255```lua
5256loadstring: function(input: string, chunkname: string, config?: Config):
5257 --[[loaded function]] nil | function(...: any): (any...),
5258 --[[error]] string | nil
5259```
5260
5261**Parameter:**
5262
5263| Parameter | Tipe | Deskripsi |
5264| --------- | ------ | ------------------------- |
5265| input | string | Kode YueScript. |
5266| chunkname | string | Nama chunk kode. |
5267| config | Config | [Opsional] Opsi kompiler. |
5268
5269**Return:**
5270
5271| Tipe Return | Deskripsi |
5272| --------------- | ------------------------------------------------- |
5273| function \| nil | Fungsi yang dimuat, atau nil jika pemuatan gagal. |
5274| string \| nil | Pesan error, atau nil jika pemuatan berhasil. |
5275
5276### loadstring
5277
5278**Tipe:** Function.
5279
5280**Deskripsi:**
5281
5282Memuat kode YueScript dari string menjadi fungsi.
5283
5284**Signature:**
5285
5286```lua
5287loadstring: function(input: string, config?: Config):
5288 --[[loaded function]] nil | function(...: any): (any...),
5289 --[[error]] string | nil
5290```
5291
5292**Parameter:**
5293
5294| Parameter | Tipe | Deskripsi |
5295| --------- | ------ | ------------------------- |
5296| input | string | Kode YueScript. |
5297| config | Config | [Opsional] Opsi kompiler. |
5298
5299**Return:**
5300
5301| Tipe Return | Deskripsi |
5302| --------------- | ------------------------------------------------- |
5303| function \| nil | Fungsi yang dimuat, atau nil jika pemuatan gagal. |
5304| string \| nil | Pesan error, atau nil jika pemuatan berhasil. |
5305
5306### loadfile
5307
5308**Tipe:** Function.
5309
5310**Deskripsi:**
5311
5312Memuat kode YueScript dari file menjadi fungsi.
5313
5314**Signature:**
5315
5316```lua
5317loadfile: function(filename: string, env: table, config?: Config):
5318 nil | function(...: any): (any...),
5319 string | nil
5320```
5321
5322**Parameter:**
5323
5324| Parameter | Tipe | Deskripsi |
5325| --------- | ------ | ------------------------- |
5326| filename | string | Nama file. |
5327| env | table | Tabel environment. |
5328| config | Config | [Opsional] Opsi kompiler. |
5329
5330**Return:**
5331
5332| Tipe Return | Deskripsi |
5333| --------------- | ------------------------------------------------- |
5334| function \| nil | Fungsi yang dimuat, atau nil jika pemuatan gagal. |
5335| string \| nil | Pesan error, atau nil jika pemuatan berhasil. |
5336
5337### loadfile
5338
5339**Tipe:** Function.
5340
5341**Deskripsi:**
5342
5343Memuat kode YueScript dari file menjadi fungsi.
5344
5345**Signature:**
5346
5347```lua
5348loadfile: function(filename: string, config?: Config):
5349 nil | function(...: any): (any...),
5350 string | nil
5351```
5352
5353**Parameter:**
5354
5355| Parameter | Tipe | Deskripsi |
5356| --------- | ------ | ------------------------- |
5357| filename | string | Nama file. |
5358| config | Config | [Opsional] Opsi kompiler. |
5359
5360**Return:**
5361
5362| Tipe Return | Deskripsi |
5363| --------------- | ------------------------------------------------- |
5364| function \| nil | Fungsi yang dimuat, atau nil jika pemuatan gagal. |
5365| string \| nil | Pesan error, atau nil jika pemuatan berhasil. |
5366
5367### dofile
5368
5369**Tipe:** Function.
5370
5371**Deskripsi:**
5372
5373Memuat kode YueScript dari file menjadi fungsi dan mengeksekusinya.
5374
5375**Signature:**
5376
5377```lua
5378dofile: function(filename: string, env: table, config?: Config): any...
5379```
5380
5381**Parameter:**
5382
5383| Parameter | Tipe | Deskripsi |
5384| --------- | ------ | ------------------------- |
5385| filename | string | Nama file. |
5386| env | table | Tabel environment. |
5387| config | Config | [Opsional] Opsi kompiler. |
5388
5389**Return:**
5390
5391| Tipe Return | Deskripsi |
5392| ----------- | ------------------------------------- |
5393| any... | Nilai return dari fungsi yang dimuat. |
5394
5395### dofile
5396
5397**Tipe:** Function.
5398
5399**Deskripsi:**
5400
5401Memuat kode YueScript dari file menjadi fungsi dan mengeksekusinya.
5402
5403**Signature:**
5404
5405```lua
5406dofile: function(filename: string, config?: Config): any...
5407```
5408
5409**Parameter:**
5410
5411| Parameter | Tipe | Deskripsi |
5412| --------- | ------ | ------------------------- |
5413| filename | string | Nama file. |
5414| config | Config | [Opsional] Opsi kompiler. |
5415
5416**Return:**
5417
5418| Tipe Return | Deskripsi |
5419| ----------- | ------------------------------------- |
5420| any... | Nilai return dari fungsi yang dimuat. |
5421
5422### find_modulepath
5423
5424**Tipe:** Function.
5425
5426**Deskripsi:**
5427
5428Menguraikan nama modul YueScript menjadi path file.
5429
5430**Signature:**
5431
5432```lua
5433find_modulepath: function(name: string): string
5434```
5435
5436**Parameter:**
5437
5438| Parameter | Tipe | Deskripsi |
5439| --------- | ------ | ----------- |
5440| name | string | Nama modul. |
5441
5442**Return:**
5443
5444| Tipe Return | Deskripsi |
5445| ----------- | ---------- |
5446| string | Path file. |
5447
5448### pcall
5449
5450**Tipe:** Function.
5451
5452**Deskripsi:**
5453
5454Memanggil fungsi dalam mode terlindungi.
5455Menangkap error apa pun dan mengembalikan kode status beserta hasil atau objek error.
5456Menulis ulang nomor baris error ke nomor baris asli di kode YueScript saat error terjadi.
5457
5458**Signature:**
5459
5460```lua
5461pcall: function(f: function, ...: any): boolean, any...
5462```
5463
5464**Parameter:**
5465
5466| Parameter | Tipe | Deskripsi |
5467| --------- | -------- | ---------------------------------- |
5468| f | function | Fungsi yang akan dipanggil. |
5469| ... | any | Argumen yang diteruskan ke fungsi. |
5470
5471**Return:**
5472
5473| Tipe Return | Deskripsi |
5474| ------------ | ---------------------------------------------- |
5475| boolean, ... | Kode status dan hasil fungsi atau objek error. |
5476
5477### require
5478
5479**Tipe:** Function.
5480
5481**Deskripsi:**
5482
5483Memuat modul tertentu. Bisa berupa modul Lua atau modul YueScript.
5484Menulis ulang nomor baris error ke nomor baris asli di kode YueScript jika modul adalah modul YueScript dan pemuatan gagal.
5485
5486**Signature:**
5487
5488```lua
5489require: function(name: string): any...
5490```
5491
5492**Parameter:**
5493
5494| Parameter | Tipe | Deskripsi |
5495| --------- | ------ | ---------------------------- |
5496| modname | string | Nama modul yang akan dimuat. |
5497
5498**Return:**
5499
5500| Tipe Return | Deskripsi |
5501| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5502| any | Nilai yang disimpan di package.loaded[modname] jika modul sudah dimuat. Jika belum, mencoba mencari loader dan mengembalikan nilai akhir package.loaded[modname] serta data loader sebagai hasil kedua. |
5503
5504### p
5505
5506**Tipe:** Function.
5507
5508**Deskripsi:**
5509
5510Memeriksa struktur nilai yang diteruskan dan mencetak representasi string.
5511
5512**Signature:**
5513
5514```lua
5515p: function(...: any)
5516```
5517
5518**Parameter:**
5519
5520| Parameter | Tipe | Deskripsi |
5521| --------- | ---- | -------------------------- |
5522| ... | any | Nilai yang akan diperiksa. |
5523
5524### options
5525
5526**Tipe:** Field.
5527
5528**Deskripsi:**
5529
5530Opsi kompiler saat ini.
5531
5532**Signature:**
5533
5534```lua
5535options: Config.Options
5536```
5537
5538### traceback
5539
5540**Tipe:** Function.
5541
5542**Deskripsi:**
5543
5544Fungsi traceback yang menulis ulang nomor baris stack trace ke nomor baris asli di kode YueScript.
5545
5546**Signature:**
5547
5548```lua
5549traceback: function(message: string): string
5550```
5551
5552**Parameter:**
5553
5554| Parameter | Tipe | Deskripsi |
5555| --------- | ------ | ---------------- |
5556| message | string | Pesan traceback. |
5557
5558**Return:**
5559
5560| Tipe Return | Deskripsi |
5561| ----------- | ----------------------------------------- |
5562| string | Pesan traceback yang telah ditulis ulang. |
5563
5564### is_ast
5565
5566**Tipe:** Function.
5567
5568**Deskripsi:**
5569
5570Memeriksa apakah kode cocok dengan AST yang ditentukan.
5571
5572**Signature:**
5573
5574```lua
5575is_ast: function(astName: string, code: string): boolean
5576```
5577
5578**Parameter:**
5579
5580| Parameter | Tipe | Deskripsi |
5581| --------- | ------ | --------- |
5582| astName | string | Nama AST. |
5583| code | string | Kode. |
5584
5585**Return:**
5586
5587| Tipe Return | Deskripsi |
5588| ----------- | ----------------------------- |
5589| boolean | Apakah kode cocok dengan AST. |
5590
5591### AST
5592
5593**Tipe:** Field.
5594
5595**Deskripsi:**
5596
5597Definisi tipe AST dengan nama, baris, kolom, dan sub-node.
5598
5599**Signature:**
5600
5601```lua
5602type AST = {string, integer, integer, any}
5603```
5604
5605### to_ast
5606
5607**Tipe:** Function.
5608
5609**Deskripsi:**
5610
5611Mengonversi kode menjadi AST.
5612
5613**Signature:**
5614
5615```lua
5616to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
5617 --[[AST]] AST | nil,
5618 --[[error]] nil | string
5619```
5620
5621**Parameter:**
5622
5623| Parameter | Tipe | Deskripsi |
5624| -------------- | ------- | ---------------------------------------------------------------------------------------- |
5625| code | string | Kode. |
5626| flattenLevel | integer | [Opsional] Tingkat perataan. Semakin tinggi berarti semakin rata. Default 0. Maksimum 2. |
5627| astName | string | [Opsional] Nama AST. Default "File". |
5628| reserveComment | boolean | [Opsional] Apakah akan mempertahankan komentar asli. Default false. |
5629
5630**Return:**
5631
5632| Tipe Return | Deskripsi |
5633| ------------- | --------------------------------------------- |
5634| AST \| nil | AST, atau nil jika konversi gagal. |
5635| string \| nil | Pesan error, atau nil jika konversi berhasil. |
5636
5637### format
5638
5639**Tipe:** Function.
5640
5641**Deskripsi:**
5642
5643Memformat kode YueScript.
5644
5645**Signature:**
5646
5647```lua
5648format: function(code: string, tabSize?: number, reserveComment?: boolean): string
5649```
5650
5651**Parameter:**
5652
5653| Parameter | Tipe | Deskripsi |
5654| -------------- | ------- | ------------------------------------------------------------- |
5655| code | string | Kode. |
5656| tabSize | integer | [Opsional] Ukuran tab. Default 4. |
5657| reserveComment | boolean | [Opsional] Apakah mempertahankan komentar asli. Default true. |
5658
5659**Return:**
5660
5661| Tipe Return | Deskripsi |
5662| ----------- | ------------------------- |
5663| string | Kode yang telah diformat. |
5664
5665### \_\_call
5666
5667**Tipe:** Metamethod.
5668
5669**Deskripsi:**
5670
5671Me-require modul YueScript.
5672Menulis ulang nomor baris error ke nomor baris asli di kode YueScript saat pemuatan gagal.
5673
5674**Signature:**
5675
5676```lua
5677metamethod __call: function(self: yue, module: string): any...
5678```
5679
5680**Parameter:**
5681
5682| Parameter | Tipe | Deskripsi |
5683| --------- | ------ | ----------- |
5684| module | string | Nama modul. |
5685
5686**Return:**
5687
5688| Tipe Return | Deskripsi |
5689| ----------- | ------------ |
5690| any | Nilai modul. |
5691
5692## Config
5693
5694**Deskripsi:**
5695
5696Opsi kompilasi kompiler.
5697
5698### lint_global
5699
5700**Tipe:** Field.
5701
5702**Deskripsi:**
5703
5704Apakah kompiler harus mengumpulkan variabel global yang muncul dalam kode.
5705
5706**Signature:**
5707
5708```lua
5709lint_global: boolean
5710```
5711
5712### implicit_return_root
5713
5714**Tipe:** Field.
5715
5716**Deskripsi:**
5717
5718Apakah kompiler harus melakukan return implisit untuk blok kode root.
5719
5720**Signature:**
5721
5722```lua
5723implicit_return_root: boolean
5724```
5725
5726### reserve_line_number
5727
5728**Tipe:** Field.
5729
5730**Deskripsi:**
5731
5732Apakah kompiler harus mempertahankan nomor baris asli di kode hasil kompilasi.
5733
5734**Signature:**
5735
5736```lua
5737reserve_line_number: boolean
5738```
5739
5740### reserve_comment
5741
5742**Tipe:** Field.
5743
5744**Deskripsi:**
5745
5746Apakah kompiler harus mempertahankan komentar asli di kode hasil kompilasi.
5747
5748**Signature:**
5749
5750```lua
5751reserve_comment: boolean
5752```
5753
5754### space_over_tab
5755
5756**Tipe:** Field.
5757
5758**Deskripsi:**
5759
5760Apakah kompiler harus menggunakan karakter spasi alih-alih tab di kode hasil kompilasi.
5761
5762**Signature:**
5763
5764```lua
5765space_over_tab: boolean
5766```
5767
5768### same_module
5769
5770**Tipe:** Field.
5771
5772**Deskripsi:**
5773
5774Apakah kompiler harus memperlakukan kode yang akan dikompilasi sebagai modul yang sama dengan modul yang sedang dikompilasi. Untuk penggunaan internal saja.
5775
5776**Signature:**
5777
5778```lua
5779same_module: boolean
5780```
5781
5782### line_offset
5783
5784**Tipe:** Field.
5785
5786**Deskripsi:**
5787
5788Apakah pesan error kompiler harus menyertakan offset nomor baris. Untuk penggunaan internal saja.
5789
5790**Signature:**
5791
5792```lua
5793line_offset: integer
5794```
5795
5796### yue.Config.LuaTarget
5797
5798**Tipe:** Enumeration.
5799
5800**Deskripsi:**
5801
5802Enumerasi versi Lua target.
5803
5804**Signature:**
5805
5806```lua
5807enum LuaTarget
5808 "5.1"
5809 "5.2"
5810 "5.3"
5811 "5.4"
5812 "5.5"
5813end
5814```
5815
5816### options
5817
5818**Tipe:** Field.
5819
5820**Deskripsi:**
5821
5822Opsi tambahan untuk diteruskan ke fungsi kompilasi.
5823
5824**Signature:**
5825
5826```lua
5827options: Options
5828```
5829
5830## Options
5831
5832**Deskripsi:**
5833
5834Definisi opsi kompiler tambahan.
5835
5836### target
5837
5838**Tipe:** Field.
5839
5840**Deskripsi:**
5841
5842Versi Lua target untuk kompilasi.
5843
5844**Signature:**
5845
5846```lua
5847target: LuaTarget
5848```
5849
5850### path
5851
5852**Tipe:** Field.
5853
5854**Deskripsi:**
5855
5856Path pencarian modul tambahan.
5857
5858**Signature:**
5859
5860```lua
5861path: string
5862```
5863
5864### dump_locals
5865
5866**Tipe:** Field.
5867
5868**Deskripsi:**
5869
5870Apakah akan menampilkan variabel local dalam pesan error traceback. Default false.
5871
5872**Signature:**
5873
5874```lua
5875dump_locals: boolean
5876```
5877
5878### simplified
5879
5880**Tipe:** Field.
5881
5882**Deskripsi:**
5883
5884Apakah akan menyederhanakan pesan error. Default true.
5885
5886**Signature:**
5887
5888```lua
5889simplified: boolean
5890```
diff --git a/doc/yue-pt-br.md b/doc/yue-pt-br.md
new file mode 100644
index 0000000..fccbdf6
--- /dev/null
+++ b/doc/yue-pt-br.md
@@ -0,0 +1,5890 @@
1---
2title: Referência
3---
4
5# Documentação do YueScript
6
7<img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em; padding-bottom: 2em;"/>
8
9Bem-vindo à documentação oficial do <b>YueScript</b>!<br/>
10Aqui você encontra recursos da linguagem, uso, exemplos de referência e materiais úteis.<br/>
11Selecione um capítulo na barra lateral para começar a aprender YueScript.
12
13# Do
14
15Quando usado como instrução, do funciona exatamente como no Lua.
16
17```yuescript
18do
19 var = "hello"
20 print var
21print var -- nil aqui
22```
23
24<YueDisplay>
25
26```yue
27do
28 var = "hello"
29 print var
30print var -- nil aqui
31```
32
33</YueDisplay>
34
35O **do** do YueScript também pode ser usado como expressão. Permitindo combinar múltiplas linhas em uma. O resultado da expressão do é a última instrução em seu corpo. Expressões `do` suportam usar `break` para interromper o fluxo de execução e retornar múltiplos valores antecipadamente.
36
37```yuescript
38status, value = do
39 n = 12
40 if n > 10
41 break "large", n
42 break "small", n
43```
44
45<YueDisplay>
46
47```yue
48status, value = do
49 n = 12
50 if n > 10
51 break "large", n
52 break "small", n
53```
54
55</YueDisplay>
56
57```yuescript
58counter = do
59 i = 0
60 ->
61 i += 1
62 i
63
64print counter!
65print counter!
66```
67
68<YueDisplay>
69
70```yue
71counter = do
72 i = 0
73 ->
74 i += 1
75 i
76
77print counter!
78print counter!
79```
80
81</YueDisplay>
82
83```yuescript
84tbl = {
85 key: do
86 print "assigning key!"
87 1234
88}
89```
90
91<YueDisplay>
92
93```yue
94tbl = {
95 key: do
96 print "assigning key!"
97 1234
98}
99```
100
101</YueDisplay>
102
103# Decoradores de linha
104
105Por conveniência, o loop for e a instrução if podem ser aplicados a instruções únicas no final da linha:
106
107```yuescript
108print "hello world" if name == "Rob"
109```
110
111<YueDisplay>
112
113```yue
114print "hello world" if name == "Rob"
115```
116
117</YueDisplay>
118
119E com loops básicos:
120
121```yuescript
122print "item: ", item for item in *items
123```
124
125<YueDisplay>
126
127```yue
128print "item: ", item for item in *items
129```
130
131</YueDisplay>
132
133E com loops while:
134
135```yuescript
136game\update! while game\isRunning!
137
138reader\parse_line! until reader\eof!
139```
140
141<YueDisplay>
142
143```yue
144game\update! while game\isRunning!
145
146reader\parse_line! until reader\eof!
147```
148
149</YueDisplay>
150
151# Macro
152
153## Uso comum
154
155A função macro é usada para avaliar uma string em tempo de compilação e inserir os códigos gerados na compilação final.
156
157```yuescript
158macro PI2 = -> math.pi * 2
159area = $PI2 * 5
160
161macro HELLO = -> "'hello world'"
162print $HELLO
163
164macro config = (debugging) ->
165 global debugMode = debugging == "true"
166 ""
167
168macro asserts = (cond) ->
169 debugMode and "assert #{cond}" or ""
170
171macro assert = (cond) ->
172 debugMode and "assert #{cond}" or "#{cond}"
173
174$config true
175$asserts item ~= nil
176
177$config false
178value = $assert item
179
180-- as expressões passadas são tratadas como strings
181macro and = (...) -> "#{ table.concat {...}, ' and ' }"
182if $and f1!, f2!, f3!
183 print "OK"
184```
185
186<YueDisplay>
187
188```yue
189macro PI2 = -> math.pi * 2
190area = $PI2 * 5
191
192macro HELLO = -> "'hello world'"
193print $HELLO
194
195macro config = (debugging) ->
196 global debugMode = debugging == "true"
197 ""
198
199macro asserts = (cond) ->
200 debugMode and "assert #{cond}" or ""
201
202macro assert = (cond) ->
203 debugMode and "assert #{cond}" or "#{cond}"
204
205$config true
206$asserts item ~= nil
207
208$config false
209value = $assert item
210
211-- as expressões passadas são tratadas como strings
212macro and = (...) -> "#{ table.concat {...}, ' and ' }"
213if $and f1!, f2!, f3!
214 print "OK"
215```
216
217</YueDisplay>
218
219## Inserir códigos brutos
220
221Uma função macro pode retornar uma string YueScript ou uma tabela de configuração contendo códigos Lua.
222
223```yuescript
224macro yueFunc = (var) -> "local #{var} = ->"
225$yueFunc funcA
226funcA = -> "fail to assign to the Yue macro defined variable"
227
228macro luaFunc = (var) -> {
229 code: "local function #{var}() end"
230 type: "lua"
231}
232$luaFunc funcB
233funcB = -> "fail to assign to the Lua macro defined variable"
234
235macro lua = (code) -> {
236 :code
237 type: "lua"
238}
239
240-- os símbolos inicial e final da string bruta são aparados automaticamente
241$lua[==[
242-- inserção de códigos Lua brutos
243if cond then
244 print("output")
245end
246]==]
247```
248
249<YueDisplay>
250
251```yue
252macro yueFunc = (var) -> "local #{var} = ->"
253$yueFunc funcA
254funcA = -> "fail to assign to the Yue macro defined variable"
255
256macro luaFunc = (var) -> {
257 code: "local function #{var}() end"
258 type: "lua"
259}
260$luaFunc funcB
261funcB = -> "fail to assign to the Lua macro defined variable"
262
263macro lua = (code) -> {
264 :code
265 type: "lua"
266}
267
268-- os símbolos inicial e final da string bruta são aparados automaticamente
269$lua[==[
270-- inserção de códigos Lua brutos
271if cond then
272 print("output")
273end
274]==]
275```
276
277</YueDisplay>
278
279## Exportar macro
280
281Funções macro podem ser exportadas de um módulo e importadas em outro módulo. Você deve colocar funções export macro em um único arquivo para uso, e apenas definição de macro, importação de macro e expansão de macro inline podem ser colocadas no módulo exportador de macro.
282
283```yuescript
284-- arquivo: utils.yue
285export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
286export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
287export macro foreach = (items, action) -> "for _ in *#{items}
288 #{action}"
289
290-- arquivo main.yue
291import "utils" as {
292 $, -- símbolo para importar todas as macros
293 $foreach: $each -- renomear macro $foreach para $each
294}
295[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
296```
297
298<YueDisplay>
299
300```yue
301-- arquivo: utils.yue
302export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
303export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
304export macro foreach = (items, action) -> "for _ in *#{items}
305 #{action}"
306
307-- arquivo main.yue
308--[[
309import "utils" as {
310 $, -- símbolo para importar todas as macros
311 $foreach: $each -- renomear macro $foreach para $each
312}
313[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
314]]
315```
316
317</YueDisplay>
318
319## Macro embutida
320
321Existem algumas macros embutidas, mas você pode sobrescrevê-las declarando macros com os mesmos nomes.
322
323```yuescript
324print $FILE -- obtém string do nome do módulo atual
325print $LINE -- obtém número 2
326```
327
328<YueDisplay>
329
330```yue
331print $FILE -- obtém string do nome do módulo atual
332print $LINE -- obtém número 2
333```
334
335</YueDisplay>
336
337## Gerando macros com macros
338
339No YueScript, as funções macro permitem que você gere código em tempo de compilação. Aninhando funções macro, você pode criar padrões de geração mais complexos. Este recurso permite que você defina uma função macro que gera outra função macro, permitindo geração de código mais dinâmica.
340
341```yuescript
342macro Enum = (...) ->
343 items = {...}
344 itemSet = {item, true for item in *items}
345 (item) ->
346 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
347 "\"#{item}\""
348
349macro BodyType = $Enum(
350 Static
351 Dynamic
352 Kinematic
353)
354
355print "Valid enum type:", $BodyType Static
356-- print "Compilation error with enum type:", $BodyType Unknown
357```
358
359<YueDisplay>
360
361```yue
362macro Enum = (...) ->
363 items = {...}
364 itemSet = {item, true for item in *items}
365 (item) ->
366 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
367 "\"#{item}\""
368
369macro BodyType = $Enum(
370 Static
371 Dynamic
372 Kinematic
373)
374
375print "Valid enum type:", $BodyType Static
376-- print "Compilation error with enum type:", $BodyType Unknown
377```
378
379</YueDisplay>
380
381## Validação de argumentos
382
383Você pode declarar os tipos de nós AST esperados na lista de argumentos e verificar se os argumentos da macro recebidos atendem às expectativas em tempo de compilação.
384
385```yuescript
386macro printNumAndStr = (num `Num, str `String) -> |
387 print(
388 #{num}
389 #{str}
390 )
391
392$printNumAndStr 123, "hello"
393```
394
395<YueDisplay>
396
397```yue
398macro printNumAndStr = (num `Num, str `String) -> |
399 print(
400 #{num}
401 #{str}
402 )
403
404$printNumAndStr 123, "hello"
405```
406
407</YueDisplay>
408
409Se você precisar de verificação de argumentos mais flexível, pode usar a função macro embutida `$is_ast` para verificar manualmente no lugar apropriado.
410
411```yuescript
412macro printNumAndStr = (num, str) ->
413 error "expected Num as first argument" unless $is_ast Num, num
414 error "expected String as second argument" unless $is_ast String, str
415 "print(#{num}, #{str})"
416
417$printNumAndStr 123, "hello"
418```
419
420<YueDisplay>
421
422```yue
423macro printNumAndStr = (num, str) ->
424 error "expected Num as first argument" unless $is_ast Num, num
425 error "expected String as second argument" unless $is_ast String, str
426 "print(#{num}, #{str})"
427
428$printNumAndStr 123, "hello"
429```
430
431</YueDisplay>
432
433Para mais detalhes sobre os nós AST disponíveis, consulte as definições em maiúsculas em [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).
434
435# Try
436
437A sintaxe para tratamento de erros do Lua em uma forma comum.
438
439```yuescript
440try
441 func 1, 2, 3
442catch err
443 print yue.traceback err
444
445success, result = try
446 func 1, 2, 3
447catch err
448 yue.traceback err
449
450try func 1, 2, 3
451catch err
452 print yue.traceback err
453
454success, result = try func 1, 2, 3
455
456try
457 print "trying"
458 func 1, 2, 3
459
460-- funcionando com padrão de atribuição em if
461if success, result := try func 1, 2, 3
462catch err
463 print yue.traceback err
464 print result
465```
466
467<YueDisplay>
468
469```yue
470try
471 func 1, 2, 3
472catch err
473 print yue.traceback err
474
475success, result = try
476 func 1, 2, 3
477catch err
478 yue.traceback err
479
480try func 1, 2, 3
481catch err
482 print yue.traceback err
483
484success, result = try func 1, 2, 3
485
486try
487 print "trying"
488 func 1, 2, 3
489
490-- funcionando com padrão de atribuição em if
491if success, result := try func 1, 2, 3
492catch err
493 print yue.traceback err
494 print result
495```
496
497</YueDisplay>
498
499## Try?
500
501`try?` é um uso simplificado para sintaxe de tratamento de erros que omite o status booleano da instrução `try`, e retornará o resultado do bloco try quando tiver sucesso, retornando nil em vez do objeto de erro caso contrário.
502
503```yuescript
504a, b, c = try? func!
505
506-- com operador de coalescência de nil
507a = (try? func!) ?? "default"
508
509-- como argumento de função
510f try? func!
511
512-- com bloco catch
513f try?
514 print 123
515 func!
516catch e
517 print e
518 e
519```
520
521<YueDisplay>
522
523```yue
524a, b, c = try? func!
525
526-- com operador de coalescência de nil
527a = (try? func!) ?? "default"
528
529-- como argumento de função
530f try? func!
531
532-- com bloco catch
533f try?
534 print 123
535 func!
536catch e
537 print e
538 e
539```
540
541</YueDisplay>
542
543# Literais de tabela
544
545Como no Lua, as tabelas são delimitadas por chaves.
546
547```yuescript
548some_values = [1, 2, 3, 4]
549```
550
551<YueDisplay>
552
553```yue
554some_values = [1, 2, 3, 4]
555```
556
557</YueDisplay>
558
559Diferente do Lua, atribuir um valor a uma chave em uma tabela é feito com **:** (em vez de **=**).
560
561```yuescript
562some_values = {
563 name: "Bill",
564 age: 200,
565 ["favorite food"]: "rice"
566}
567```
568
569<YueDisplay>
570
571```yue
572some_values = {
573 name: "Bill",
574 age: 200,
575 ["favorite food"]: "rice"
576}
577```
578
579</YueDisplay>
580
581As chaves podem ser omitidas se uma única tabela de pares chave-valor está sendo atribuída.
582
583```yuescript
584profile =
585 height: "4 feet",
586 shoe_size: 13,
587 favorite_foods: ["ice cream", "donuts"]
588```
589
590<YueDisplay>
591
592```yue
593profile =
594 height: "4 feet",
595 shoe_size: 13,
596 favorite_foods: ["ice cream", "donuts"]
597```
598
599</YueDisplay>
600
601Quebras de linha podem ser usadas para delimitar valores em vez de vírgula (ou ambos):
602
603```yuescript
604values = {
605 1, 2, 3, 4
606 5, 6, 7, 8
607 name: "superman"
608 occupation: "crime fighting"
609}
610```
611
612<YueDisplay>
613
614```yue
615values = {
616 1, 2, 3, 4
617 5, 6, 7, 8
618 name: "superman"
619 occupation: "crime fighting"
620}
621```
622
623</YueDisplay>
624
625Ao criar um literal de tabela em uma única linha, as chaves também podem ser omitidas:
626
627```yuescript
628my_function dance: "Tango", partner: "none"
629
630y = type: "dog", legs: 4, tails: 1
631```
632
633<YueDisplay>
634
635```yue
636my_function dance: "Tango", partner: "none"
637
638y = type: "dog", legs: 4, tails: 1
639```
640
641</YueDisplay>
642
643As chaves de um literal de tabela podem ser palavras-chave da linguagem sem precisar escapar:
644
645```yuescript
646tbl = {
647 do: "something"
648 end: "hunger"
649}
650```
651
652<YueDisplay>
653
654```yue
655tbl = {
656 do: "something"
657 end: "hunger"
658}
659```
660
661</YueDisplay>
662
663Se você está construindo uma tabela a partir de variáveis e deseja que as chaves sejam iguais aos nomes das variáveis, então o operador de prefixo **:** pode ser usado:
664
665```yuescript
666hair = "golden"
667height = 200
668person = { :hair, :height, shoe_size: 40 }
669
670print_table :hair, :height
671```
672
673<YueDisplay>
674
675```yue
676hair = "golden"
677height = 200
678person = { :hair, :height, shoe_size: 40 }
679
680print_table :hair, :height
681```
682
683</YueDisplay>
684
685Se você quiser que a chave de um campo na tabela seja o resultado de uma expressão, então pode envolvê-la em **[ ]**, assim como no Lua. Você também pode usar um literal de string diretamente como chave, omitindo os colchetes. Isso é útil se sua chave tiver caracteres especiais.
686
687```yuescript
688t = {
689 [1 + 2]: "hello"
690 "hello world": true
691}
692```
693
694<YueDisplay>
695
696```yue
697t = {
698 [1 + 2]: "hello"
699 "hello world": true
700}
701```
702
703</YueDisplay>
704
705As tabelas Lua têm tanto uma parte array quanto uma parte hash, mas às vezes você quer fazer uma distinção semântica entre uso de array e hash ao escrever tabelas Lua. Então você pode escrever tabela Lua com **[ ]** em vez de **{ }** para representar uma tabela array, e escrever qualquer par chave-valor em uma tabela lista não será permitido.
706
707```yuescript
708some_values = [1, 2, 3, 4]
709list_with_one_element = [1, ]
710```
711
712<YueDisplay>
713
714```yue
715some_values = [1, 2, 3, 4]
716list_with_one_element = [1, ]
717```
718
719</YueDisplay>
720
721# Compreensões
722
723As compreensões fornecem uma sintaxe conveniente para construir uma nova tabela iterando sobre algum objeto existente e aplicando uma expressão a seus valores. Existem dois tipos de compreensões: compreensões de lista e compreensões de tabela. Ambas produzem tabelas Lua; as compreensões de lista acumulam valores em uma tabela semelhante a array, e as compreensões de tabela permitem definir tanto a chave quanto o valor em cada iteração.
724
725## Compreensões de lista
726
727O seguinte cria uma cópia da tabela items mas com todos os valores dobrados.
728
729```yuescript
730items = [ 1, 2, 3, 4 ]
731doubled = [item * 2 for i, item in ipairs items]
732```
733
734<YueDisplay>
735
736```yue
737items = [ 1, 2, 3, 4 ]
738doubled = [item * 2 for i, item in ipairs items]
739```
740
741</YueDisplay>
742
743Os itens incluídos na nova tabela podem ser restringidos com uma cláusula when:
744
745```yuescript
746slice = [item for i, item in ipairs items when i > 1 and i < 3]
747```
748
749<YueDisplay>
750
751```yue
752slice = [item for i, item in ipairs items when i > 1 and i < 3]
753```
754
755</YueDisplay>
756
757Como é comum iterar sobre os valores de uma tabela indexada numericamente, um operador **\*** é introduzido. O exemplo doubled pode ser reescrito como:
758
759```yuescript
760doubled = [item * 2 for item in *items]
761```
762
763<YueDisplay>
764
765```yue
766doubled = [item * 2 for item in *items]
767```
768
769</YueDisplay>
770
771Nas compreensões de lista, você também pode usar o operador spread `...` para achatar listas aninhadas, alcançando um efeito de flat map:
772
773```yuescript
774data =
775 a: [1, 2, 3]
776 b: [4, 5, 6]
777
778flat = [...v for k,v in pairs data]
779-- flat agora é [1, 2, 3, 4, 5, 6]
780```
781
782<YueDisplay>
783
784```yue
785data =
786 a: [1, 2, 3]
787 b: [4, 5, 6]
788
789flat = [...v for k,v in pairs data]
790-- flat agora é [1, 2, 3, 4, 5, 6]
791```
792
793</YueDisplay>
794
795As cláusulas for e when podem ser encadeadas tanto quanto desejado. O único requisito é que uma compreensão tenha pelo menos uma cláusula for.
796
797Usar múltiplas cláusulas for é o mesmo que usar loops aninhados:
798
799```yuescript
800x_coords = [4, 5, 6, 7]
801y_coords = [9, 2, 3]
802
803points = [ [x, y] for x in *x_coords \
804for y in *y_coords]
805```
806
807<YueDisplay>
808
809```yue
810x_coords = [4, 5, 6, 7]
811y_coords = [9, 2, 3]
812
813points = [ [x, y] for x in *x_coords \
814for y in *y_coords]
815```
816
817</YueDisplay>
818
819Loops for numéricos também podem ser usados em compreensões:
820
821```yuescript
822evens = [i for i = 1, 100 when i % 2 == 0]
823```
824
825<YueDisplay>
826
827```yue
828evens = [i for i = 1, 100 when i % 2 == 0]
829```
830
831</YueDisplay>
832
833## Compreensões de tabela
834
835A sintaxe para compreensões de tabela é muito semelhante, diferindo apenas por usar **{** e **}** e receber dois valores de cada iteração.
836
837Este exemplo faz uma cópia da tabela thing:
838
839```yuescript
840thing = {
841 color: "red"
842 name: "fast"
843 width: 123
844}
845
846thing_copy = {k, v for k, v in pairs thing}
847```
848
849<YueDisplay>
850
851```yue
852thing = {
853 color: "red"
854 name: "fast"
855 width: 123
856}
857
858thing_copy = {k, v for k, v in pairs thing}
859```
860
861</YueDisplay>
862
863```yuescript
864no_color = {k, v for k, v in pairs thing when k != "color"}
865```
866
867<YueDisplay>
868
869```yue
870no_color = {k, v for k, v in pairs thing when k != "color"}
871```
872
873</YueDisplay>
874
875O operador **\*** também é suportado. Aqui criamos uma tabela de consulta de raiz quadrada para alguns números.
876
877```yuescript
878numbers = [1, 2, 3, 4]
879sqrts = {i, math.sqrt i for i in *numbers}
880```
881
882<YueDisplay>
883
884```yue
885numbers = [1, 2, 3, 4]
886sqrts = {i, math.sqrt i for i in *numbers}
887```
888
889</YueDisplay>
890
891A tupla chave-valor em uma compreensão de tabela também pode vir de uma única expressão, caso em que a expressão deve retornar dois valores. O primeiro é usado como chave e o segundo é usado como valor:
892
893Neste exemplo convertemos um array de pares em uma tabela onde o primeiro item do par é a chave e o segundo é o valor.
894
895```yuescript
896tuples = [ ["hello", "world"], ["foo", "bar"]]
897tbl = {unpack tuple for tuple in *tuples}
898```
899
900<YueDisplay>
901
902```yue
903tuples = [ ["hello", "world"], ["foo", "bar"]]
904tbl = {unpack tuple for tuple in *tuples}
905```
906
907</YueDisplay>
908
909## Slicing
910
911Uma sintaxe especial é fornecida para restringir os itens sobre os quais se itera ao usar o operador **\***. Isso é equivalente a definir os limites de iteração e um tamanho de passo em um loop for.
912
913Aqui podemos definir os limites mínimo e máximo, pegando todos os itens com índices entre 1 e 5 inclusive:
914
915```yuescript
916slice = [item for item in *items[1, 5]]
917```
918
919<YueDisplay>
920
921```yue
922slice = [item for item in *items[1, 5]]
923```
924
925</YueDisplay>
926
927Qualquer um dos argumentos do slice pode ser omitido para usar um padrão sensato. Neste exemplo, se o índice máximo for omitido, ele usa como padrão o comprimento da tabela. Isso pegará tudo exceto o primeiro elemento:
928
929```yuescript
930slice = [item for item in *items[2,]]
931```
932
933<YueDisplay>
934
935```yue
936slice = [item for item in *items[2,]]
937```
938
939</YueDisplay>
940
941Se o limite mínimo for omitido, ele usa como padrão 1. Aqui fornecemos apenas um tamanho de passo e deixamos os outros limites em branco. Isso pega todos os itens com índice ímpar: (1, 3, 5, …)
942
943```yuescript
944slice = [item for item in *items[,,2]]
945```
946
947<YueDisplay>
948
949```yue
950slice = [item for item in *items[,,2]]
951```
952
953</YueDisplay>
954
955Tanto o limite mínimo quanto o máximo podem ser negativos, o que significa que os limites são contados a partir do fim da tabela.
956
957```yuescript
958-- pegar os últimos 4 itens
959slice = [item for item in *items[-4,-1]]
960```
961
962<YueDisplay>
963
964```yue
965-- pegar os últimos 4 itens
966slice = [item for item in *items[-4,-1]]
967```
968
969</YueDisplay>
970
971O tamanho do passo também pode ser negativo, o que significa que os itens são tomados em ordem reversa.
972
973```yuescript
974reverse_slice = [item for item in *items[-1,1,-1]]
975```
976
977<YueDisplay>
978
979```yue
980reverse_slice = [item for item in *items[-1,1,-1]]
981```
982
983</YueDisplay>
984
985### Expressão de slicing
986
987O slicing também pode ser usado como expressão. Isso é útil para obter uma sublista de uma tabela.
988
989```yuescript
990-- pegar o 2º e 4º itens como nova lista
991sub_list = items[2, 4]
992
993-- pegar os últimos 4 itens
994last_four_items = items[-4, -1]
995```
996
997<YueDisplay>
998
999```yue
1000-- pegar o 2º e 4º itens como nova lista
1001sub_list = items[2, 4]
1002
1003-- pegar os últimos 4 itens
1004last_four_items = items[-4, -1]
1005```
1006
1007</YueDisplay>
1008
1009# Programação orientada a objetos
1010
1011Nestes exemplos, o código Lua gerado pode parecer avassalador. É melhor focar primeiro no significado do código YueScript e depois olhar o código Lua se desejar conhecer os detalhes da implementação.
1012
1013Uma classe simples:
1014
1015```yuescript
1016class Inventory
1017 new: =>
1018 @items = {}
1019
1020 add_item: (name) =>
1021 if @items[name]
1022 @items[name] += 1
1023 else
1024 @items[name] = 1
1025```
1026
1027<YueDisplay>
1028
1029```yue
1030class Inventory
1031 new: =>
1032 @items = {}
1033
1034 add_item: (name) =>
1035 if @items[name]
1036 @items[name] += 1
1037 else
1038 @items[name] = 1
1039```
1040
1041</YueDisplay>
1042
1043Uma classe é declarada com uma instrução class seguida de uma declaração semelhante a tabela onde todos os métodos e propriedades são listados.
1044
1045A propriedade new é especial pois se tornará o construtor.
1046
1047Observe como todos os métodos da classe usam a sintaxe de função seta fat. Ao chamar métodos em uma instância, a própria instância é enviada como primeiro argumento. A seta fat cuida da criação do argumento self.
1048
1049O prefixo @ em um nome de variável é abreviação para self.. @items torna-se self.items.
1050
1051Criar uma instância da classe é feito chamando o nome da classe como uma função.
1052
1053```yuescript
1054inv = Inventory!
1055inv\add_item "t-shirt"
1056inv\add_item "pants"
1057```
1058
1059<YueDisplay>
1060
1061```yue
1062inv = Inventory!
1063inv\add_item "t-shirt"
1064inv\add_item "pants"
1065```
1066
1067</YueDisplay>
1068
1069Como a instância da classe precisa ser enviada aos métodos quando são chamados, o operador \ é usado.
1070
1071Todas as propriedades de uma classe são compartilhadas entre as instâncias. Isso é bom para funções, mas para outros tipos de objetos, resultados indesejados podem ocorrer.
1072
1073Considere o exemplo abaixo, a propriedade clothes é compartilhada entre todas as instâncias, então modificações nela em uma instância aparecerão em outra:
1074
1075```yuescript
1076class Person
1077 clothes: []
1078 give_item: (name) =>
1079 table.insert @clothes, name
1080
1081a = Person!
1082b = Person!
1083
1084a\give_item "pants"
1085b\give_item "shirt"
1086
1087-- vai imprimir tanto pants quanto shirt
1088print item for item in *a.clothes
1089```
1090
1091<YueDisplay>
1092
1093```yue
1094class Person
1095 clothes: []
1096 give_item: (name) =>
1097 table.insert @clothes, name
1098
1099a = Person!
1100b = Person!
1101
1102a\give_item "pants"
1103b\give_item "shirt"
1104
1105-- vai imprimir tanto pants quanto shirt
1106print item for item in *a.clothes
1107```
1108
1109</YueDisplay>
1110
1111A forma correta de evitar esse problema é criar o estado mutável do objeto no construtor:
1112
1113```yuescript
1114class Person
1115 new: =>
1116 @clothes = []
1117```
1118
1119<YueDisplay>
1120
1121```yue
1122class Person
1123 new: =>
1124 @clothes = []
1125```
1126
1127</YueDisplay>
1128
1129## Herança
1130
1131A palavra-chave extends pode ser usada em uma declaração de classe para herdar as propriedades e métodos de outra classe.
1132
1133```yuescript
1134class BackPack extends Inventory
1135 size: 10
1136 add_item: (name) =>
1137 if #@items > size then error "backpack is full"
1138 super name
1139```
1140
1141<YueDisplay>
1142
1143```yue
1144class BackPack extends Inventory
1145 size: 10
1146 add_item: (name) =>
1147 if #@items > size then error "backpack is full"
1148 super name
1149```
1150
1151</YueDisplay>
1152
1153Aqui estendemos nossa classe Inventory e limitamos a quantidade de itens que ela pode carregar.
1154
1155Neste exemplo, não definimos um construtor na subclasse, então o construtor da classe pai é chamado quando criamos uma nova instância. Se definirmos um construtor, podemos usar o método super para chamar o construtor pai.
1156
1157Sempre que uma classe herda de outra, ela envia uma mensagem à classe pai chamando o método \_\_inherited na classe pai se ele existir. A função recebe dois argumentos: a classe que está sendo herdada e a classe filha.
1158
1159```yuescript
1160class Shelf
1161 @__inherited: (child) =>
1162 print @__name, "was inherited by", child.__name
1163
1164-- vai imprimir: Shelf was inherited by Cupboard
1165class Cupboard extends Shelf
1166```
1167
1168<YueDisplay>
1169
1170```yue
1171class Shelf
1172 @__inherited: (child) =>
1173 print @__name, "was inherited by", child.__name
1174
1175-- vai imprimir: Shelf was inherited by Cupboard
1176class Cupboard extends Shelf
1177```
1178
1179</YueDisplay>
1180
1181## Super
1182
1183**super** é uma palavra-chave especial que pode ser usada de duas formas diferentes: pode ser tratado como um objeto, ou pode ser chamado como uma função. Só tem funcionalidade especial quando está dentro de uma classe.
1184
1185Quando chamado como função, chamará a função de mesmo nome na classe pai. O self atual será automaticamente passado como primeiro argumento. (Como visto no exemplo de herança acima)
1186
1187Quando super é usado como valor normal, é uma referência ao objeto da classe pai.
1188
1189Pode ser acessado como qualquer objeto para recuperar valores na classe pai que possam ter sido sombreados pela classe filha.
1190
1191Quando o operador de chamada \ é usado com super, self é inserido como primeiro argumento em vez do valor do próprio super. Ao usar . para recuperar uma função, a função bruta é retornada.
1192
1193Alguns exemplos de uso de super de diferentes formas:
1194
1195```yuescript
1196class MyClass extends ParentClass
1197 a_method: =>
1198 -- os seguintes têm o mesmo efeito:
1199 super "hello", "world"
1200 super\a_method "hello", "world"
1201 super.a_method self, "hello", "world"
1202
1203 -- super como valor é igual à classe pai:
1204 assert super == ParentClass
1205```
1206
1207<YueDisplay>
1208
1209```yue
1210class MyClass extends ParentClass
1211 a_method: =>
1212 -- os seguintes têm o mesmo efeito:
1213 super "hello", "world"
1214 super\a_method "hello", "world"
1215 super.a_method self, "hello", "world"
1216
1217 -- super como valor é igual à classe pai:
1218 assert super == ParentClass
1219```
1220
1221</YueDisplay>
1222
1223**super** também pode ser usado no lado esquerdo de um Function Stub. A única diferença principal é que, em vez da função resultante estar vinculada ao valor de super, ela está vinculada a self.
1224
1225## Tipos
1226
1227Cada instância de uma classe carrega seu tipo consigo. Isso é armazenado na propriedade especial \_\_class. Esta propriedade contém o objeto da classe. O objeto da classe é o que chamamos para construir uma nova instância. Também podemos indexar o objeto da classe para recuperar métodos e propriedades da classe.
1228
1229```yuescript
1230b = BackPack!
1231assert b.__class == BackPack
1232
1233print BackPack.size -- imprime 10
1234```
1235
1236<YueDisplay>
1237
1238```yue
1239b = BackPack!
1240assert b.__class == BackPack
1241
1242print BackPack.size -- imprime 10
1243```
1244
1245</YueDisplay>
1246
1247## Objetos de classe
1248
1249O objeto da classe é o que criamos quando usamos uma instrução class. O objeto da classe é armazenado em uma variável com o mesmo nome da classe.
1250
1251O objeto da classe pode ser chamado como uma função para criar novas instâncias. É assim que criamos instâncias de classes nos exemplos acima.
1252
1253Uma classe é composta por duas tabelas. A própria tabela da classe e a tabela base. A base é usada como metatable para todas as instâncias. Todas as propriedades listadas na declaração da classe são colocadas na base.
1254
1255A metatable do objeto da classe lê propriedades da base se não existirem no objeto da classe. Isso significa que podemos acessar funções e propriedades diretamente da classe.
1256
1257É importante notar que atribuir ao objeto da classe não atribui à base, então não é uma forma válida de adicionar novos métodos às instâncias. Em vez disso, a base deve ser alterada explicitamente. Veja o campo \_\_base abaixo.
1258
1259O objeto da classe tem algumas propriedades especiais:
1260
1261O nome da classe quando foi declarada é armazenado como string no campo \_\_name do objeto da classe.
1262
1263```yuescript
1264print BackPack.__name -- imprime Backpack
1265```
1266
1267<YueDisplay>
1268
1269```yue
1270print BackPack.__name -- imprime Backpack
1271```
1272
1273</YueDisplay>
1274
1275O objeto base é armazenado em \_\_base. Podemos modificar esta tabela para adicionar funcionalidade a instâncias que já foram criadas e às que ainda serão criadas.
1276
1277Se a classe estende de algo, o objeto da classe pai é armazenado em \_\_parent.
1278
1279## Variáveis de classe
1280
1281Podemos criar variáveis diretamente no objeto da classe em vez da base usando @ na frente do nome da propriedade em uma declaração de classe.
1282
1283```yuescript
1284class Things
1285 @some_func: => print "Hello from", @__name
1286
1287Things\some_func!
1288
1289-- variáveis de classe não visíveis em instâncias
1290assert Things().some_func == nil
1291```
1292
1293<YueDisplay>
1294
1295```yue
1296class Things
1297 @some_func: => print "Hello from", @__name
1298
1299Things\some_func!
1300
1301-- variáveis de classe não visíveis em instâncias
1302assert Things().some_func == nil
1303```
1304
1305</YueDisplay>
1306
1307Em expressões, podemos usar @@ para acessar um valor armazenado no **class de self. Assim, @@hello é abreviação para self.**class.hello.
1308
1309```yuescript
1310class Counter
1311 @count: 0
1312
1313 new: =>
1314 @@count += 1
1315
1316Counter!
1317Counter!
1318
1319print Counter.count -- imprime 2
1320```
1321
1322<YueDisplay>
1323
1324```yue
1325class Counter
1326 @count: 0
1327
1328 new: =>
1329 @@count += 1
1330
1331Counter!
1332Counter!
1333
1334print Counter.count -- imprime 2
1335```
1336
1337</YueDisplay>
1338
1339A semântica de chamada de @@ é semelhante a @. Chamar um nome @@ passará a classe como primeiro argumento usando a sintaxe de dois pontos do Lua.
1340
1341```yuescript
1342@@hello 1,2,3,4
1343```
1344
1345<YueDisplay>
1346
1347```yue
1348@@hello 1,2,3,4
1349```
1350
1351</YueDisplay>
1352
1353## Instruções de declaração de classe
1354
1355No corpo de uma declaração de classe, podemos ter expressões normais além de pares chave/valor. Neste contexto, self é igual ao objeto da classe.
1356
1357Aqui está uma forma alternativa de criar variável de classe comparada ao descrito acima:
1358
1359```yuescript
1360class Things
1361 @class_var = "hello world"
1362```
1363
1364<YueDisplay>
1365
1366```yue
1367class Things
1368 @class_var = "hello world"
1369```
1370
1371</YueDisplay>
1372
1373Estas expressões são executadas após todas as propriedades terem sido adicionadas à base.
1374
1375Todas as variáveis declaradas no corpo da classe são locais às propriedades da classe. Isso é conveniente para colocar valores privados ou funções auxiliares que apenas os métodos da classe podem acessar:
1376
1377```yuescript
1378class MoreThings
1379 secret = 123
1380 log = (msg) -> print "LOG:", msg
1381
1382 some_method: =>
1383 log "hello world: " .. secret
1384```
1385
1386<YueDisplay>
1387
1388```yue
1389class MoreThings
1390 secret = 123
1391 log = (msg) -> print "LOG:", msg
1392
1393 some_method: =>
1394 log "hello world: " .. secret
1395```
1396
1397</YueDisplay>
1398
1399## Valores @ e @@
1400
1401Quando @ e @@ são prefixados na frente de um nome, eles representam, respectivamente, esse nome acessado em self e self.\_\_class.
1402
1403Se forem usados sozinhos, são aliases para self e self.\_\_class.
1404
1405```yuescript
1406assert @ == self
1407assert @@ == self.__class
1408```
1409
1410<YueDisplay>
1411
1412```yue
1413assert @ == self
1414assert @@ == self.__class
1415```
1416
1417</YueDisplay>
1418
1419Por exemplo, uma forma rápida de criar uma nova instância da mesma classe a partir de um método de instância usando @@:
1420
1421```yuescript
1422some_instance_method = (...) => @@ ...
1423```
1424
1425<YueDisplay>
1426
1427```yue
1428some_instance_method = (...) => @@ ...
1429```
1430
1431</YueDisplay>
1432
1433## Promoção de propriedade no construtor
1434
1435Para reduzir o código repetitivo na definição de objetos de valor simples. Você pode escrever uma classe simples como:
1436
1437```yuescript
1438class Something
1439 new: (@foo, @bar, @@biz, @@baz) =>
1440
1441-- O que é abreviação para
1442
1443class Something
1444 new: (foo, bar, biz, baz) =>
1445 @foo = foo
1446 @bar = bar
1447 @@biz = biz
1448 @@baz = baz
1449```
1450
1451<YueDisplay>
1452
1453```yue
1454class Something
1455 new: (@foo, @bar, @@biz, @@baz) =>
1456
1457-- O que é abreviação para
1458
1459class Something
1460 new: (foo, bar, biz, baz) =>
1461 @foo = foo
1462 @bar = bar
1463 @@biz = biz
1464 @@baz = baz
1465```
1466
1467</YueDisplay>
1468
1469Você também pode usar esta sintaxe para uma função comum para inicializar os campos de um objeto.
1470
1471```yuescript
1472new = (@fieldA, @fieldB) => @
1473obj = new {}, 123, "abc"
1474print obj
1475```
1476
1477<YueDisplay>
1478
1479```yue
1480new = (@fieldA, @fieldB) => @
1481obj = new {}, 123, "abc"
1482print obj
1483```
1484
1485</YueDisplay>
1486
1487## Expressões de classe
1488
1489A sintaxe de classe também pode ser usada como expressão que pode ser atribuída a uma variável ou retornada explicitamente.
1490
1491```yuescript
1492x = class Bucket
1493 drops: 0
1494 add_drop: => @drops += 1
1495```
1496
1497<YueDisplay>
1498
1499```yue
1500x = class Bucket
1501 drops: 0
1502 add_drop: => @drops += 1
1503```
1504
1505</YueDisplay>
1506
1507## Classes anônimas
1508
1509O nome pode ser omitido ao declarar uma classe. O atributo \_\_name será nil, a menos que a expressão da classe esteja em uma atribuição. O nome no lado esquerdo da atribuição é usado em vez de nil.
1510
1511```yuescript
1512BigBucket = class extends Bucket
1513 add_drop: => @drops += 10
1514
1515assert Bucket.__name == "BigBucket"
1516```
1517
1518<YueDisplay>
1519
1520```yue
1521BigBucket = class extends Bucket
1522 add_drop: => @drops += 10
1523
1524assert Bucket.__name == "BigBucket"
1525```
1526
1527</YueDisplay>
1528
1529Você pode até omitir o corpo, significando que pode escrever uma classe anônima em branco assim:
1530
1531```yuescript
1532x = class
1533```
1534
1535<YueDisplay>
1536
1537```yue
1538x = class
1539```
1540
1541</YueDisplay>
1542
1543## Mistura de classes
1544
1545Você pode fazer mistura com a palavra-chave `using` para copiar funções de uma tabela simples ou de um objeto de classe predefinido para sua nova classe. Ao fazer mistura com uma tabela simples, você pode sobrescrever a função de indexação da classe (metamétodo `__index`) para sua implementação personalizada. Ao fazer mistura com um objeto de classe existente, os metamétodos do objeto da classe não serão copiados.
1546
1547```yuescript
1548MyIndex = __index: var: 1
1549
1550class X using MyIndex
1551 func: =>
1552 print 123
1553
1554x = X!
1555print x.var
1556
1557class Y using X
1558
1559y = Y!
1560y\func!
1561
1562assert y.__class.__parent ~= X -- X não é pai de Y
1563```
1564
1565<YueDisplay>
1566
1567```yue
1568MyIndex = __index: var: 1
1569
1570class X using MyIndex
1571 func: =>
1572 print 123
1573
1574x = X!
1575print x.var
1576
1577class Y using X
1578
1579y = Y!
1580y\func!
1581
1582assert y.__class.__parent ~= X -- X não é pai de Y
1583```
1584
1585</YueDisplay>
1586
1587# Instrução With
1588
1589Um padrão comum envolvendo a criação de um objeto é chamar uma série de funções e definir uma série de propriedades imediatamente após criá-lo.
1590
1591Isso resulta em repetir o nome do objeto várias vezes no código, adicionando ruído desnecessário. Uma solução comum para isso é passar uma tabela como argumento que contém uma coleção de chaves e valores para sobrescrever. O inconveniente é que o construtor desse objeto deve suportar essa forma.
1592
1593O bloco with ajuda a aliviar isso. Dentro de um bloco with podemos usar instruções especiais que começam com . ou \ que representam essas operações aplicadas ao objeto com o qual estamos usando with.
1594
1595Por exemplo, trabalhamos com um objeto recém-criado:
1596
1597```yuescript
1598with Person!
1599 .name = "Oswald"
1600 \add_relative my_dad
1601 \save!
1602 print .name
1603```
1604
1605<YueDisplay>
1606
1607```yue
1608with Person!
1609 .name = "Oswald"
1610 \add_relative my_dad
1611 \save!
1612 print .name
1613```
1614
1615</YueDisplay>
1616
1617A instrução with também pode ser usada como expressão que retorna o valor ao qual foi dado acesso.
1618
1619```yuescript
1620file = with File "favorite_foods.txt"
1621 \set_encoding "utf8"
1622```
1623
1624<YueDisplay>
1625
1626```yue
1627file = with File "favorite_foods.txt"
1628 \set_encoding "utf8"
1629```
1630
1631</YueDisplay>
1632
1633Expressões `with` suportam `break` com um valor:
1634
1635```yuescript
1636result = with obj
1637 break .value
1638```
1639
1640<YueDisplay>
1641
1642```yue
1643result = with obj
1644 break .value
1645```
1646
1647</YueDisplay>
1648
1649Depois que `break value` é usado dentro de `with`, a expressão `with` deixa de retornar seu objeto-alvo e passa a retornar o valor de `break`.
1650
1651```yuescript
1652a = with obj
1653 .x = 1
1654-- a é obj
1655
1656b = with obj
1657 break .x
1658-- b é .x, não obj
1659```
1660
1661<YueDisplay>
1662
1663```yue
1664a = with obj
1665 .x = 1
1666-- a é obj
1667
1668b = with obj
1669 break .x
1670-- b é .x, não obj
1671```
1672
1673</YueDisplay>
1674
1675Diferente de `for` / `while` / `repeat` / `do`, `with` suporta apenas um valor de `break`.
1676
1677Ou…
1678
1679```yuescript
1680create_person = (name, relatives) ->
1681 with Person!
1682 .name = name
1683 \add_relative relative for relative in *relatives
1684
1685me = create_person "Leaf", [dad, mother, sister]
1686```
1687
1688<YueDisplay>
1689
1690```yue
1691create_person = (name, relatives) ->
1692 with Person!
1693 .name = name
1694 \add_relative relative for relative in *relatives
1695
1696me = create_person "Leaf", [dad, mother, sister]
1697```
1698
1699</YueDisplay>
1700
1701Neste uso, with pode ser visto como uma forma especial do combinador K.
1702
1703A expressão na instrução with também pode ser uma atribuição, se você quiser dar um nome à expressão.
1704
1705```yuescript
1706with str := "Hello"
1707 print "original:", str
1708 print "upper:", \upper!
1709```
1710
1711<YueDisplay>
1712
1713```yue
1714with str := "Hello"
1715 print "original:", str
1716 print "upper:", \upper!
1717```
1718
1719</YueDisplay>
1720
1721Você pode acessar chaves especiais com `[]` em uma instrução `with`.
1722
1723```yuescript
1724with tb
1725 [1] = 1
1726 print [2]
1727 with [abc]
1728 [3] = [2]\func!
1729 ["key-name"] = value
1730 [] = "abc" -- anexando a "tb"
1731```
1732
1733<YueDisplay>
1734
1735```yue
1736with tb
1737 [1] = 1
1738 print [2]
1739 with [abc]
1740 [3] = [2]\func!
1741 ["key-name"] = value
1742 [] = "abc" -- anexando a "tb"
1743```
1744
1745</YueDisplay>
1746
1747`with?` é uma versão aprimorada da sintaxe `with`, que introduz uma verificação existencial para acessar com segurança objetos que podem ser nil sem verificações explícitas de null.
1748
1749```yuescript
1750with? obj
1751 print obj.name
1752```
1753
1754<YueDisplay>
1755
1756```yue
1757with? obj
1758 print obj.name
1759```
1760
1761</YueDisplay>
1762
1763# Atribuição
1764
1765A variável é tipada dinamicamente e é definida como local por padrão. Mas você pode alterar o escopo da declaração pelas instruções **local** e **global**.
1766
1767```yuescript
1768hello = "world"
1769a, b, c = 1, 2, 3
1770hello = 123 -- usa a variável existente
1771```
1772
1773<YueDisplay>
1774
1775```yue
1776hello = "world"
1777a, b, c = 1, 2, 3
1778hello = 123 -- usa a variável existente
1779```
1780
1781</YueDisplay>
1782
1783## Atualização
1784
1785Você pode realizar atribuição de atualização com muitos operadores binários.
1786
1787```yuescript
1788x = 1
1789x += 1
1790x -= 1
1791x *= 10
1792x /= 10
1793x %= 10
1794s ..= "world" -- adiciona um novo local se a variável local não existir
1795arg or= "valor padrão"
1796```
1797
1798<YueDisplay>
1799
1800```yue
1801x = 1
1802x += 1
1803x -= 1
1804x *= 10
1805x /= 10
1806x %= 10
1807s ..= "world" -- adiciona um novo local se a variável local não existir
1808arg or= "valor padrão"
1809```
1810
1811</YueDisplay>
1812
1813## Atribuição encadeada
1814
1815Você pode fazer atribuição encadeada para atribuir múltiplos itens ao mesmo valor.
1816
1817```yuescript
1818a = b = c = d = e = 0
1819x = y = z = f!
1820```
1821
1822<YueDisplay>
1823
1824```yue
1825a = b = c = d = e = 0
1826x = y = z = f!
1827```
1828
1829</YueDisplay>
1830
1831## Locais explícitos
1832
1833```yuescript
1834do
1835 local a = 1
1836 local *
1837 print "declarar antecipadamente todas as variáveis como locais"
1838 x = -> 1 + y + z
1839 y, z = 2, 3
1840 global instance = Item\new!
1841
1842do
1843 local X = 1
1844 local ^
1845 print "declarar antecipadamente apenas variáveis em maiúsculas"
1846 a = 1
1847 B = 2
1848```
1849
1850<YueDisplay>
1851
1852```yue
1853do
1854 local a = 1
1855 local *
1856 print "declarar antecipadamente todas as variáveis como locais"
1857 x = -> 1 + y + z
1858 y, z = 2, 3
1859 global instance = Item\new!
1860
1861do
1862 local X = 1
1863 local ^
1864 print "declarar antecipadamente apenas variáveis em maiúsculas"
1865 a = 1
1866 B = 2
1867```
1868
1869</YueDisplay>
1870
1871## Globais explícitos
1872
1873```yuescript
1874do
1875 global a = 1
1876 global *
1877 print "declarar todas as variáveis como globais"
1878 x = -> 1 + y + z
1879 y, z = 2, 3
1880
1881do
1882 global X = 1
1883 global ^
1884 print "declarar apenas variáveis em maiúsculas como globais"
1885 a = 1
1886 B = 2
1887 local Temp = "um valor local"
1888```
1889
1890<YueDisplay>
1891
1892```yue
1893do
1894 global a = 1
1895 global *
1896 print "declarar todas as variáveis como globais"
1897 x = -> 1 + y + z
1898 y, z = 2, 3
1899
1900do
1901 global X = 1
1902 global ^
1903 print "declarar apenas variáveis em maiúsculas como globais"
1904 a = 1
1905 B = 2
1906 local Temp = "um valor local"
1907```
1908
1909</YueDisplay>
1910
1911# Atribuição de varargs
1912
1913Você pode atribuir os resultados retornados de uma função a um símbolo varargs `...`. E então acessar seu conteúdo da forma Lua.
1914
1915```yuescript
1916list = [1, 2, 3, 4, 5]
1917fn = (ok) -> ok, table.unpack list
1918ok, ... = fn true
1919count = select '#', ...
1920first = select 1, ...
1921print ok, count, first
1922```
1923
1924<YueDisplay>
1925
1926```yue
1927list = [1, 2, 3, 4, 5]
1928fn = (ok) -> ok, table.unpack list
1929ok, ... = fn true
1930count = select '#', ...
1931first = select 1, ...
1932print ok, count, first
1933```
1934
1935</YueDisplay>
1936
1937# Atribuição em if
1938
1939Os blocos `if` e `elseif` podem receber uma atribuição no lugar de uma expressão condicional. Ao avaliar o condicional, a atribuição será realizada e o valor que foi atribuído será usado como expressão condicional. A variável atribuída está no escopo apenas para o corpo do condicional, ou seja, nunca está disponível se o valor não for truthy. E você precisa usar o "operador walrus" `:=` em vez de `=` para fazer a atribuição.
1940
1941```yuescript
1942if user := database.find_user "moon"
1943 print user.name
1944```
1945
1946<YueDisplay>
1947
1948```yue
1949if user := database.find_user "moon"
1950 print user.name
1951```
1952
1953</YueDisplay>
1954
1955```yuescript
1956if hello := os.getenv "hello"
1957 print "Você tem hello", hello
1958elseif world := os.getenv "world"
1959 print "você tem world", world
1960else
1961 print "nada :("
1962```
1963
1964<YueDisplay>
1965
1966```yue
1967if hello := os.getenv "hello"
1968 print "Você tem hello", hello
1969elseif world := os.getenv "world"
1970 print "você tem world", world
1971else
1972 print "nada :("
1973```
1974
1975</YueDisplay>
1976
1977Atribuição em if com múltiplos valores de retorno. Apenas o primeiro valor é verificado, os outros valores estão no escopo.
1978
1979```yuescript
1980if success, result := pcall -> "obter resultado sem problemas"
1981 print result -- variável result está no escopo
1982print "OK"
1983```
1984
1985<YueDisplay>
1986
1987```yue
1988if success, result := pcall -> "obter resultado sem problemas"
1989 print result -- variável result está no escopo
1990print "OK"
1991```
1992
1993</YueDisplay>
1994
1995## Atribuição em while
1996
1997Você também pode usar atribuição em if em um loop while para obter o valor como condição do loop.
1998
1999```yuescript
2000while byte := stream\read_one!
2001 -- fazer algo com o byte
2002 print byte
2003```
2004
2005<YueDisplay>
2006
2007```yue
2008while byte := stream\read_one!
2009 -- fazer algo com o byte
2010 print byte
2011```
2012
2013</YueDisplay>
2014
2015# Atribuição por desestruturação
2016
2017A atribuição por desestruturação é uma forma de extrair rapidamente valores de uma tabela por seu nome ou posição em tabelas baseadas em array.
2018
2019Tipicamente, quando você vê um literal de tabela, {1,2,3}, ele está no lado direito de uma atribuição porque é um valor. A atribuição por desestruturação troca o papel do literal de tabela e o coloca no lado esquerdo de uma instrução de atribuição.
2020
2021Isso é melhor explicado com exemplos. Assim você extrairia os dois primeiros valores de uma tabela:
2022
2023```yuescript
2024thing = [1, 2]
2025
2026[a, b] = thing
2027print a, b
2028```
2029
2030<YueDisplay>
2031
2032```yue
2033thing = [1, 2]
2034
2035[a, b] = thing
2036print a, b
2037```
2038
2039</YueDisplay>
2040
2041No literal de tabela de desestruturação, a chave representa a chave para ler do lado direito, e o valor representa o nome ao qual o valor lido será atribuído.
2042
2043```yuescript
2044obj = {
2045 hello: "world"
2046 day: "tuesday"
2047 length: 20
2048}
2049
2050{hello: hello, day: the_day} = obj
2051print hello, the_day
2052
2053:day = obj -- OK fazer desestruturação simples sem chaves
2054```
2055
2056<YueDisplay>
2057
2058```yue
2059obj = {
2060 hello: "world"
2061 day: "tuesday"
2062 length: 20
2063}
2064
2065{hello: hello, day: the_day} = obj
2066print hello, the_day
2067
2068:day = obj -- OK fazer desestruturação simples sem chaves
2069```
2070
2071</YueDisplay>
2072
2073Isso também funciona com estruturas de dados aninhadas:
2074
2075```yuescript
2076obj2 = {
2077 numbers: [1, 2, 3, 4]
2078 properties: {
2079 color: "green"
2080 height: 13.5
2081 }
2082}
2083
2084{numbers: [first, second], properties: {color: color}} = obj2
2085print first, second, color
2086```
2087
2088<YueDisplay>
2089
2090```yue
2091obj2 = {
2092 numbers: [1, 2, 3, 4]
2093 properties: {
2094 color: "green"
2095 height: 13.5
2096 }
2097}
2098
2099{numbers: [first, second], properties: {color: color}} = obj2
2100print first, second, color
2101```
2102
2103</YueDisplay>
2104
2105Se a instrução de desestruturação for complicada, sinta-se à vontade para espalhá-la em várias linhas. Um exemplo um pouco mais complicado:
2106
2107```yuescript
2108{
2109 numbers: [first, second]
2110 properties: {
2111 color: color
2112 }
2113} = obj2
2114```
2115
2116<YueDisplay>
2117
2118```yue
2119{
2120 numbers: [first, second]
2121 properties: {
2122 color: color
2123 }
2124} = obj2
2125```
2126
2127</YueDisplay>
2128
2129É comum extrair valores de uma tabela e atribuí-los a variáveis locais que têm o mesmo nome da chave. Para evitar repetição, podemos usar o operador de prefixo **:**:
2130
2131```yuescript
2132{:concat, :insert} = table
2133```
2134
2135<YueDisplay>
2136
2137```yue
2138{:concat, :insert} = table
2139```
2140
2141</YueDisplay>
2142
2143Isso é efetivamente o mesmo que import, mas podemos renomear campos que queremos extrair misturando a sintaxe:
2144
2145```yuescript
2146{:mix, :max, random: rand} = math
2147```
2148
2149<YueDisplay>
2150
2151```yue
2152{:mix, :max, random: rand} = math
2153```
2154
2155</YueDisplay>
2156
2157Você pode escrever valores padrão ao fazer desestruturação:
2158
2159```yuescript
2160{:name = "sem nome", :job = "sem emprego"} = person
2161```
2162
2163<YueDisplay>
2164
2165```yue
2166{:name = "sem nome", :job = "sem emprego"} = person
2167```
2168
2169</YueDisplay>
2170
2171Você pode usar `_` como placeholder ao fazer desestruturação de lista:
2172
2173```yuescript
2174[_, two, _, four] = items
2175```
2176
2177<YueDisplay>
2178
2179```yue
2180[_, two, _, four] = items
2181```
2182
2183</YueDisplay>
2184
2185## Desestruturação por intervalo
2186
2187Você pode usar o operador spread `...` na desestruturação de lista para capturar um intervalo de valores. Isso é útil quando você quer extrair elementos específicos do início e do fim de uma lista enquanto coleta o restante entre eles.
2188
2189```yuescript
2190orders = ["first", "second", "third", "fourth", "last"]
2191[first, ...bulk, last] = orders
2192print first -- imprime: first
2193print bulk -- imprime: {"second", "third", "fourth"}
2194print last -- imprime: last
2195```
2196
2197<YueDisplay>
2198
2199```yue
2200orders = ["first", "second", "third", "fourth", "last"]
2201[first, ...bulk, last] = orders
2202print first -- imprime: first
2203print bulk -- imprime: {"second", "third", "fourth"}
2204print last -- imprime: last
2205```
2206
2207</YueDisplay>
2208
2209O operador spread pode ser usado em diferentes posições para capturar diferentes intervalos, e você pode usar `_` como placeholder para os valores que não quer capturar:
2210
2211```yuescript
2212-- Capturar tudo após o primeiro elemento
2213[first, ...rest] = orders
2214
2215-- Capturar tudo antes do último elemento
2216[...start, last] = orders
2217
2218-- Capturar tudo exceto os elementos do meio
2219[first, ..._, last] = orders
2220```
2221
2222<YueDisplay>
2223
2224```yue
2225-- Capturar tudo após o primeiro elemento
2226[first, ...rest] = orders
2227
2228-- Capturar tudo antes do último elemento
2229[...start, last] = orders
2230
2231-- Capturar tudo exceto os elementos do meio
2232[first, ..._, last] = orders
2233```
2234
2235</YueDisplay>
2236
2237## Desestruturação em outros lugares
2238
2239A desestruturação também pode aparecer em lugares onde uma atribuição ocorre implicitamente. Um exemplo disso é um loop for:
2240
2241```yuescript
2242tuples = [
2243 ["hello", "world"]
2244 ["egg", "head"]
2245]
2246
2247for [left, right] in *tuples
2248 print left, right
2249```
2250
2251<YueDisplay>
2252
2253```yue
2254tuples = [
2255 ["hello", "world"]
2256 ["egg", "head"]
2257]
2258
2259for [left, right] in *tuples
2260 print left, right
2261```
2262
2263</YueDisplay>
2264
2265Sabemos que cada elemento na tabela array é uma tupla de dois itens, então podemos desempacotá-lo diretamente na cláusula de nomes da instrução for usando desestruturação.
2266
2267# A cláusula Using; controlando atribuição destrutiva
2268
2269Embora o escopo léxico possa ser uma grande ajuda na redução da complexidade do código que escrevemos, as coisas podem ficar difíceis de gerenciar conforme o tamanho do código aumenta. Considere o seguinte trecho:
2270
2271```yuescript
2272i = 100
2273
2274-- muitas linhas de código...
2275
2276my_func = ->
2277 i = 10
2278 while i > 0
2279 print i
2280 i -= 1
2281
2282my_func!
2283
2284print i -- vai imprimir 0
2285```
2286
2287<YueDisplay>
2288
2289```yue
2290i = 100
2291
2292-- muitas linhas de código...
2293
2294my_func = ->
2295 i = 10
2296 while i > 0
2297 print i
2298 i -= 1
2299
2300my_func!
2301
2302print i -- vai imprimir 0
2303```
2304
2305</YueDisplay>
2306
2307Em my_func, sobrescrevemos o valor de i por engano. Neste exemplo é bem óbvio, mas considere uma base de código grande ou estrangeira onde não está claro quais nomes já foram declarados.
2308
2309Seria útil dizer quais variáveis do escopo envolvente pretendemos alterar, para evitar que alteremos outras por acidente.
2310
2311A palavra-chave using nos permite fazer isso. using nil garante que nenhuma variável fechada seja sobrescrita na atribuição. A cláusula using é colocada após a lista de argumentos em uma função, ou no lugar dela se não houver argumentos.
2312
2313```yuescript
2314i = 100
2315
2316my_func = (using nil) ->
2317 i = "hello" -- uma nova variável local é criada aqui
2318
2319my_func!
2320print i -- imprime 100, i não é afetado
2321```
2322
2323<YueDisplay>
2324
2325```yue
2326i = 100
2327
2328my_func = (using nil) ->
2329 i = "hello" -- uma nova variável local é criada aqui
2330
2331my_func!
2332print i -- imprime 100, i não é afetado
2333```
2334
2335</YueDisplay>
2336
2337Múltiplos nomes podem ser separados por vírgulas. Os valores do closure ainda podem ser acessados, apenas não podem ser modificados:
2338
2339```yuescript
2340tmp = 1213
2341i, k = 100, 50
2342
2343my_func = (add using k, i) ->
2344 tmp = tmp + add -- uma nova variável local tmp é criada
2345 i += tmp
2346 k += tmp
2347
2348my_func(22)
2349print i, k -- estes foram atualizados
2350```
2351
2352<YueDisplay>
2353
2354```yue
2355tmp = 1213
2356i, k = 100, 50
2357
2358my_func = (add using k, i) ->
2359 tmp = tmp + add -- uma nova variável local tmp é criada
2360 i += tmp
2361 k += tmp
2362
2363my_func(22)
2364print i, k -- estes foram atualizados
2365```
2366
2367</YueDisplay>
2368
2369# Uso
2370
2371## Módulo Lua
2372
2373Use o módulo YueScript em Lua:
2374
2375- **Caso 1**
2376
2377 Use require em "your_yuescript_entry.yue" no Lua.
2378
2379 ```Lua
2380 require("yue")("your_yuescript_entry")
2381 ```
2382
2383 E esse código continua funcionando quando você compila "your_yuescript_entry.yue" para "your_yuescript_entry.lua" no mesmo caminho. Nos demais arquivos YueScript, use normalmente o **require** ou **import**. Os números de linha nas mensagens de erro também serão tratados corretamente.
2384
2385- **Caso 2**
2386
2387 Requerer o módulo YueScript e reescrever a mensagem manualmente.
2388
2389 ```lua
2390 local yue = require("yue")
2391 yue.insert_loader()
2392 local success, result = xpcall(function()
2393 return require("yuescript_module_name")
2394 end, function(err)
2395 return yue.traceback(err)
2396 end)
2397 ```
2398
2399- **Caso 3**
2400
2401 Usar a função compiladora do YueScript em Lua.
2402
2403 ```lua
2404 local yue = require("yue")
2405 local codes, err, globals = yue.to_lua([[
2406 f = ->
2407 print "hello world"
2408 f!
2409 ]],{
2410 implicit_return_root = true,
2411 reserve_line_number = true,
2412 lint_global = true,
2413 space_over_tab = false,
2414 options = {
2415 target = "5.4",
2416 path = "/script"
2417 }
2418 })
2419 ```
2420
2421## Ferramenta YueScript
2422
2423Use a ferramenta YueScript com:
2424
2425```shell
2426> yue -h
2427Usage: yue
2428 [options] [<file/directory>] ...
2429 yue -e <code_or_file> [args...]
2430 yue -w [<directory>] [options]
2431 yue -
2432
2433Notas:
2434 - '-' / '--' deve ser o primeiro e único argumento.
2435 - '-o/--output' não pode ser usado com múltiplos arquivos de entrada.
2436 - '-w/--watch' não pode ser usado com entrada de arquivo (apenas diretório).
2437 - com '-e/--execute', os tokens restantes são tratados como argumentos do script.
2438
2439Opções:
2440 -h, --help Mostrar esta mensagem de ajuda e sair.
2441 -e <str>, --execute <str> Executar um arquivo ou código bruto
2442 -m, --minify Gerar código minificado
2443 -r, --rewrite Reescrever saída para corresponder aos números de linha originais
2444 -t <output_to>, --output-to <output_to>
2445 Especificar onde colocar os arquivos compilados
2446 -o <file>, --output <file> Escrever saída em arquivo
2447 -p, --print Escrever saída na saída padrão
2448 -b, --benchmark Mostrar tempo de compilação (não grava saída)
2449 -g, --globals Listar variáveis globais usadas em NOME LINHA COLUNA
2450 -s, --spaces Usar espaços no código gerado em vez de tabulações
2451 -l, --line-numbers Escrever números de linha do código fonte
2452 -j, --no-implicit-return Desabilitar retorno implícito no final do arquivo
2453 -c, --reserve-comments Preservar comentários antes de instruções do código fonte
2454 -w [<dir>], --watch [<dir>]
2455 Observar alterações e compilar cada arquivo no diretório
2456 -v, --version Imprimir versão
2457 - Ler da entrada padrão, imprimir na saída padrão
2458 (Deve ser o primeiro e único argumento)
2459 -- Igual a '-' (mantido para compatibilidade retroativa)
2460
2461 --target <version> Especificar a versão do Lua para a qual o código será gerado
2462 (a versão pode ser apenas 5.1 a 5.5)
2463 --path <path_str> Adicionar um caminho de busca Lua extra ao package.path
2464 --<key>=<value> Passar opção do compilador no formato key=value (comportamento existente)
2465
2466 Execute sem opções para entrar no REPL, digite o símbolo '$'
2467 em uma única linha para iniciar/parar o modo multilinha
2468```
2469
2470Casos de uso:
2471
2472Compilar recursivamente todos os arquivos YueScript com extensão **.yue** no caminho atual: **yue .**
2473
2474Compilar e salvar resultados em um caminho de destino: **yue -t /target/path/ .**
2475
2476Compilar e preservar informações de debug: **yue -l .**
2477
2478Compilar e gerar código minificado: **yue -m .**
2479
2480Executar código bruto: **yue -e 'print 123'**
2481
2482Executar um arquivo YueScript: **yue -e main.yue**
2483
2484# Introdução
2485
2486YueScript é uma linguagem dinâmica que compila para Lua. É um dialeto do [MoonScript](https://github.com/leafo/moonscript). O código escrito em YueScript é expressivo e extremamente conciso. É adequado para escrever lógica de aplicação variável com código mais manutenível e roda em ambientes Lua embutidos, como jogos ou servidores web.
2487
2488Yue (月) é o nome da lua em chinês e é pronunciado como [jyɛ].
2489
2490## Uma visão geral do YueScript
2491
2492```yuescript
2493-- sintaxe de importação
2494import p, to_lua from "yue"
2495
2496-- literais de objeto
2497inventory =
2498 equipment:
2499 - "sword"
2500 - "shield"
2501 items:
2502 - name: "potion"
2503 count: 10
2504 - name: "bread"
2505 count: 3
2506
2507-- compreensão de lista
2508map = (arr, action) ->
2509 [action item for item in *arr]
2510
2511filter = (arr, cond) ->
2512 [item for item in *arr when cond item]
2513
2514reduce = (arr, init, action): init ->
2515 init = action init, item for item in *arr
2516
2517-- operador pipe
2518[1, 2, 3]
2519 |> map (x) -> x * 2
2520 |> filter (x) -> x > 4
2521 |> reduce 0, (a, b) -> a + b
2522 |> print
2523
2524-- manipulação de metatable
2525apple =
2526 size: 15
2527 <index>:
2528 color: 0x00ffff
2529
2530with apple
2531 p .size, .color, .<index> if .<>?
2532
2533-- sintaxe de exportação estilo js
2534export 🌛 = "Script da Lua"
2535```
2536
2537<YueDisplay>
2538
2539```yue
2540-- sintaxe de importação
2541import p, to_lua from "yue"
2542
2543-- literais de objeto
2544inventory =
2545 equipment:
2546 - "sword"
2547 - "shield"
2548 items:
2549 - name: "potion"
2550 count: 10
2551 - name: "bread"
2552 count: 3
2553
2554-- compreensão de lista
2555map = (arr, action) ->
2556 [action item for item in *arr]
2557
2558filter = (arr, cond) ->
2559 [item for item in *arr when cond item]
2560
2561reduce = (arr, init, action): init ->
2562 init = action init, item for item in *arr
2563
2564-- operador pipe
2565[1, 2, 3]
2566 |> map (x) -> x * 2
2567 |> filter (x) -> x > 4
2568 |> reduce 0, (a, b) -> a + b
2569 |> print
2570
2571-- manipulação de metatable
2572apple =
2573 size: 15
2574 <index>:
2575 color: 0x00ffff
2576
2577with apple
2578 p .size, .color, .<index> if .<>?
2579
2580-- sintaxe de exportação estilo js
2581export 🌛 = "Script da Lua"
2582```
2583
2584</YueDisplay>
2585
2586## Sobre o Dora SSR
2587
2588O YueScript está sendo desenvolvido e mantido em conjunto com o motor de jogo open-source [Dora SSR](https://github.com/Dora-SSR/Dora-SSR). Tem sido usado para criar ferramentas do motor, demonstrações de jogos e protótipos, validando suas capacidades em cenários do mundo real e aprimorando a experiência de desenvolvimento do Dora SSR.
2589
2590# Instalação
2591
2592## Módulo Lua
2593
2594Instale o [luarocks](https://luarocks.org), um gerenciador de pacotes para módulos Lua. Em seguida, instale-o como módulo Lua e executável com:
2595
2596```shell
2597luarocks install yuescript
2598```
2599
2600Ou você pode compilar o arquivo `yue.so` com:
2601
2602```shell
2603make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua
2604```
2605
2606Depois, obtenha o arquivo binário no caminho **bin/shared/yue.so**.
2607
2608## Compilar ferramenta binária
2609
2610Clone este repositório e compile e instale o executável com:
2611
2612```shell
2613make install
2614```
2615
2616Compilar a ferramenta YueScript sem o recurso de macro:
2617
2618```shell
2619make install NO_MACRO=true
2620```
2621
2622Compilar a ferramenta YueScript sem o binário Lua embutido:
2623
2624```shell
2625make install NO_LUA=true
2626```
2627
2628## Baixar binário pré-compilado
2629
2630Você pode baixar arquivos binários pré-compilados, incluindo executáveis compatíveis com diferentes versões do Lua e arquivos de biblioteca.
2631
2632Baixe os arquivos binários pré-compilados [aqui](https://github.com/IppClub/YueScript/releases).
2633
2634# Condicionais
2635
2636```yuescript
2637have_coins = false
2638if have_coins
2639 print "Tem moedas"
2640else
2641 print "Sem moedas"
2642```
2643
2644<YueDisplay>
2645
2646```yue
2647have_coins = false
2648if have_coins
2649 print "Tem moedas"
2650else
2651 print "Sem moedas"
2652```
2653
2654</YueDisplay>
2655
2656Uma sintaxe curta para instruções únicas também pode ser usada:
2657
2658```yuescript
2659have_coins = false
2660if have_coins then print "Tem moedas" else print "Sem moedas"
2661```
2662
2663<YueDisplay>
2664
2665```yue
2666have_coins = false
2667if have_coins then print "Tem moedas" else print "Sem moedas"
2668```
2669
2670</YueDisplay>
2671
2672Como instruções if podem ser usadas como expressões, isso também pode ser escrito como:
2673
2674```yuescript
2675have_coins = false
2676print if have_coins then "Tem moedas" else "Sem moedas"
2677```
2678
2679<YueDisplay>
2680
2681```yue
2682have_coins = false
2683print if have_coins then "Tem moedas" else "Sem moedas"
2684```
2685
2686</YueDisplay>
2687
2688Condicionais também podem ser usados em instruções de retorno e atribuições:
2689
2690```yuescript
2691is_tall = (name) ->
2692 if name == "Rob"
2693 true
2694 else
2695 false
2696
2697message = if is_tall "Rob"
2698 "Sou muito alto"
2699else
2700 "Não sou tão alto"
2701
2702print message -- imprime: Sou muito alto
2703```
2704
2705<YueDisplay>
2706
2707```yue
2708is_tall = (name) ->
2709 if name == "Rob"
2710 true
2711 else
2712 false
2713
2714message = if is_tall "Rob"
2715 "Sou muito alto"
2716else
2717 "Não sou tão alto"
2718
2719print message -- imprime: Sou muito alto
2720```
2721
2722</YueDisplay>
2723
2724O oposto de if é unless:
2725
2726```yuescript
2727unless os.date("%A") == "Monday"
2728 print "não é segunda-feira!"
2729```
2730
2731<YueDisplay>
2732
2733```yue
2734unless os.date("%A") == "Monday"
2735 print "não é segunda-feira!"
2736```
2737
2738</YueDisplay>
2739
2740```yuescript
2741print "Você tem sorte!" unless math.random! > 0.1
2742```
2743
2744<YueDisplay>
2745
2746```yue
2747print "Você tem sorte!" unless math.random! > 0.1
2748```
2749
2750</YueDisplay>
2751
2752## Em expressão
2753
2754Você pode escrever código de verificação de intervalo com uma `in-expression`.
2755
2756```yuescript
2757a = 5
2758
2759if a in [1, 3, 5, 7]
2760 print "verificando igualdade com valores discretos"
2761
2762if a in list
2763 print "verificando se `a` está na lista"
2764```
2765
2766<YueDisplay>
2767
2768```yue
2769a = 5
2770
2771if a in [1, 3, 5, 7]
2772 print "verificando igualdade com valores discretos"
2773
2774if a in list
2775 print "verificando se `a` está na lista"
2776```
2777
2778</YueDisplay>
2779
2780# Loop For
2781
2782Existem duas formas de loop for, assim como no Lua. Uma numérica e uma genérica:
2783
2784```yuescript
2785for i = 10, 20
2786 print i
2787
2788for k = 1, 15, 2 -- um passo opcional fornecido
2789 print k
2790
2791for key, value in pairs object
2792 print key, value
2793```
2794
2795<YueDisplay>
2796
2797```yue
2798for i = 10, 20
2799 print i
2800
2801for k = 1, 15, 2 -- um passo opcional fornecido
2802 print k
2803
2804for key, value in pairs object
2805 print key, value
2806```
2807
2808</YueDisplay>
2809
2810Os operadores de slicing e **\*** podem ser usados, assim como com compreensões:
2811
2812```yuescript
2813for item in *items[2, 4]
2814 print item
2815```
2816
2817<YueDisplay>
2818
2819```yue
2820for item in *items[2, 4]
2821 print item
2822```
2823
2824</YueDisplay>
2825
2826Uma sintaxe mais curta também está disponível para todas as variações quando o corpo é apenas uma linha:
2827
2828```yuescript
2829for item in *items do print item
2830
2831for j = 1, 10, 3 do print j
2832```
2833
2834<YueDisplay>
2835
2836```yue
2837for item in *items do print item
2838
2839for j = 1, 10, 3 do print j
2840```
2841
2842</YueDisplay>
2843
2844Um loop for também pode ser usado como expressão. A última instrução no corpo do loop for é convertida em expressão e anexada a uma tabela array acumuladora.
2845
2846Dobrando cada número par:
2847
2848```yuescript
2849doubled_evens = for i = 1, 20
2850 if i % 2 == 0
2851 i * 2
2852 else
2853 i
2854```
2855
2856<YueDisplay>
2857
2858```yue
2859doubled_evens = for i = 1, 20
2860 if i % 2 == 0
2861 i * 2
2862 else
2863 i
2864```
2865
2866</YueDisplay>
2867
2868Além disso, os loops for suportam break com valores de retorno, permitindo que o próprio loop seja usado como expressão que sai antecipadamente com um resultado significativo. Expressões `for` suportam `break` com múltiplos valores.
2869
2870Por exemplo, para encontrar o primeiro número maior que 10:
2871
2872```yuescript
2873first_large = for n in *numbers
2874 break n if n > 10
2875```
2876
2877<YueDisplay>
2878
2879```yue
2880first_large = for n in *numbers
2881 break n if n > 10
2882```
2883
2884</YueDisplay>
2885
2886Esta sintaxe de break-com-valor permite padrões concisos e expressivos de busca ou saída antecipada diretamente em expressões de loop.
2887
2888```yuescript
2889key, score = for k, v in pairs data
2890 break k, v * 10 if k == "target"
2891```
2892
2893<YueDisplay>
2894
2895```yue
2896key, score = for k, v in pairs data
2897 break k, v * 10 if k == "target"
2898```
2899
2900</YueDisplay>
2901
2902Você também pode filtrar valores combinando a expressão do loop for com a instrução continue.
2903
2904Loops for no final do corpo de uma função não são acumulados em uma tabela para valor de retorno (em vez disso, a função retornará nil). Uma instrução return explícita pode ser usada, ou o loop pode ser convertido em compreensão de lista.
2905
2906```yuescript
2907func_a = -> for i = 1, 10 do print i
2908func_b = -> return for i = 1, 10 do i
2909
2910print func_a! -- imprime nil
2911print func_b! -- imprime objeto table
2912```
2913
2914<YueDisplay>
2915
2916```yue
2917func_a = -> for i = 1, 10 do print i
2918func_b = -> return for i = 1, 10 do i
2919
2920print func_a! -- imprime nil
2921print func_b! -- imprime objeto table
2922```
2923
2924</YueDisplay>
2925
2926Isso é feito para evitar a criação desnecessária de tabelas para funções que não precisam retornar os resultados do loop.
2927
2928# Continue
2929
2930Uma instrução continue pode ser usada para pular a iteração atual em um loop.
2931
2932```yuescript
2933i = 0
2934while i < 10
2935 i += 1
2936 continue if i % 2 == 0
2937 print i
2938```
2939
2940<YueDisplay>
2941
2942```yue
2943i = 0
2944while i < 10
2945 i += 1
2946 continue if i % 2 == 0
2947 print i
2948```
2949
2950</YueDisplay>
2951
2952continue também pode ser usado com expressões de loop para impedir que essa iteração seja acumulada no resultado. Este exemplo filtra a tabela array para apenas números pares:
2953
2954```yuescript
2955my_numbers = [1, 2, 3, 4, 5, 6]
2956odds = for x in *my_numbers
2957 continue if x % 2 == 1
2958 x
2959```
2960
2961<YueDisplay>
2962
2963```yue
2964my_numbers = [1, 2, 3, 4, 5, 6]
2965odds = for x in *my_numbers
2966 continue if x % 2 == 1
2967 x
2968```
2969
2970</YueDisplay>
2971
2972# Switch
2973
2974A instrução switch é uma forma abreviada de escrever uma série de instruções if que verificam o mesmo valor. Observe que o valor é avaliado apenas uma vez. Como as instruções if, os switches podem ter um bloco else para tratar ausência de correspondências. A comparação é feita com o operador ==. Na instrução switch, você também pode usar expressão de atribuição para armazenar valor de variável temporária.
2975
2976```yuescript
2977switch name := "Dan"
2978 when "Robert"
2979 print "Você é Robert"
2980 when "Dan", "Daniel"
2981 print "Seu nome é Dan"
2982 else
2983 print "Não sei quem você é com o nome #{name}"
2984```
2985
2986<YueDisplay>
2987
2988```yue
2989switch name := "Dan"
2990 when "Robert"
2991 print "Você é Robert"
2992 when "Dan", "Daniel"
2993 print "Seu nome é Dan"
2994 else
2995 print "Não sei quem você é com o nome #{name}"
2996```
2997
2998</YueDisplay>
2999
3000Uma cláusula when de um switch pode corresponder a múltiplos valores listando-os separados por vírgula.
3001
3002Os switches também podem ser usados como expressões; aqui podemos atribuir o resultado do switch a uma variável:
3003
3004```yuescript
3005b = 1
3006next_number = switch b
3007 when 1
3008 2
3009 when 2
3010 3
3011 else
3012 error "não consigo contar tão alto!"
3013```
3014
3015<YueDisplay>
3016
3017```yue
3018b = 1
3019next_number = switch b
3020 when 1
3021 2
3022 when 2
3023 3
3024 else
3025 error "não consigo contar tão alto!"
3026```
3027
3028</YueDisplay>
3029
3030Podemos usar a palavra-chave then para escrever o bloco when de um switch em uma única linha. Nenhuma palavra-chave extra é necessária para escrever o bloco else em uma única linha.
3031
3032```yuescript
3033msg = switch math.random(1, 5)
3034 when 1 then "você tem sorte"
3035 when 2 then "você quase tem sorte"
3036 else "não tão sortudo"
3037```
3038
3039<YueDisplay>
3040
3041```yue
3042msg = switch math.random(1, 5)
3043 when 1 then "você tem sorte"
3044 when 2 then "você quase tem sorte"
3045 else "não tão sortudo"
3046```
3047
3048</YueDisplay>
3049
3050Se você quiser escrever código com uma indentação a menos ao escrever uma instrução switch, pode colocar a primeira cláusula when na linha de início da instrução, e então todas as outras cláusulas podem ser escritas com uma indentação a menos.
3051
3052```yuescript
3053switch math.random(1, 5)
3054 when 1
3055 print "você tem sorte" -- duas indentações
3056 else
3057 print "não tão sortudo"
3058
3059switch math.random(1, 5) when 1
3060 print "você tem sorte" -- uma indentação
3061else
3062 print "não tão sortudo"
3063```
3064
3065<YueDisplay>
3066
3067```yue
3068switch math.random(1, 5)
3069 when 1
3070 print "você tem sorte" -- duas indentações
3071 else
3072 print "não tão sortudo"
3073
3074switch math.random(1, 5) when 1
3075 print "você tem sorte" -- uma indentação
3076else
3077 print "não tão sortudo"
3078```
3079
3080</YueDisplay>
3081
3082Vale notar a ordem da expressão de comparação do case. A expressão do case está no lado esquerdo. Isso pode ser útil se a expressão do case quiser sobrescrever como a comparação é feita definindo um metamétodo eq.
3083
3084## Correspondência de tabela
3085
3086Você pode fazer correspondência de tabela em uma cláusula when de switch, se a tabela puder ser desestruturada por uma estrutura específica e obter valores não-nil.
3087
3088```yuescript
3089items =
3090 * x: 100
3091 y: 200
3092 * width: 300
3093 height: 400
3094
3095for item in *items
3096 switch item
3097 when :x, :y
3098 print "Vec2 #{x}, #{y}"
3099 when :width, :height
3100 print "tamanho #{width}, #{height}"
3101```
3102
3103<YueDisplay>
3104
3105```yue
3106items =
3107 * x: 100
3108 y: 200
3109 * width: 300
3110 height: 400
3111
3112for item in *items
3113 switch item
3114 when :x, :y
3115 print "Vec2 #{x}, #{y}"
3116 when :width, :height
3117 print "tamanho #{width}, #{height}"
3118```
3119
3120</YueDisplay>
3121
3122Você pode usar valores padrão para opcionalmente desestruturar a tabela para alguns campos.
3123
3124```yuescript
3125item = {}
3126
3127{pos: {:x = 50, :y = 200}} = item -- obtém erro: attempt to index a nil value (field 'pos')
3128
3129switch item
3130 when {pos: {:x = 50, :y = 200}}
3131 print "Vec2 #{x}, #{y}" -- a desestruturação de tabela ainda passará
3132```
3133
3134<YueDisplay>
3135
3136```yue
3137item = {}
3138
3139{pos: {:x = 50, :y = 200}} = item -- obtém erro: attempt to index a nil value (field 'pos')
3140
3141switch item
3142 when {pos: {:x = 50, :y = 200}}
3143 print "Vec2 #{x}, #{y}" -- a desestruturação de tabela ainda passará
3144```
3145
3146</YueDisplay>
3147
3148Você também pode corresponder contra elementos de array, campos de tabela, e até estruturas aninhadas com literais de array ou tabela.
3149
3150Corresponder contra elementos de array.
3151
3152```yuescript
3153switch tb
3154 when [1, 2, 3]
3155 print "1, 2, 3"
3156 when [1, b, 3]
3157 print "1, #{b}, 3"
3158 when [1, 2, b = 3] -- b tem valor padrão
3159 print "1, 2, #{b}"
3160```
3161
3162<YueDisplay>
3163
3164```yue
3165switch tb
3166 when [1, 2, 3]
3167 print "1, 2, 3"
3168 when [1, b, 3]
3169 print "1, #{b}, 3"
3170 when [1, 2, b = 3] -- b tem valor padrão
3171 print "1, 2, #{b}"
3172```
3173
3174</YueDisplay>
3175
3176Corresponder contra campos de tabela com desestruturação.
3177
3178```yuescript
3179switch tb
3180 when success: true, :result
3181 print "sucesso", result
3182 when success: false
3183 print "falhou", result
3184 else
3185 print "inválido"
3186```
3187
3188<YueDisplay>
3189
3190```yue
3191switch tb
3192 when success: true, :result
3193 print "sucesso", result
3194 when success: false
3195 print "falhou", result
3196 else
3197 print "inválido"
3198```
3199
3200</YueDisplay>
3201
3202Corresponder contra estruturas de tabela aninhadas.
3203
3204```yuescript
3205switch tb
3206 when data: {type: "success", :content}
3207 print "sucesso", content
3208 when data: {type: "error", :content}
3209 print "erro", content
3210 else
3211 print "inválido"
3212```
3213
3214<YueDisplay>
3215
3216```yue
3217switch tb
3218 when data: {type: "success", :content}
3219 print "sucesso", content
3220 when data: {type: "error", :content}
3221 print "erro", content
3222 else
3223 print "inválido"
3224```
3225
3226</YueDisplay>
3227
3228Corresponder contra array de tabelas.
3229
3230```yuescript
3231switch tb
3232 when [
3233 {a: 1, b: 2}
3234 {a: 3, b: 4}
3235 {a: 5, b: 6}
3236 fourth
3237 ]
3238 print "correspondido", fourth
3239```
3240
3241<YueDisplay>
3242
3243```yue
3244switch tb
3245 when [
3246 {a: 1, b: 2}
3247 {a: 3, b: 4}
3248 {a: 5, b: 6}
3249 fourth
3250 ]
3251 print "correspondido", fourth
3252```
3253
3254</YueDisplay>
3255
3256Corresponder contra uma lista e capturar um intervalo de elementos.
3257
3258```yuescript
3259segments = ["admin", "users", "logs", "view"]
3260switch segments
3261 when [...groups, resource, action]
3262 print "Grupo:", groups -- imprime: {"admin", "users"}
3263 print "Recurso:", resource -- imprime: "logs"
3264 print "Ação:", action -- imprime: "view"
3265```
3266
3267<YueDisplay>
3268
3269```yue
3270segments = ["admin", "users", "logs", "view"]
3271switch segments
3272 when [...groups, resource, action]
3273 print "Grupo:", groups -- imprime: {"admin", "users"}
3274 print "Recurso:", resource -- imprime: "logs"
3275 print "Ação:", action -- imprime: "view"
3276```
3277
3278</YueDisplay>
3279
3280# Loop While
3281
3282O loop while também vem em quatro variações:
3283
3284```yuescript
3285i = 10
3286while i > 0
3287 print i
3288 i -= 1
3289
3290while running == true do my_function!
3291```
3292
3293<YueDisplay>
3294
3295```yue
3296i = 10
3297while i > 0
3298 print i
3299 i -= 1
3300
3301while running == true do my_function!
3302```
3303
3304</YueDisplay>
3305
3306```yuescript
3307i = 10
3308until i == 0
3309 print i
3310 i -= 1
3311
3312until running == false do my_function!
3313```
3314
3315<YueDisplay>
3316
3317```yue
3318i = 10
3319until i == 0
3320 print i
3321 i -= 1
3322until running == false do my_function!
3323```
3324
3325</YueDisplay>
3326
3327Como os loops for, o loop while também pode ser usado como expressão. Expressões `while` e `until` suportam `break` com múltiplos valores.
3328
3329```yuescript
3330value, doubled = while true
3331 n = get_next!
3332 break n, n * 2 if n > 10
3333```
3334
3335<YueDisplay>
3336
3337```yue
3338value, doubled = while true
3339 n = get_next!
3340 break n, n * 2 if n > 10
3341```
3342
3343</YueDisplay>
3344
3345Além disso, para uma função retornar o valor acumulado de um loop while, a instrução deve ser explicitamente retornada.
3346
3347## Loop Repeat
3348
3349O loop repeat vem do Lua:
3350
3351```yuescript
3352i = 10
3353repeat
3354 print i
3355 i -= 1
3356until i == 0
3357```
3358
3359<YueDisplay>
3360
3361```yue
3362i = 10
3363repeat
3364 print i
3365 i -= 1
3366until i == 0
3367```
3368
3369</YueDisplay>
3370
3371Expressões `repeat` também suportam `break` com múltiplos valores:
3372
3373```yuescript
3374i = 1
3375value, scaled = repeat
3376 break i, i * 100 if i > 3
3377 i += 1
3378until false
3379```
3380
3381<YueDisplay>
3382
3383```yue
3384i = 1
3385value, scaled = repeat
3386 break i, i * 100 if i > 3
3387 i += 1
3388until false
3389```
3390
3391</YueDisplay>
3392
3393# Stubs de função
3394
3395É comum passar uma função de um objeto como valor, por exemplo, passando um método de instância para uma função como callback. Se a função espera o objeto em que está operando como primeiro argumento, então você deve de alguma forma empacotar esse objeto com a função para que ela possa ser chamada corretamente.
3396
3397A sintaxe de function stub é uma forma abreviada de criar uma nova função closure que empacota tanto o objeto quanto a função. Esta nova função chama a função empacotada no contexto correto do objeto.
3398
3399Sua sintaxe é a mesma que chamar um método de instância com o operador \, mas sem lista de argumentos fornecida.
3400
3401```yuescript
3402my_object = {
3403 value: 1000
3404 write: => print "the value:", @value
3405}
3406
3407run_callback = (func) ->
3408 print "running callback..."
3409 func!
3410
3411-- isso não funcionará:
3412-- a função não tem referência a my_object
3413run_callback my_object.write
3414
3415-- sintaxe de function stub
3416-- nos permite empacotar o objeto em uma nova função
3417run_callback my_object\write
3418```
3419
3420<YueDisplay>
3421
3422```yue
3423my_object = {
3424 value: 1000
3425 write: => print "the value:", @value
3426}
3427
3428run_callback = (func) ->
3429 print "running callback..."
3430 func!
3431
3432-- isso não funcionará:
3433-- a função não tem referência a my_object
3434run_callback my_object.write
3435
3436-- sintaxe de function stub
3437-- nos permite empacotar o objeto em uma nova função
3438run_callback my_object\write
3439```
3440
3441</YueDisplay>
3442
3443# Backcalls
3444
3445Backcalls são usados para desaninhar callbacks. Eles são definidos usando setas apontando para a esquerda como o último parâmetro, preenchendo por padrão uma chamada de função. Toda a sintaxe é basicamente a mesma das funções seta regulares, exceto que apenas aponta para o outro lado e o corpo da função não requer indentação.
3446
3447```yuescript
3448x <- f
3449print "hello" .. x
3450```
3451
3452<YueDisplay>
3453
3454```yue
3455x <- f
3456print "hello" .. x
3457```
3458
3459</YueDisplay>
3460
3461Funções seta "fat" também estão disponíveis.
3462
3463```yuescript
3464<= f
3465print @value
3466```
3467
3468<YueDisplay>
3469
3470```yue
3471<= f
3472print @value
3473```
3474
3475</YueDisplay>
3476
3477Você pode especificar um placeholder para onde deseja que a função backcall vá como parâmetro.
3478
3479```yuescript
3480(x) <- map _, [1, 2, 3]
3481x * 2
3482```
3483
3484<YueDisplay>
3485
3486```yue
3487(x) <- map _, [1, 2, 3]
3488x * 2
3489```
3490
3491</YueDisplay>
3492
3493Se você desejar ter mais código após seus backcalls, pode colocá-los em uma instrução do. E os parênteses podem ser omitidos com funções seta não-fat.
3494
3495```yuescript
3496result, msg = do
3497 data <- readAsync "filename.txt"
3498 print data
3499 info <- processAsync data
3500 check info
3501print result, msg
3502```
3503
3504<YueDisplay>
3505
3506```yue
3507result, msg = do
3508 data <- readAsync "filename.txt"
3509 print data
3510 info <- processAsync data
3511 check info
3512print result, msg
3513```
3514
3515</YueDisplay>
3516
3517# Literais de função
3518
3519Todas as funções são criadas usando uma expressão de função. Uma função simples é denotada usando a seta: **->**.
3520
3521```yuescript
3522my_function = ->
3523my_function() -- chama a função vazia
3524```
3525
3526<YueDisplay>
3527
3528```yue
3529my_function = ->
3530my_function() -- chama a função vazia
3531```
3532
3533</YueDisplay>
3534
3535O corpo da função pode ser uma instrução colocada diretamente após a seta, ou pode ser uma série de instruções indentadas nas linhas seguintes:
3536
3537```yuescript
3538func_a = -> print "hello world"
3539
3540func_b = ->
3541 value = 100
3542 print "The value:", value
3543```
3544
3545<YueDisplay>
3546
3547```yue
3548func_a = -> print "hello world"
3549
3550func_b = ->
3551 value = 100
3552 print "The value:", value
3553```
3554
3555</YueDisplay>
3556
3557Se uma função não tem argumentos, ela pode ser chamada usando o operador !, em vez de parênteses vazios. A invocação ! é a forma preferida de chamar funções sem argumentos.
3558
3559```yuescript
3560func_a!
3561func_b()
3562```
3563
3564<YueDisplay>
3565
3566```yue
3567func_a!
3568func_b()
3569```
3570
3571</YueDisplay>
3572
3573Funções com argumentos podem ser criadas precedendo a seta com uma lista de nomes de argumentos entre parênteses:
3574
3575```yuescript
3576sum = (x, y) -> print "sum", x + y
3577```
3578
3579<YueDisplay>
3580
3581```yue
3582sum = (x, y) -> print "sum", x + y
3583```
3584
3585</YueDisplay>
3586
3587Funções podem ser chamadas listando os argumentos após o nome de uma expressão que avalia para uma função. Ao encadear chamadas de função, os argumentos são aplicados à função mais próxima à esquerda.
3588
3589```yuescript
3590sum 10, 20
3591print sum 10, 20
3592
3593a b c "a", "b", "c"
3594```
3595
3596<YueDisplay>
3597
3598```yue
3599sum 10, 20
3600print sum 10, 20
3601
3602a b c "a", "b", "c"
3603```
3604
3605</YueDisplay>
3606
3607Para evitar ambiguidade ao chamar funções, parênteses também podem ser usados para envolver os argumentos. Isso é necessário aqui para garantir que os argumentos certos sejam enviados às funções certas.
3608
3609```yuescript
3610print "x:", sum(10, 20), "y:", sum(30, 40)
3611```
3612
3613<YueDisplay>
3614
3615```yue
3616print "x:", sum(10, 20), "y:", sum(30, 40)
3617```
3618
3619</YueDisplay>
3620
3621Não deve haver espaço entre o parêntese de abertura e a função.
3622
3623As funções convertem a última instrução em seu corpo em uma instrução de retorno, isso é chamado de retorno implícito:
3624
3625```yuescript
3626sum = (x, y) -> x + y
3627print "The sum is ", sum 10, 20
3628```
3629
3630<YueDisplay>
3631
3632```yue
3633sum = (x, y) -> x + y
3634print "The sum is ", sum 10, 20
3635```
3636
3637</YueDisplay>
3638
3639E se você precisar retornar explicitamente, pode usar a palavra-chave return:
3640
3641```yuescript
3642sum = (x, y) -> return x + y
3643```
3644
3645<YueDisplay>
3646
3647```yue
3648sum = (x, y) -> return x + y
3649```
3650
3651</YueDisplay>
3652
3653Assim como no Lua, as funções podem retornar múltiplos valores. A última instrução deve ser uma lista de valores separados por vírgulas:
3654
3655```yuescript
3656mystery = (x, y) -> x + y, x - y
3657a, b = mystery 10, 20
3658```
3659
3660<YueDisplay>
3661
3662```yue
3663mystery = (x, y) -> x + y, x - y
3664a, b = mystery 10, 20
3665```
3666
3667</YueDisplay>
3668
3669## Setas fat
3670
3671Como é um idioma em Lua enviar um objeto como primeiro argumento ao chamar um método, uma sintaxe especial é fornecida para criar funções que incluem automaticamente um argumento self.
3672
3673```yuescript
3674func = (num) => @value + num
3675```
3676
3677<YueDisplay>
3678
3679```yue
3680func = (num) => @value + num
3681```
3682
3683</YueDisplay>
3684
3685## Valores padrão de argumentos
3686
3687É possível fornecer valores padrão para os argumentos de uma função. Um argumento é determinado como vazio se seu valor for nil. Qualquer argumento nil que tenha valor padrão será substituído antes da execução do corpo da função.
3688
3689```yuescript
3690my_function = (name = "something", height = 100) ->
3691 print "Hello I am", name
3692 print "My height is", height
3693```
3694
3695<YueDisplay>
3696
3697```yue
3698my_function = (name = "something", height = 100) ->
3699 print "Hello I am", name
3700 print "My height is", height
3701```
3702
3703</YueDisplay>
3704
3705Uma expressão de valor padrão de argumento é avaliada no corpo da função na ordem das declarações de argumentos. Por esse motivo, os valores padrão têm acesso aos argumentos declarados anteriormente.
3706
3707```yuescript
3708some_args = (x = 100, y = x + 1000) ->
3709 print x + y
3710```
3711
3712<YueDisplay>
3713
3714```yue
3715some_args = (x = 100, y = x + 1000) ->
3716 print x + y
3717```
3718
3719</YueDisplay>
3720
3721## Considerações
3722
3723Devido à forma expressiva de chamar funções sem parênteses, algumas restrições devem ser colocadas para evitar ambiguidade de análise envolvendo espaço em branco.
3724
3725O sinal de menos desempenha dois papéis: um operador de negação unário e um operador de subtração binário. Considere como os seguintes exemplos compilam:
3726
3727```yuescript
3728a = x - 10
3729b = x-10
3730c = x -y
3731d = x- z
3732```
3733
3734<YueDisplay>
3735
3736```yue
3737a = x - 10
3738b = x-10
3739c = x -y
3740d = x- z
3741```
3742
3743</YueDisplay>
3744
3745A precedência do primeiro argumento de uma chamada de função pode ser controlada usando espaço em branco se o argumento for um literal de string. Em Lua, é comum omitir parênteses ao chamar uma função com uma única string ou literal de tabela.
3746
3747Quando não há espaço entre uma variável e um literal de string, a chamada de função tem precedência sobre quaisquer expressões seguintes. Nenhum outro argumento pode ser passado para a função quando ela é chamada dessa forma.
3748
3749Quando há um espaço após uma variável e um literal de string, a chamada de função age como mostrado acima. O literal de string pertence a quaisquer expressões seguintes (se existirem), que servem como lista de argumentos.
3750
3751```yuescript
3752x = func"hello" + 100
3753y = func "hello" + 100
3754```
3755
3756<YueDisplay>
3757
3758```yue
3759x = func"hello" + 100
3760y = func "hello" + 100
3761```
3762
3763</YueDisplay>
3764
3765## Argumentos multilinha
3766
3767Ao chamar funções que recebem um grande número de argumentos, é conveniente dividir a lista de argumentos em várias linhas. Devido à natureza sensível a espaço em branco da linguagem, deve-se ter cuidado ao dividir a lista de argumentos.
3768
3769Se uma lista de argumentos for continuada na próxima linha, a linha atual deve terminar em vírgula. E a linha seguinte deve estar mais indentada que a indentação atual. Uma vez indentada, todas as outras linhas de argumentos devem estar no mesmo nível de indentação para fazer parte da lista de argumentos.
3770
3771```yuescript
3772my_func 5, 4, 3,
3773 8, 9, 10
3774
3775cool_func 1, 2,
3776 3, 4,
3777 5, 6,
3778 7, 8
3779```
3780
3781<YueDisplay>
3782
3783```yue
3784my_func 5, 4, 3,
3785 8, 9, 10
3786
3787cool_func 1, 2,
3788 3, 4,
3789 5, 6,
3790 7, 8
3791```
3792
3793</YueDisplay>
3794
3795Este tipo de invocação pode ser aninhado. O nível de indentação é usado para determinar a qual função os argumentos pertencem.
3796
3797```yuescript
3798my_func 5, 6, 7,
3799 6, another_func 6, 7, 8,
3800 9, 1, 2,
3801 5, 4
3802```
3803
3804<YueDisplay>
3805
3806```yue
3807my_func 5, 6, 7,
3808 6, another_func 6, 7, 8,
3809 9, 1, 2,
3810 5, 4
3811```
3812
3813</YueDisplay>
3814
3815Como as tabelas também usam vírgula como delimitador, esta sintaxe de indentação ajuda a deixar os valores fazerem parte da lista de argumentos em vez de fazerem parte da tabela.
3816
3817```yuescript
3818x = [
3819 1, 2, 3, 4, a_func 4, 5,
3820 5, 6,
3821 8, 9, 10
3822]
3823```
3824
3825<YueDisplay>
3826
3827```yue
3828x = [
3829 1, 2, 3, 4, a_func 4, 5,
3830 5, 6,
3831 8, 9, 10
3832]
3833```
3834
3835</YueDisplay>
3836
3837Embora incomum, observe como podemos dar uma indentação mais profunda para argumentos de função se soubermos que usaremos uma indentação menor mais adiante.
3838
3839```yuescript
3840y = [ my_func 1, 2, 3,
3841 4, 5,
3842 5, 6, 7
3843]
3844```
3845
3846<YueDisplay>
3847
3848```yue
3849y = [ my_func 1, 2, 3,
3850 4, 5,
3851 5, 6, 7
3852]
3853```
3854
3855</YueDisplay>
3856
3857A mesma coisa pode ser feita com outras instruções em nível de bloco como condicionais. Podemos usar o nível de indentação para determinar a qual instrução um valor pertence:
3858
3859```yuescript
3860if func 1, 2, 3,
3861 "hello",
3862 "world"
3863 print "hello"
3864 print "I am inside if"
3865
3866if func 1, 2, 3,
3867 "hello",
3868 "world"
3869 print "hello"
3870 print "I am inside if"
3871```
3872
3873<YueDisplay>
3874
3875```yue
3876if func 1, 2, 3,
3877 "hello",
3878 "world"
3879 print "hello"
3880 print "I am inside if"
3881
3882if func 1, 2, 3,
3883 "hello",
3884 "world"
3885 print "hello"
3886 print "I am inside if"
3887```
3888
3889</YueDisplay>
3890
3891## Desestruturação de parâmetros
3892
3893YueScript agora suporta desestruturação de parâmetros de função quando o argumento é um objeto. Duas formas de literais de tabela de desestruturação estão disponíveis:
3894
3895- **Literais/parâmetros de objeto envolvidos em chaves**, permitindo valores padrão opcionais quando os campos estão ausentes (ex.: `{:a, :b}`, `{a: a1 = 123}`).
3896
3897- **Sintaxe de tabela simples não envolvida**, começando com uma sequência de ligações chave-valor ou abreviadas e continuando até outra expressão terminá-la (ex.: `:a, b: b1, :c`). Esta forma extrai múltiplos campos do mesmo objeto.
3898
3899```yuescript
3900f1 = (:a, :b, :c) ->
3901 print a, b, c
3902
3903f1 a: 1, b: "2", c: {}
3904
3905f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3906 print a1, b, c
3907
3908arg1 = {a: 0}
3909f2 arg1, arg2
3910```
3911
3912<YueDisplay>
3913
3914```yue
3915f1 = (:a, :b, :c) ->
3916 print a, b, c
3917
3918f1 a: 1, b: "2", c: {}
3919
3920f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3921print a1, b, c
3922
3923arg1 = {a: 0}
3924f2 arg1, arg2
3925```
3926
3927</YueDisplay>
3928
3929## Expressão de retorno prefixada
3930
3931Ao trabalhar com corpos de função profundamente aninhados, pode ser tedioso manter a legibilidade e consistência do valor de retorno. Para resolver isso, YueScript introduz a sintaxe **Expressão de Retorno Prefixada**. Sua forma é a seguinte:
3932
3933```yuescript
3934findFirstEven = (list): nil ->
3935 for item in *list
3936 if type(item) == "table"
3937 for sub in *item
3938 if sub % 2 == 0
3939 return sub
3940```
3941
3942<YueDisplay>
3943
3944```yue
3945findFirstEven = (list): nil ->
3946 for item in *list
3947 if type(item) == "table"
3948 for sub in *item
3949 if sub % 2 == 0
3950 return sub
3951```
3952
3953</YueDisplay>
3954
3955Isso é equivalente a:
3956
3957```yuescript
3958findFirstEven = (list) ->
3959 for item in *list
3960 if type(item) == "table"
3961 for sub in *item
3962 if sub % 2 == 0
3963 return sub
3964 nil
3965```
3966
3967<YueDisplay>
3968
3969```yue
3970findFirstEven = (list) ->
3971 for item in *list
3972 if type(item) == "table"
3973 for sub in *item
3974 if sub % 2 == 0
3975 return sub
3976 nil
3977```
3978
3979</YueDisplay>
3980
3981A única diferença é que você pode mover a expressão de retorno final antes do token `->` ou `=>` para indicar o valor de retorno implícito da função como última instrução. Dessa forma, mesmo em funções com múltiplos loops aninhados ou ramificações condicionais, você não precisa mais escrever uma expressão de retorno no final do corpo da função, tornando a estrutura lógica mais direta e fácil de seguir.
3982
3983## Varargs nomeados
3984
3985Você pode usar a sintaxe `(...t) ->` para armazenar automaticamente varargs em uma tabela nomeada. Esta tabela conterá todos os argumentos passados (incluindo valores `nil`), e o campo `n` da tabela armazenará o número real de argumentos passados (incluindo valores `nil`).
3986
3987```yuescript
3988f = (...t) ->
3989 print "contagem de argumentos:", t.n
3990 print "comprimento da tabela:", #t
3991 for i = 1, t.n
3992 print t[i]
3993
3994f 1, 2, 3
3995f "a", "b", "c", "d"
3996f!
3997
3998-- Tratando casos com valores nil
3999process = (...args) ->
4000 sum = 0
4001 for i = 1, args.n
4002 if args[i] != nil and type(args[i]) == "number"
4003 sum += args[i]
4004 sum
4005
4006process 1, nil, 3, nil, 5
4007```
4008
4009<YueDisplay>
4010
4011```yue
4012f = (...t) ->
4013 print "contagem de argumentos:", t.n
4014 print "comprimento da tabela:", #t
4015 for i = 1, t.n
4016 print t[i]
4017
4018f 1, 2, 3
4019f "a", "b", "c", "d"
4020f!
4021
4022-- Tratando casos com valores nil
4023process = (...args) ->
4024 sum = 0
4025 for i = 1, args.n
4026 if args[i] != nil and type(args[i]) == "number"
4027 sum += args[i]
4028 sum
4029
4030process 1, nil, 3, nil, 5
4031```
4032
4033</YueDisplay>
4034
4035# Espaço em branco
4036
4037YueScript é uma linguagem sensível a espaço em branco. Você precisa escrever blocos de código na mesma indentação com espaço **' '** ou tabulação **'\t'**, como corpo de função, lista de valores e alguns blocos de controle. E expressões contendo diferentes espaços em branco podem significar coisas diferentes. Tabulação é tratada como 4 espaços, mas é melhor não misturar o uso de espaços e tabulações.
4038
4039## Separador de instrução
4040
4041Uma instrução normalmente termina em uma quebra de linha. Você também pode usar ponto e vírgula `;` para terminar explicitamente uma instrução, o que permite escrever múltiplas instruções na mesma linha:
4042
4043```yuescript
4044a = 1; b = 2; print a + b
4045```
4046
4047<YueDisplay>
4048
4049```yue
4050a = 1; b = 2; print a + b
4051```
4052
4053</YueDisplay>
4054
4055## Encadeamento multilinha
4056
4057Você pode escrever chamadas de função encadeadas em múltiplas linhas com a mesma indentação.
4058
4059```yuescript
4060Rx.Observable
4061 .fromRange 1, 8
4062 \filter (x) -> x % 2 == 0
4063 \concat Rx.Observable.of 'who do we appreciate'
4064 \map (value) -> value .. '!'
4065 \subscribe print
4066```
4067
4068<YueDisplay>
4069
4070```yue
4071Rx.Observable
4072 .fromRange 1, 8
4073 \filter (x) -> x % 2 == 0
4074 \concat Rx.Observable.of 'who do we appreciate'
4075 \map (value) -> value .. '!'
4076 \subscribe print
4077```
4078
4079</YueDisplay>
4080
4081# Comentário
4082
4083```yuescript
4084-- Eu sou um comentário
4085
4086str = --[[
4087Este é um comentário multilinha.
4088Está OK.
4089]] strA \ -- comentário 1
4090 .. strB \ -- comentário 2
4091 .. strC
4092
4093func --[[port]] 3000, --[[ip]] "192.168.1.1"
4094```
4095
4096<YueDisplay>
4097
4098```yue
4099-- Eu sou um comentário
4100
4101str = --[[
4102Este é um comentário multilinha.
4103Está OK.
4104]] strA \ -- comentário 1
4105 .. strB \ -- comentário 2
4106 .. strC
4107
4108func --[[port]] 3000, --[[ip]] "192.168.1.1"
4109```
4110
4111</YueDisplay>
4112
4113# Atributos
4114
4115Suporte de sintaxe para atributos do Lua 5.4. E você ainda pode usar tanto a declaração `const` quanto `close` e obter verificação de constante e callback com escopo funcionando ao direcionar para versões do Lua abaixo da 5.4.
4116
4117```yuescript
4118const a = 123
4119close _ = <close>: -> print "Fora do escopo."
4120```
4121
4122<YueDisplay>
4123
4124```yue
4125const a = 123
4126close _ = <close>: -> print "Fora do escopo."
4127```
4128
4129</YueDisplay>
4130
4131Você pode fazer desestruturação com variáveis atribuídas como constante.
4132
4133```yuescript
4134const {:a, :b, c, d} = tb
4135-- a = 1
4136```
4137
4138<YueDisplay>
4139
4140```yue
4141const {:a, :b, c, d} = tb
4142-- a = 1
4143```
4144
4145</YueDisplay>
4146
4147Você também pode declarar uma variável global como `const`.
4148
4149```yuescript
4150global const Constant = 123
4151-- Constant = 1
4152```
4153
4154<YueDisplay>
4155
4156```yue
4157global const Constant = 123
4158-- Constant = 1
4159```
4160
4161</YueDisplay>
4162
4163# Operador
4164
4165Todos os operadores binários e unários do Lua estão disponíveis. Além disso, **!=** é um alias para **~=**, e **\\** ou **::** podem ser usados para escrever uma chamada de função encadeada como `tb\func!` ou `tb::func!`. E o YueScript oferece alguns outros operadores especiais para escrever códigos mais expressivos.
4166
4167```yuescript
4168tb\func! if tb ~= nil
4169tb::func! if tb != nil
4170```
4171
4172<YueDisplay>
4173
4174```yue
4175tb\func! if tb ~= nil
4176tb::func! if tb != nil
4177```
4178
4179</YueDisplay>
4180
4181## Comparações encadeadas
4182
4183Comparações podem ser encadeadas arbitrariamente:
4184
4185```yuescript
4186print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4187-- saída: true
4188
4189a = 5
4190print 1 <= a <= 10
4191-- saída: true
4192```
4193
4194<YueDisplay>
4195
4196```yue
4197print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4198-- saída: true
4199
4200a = 5
4201print 1 <= a <= 10
4202-- saída: true
4203```
4204
4205</YueDisplay>
4206
4207Observe o comportamento de avaliação das comparações encadeadas:
4208
4209```yuescript
4210v = (x) ->
4211 print x
4212 x
4213
4214print v(1) < v(2) <= v(3)
4215--[[
4216 saída:
4217 2
4218 1
4219 3
4220 true
4221]]
4222
4223print v(1) > v(2) <= v(3)
4224--[[
4225 saída:
4226 2
4227 1
4228 false
4229]]
4230```
4231
4232<YueDisplay>
4233
4234```yue
4235v = (x) ->
4236 print x
4237 x
4238
4239print v(1) < v(2) <= v(3)
4240--[[
4241 saída:
4242 2
4243 1
4244 3
4245 true
4246]]
4247
4248print v(1) > v(2) <= v(3)
4249--[[
4250 saída:
4251 2
4252 1
4253 false
4254]]
4255```
4256
4257</YueDisplay>
4258
4259A expressão do meio é avaliada apenas uma vez, em vez de duas vezes como seria se a expressão fosse escrita como `v(1) < v(2) and v(2) <= v(3)`. No entanto, a ordem das avaliações em uma comparação encadeada é indefinida. É fortemente recomendado não usar expressões com efeitos colaterais (como impressão) em comparações encadeadas. Se efeitos colaterais forem necessários, o operador de curto-circuito `and` deve ser usado explicitamente.
4260
4261## Anexar à tabela
4262
4263O operador **[] =** é usado para anexar valores a tabelas.
4264
4265```yuescript
4266tab = []
4267tab[] = "Value"
4268```
4269
4270<YueDisplay>
4271
4272```yue
4273tab = []
4274tab[] = "Value"
4275```
4276
4277</YueDisplay>
4278
4279Você também pode usar o operador spread `...` para anexar todos os elementos de uma lista a outra:
4280
4281```yuescript
4282tbA = [1, 2, 3]
4283tbB = [4, 5, 6]
4284tbA[] = ...tbB
4285-- tbA agora é [1, 2, 3, 4, 5, 6]
4286```
4287
4288<YueDisplay>
4289
4290```yue
4291tbA = [1, 2, 3]
4292tbB = [4, 5, 6]
4293tbA[] = ...tbB
4294-- tbA agora é [1, 2, 3, 4, 5, 6]
4295```
4296
4297</YueDisplay>
4298
4299## Spread de tabela
4300
4301Você pode concatenar tabelas de array ou tabelas hash usando o operador spread `...` antes de expressões em literais de tabela.
4302
4303```yuescript
4304parts =
4305 * "shoulders"
4306 * "knees"
4307lyrics =
4308 * "head"
4309 * ...parts
4310 * "and"
4311 * "toes"
4312
4313copy = {...other}
4314
4315a = {1, 2, 3, x: 1}
4316b = {4, 5, y: 1}
4317merge = {...a, ...b}
4318```
4319
4320<YueDisplay>
4321
4322```yue
4323parts =
4324 * "shoulders"
4325 * "knees"
4326lyrics =
4327 * "head"
4328 * ...parts
4329 * "and"
4330 * "toes"
4331
4332copy = {...other}
4333
4334a = {1, 2, 3, x: 1}
4335b = {4, 5, y: 1}
4336merge = {...a, ...b}
4337```
4338
4339</YueDisplay>
4340
4341## Indexação reversa de tabela
4342
4343Você pode usar o operador **#** para obter os últimos elementos de uma tabela.
4344
4345```yuescript
4346last = data.items[#]
4347second_last = data.items[#-1]
4348data.items[#] = 1
4349```
4350
4351<YueDisplay>
4352
4353```yue
4354last = data.items[#]
4355second_last = data.items[#-1]
4356data.items[#] = 1
4357```
4358
4359</YueDisplay>
4360
4361## Metatable
4362
4363O operador **<>** pode ser usado como atalho para manipulação de metatable.
4364
4365### Criação de metatable
4366
4367Crie tabela normal com chaves vazias **<>** ou chave de metamétodo cercada por **<>**.
4368
4369```yuescript
4370mt = {}
4371add = (right) => <>: mt, value: @value + right.value
4372mt.__add = add
4373
4374a = <>: mt, value: 1
4375 -- definir campo com variável de mesmo nome
4376b = :<add>, value: 2
4377c = <add>: mt.__add, value: 3
4378
4379d = a + b + c
4380print d.value
4381
4382close _ = <close>: -> print "fora do escopo"
4383```
4384
4385<YueDisplay>
4386
4387```yue
4388mt = {}
4389add = (right) => <>: mt, value: @value + right.value
4390mt.__add = add
4391
4392a = <>: mt, value: 1
4393 -- definir campo com variável de mesmo nome
4394b = :<add>, value: 2
4395c = <add>: mt.__add, value: 3
4396
4397d = a + b + c
4398print d.value
4399
4400close _ = <close>: -> print "fora do escopo"
4401```
4402
4403</YueDisplay>
4404
4405### Acesso à metatable
4406
4407Acesse a metatable com **<>** ou nome do metamétodo cercado por **<>** ou escrevendo alguma expressão em **<>**.
4408
4409```yuescript
4410-- criar com metatable contendo campo "value"
4411tb = <"value">: 123
4412tb.<index> = tb.<>
4413print tb.value
4414
4415tb.<> = __index: {item: "hello"}
4416print tb.item
4417```
4418
4419<YueDisplay>
4420
4421```yue
4422-- criar com metatable contendo campo "value"
4423tb = <"value">: 123
4424tb.<index> = tb.<>
4425print tb.value
4426tb.<> = __index: {item: "hello"}
4427print tb.item
4428```
4429
4430</YueDisplay>
4431
4432### Desestruturação de metatable
4433
4434Desestruture a metatable com chave de metamétodo cercada por **<>**.
4435
4436```yuescript
4437{item, :new, :<close>, <index>: getter} = tb
4438print item, new, close, getter
4439```
4440
4441<YueDisplay>
4442
4443```yue
4444{item, :new, :<close>, <index>: getter} = tb
4445print item, new, close, getter
4446```
4447
4448</YueDisplay>
4449
4450## Existência
4451
4452O operador **?** pode ser usado em diversos contextos para verificar existência.
4453
4454```yuescript
4455func?!
4456print abc?["hello world"]?.xyz
4457
4458x = tab?.value
4459len = utf8?.len or string?.len or (o) -> #o
4460
4461if print and x?
4462 print x
4463
4464with? io.open "test.txt", "w"
4465 \write "hello"
4466 \close!
4467```
4468
4469<YueDisplay>
4470
4471```yue
4472func?!
4473print abc?["hello world"]?.xyz
4474
4475x = tab?.value
4476len = utf8?.len or string?.len or (o) -> #o
4477
4478if print and x?
4479 print x
4480
4481with? io.open "test.txt", "w"
4482 \write "hello"
4483 \close!
4484```
4485
4486</YueDisplay>
4487
4488## Pipe
4489
4490Em vez de uma série de chamadas de função aninhadas, você pode encaminhar valores com o operador **|>**.
4491
4492```yuescript
4493"hello" |> print
44941 |> print 2 -- insere o item do pipe como primeiro argumento
44952 |> print 1, _, 3 -- pipe com um placeholder
4496
4497-- expressão pipe em multilinha
4498readFile "example.txt"
4499 |> extract language, {}
4500 |> parse language
4501 |> emit
4502 |> render
4503 |> print
4504```
4505
4506<YueDisplay>
4507
4508```yue
4509"hello" |> print
45101 |> print 2 -- insere o item do pipe como primeiro argumento
45112 |> print 1, _, 3 -- pipe com um placeholder
4512-- expressão pipe em multilinha
4513readFile "example.txt"
4514 |> extract language, {}
4515 |> parse language
4516 |> emit
4517 |> render
4518 |> print
4519```
4520
4521</YueDisplay>
4522
4523## Coalescência de nil
4524
4525O operador de coalescência de nil **??** retorna o valor do operando esquerdo se não for **nil**; caso contrário, avalia o operando direito e retorna seu resultado. O operador **??** não avalia seu operando direito se o operando esquerdo avaliar para não-nil.
4526
4527```yuescript
4528local a, b, c, d
4529a = b ?? c ?? d
4530func a ?? {}
4531
4532a ??= false
4533```
4534
4535<YueDisplay>
4536
4537```yue
4538local a, b, c, d
4539a = b ?? c ?? d
4540func a ?? {}
4541a ??= false
4542```
4543
4544</YueDisplay>
4545
4546## Objeto implícito
4547
4548Você pode escrever uma lista de estruturas implícitas que começa com o símbolo **\*** ou **-** dentro de um bloco de tabela. Se você está criando objeto implícito, os campos do objeto devem estar com a mesma indentação.
4549
4550```yuescript
4551-- atribuição com objeto implícito
4552list =
4553 * 1
4554 * 2
4555 * 3
4556
4557-- chamada de função com objeto implícito
4558func
4559 * 1
4560 * 2
4561 * 3
4562
4563-- retorno com objeto implícito
4564f = ->
4565 return
4566 * 1
4567 * 2
4568 * 3
4569
4570-- tabela com objeto implícito
4571tb =
4572 name: "abc"
4573
4574 values:
4575 - "a"
4576 - "b"
4577 - "c"
4578
4579 objects:
4580 - name: "a"
4581 value: 1
4582 func: => @value + 1
4583 tb:
4584 fieldA: 1
4585
4586 - name: "b"
4587 value: 2
4588 func: => @value + 2
4589 tb: { }
4590
4591```
4592
4593<YueDisplay>
4594
4595```yue
4596-- atribuição com objeto implícito
4597list =
4598 * 1
4599 * 2
4600 * 3
4601
4602-- chamada de função com objeto implícito
4603func
4604 * 1
4605 * 2
4606 * 3
4607
4608-- retorno com objeto implícito
4609f = ->
4610 return
4611 * 1
4612 * 2
4613 * 3
4614
4615-- tabela com objeto implícito
4616tb =
4617 name: "abc"
4618
4619 values:
4620 - "a"
4621 - "b"
4622 - "c"
4623
4624 objects:
4625 - name: "a"
4626 value: 1
4627 func: => @value + 1
4628 tb:
4629 fieldA: 1
4630
4631 - name: "b"
4632 value: 2
4633 func: => @value + 2
4634 tb: { }
4635```
4636
4637</YueDisplay>
4638
4639# Literais
4640
4641Todos os literais primitivos do Lua podem ser usados. Isso se aplica a números, strings, booleanos e **nil**.
4642
4643Diferente do Lua, quebras de linha são permitidas dentro de strings com aspas simples e duplas sem sequência de escape:
4644
4645```yuescript
4646some_string = "Aqui está uma string
4647 que tem uma quebra de linha."
4648
4649-- Você pode misturar expressões em literais de string usando a sintaxe #{}.
4650-- Interpolação de string está disponível apenas em strings com aspas duplas.
4651print "Tenho #{math.random! * 100}% de certeza."
4652```
4653
4654<YueDisplay>
4655
4656```yue
4657some_string = "Aqui está uma string
4658 que tem uma quebra de linha."
4659
4660-- Você pode misturar expressões em literais de string usando a sintaxe #{}.
4661-- Interpolação de string está disponível apenas em strings com aspas duplas.
4662print "Tenho #{math.random! * 100}% de certeza."
4663```
4664
4665</YueDisplay>
4666
4667## Literais numéricos
4668
4669Você pode usar underscores em um literal numérico para aumentar a legibilidade.
4670
4671```yuescript
4672integer = 1_000_000
4673hex = 0xEF_BB_BF
4674binary = 0B10011
4675```
4676
4677<YueDisplay>
4678
4679```yue
4680integer = 1_000_000
4681hex = 0xEF_BB_BF
4682binary = 0B10011
4683```
4684
4685</YueDisplay>
4686
4687## String multilinha estilo YAML
4688
4689O prefixo `|` introduz um literal de string multilinha no estilo YAML:
4690
4691```yuescript
4692str = |
4693 key: value
4694 list:
4695 - item1
4696 - #{expr}
4697```
4698
4699<YueDisplay>
4700
4701```yue
4702str = |
4703 key: value
4704 list:
4705 - item1
4706 - #{expr}
4707```
4708
4709</YueDisplay>
4710
4711Isso permite escrever texto estruturado multilinha convenientemente. Todas as quebras de linha e indentação são preservadas em relação à primeira linha não vazia, e expressões dentro de `#{...}` são interpoladas automaticamente como `tostring(expr)`.
4712
4713A string multilinha YAML detecta automaticamente o prefixo comum de espaço em branco à esquerda (indentação mínima em todas as linhas não vazias) e remove-o de todas as linhas. Isso facilita a indentação visual do seu código sem afetar o conteúdo da string resultante.
4714
4715```yuescript
4716fn = ->
4717 str = |
4718 foo:
4719 bar: baz
4720 return str
4721```
4722
4723<YueDisplay>
4724
4725```yue
4726fn = ->
4727 str = |
4728 foo:
4729 bar: baz
4730 return str
4731```
4732
4733</YueDisplay>
4734
4735A indentação interna é preservada em relação ao prefixo comum removido, permitindo estruturas aninhadas limpas.
4736
4737Todos os caracteres especiais como aspas (`"`) e barras invertidas (`\`) no bloco YAML Multiline são escapados automaticamente para que a string Lua gerada seja sintaticamente válida e se comporte como esperado.
4738
4739```yuescript
4740str = |
4741 path: "C:\Program Files\App"
4742 note: 'Ele disse: "#{Hello}!"'
4743```
4744
4745<YueDisplay>
4746
4747```yue
4748str = |
4749 path: "C:\Program Files\App"
4750 note: 'Ele disse: "#{Hello}!"'
4751```
4752
4753</YueDisplay>
4754
4755# Módulo
4756
4757## Import
4758
4759A instrução import é um açúcar sintático para requerer um módulo ou ajudar a extrair itens de um módulo importado. Os itens importados são const por padrão.
4760
4761```yuescript
4762-- usado como desestruturação de tabela
4763do
4764 import insert, concat from table
4765 -- reporta erro ao atribuir a insert, concat
4766 import C, Ct, Cmt from require "lpeg"
4767 -- atalho para require implícito
4768 import x, y, z from 'mymodule'
4769 -- import com estilo Python
4770 from 'module' import a, b, c
4771
4772-- atalho para requerer um módulo
4773do
4774 import 'module'
4775 import 'module_x'
4776 import "d-a-s-h-e-s"
4777 import "module.part"
4778
4779-- requerer módulo com aliasing ou desestruturação de tabela
4780do
4781 import "player" as PlayerModule
4782 import "lpeg" as :C, :Ct, :Cmt
4783 import "export" as {one, two, Something:{umm:{ch}}}
4784```
4785
4786<YueDisplay>
4787
4788```yue
4789-- usado como desestruturação de tabela
4790do
4791 import insert, concat from table
4792 -- reporta erro ao atribuir a insert, concat
4793 import C, Ct, Cmt from require "lpeg"
4794 -- atalho para require implícito
4795 import x, y, z from 'mymodule'
4796 -- import com estilo Python
4797 from 'module' import a, b, c
4798
4799-- atalho para requerer um módulo
4800do
4801 import 'module'
4802 import 'module_x'
4803 import "d-a-s-h-e-s"
4804 import "module.part"
4805
4806-- requerer módulo com aliasing ou desestruturação de tabela
4807do
4808 import "player" as PlayerModule
4809 import "lpeg" as :C, :Ct, :Cmt
4810 import "export" as {one, two, Something:{umm:{ch}}}
4811```
4812
4813</YueDisplay>
4814
4815## Import Global
4816
4817Você pode importar globais específicos para variáveis locais com `import`. Ao importar uma cadeia de acessos a variáveis globais, o último campo será atribuído à variável local.
4818
4819```yuescript
4820do
4821 import tostring
4822 import table.concat
4823 print concat ["a", tostring 1]
4824```
4825
4826<YueDisplay>
4827
4828```yue
4829do
4830 import tostring
4831 import table.concat
4832 print concat ["a", tostring 1]
4833```
4834
4835</YueDisplay>
4836
4837### Importação automática de variável global
4838
4839Você pode colocar `import global` no topo de um bloco para importar automaticamente todos os nomes que não foram explicitamente declarados ou atribuídos no escopo atual como globais. Essas importações implícitas são tratadas como consts locais que referenciam os globais correspondentes na posição da instrução.
4840
4841Nomes que foram explicitamente declarados como globais no mesmo escopo não serão importados, então você ainda pode atribuir a eles.
4842
4843```yuescript
4844do
4845 import global
4846 print "hello"
4847 math.random 3
4848 -- print = nil -- erro: globais importados são const
4849
4850do
4851 -- variável global explícita não será importada
4852 import global
4853 global FLAG
4854 print FLAG
4855 FLAG = 123
4856```
4857
4858<YueDisplay>
4859
4860```yue
4861do
4862 import global
4863 print "hello"
4864 math.random 3
4865 -- print = nil -- erro: globais importados são const
4866
4867do
4868 -- variável global explícita não será importada
4869 import global
4870 global FLAG
4871 print FLAG
4872 FLAG = 123
4873```
4874
4875</YueDisplay>
4876
4877## Export
4878
4879A instrução export oferece uma forma concisa de definir módulos.
4880
4881### Export nomeado
4882
4883Export nomeado definirá uma variável local e também adicionará um campo na tabela exportada.
4884
4885```yuescript
4886export a, b, c = 1, 2, 3
4887export cool = "cat"
4888
4889export What = if this
4890 "abc"
4891else
4892 "def"
4893
4894export y = ->
4895 hallo = 3434
4896
4897export class Something
4898 umm: "cool"
4899```
4900
4901<YueDisplay>
4902
4903```yue
4904export a, b, c = 1, 2, 3
4905export cool = "cat"
4906
4907export What = if this
4908 "abc"
4909else
4910 "def"
4911
4912export y = ->
4913 hallo = 3434
4914
4915export class Something
4916 umm: "cool"
4917```
4918
4919</YueDisplay>
4920
4921Fazendo export nomeado com desestruturação.
4922
4923```yuescript
4924export :loadstring, to_lua: tolua = yue
4925export {itemA: {:fieldA = 'default'}} = tb
4926```
4927
4928<YueDisplay>
4929
4930```yue
4931export :loadstring, to_lua: tolua = yue
4932export {itemA: {:fieldA = 'default'}} = tb
4933```
4934
4935</YueDisplay>
4936
4937Exportar itens nomeados do módulo sem criar variáveis locais.
4938
4939```yuescript
4940export.itemA = tb
4941export.<index> = items
4942export["a-b-c"] = 123
4943```
4944
4945<YueDisplay>
4946
4947```yue
4948export.itemA = tb
4949export.<index> = items
4950export["a-b-c"] = 123
4951```
4952
4953</YueDisplay>
4954
4955### Export sem nome
4956
4957Export sem nome adicionará o item alvo na parte array da tabela exportada.
4958
4959```yuescript
4960d, e, f = 3, 2, 1
4961export d, e, f
4962
4963export if this
4964 123
4965else
4966 456
4967
4968export with tmp
4969 j = 2000
4970```
4971
4972<YueDisplay>
4973
4974```yue
4975d, e, f = 3, 2, 1
4976export d, e, f
4977
4978export if this
4979 123
4980else
4981 456
4982
4983export with tmp
4984 j = 2000
4985```
4986
4987</YueDisplay>
4988
4989### Export padrão
4990
4991Usar a palavra-chave **default** na instrução export para substituir a tabela exportada por qualquer coisa.
4992
4993```yuescript
4994export default ->
4995 print "hello"
4996 123
4997```
4998
4999<YueDisplay>
5000
5001```yue
5002export default ->
5003 print "hello"
5004 123
5005```
5006
5007</YueDisplay>
5008
5009# Licença: MIT
5010
5011Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\>
5012
5013A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia
5014deste software e dos arquivos de documentação associados (o "Software"), para negociar
5015o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar,
5016modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender
5017cópias do Software, e permitir que pessoas a quem o Software seja fornecido o façam,
5018sujeito às seguintes condições:
5019
5020O aviso de direitos autorais acima e este aviso de permissão devem ser incluídos em todas as
5021cópias ou partes substanciais do Software.
5022
5023O SOFTWARE É FORNECIDO "NO ESTADO EM QUE SE ENCONTRA", SEM GARANTIA DE QUALQUER TIPO,
5024EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO,
5025ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUMA HIPÓTESE OS AUTORES OU
5026DETENTORES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUAISQUER REIVINDICAÇÕES,
5027DANOS OU OUTRAS RESPONSABILIDADES, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU OUTRA,
5028DECORRENTES DE, FORA DE OU RELACIONADAS COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES
5029NO SOFTWARE.
5030
5031# A biblioteca YueScript
5032
5033Acesse com `local yue = require("yue")` no Lua.
5034
5035## yue
5036
5037**Descrição:**
5038
5039A biblioteca da linguagem YueScript.
5040
5041### version
5042
5043**Tipo:** Campo.
5044
5045**Descrição:**
5046
5047A versão do YueScript.
5048
5049**Assinatura:**
5050
5051```lua
5052version: string
5053```
5054
5055### dirsep
5056
5057**Tipo:** Campo.
5058
5059**Descrição:**
5060
5061O separador de arquivos da plataforma atual.
5062
5063**Assinatura:**
5064
5065```lua
5066dirsep: string
5067```
5068
5069### yue_compiled
5070
5071**Tipo:** Campo.
5072
5073**Descrição:**
5074
5075O cache de código de módulo compilado.
5076
5077**Assinatura:**
5078
5079```lua
5080yue_compiled: {string: string}
5081```
5082
5083### to_lua
5084
5085**Tipo:** Função.
5086
5087**Descrição:**
5088
5089A função de compilação do YueScript. Compila o código YueScript para código Lua.
5090
5091**Assinatura:**
5092
5093```lua
5094to_lua: function(code: string, config?: Config):
5095 --[[codes]] string | nil,
5096 --[[error]] string | nil,
5097 --[[globals]] {{string, integer, integer}} | nil
5098```
5099
5100**Parâmetros:**
5101
5102| Parâmetro | Tipo | Descrição |
5103| --------- | ------ | ----------------------------------- |
5104| code | string | O código YueScript. |
5105| config | Config | [Opcional] As opções do compilador. |
5106
5107**Retorna:**
5108
5109| Tipo de Retorno | Descrição |
5110| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
5111| string \| nil | O código Lua compilado, ou nil se a compilação falhou. |
5112| string \| nil | A mensagem de erro, ou nil se a compilação foi bem-sucedida. |
5113| {{string, integer, integer}} \| nil | As variáveis globais que aparecem no código (com nome, linha e coluna), ou nil se a opção do compilador `lint_global` for false. |
5114
5115### file_exist
5116
5117**Tipo:** Função.
5118
5119**Descrição:**
5120
5121Função de verificação de existência do arquivo fonte. Pode ser sobrescrita para personalizar o comportamento.
5122
5123**Assinatura:**
5124
5125```lua
5126file_exist: function(filename: string): boolean
5127```
5128
5129**Parâmetros:**
5130
5131| Parâmetro | Tipo | Descrição |
5132| --------- | ------ | ------------------ |
5133| filename | string | O nome do arquivo. |
5134
5135**Retorna:**
5136
5137| Tipo de Retorno | Descrição |
5138| --------------- | -------------------- |
5139| boolean | Se o arquivo existe. |
5140
5141### read_file
5142
5143**Tipo:** Função.
5144
5145**Descrição:**
5146
5147Função de leitura do arquivo fonte. Pode ser sobrescrita para personalizar o comportamento.
5148
5149**Assinatura:**
5150
5151```lua
5152read_file: function(filename: string): string
5153```
5154
5155**Parâmetros:**
5156
5157| Parâmetro | Tipo | Descrição |
5158| --------- | ------ | ------------------ |
5159| filename | string | O nome do arquivo. |
5160
5161**Retorna:**
5162
5163| Tipo de Retorno | Descrição |
5164| --------------- | ---------------------- |
5165| string | O conteúdo do arquivo. |
5166
5167### insert_loader
5168
5169**Tipo:** Função.
5170
5171**Descrição:**
5172
5173Insere o carregador YueScript nos carregadores de pacote (searchers).
5174
5175**Assinatura:**
5176
5177```lua
5178insert_loader: function(pos?: integer): boolean
5179```
5180
5181**Parâmetros:**
5182
5183| Parâmetro | Tipo | Descrição |
5184| --------- | ------- | ----------------------------------------------------------- |
5185| pos | integer | [Opcional] A posição para inserir o carregador. Padrão é 3. |
5186
5187**Retorna:**
5188
5189| Tipo de Retorno | Descrição |
5190| --------------- | -------------------------------------------------------------------------------------- |
5191| boolean | Se o carregador foi inserido com sucesso. Falhará se o carregador já estiver inserido. |
5192
5193### remove_loader
5194
5195**Tipo:** Função.
5196
5197**Descrição:**
5198
5199Remove o carregador YueScript dos carregadores de pacote (searchers).
5200
5201**Assinatura:**
5202
5203```lua
5204remove_loader: function(): boolean
5205```
5206
5207**Retorna:**
5208
5209| Tipo de Retorno | Descrição |
5210| --------------- | --------------------------------------------------------------------------------------- |
5211| boolean | Se o carregador foi removido com sucesso. Falhará se o carregador não estiver inserido. |
5212
5213### loadstring
5214
5215**Tipo:** Função.
5216
5217**Descrição:**
5218
5219Carrega código YueScript de uma string em uma função.
5220
5221**Assinatura:**
5222
5223```lua
5224loadstring: function(input: string, chunkname: string, env: table, config?: Config):
5225 --[[loaded function]] nil | function(...: any): (any...),
5226 --[[error]] string | nil
5227```
5228
5229**Parâmetros:**
5230
5231| Parâmetro | Tipo | Descrição |
5232| --------- | ------ | ----------------------------------- |
5233| input | string | O código YueScript. |
5234| chunkname | string | O nome do chunk de código. |
5235| env | table | A tabela de ambiente. |
5236| config | Config | [Opcional] As opções do compilador. |
5237
5238**Retorna:**
5239
5240| Tipo de Retorno | Descrição |
5241| --------------- | -------------------------------------------------------------- |
5242| function \| nil | A função carregada, ou nil se o carregamento falhou. |
5243| string \| nil | A mensagem de erro, ou nil se o carregamento foi bem-sucedido. |
5244
5245### loadstring
5246
5247**Tipo:** Função.
5248
5249**Descrição:**
5250
5251Carrega código YueScript de uma string em uma função.
5252
5253**Assinatura:**
5254
5255```lua
5256loadstring: function(input: string, chunkname: string, config?: Config):
5257 --[[loaded function]] nil | function(...: any): (any...),
5258 --[[error]] string | nil
5259```
5260
5261**Parâmetros:**
5262
5263| Parâmetro | Tipo | Descrição |
5264| --------- | ------ | ----------------------------------- |
5265| input | string | O código YueScript. |
5266| chunkname | string | O nome do chunk de código. |
5267| config | Config | [Opcional] As opções do compilador. |
5268
5269**Retorna:**
5270
5271| Tipo de Retorno | Descrição |
5272| --------------- | -------------------------------------------------------------- |
5273| function \| nil | A função carregada, ou nil se o carregamento falhou. |
5274| string \| nil | A mensagem de erro, ou nil se o carregamento foi bem-sucedido. |
5275
5276### loadstring
5277
5278**Tipo:** Função.
5279
5280**Descrição:**
5281
5282Carrega código YueScript de uma string em uma função.
5283
5284**Assinatura:**
5285
5286```lua
5287loadstring: function(input: string, config?: Config):
5288 --[[loaded function]] nil | function(...: any): (any...),
5289 --[[error]] string | nil
5290```
5291
5292**Parâmetros:**
5293
5294| Parâmetro | Tipo | Descrição |
5295| --------- | ------ | ----------------------------------- |
5296| input | string | O código YueScript. |
5297| config | Config | [Opcional] As opções do compilador. |
5298
5299**Retorna:**
5300
5301| Tipo de Retorno | Descrição |
5302| --------------- | -------------------------------------------------------------- |
5303| function \| nil | A função carregada, ou nil se o carregamento falhou. |
5304| string \| nil | A mensagem de erro, ou nil se o carregamento foi bem-sucedido. |
5305
5306### loadfile
5307
5308**Tipo:** Função.
5309
5310**Descrição:**
5311
5312Carrega código YueScript de um arquivo em uma função.
5313
5314**Assinatura:**
5315
5316```lua
5317loadfile: function(filename: string, env: table, config?: Config):
5318 nil | function(...: any): (any...),
5319 string | nil
5320```
5321
5322**Parâmetros:**
5323
5324| Parâmetro | Tipo | Descrição |
5325| --------- | ------ | ----------------------------------- |
5326| filename | string | O nome do arquivo. |
5327| env | table | A tabela de ambiente. |
5328| config | Config | [Opcional] As opções do compilador. |
5329
5330**Retorna:**
5331
5332| Tipo de Retorno | Descrição |
5333| --------------- | -------------------------------------------------------------- |
5334| function \| nil | A função carregada, ou nil se o carregamento falhou. |
5335| string \| nil | A mensagem de erro, ou nil se o carregamento foi bem-sucedido. |
5336
5337### loadfile
5338
5339**Tipo:** Função.
5340
5341**Descrição:**
5342
5343Carrega código YueScript de um arquivo em uma função.
5344
5345**Assinatura:**
5346
5347```lua
5348loadfile: function(filename: string, config?: Config):
5349 nil | function(...: any): (any...),
5350 string | nil
5351```
5352
5353**Parâmetros:**
5354
5355| Parâmetro | Tipo | Descrição |
5356| --------- | ------ | ----------------------------------- |
5357| filename | string | O nome do arquivo. |
5358| config | Config | [Opcional] As opções do compilador. |
5359
5360**Retorna:**
5361
5362| Tipo de Retorno | Descrição |
5363| --------------- | -------------------------------------------------------------- |
5364| function \| nil | A função carregada, ou nil se o carregamento falhou. |
5365| string \| nil | A mensagem de erro, ou nil se o carregamento foi bem-sucedido. |
5366
5367### dofile
5368
5369**Tipo:** Função.
5370
5371**Descrição:**
5372
5373Carrega código YueScript de um arquivo em uma função e o executa.
5374
5375**Assinatura:**
5376
5377```lua
5378dofile: function(filename: string, env: table, config?: Config): any...
5379```
5380
5381**Parâmetros:**
5382
5383| Parâmetro | Tipo | Descrição |
5384| --------- | ------ | ----------------------------------- |
5385| filename | string | O nome do arquivo. |
5386| env | table | A tabela de ambiente. |
5387| config | Config | [Opcional] As opções do compilador. |
5388
5389**Retorna:**
5390
5391| Tipo de Retorno | Descrição |
5392| --------------- | ------------------------------------------ |
5393| any... | Os valores de retorno da função carregada. |
5394
5395### dofile
5396
5397**Tipo:** Função.
5398
5399**Descrição:**
5400
5401Carrega código YueScript de um arquivo em uma função e o executa.
5402
5403**Assinatura:**
5404
5405```lua
5406dofile: function(filename: string, config?: Config): any...
5407```
5408
5409**Parâmetros:**
5410
5411| Parâmetro | Tipo | Descrição |
5412| --------- | ------ | ----------------------------------- |
5413| filename | string | O nome do arquivo. |
5414| config | Config | [Opcional] As opções do compilador. |
5415
5416**Retorna:**
5417
5418| Tipo de Retorno | Descrição |
5419| --------------- | ------------------------------------------ |
5420| any... | Os valores de retorno da função carregada. |
5421
5422### find_modulepath
5423
5424**Tipo:** Função.
5425
5426**Descrição:**
5427
5428Resolve o nome do módulo YueScript para o caminho do arquivo.
5429
5430**Assinatura:**
5431
5432```lua
5433find_modulepath: function(name: string): string
5434```
5435
5436**Parâmetros:**
5437
5438| Parâmetro | Tipo | Descrição |
5439| --------- | ------ | ----------------- |
5440| name | string | O nome do módulo. |
5441
5442**Retorna:**
5443
5444| Tipo de Retorno | Descrição |
5445| --------------- | --------------------- |
5446| string | O caminho do arquivo. |
5447
5448### pcall
5449
5450**Tipo:** Função.
5451
5452**Descrição:**
5453
5454Chama uma função em modo protegido.
5455Captura quaisquer erros e retorna um código de status e resultados ou objeto de erro.
5456Reescreve o número da linha do erro para o número da linha original no código YueScript quando ocorrem erros.
5457
5458**Assinatura:**
5459
5460```lua
5461pcall: function(f: function, ...: any): boolean, any...
5462```
5463
5464**Parâmetros:**
5465
5466| Parâmetro | Tipo | Descrição |
5467| --------- | -------- | ---------------------------------- |
5468| f | function | A função a chamar. |
5469| ... | any | Argumentos a passar para a função. |
5470
5471**Retorna:**
5472
5473| Tipo de Retorno | Descrição |
5474| --------------- | ---------------------------------------------------------- |
5475| boolean, ... | Código de status e resultados da função ou objeto de erro. |
5476
5477### require
5478
5479**Tipo:** Função.
5480
5481**Descrição:**
5482
5483Carrega um módulo dado. Pode ser um módulo Lua ou um módulo YueScript.
5484Reescreve o número da linha do erro para o número da linha original no código YueScript se o módulo for um módulo YueScript e o carregamento falhar.
5485
5486**Assinatura:**
5487
5488```lua
5489require: function(name: string): any...
5490```
5491
5492**Parâmetros:**
5493
5494| Parâmetro | Tipo | Descrição |
5495| --------- | ------ | ---------------------------- |
5496| modname | string | O nome do módulo a carregar. |
5497
5498**Retorna:**
5499
5500| Tipo de Retorno | Descrição |
5501| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5502| any | O valor armazenado em package.loaded[modname] se o módulo já estiver carregado. Caso contrário, tenta encontrar um carregador e retorna o valor final de package.loaded[modname] e os dados do carregador como segundo resultado. |
5503
5504### p
5505
5506**Tipo:** Função.
5507
5508**Descrição:**
5509
5510Inspeciona as estruturas dos valores passados e imprime representações em string.
5511
5512**Assinatura:**
5513
5514```lua
5515p: function(...: any)
5516```
5517
5518**Parâmetros:**
5519
5520| Parâmetro | Tipo | Descrição |
5521| --------- | ---- | ------------------------- |
5522| ... | any | Os valores a inspecionar. |
5523
5524### options
5525
5526**Tipo:** Campo.
5527
5528**Descrição:**
5529
5530As opções atuais do compilador.
5531
5532**Assinatura:**
5533
5534```lua
5535options: Config.Options
5536```
5537
5538### traceback
5539
5540**Tipo:** Função.
5541
5542**Descrição:**
5543
5544A função traceback que reescreve os números das linhas do stack trace para os números das linhas originais no código YueScript.
5545
5546**Assinatura:**
5547
5548```lua
5549traceback: function(message: string): string
5550```
5551
5552**Parâmetros:**
5553
5554| Parâmetro | Tipo | Descrição |
5555| --------- | ------ | ------------------------ |
5556| message | string | A mensagem de traceback. |
5557
5558**Retorna:**
5559
5560| Tipo de Retorno | Descrição |
5561| --------------- | ---------------------------------- |
5562| string | A mensagem de traceback reescrita. |
5563
5564### is_ast
5565
5566**Tipo:** Função.
5567
5568**Descrição:**
5569
5570Verifica se o código corresponde ao AST especificado.
5571
5572**Assinatura:**
5573
5574```lua
5575is_ast: function(astName: string, code: string): boolean
5576```
5577
5578**Parâmetros:**
5579
5580| Parâmetro | Tipo | Descrição |
5581| --------- | ------ | -------------- |
5582| astName | string | O nome do AST. |
5583| code | string | O código. |
5584
5585**Retorna:**
5586
5587| Tipo de Retorno | Descrição |
5588| --------------- | ------------------------------- |
5589| boolean | Se o código corresponde ao AST. |
5590
5591### AST
5592
5593**Tipo:** Campo.
5594
5595**Descrição:**
5596
5597A definição do tipo AST com nome, linha, coluna e subnós.
5598
5599**Assinatura:**
5600
5601```lua
5602type AST = {string, integer, integer, any}
5603```
5604
5605### to_ast
5606
5607**Tipo:** Função.
5608
5609**Descrição:**
5610
5611Converte o código para o AST.
5612
5613**Assinatura:**
5614
5615```lua
5616to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
5617 --[[AST]] AST | nil,
5618 --[[error]] nil | string
5619```
5620
5621**Parâmetros:**
5622
5623| Parâmetro | Tipo | Descrição |
5624| -------------- | ------- | ------------------------------------------------------------------------------------------------------ |
5625| code | string | O código. |
5626| flattenLevel | integer | [Opcional] O nível de achatamento. Nível mais alto significa mais achatamento. Padrão é 0. Máximo é 2. |
5627| astName | string | [Opcional] O nome do AST. Padrão é "File". |
5628| reserveComment | boolean | [Opcional] Se deve preservar os comentários originais. Padrão é false. |
5629
5630**Retorna:**
5631
5632| Tipo de Retorno | Descrição |
5633| --------------- | ----------------------------------------------------------- |
5634| AST \| nil | O AST, ou nil se a conversão falhou. |
5635| string \| nil | A mensagem de erro, ou nil se a conversão foi bem-sucedida. |
5636
5637### format
5638
5639**Tipo:** Função.
5640
5641**Descrição:**
5642
5643Formata o código YueScript.
5644
5645**Assinatura:**
5646
5647```lua
5648format: function(code: string, tabSize?: number, reserveComment?: boolean): string
5649```
5650
5651**Parâmetros:**
5652
5653| Parâmetro | Tipo | Descrição |
5654| -------------- | ------- | --------------------------------------------------------------------- |
5655| code | string | O código. |
5656| tabSize | integer | [Opcional] O tamanho da tabulação. Padrão é 4. |
5657| reserveComment | boolean | [Opcional] Se deve preservar os comentários originais. Padrão é true. |
5658
5659**Retorna:**
5660
5661| Tipo de Retorno | Descrição |
5662| --------------- | ------------------- |
5663| string | O código formatado. |
5664
5665### \_\_call
5666
5667**Tipo:** Metamétodo.
5668
5669**Descrição:**
5670
5671Requer o módulo YueScript.
5672Reescreve o número da linha do erro para o número da linha original no código YueScript quando o carregamento falha.
5673
5674**Assinatura:**
5675
5676```lua
5677metamethod __call: function(self: yue, module: string): any...
5678```
5679
5680**Parâmetros:**
5681
5682| Parâmetro | Tipo | Descrição |
5683| --------- | ------ | ----------------- |
5684| module | string | O nome do módulo. |
5685
5686**Retorna:**
5687
5688| Tipo de Retorno | Descrição |
5689| --------------- | ------------------ |
5690| any | O valor do módulo. |
5691
5692## Config
5693
5694**Descrição:**
5695
5696As opções de compilação do compilador.
5697
5698### lint_global
5699
5700**Tipo:** Campo.
5701
5702**Descrição:**
5703
5704Se o compilador deve coletar as variáveis globais que aparecem no código.
5705
5706**Assinatura:**
5707
5708```lua
5709lint_global: boolean
5710```
5711
5712### implicit_return_root
5713
5714**Tipo:** Campo.
5715
5716**Descrição:**
5717
5718Se o compilador deve fazer retorno implícito para o bloco de código raiz.
5719
5720**Assinatura:**
5721
5722```lua
5723implicit_return_root: boolean
5724```
5725
5726### reserve_line_number
5727
5728**Tipo:** Campo.
5729
5730**Descrição:**
5731
5732Se o compilador deve preservar o número da linha original no código compilado.
5733
5734**Assinatura:**
5735
5736```lua
5737reserve_line_number: boolean
5738```
5739
5740### reserve_comment
5741
5742**Tipo:** Campo.
5743
5744**Descrição:**
5745
5746Se o compilador deve preservar os comentários originais no código compilado.
5747
5748**Assinatura:**
5749
5750```lua
5751reserve_comment: boolean
5752```
5753
5754### space_over_tab
5755
5756**Tipo:** Campo.
5757
5758**Descrição:**
5759
5760Se o compilador deve usar o caractere de espaço em vez do caractere de tabulação no código compilado.
5761
5762**Assinatura:**
5763
5764```lua
5765space_over_tab: boolean
5766```
5767
5768### same_module
5769
5770**Tipo:** Campo.
5771
5772**Descrição:**
5773
5774Se o compilador deve tratar o código a ser compilado como o mesmo módulo que está sendo compilado atualmente. Apenas para uso interno.
5775
5776**Assinatura:**
5777
5778```lua
5779same_module: boolean
5780```
5781
5782### line_offset
5783
5784**Tipo:** Campo.
5785
5786**Descrição:**
5787
5788Se a mensagem de erro do compilador deve incluir o deslocamento do número da linha. Apenas para uso interno.
5789
5790**Assinatura:**
5791
5792```lua
5793line_offset: integer
5794```
5795
5796### yue.Config.LuaTarget
5797
5798**Tipo:** Enumeração.
5799
5800**Descrição:**
5801
5802A enumeração da versão alvo do Lua.
5803
5804**Assinatura:**
5805
5806```lua
5807enum LuaTarget
5808 "5.1"
5809 "5.2"
5810 "5.3"
5811 "5.4"
5812 "5.5"
5813end
5814```
5815
5816### options
5817
5818**Tipo:** Campo.
5819
5820**Descrição:**
5821
5822As opções extras a serem passadas para a função de compilação.
5823
5824**Assinatura:**
5825
5826```lua
5827options: Options
5828```
5829
5830## Options
5831
5832**Descrição:**
5833
5834A definição das opções extras do compilador.
5835
5836### target
5837
5838**Tipo:** Campo.
5839
5840**Descrição:**
5841
5842A versão alvo do Lua para a compilação.
5843
5844**Assinatura:**
5845
5846```lua
5847target: LuaTarget
5848```
5849
5850### path
5851
5852**Tipo:** Campo.
5853
5854**Descrição:**
5855
5856O caminho de busca de módulo extra.
5857
5858**Assinatura:**
5859
5860```lua
5861path: string
5862```
5863
5864### dump_locals
5865
5866**Tipo:** Campo.
5867
5868**Descrição:**
5869
5870Se deve incluir as variáveis locais na mensagem de erro do traceback. Padrão é false.
5871
5872**Assinatura:**
5873
5874```lua
5875dump_locals: boolean
5876```
5877
5878### simplified
5879
5880**Tipo:** Campo.
5881
5882**Descrição:**
5883
5884Se deve simplificar a mensagem de erro. Padrão é true.
5885
5886**Assinatura:**
5887
5888```lua
5889simplified: boolean
5890```
diff --git a/doc/yue-zh.md b/doc/yue-zh.md
new file mode 100644
index 0000000..7454eab
--- /dev/null
+++ b/doc/yue-zh.md
@@ -0,0 +1,5866 @@
1---
2title: 参考手册
3---
4
5# 月之脚本文档
6
7<img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em;padding-bottom: 2em;"/>
8
9欢迎来到 <b>月之脚本(YueScript)</b> 官方文档!<br/>
10这里收录了语言特性、用法、参考示例和资源。<br/>
11请选择左侧的章节索引或目录,开启你的月之脚本之旅 ☽
12
13# do 语句
14
15&emsp;&emsp;当用作语句时,do 语句的作用就像在 Lua 中差不多。
16
17```yuescript
18do
19 var = "hello"
20 print var
21print var -- 这里是nil
22```
23
24<YueDisplay>
25
26```yue
27do
28 var = "hello"
29 print var
30print var -- 这里是nil
31```
32
33</YueDisplay>
34
35&emsp;&emsp;月之脚本的 **do** 也可以用作表达式。允许你将多行代码的处理合并为一个表达式,并将 do 语句代码块的最后一个语句作为表达式返回的结果。`do` 表达式支持通过 `break` 打断执行流并提前返回多个值。
36
37```yuescript
38status, value = do
39 n = 12
40 if n > 10
41 break "large", n
42 break "small", n
43```
44
45<YueDisplay>
46
47```yue
48status, value = do
49 n = 12
50 if n > 10
51 break "large", n
52 break "small", n
53```
54
55</YueDisplay>
56
57```yuescript
58counter = do
59 i = 0
60 ->
61 i += 1
62 i
63
64print counter!
65print counter!
66```
67
68<YueDisplay>
69
70```yue
71counter = do
72 i = 0
73 ->
74 i += 1
75 i
76
77print counter!
78print counter!
79```
80
81</YueDisplay>
82
83```yuescript
84tbl = {
85 key: do
86 print "分配键值!"
87 1234
88}
89```
90
91<YueDisplay>
92
93```yue
94tbl = {
95 key: do
96 print "分配键值!"
97 1234
98}
99```
100
101</YueDisplay>
102
103# 代码行修饰
104
105&emsp;&emsp;为了方便编写代码,循环语句和 if 语句可以应用于单行代码语句的末尾:
106
107```yuescript
108print "你好,世界" if name == "Rob"
109```
110
111<YueDisplay>
112
113```yue
114print "你好,世界" if name == "Rob"
115```
116
117</YueDisplay>
118
119&emsp;&emsp;修饰 for 循环的示例:
120
121```yuescript
122print "项目: ", item for item in *items
123```
124
125<YueDisplay>
126
127```yue
128print "项目: ", item for item in *items
129```
130
131</YueDisplay>
132
133&emsp;&emsp;修饰 while 循环的示例:
134
135```yuescript
136game\update! while game\isRunning!
137
138reader\parse_line! until reader\eof!
139```
140
141<YueDisplay>
142
143```yue
144game\update! while game\isRunning!
145
146reader\parse_line! until reader\eof!
147```
148
149</YueDisplay>
150
151# 宏
152
153## 常见用法
154
155&emsp;&emsp;宏函数用于在编译时执行一段代码来生成新的代码,并将生成的代码插入到最终编译结果中。
156
157```yuescript
158macro PI2 = -> math.pi * 2
159area = $PI2 * 5
160
161macro HELLO = -> "'你好 世界'"
162print $HELLO
163
164macro config = (debugging) ->
165 global debugMode = debugging == "true"
166 ""
167
168macro asserts = (cond) ->
169 debugMode and "assert #{cond}" or ""
170
171macro assert = (cond) ->
172 debugMode and "assert #{cond}" or "#{cond}"
173
174$config true
175$asserts item ~= nil
176
177$config false
178value = $assert item
179
180-- 宏函数参数传递的表达式会被转换为字符串
181macro and = (...) -> "#{ table.concat {...}, ' and ' }"
182if $and f1!, f2!, f3!
183 print "OK"
184```
185
186<YueDisplay>
187
188```yue
189macro PI2 = -> math.pi * 2
190area = $PI2 * 5
191
192macro HELLO = -> "'你好 世界'"
193print $HELLO
194
195macro config = (debugging) ->
196 global debugMode = debugging == "true"
197 ""
198
199macro asserts = (cond) ->
200 debugMode and "assert #{cond}" or ""
201
202macro assert = (cond) ->
203 debugMode and "assert #{cond}" or "#{cond}"
204
205$config true
206$asserts item ~= nil
207
208$config false
209value = $assert item
210
211-- 宏函数参数传递的表达式会被转换为字符串
212macro and = (...) -> "#{ table.concat {...}, ' and ' }"
213if $and f1!, f2!, f3!
214 print "OK"
215```
216
217</YueDisplay>
218
219## 直接插入代码
220
221&emsp;&emsp;宏函数可以返回一个包含月之脚本代码的字符串,或是一个包含 Lua 代码字符串的配置表。
222
223```yuescript
224macro yueFunc = (var) -> "local #{var} = ->"
225$yueFunc funcA
226funcA = -> "无法访问宏生成月之脚本里定义的变量"
227
228macro luaFunc = (var) -> {
229 code: "local function #{var}() end"
230 type: "lua"
231}
232$luaFunc funcB
233funcB = -> "无法访问宏生成 Lua 代码里定义的变量"
234
235macro lua = (code) -> {
236 :code
237 type: "lua"
238}
239
240-- raw字符串的开始和结束符号会自动被去除了再传入宏函数
241$lua[==[
242-- 插入原始Lua代码
243if cond then
244 print("输出")
245end
246]==]
247```
248
249<YueDisplay>
250
251```yue
252macro yueFunc = (var) -> "local #{var} = ->"
253$yueFunc funcA
254funcA = -> "无法访问宏生成月之脚本里定义的变量"
255
256macro luaFunc = (var) -> {
257 code: "local function #{var}() end"
258 type: "lua"
259}
260$luaFunc funcB
261funcB = -> "无法访问宏生成 Lua 代码里定义的变量"
262
263macro lua = (code) -> {
264 :code
265 type: "lua"
266}
267
268-- raw字符串的开始和结束符号会自动被去除了再传入宏函数
269$lua[==[
270-- 插入原始Lua代码
271if cond then
272 print("输出")
273end
274]==]
275```
276
277</YueDisplay>
278
279## 导出宏
280
281&emsp;&emsp;宏函数可以从一个模块中导出,并在另一个模块中导入。你必须将导出的宏函数放在一个单独的文件中使用,而且只有宏定义、宏导入和宏展开可以放入这个宏导出模块中。
282
283```yuescript
284-- 文件: utils.yue
285export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
286export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
287export macro foreach = (items, action) -> "for _ in *#{items}
288 #{action}"
289
290-- 文件 main.yue
291import "utils" as {
292 $, -- 表示导入所有宏的符号
293 $foreach: $each -- 重命名宏 $foreach 为 $each
294}
295[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
296```
297
298<YueDisplay>
299
300```yue
301-- 文件: utils.yue
302export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
303export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
304export macro foreach = (items, action) -> "for _ in *#{items}
305 #{action}"
306
307-- 文件 main.yue
308-- 在浏览器中不支持import函数,请在真实环境中尝试
309--[[
310import "utils" as {
311 $, -- 表示导入所有宏的符号
312 $foreach: $each -- 重命名宏 $foreach 为 $each
313}
314[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
315]]
316```
317
318</YueDisplay>
319
320## 内置宏
321
322&emsp;&emsp;月之脚本中有一些内置可以直接使用的宏,但你可以通过声明相同名称的宏来覆盖它们。
323
324```yuescript
325print $FILE -- 获取当前模块名称的字符串
326print $LINE -- 获取当前代码行数:2
327```
328
329<YueDisplay>
330
331```yue
332print $FILE -- 获取当前模块名称的字符串
333print $LINE -- 获取当前代码行数:2
334```
335
336</YueDisplay>
337
338## 用宏生成宏
339
340&emsp;&emsp;在月之脚本中,宏函数允许你在编译时生成代码。通过嵌套的宏函数,你可以创建更复杂的生成模式。这个特性允许你定义一个宏函数,用它来生成另一个宏函数,从而实现更加动态的代码生成。
341
342```yuescript
343macro Enum = (...) ->
344 items = {...}
345 itemSet = {item, true for item in *items}
346 (item) ->
347 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
348 "\"#{item}\""
349
350macro BodyType = $Enum(
351 Static
352 Dynamic
353 Kinematic
354)
355
356print "有效的枚举类型:", $BodyType Static
357-- print "编译报错的枚举类型:", $BodyType Unknown
358```
359
360<YueDisplay>
361
362```yue
363macro Enum = (...) ->
364 items = {...}
365 itemSet = {item, true for item in *items}
366 (item) ->
367 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
368 "\"#{item}\""
369
370macro BodyType = $Enum(
371 Static
372 Dynamic
373 Kinematic
374)
375
376print "有效的枚举类型:", $BodyType Static
377-- print "编译报错的枚举类型:", $BodyType Unknown
378```
379
380</YueDisplay>
381
382## 宏参数检查
383
384&emsp;&emsp;可以直接在参数列表中声明期望的 AST 节点类型,并在编译时检查传入的宏参数是否符合预期。
385
386```yuescript
387macro printNumAndStr = (num `Num, str `String) -> |
388 print(
389 #{num}
390 #{str}
391 )
392
393$printNumAndStr 123, "hello"
394```
395
396<YueDisplay>
397
398```yue
399macro printNumAndStr = (num `Num, str `String) -> |
400 print(
401 #{num}
402 #{str}
403 )
404
405$printNumAndStr 123, "hello"
406```
407
408</YueDisplay>
409
410&emsp;&emsp;如果需要做更加灵活的参数检查操作,可以使用内置的 `$is_ast` 宏函数在合适的位置进行手动检查。
411
412```yuescript
413macro printNumAndStr = (num, str) ->
414 error "expected Num as first argument" unless $is_ast Num, num
415 error "expected String as second argument" unless $is_ast String, str
416 "print(#{num}, #{str})"
417
418$printNumAndStr 123, "hello"
419```
420
421<YueDisplay>
422
423```yue
424macro printNumAndStr = (num, str) ->
425 error "expected Num as first argument" unless $is_ast Num, num
426 error "expected String as second argument" unless $is_ast String, str
427 "print(#{num}, #{str})"
428
429$printNumAndStr 123, "hello"
430```
431
432</YueDisplay>
433
434&emsp;&emsp;更多关于可用 AST 节点的详细信息,请参考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) 中大写的规则定义。
435
436# 错误处理
437
438&emsp;&emsp;用于统一进行 Lua 错误处理的便捷语法。
439
440```yuescript
441try
442 func 1, 2, 3
443catch err
444 print yue.traceback err
445
446success, result = try
447 func 1, 2, 3
448catch err
449 yue.traceback err
450
451try func 1, 2, 3
452catch err
453 print yue.traceback err
454
455success, result = try func 1, 2, 3
456
457try
458 print "尝试中"
459 func 1, 2, 3
460
461-- 使用if赋值模式
462if success, result := try func 1, 2, 3
463catch err
464 print yue.traceback err
465 print result
466```
467
468<YueDisplay>
469
470```yue
471try
472 func 1, 2, 3
473catch err
474 print yue.traceback err
475
476success, result = try
477 func 1, 2, 3
478catch err
479 yue.traceback err
480
481try func 1, 2, 3
482catch err
483 print yue.traceback err
484
485success, result = try func 1, 2, 3
486
487try
488 print "尝试中"
489 func 1, 2, 3
490
491-- 使用if赋值模式
492if success, result := try func 1, 2, 3
493catch err
494 print yue.traceback err
495 print result
496```
497
498</YueDisplay>
499
500## 错误处理简化
501
502&emsp;&emsp;`try?` 是 `try` 的功能简化语法,它不再返回 `try` 语句的布尔状态,并在成功时直接返回 `try` 代码块的结果,失败时返回 `nil` 值而非错误对象。
503
504```yuescript
505a, b, c = try? func!
506
507-- 与空值合并运算符一起使用
508a = (try? func!) ?? "default"
509
510-- 作为函数参数
511f try? func!
512
513-- 带 catch 块的 try!
514f try?
515 print 123
516 func!
517catch e
518 print e
519 e
520```
521
522<YueDisplay>
523
524```yue
525a, b, c = try? func!
526
527-- 与空值合并运算符一起使用
528a = (try? func!) ?? "default"
529
530-- 作为函数参数
531f try? func!
532
533-- 带 catch 块的 try!
534f try?
535 print 123
536 func!
537catch e
538 print e
539 e
540```
541
542</YueDisplay>
543
544# 表格字面量
545
546&emsp;&emsp;和 Lua 一样,表格可以通过花括号进行定义。
547
548```yuescript
549some_values = [1, 2, 3, 4]
550```
551
552<YueDisplay>
553
554```yue
555some_values = [1, 2, 3, 4]
556```
557
558</YueDisplay>
559
560&emsp;&emsp;但与Lua不同的是,给表格中的键赋值是用 **:**(而不是 **=**)。
561
562```yuescript
563some_values = {
564 name: "Bill",
565 age: 200,
566 ["favorite food"]: "rice"
567}
568```
569
570<YueDisplay>
571
572```yue
573some_values = {
574 name: "Bill",
575 age: 200,
576 ["favorite food"]: "rice"
577}
578```
579
580</YueDisplay>
581
582&emsp;&emsp;如果只分配一个键值对的表格,可以省略花括号。
583
584```yuescript
585profile =
586 height: "4英尺",
587 shoe_size: 13,
588 favorite_foods: ["冰淇淋", "甜甜圈"]
589```
590
591<YueDisplay>
592
593```yue
594profile =
595 height: "4英尺",
596 shoe_size: 13,
597 favorite_foods: ["冰淇淋", "甜甜圈"]
598```
599
600</YueDisplay>
601
602&emsp;&emsp;可以使用换行符而不使用逗号(或两者都用)来分隔表格中的值:
603
604```yuescript
605values = {
606 1, 2, 3, 4
607 5, 6, 7, 8
608 name: "超人"
609 occupation: "打击犯罪"
610}
611```
612
613<YueDisplay>
614
615```yue
616values = {
617 1, 2, 3, 4
618 5, 6, 7, 8
619 name: "超人"
620 occupation: "打击犯罪"
621}
622```
623
624</YueDisplay>
625
626&emsp;&emsp;创建单行表格字面量时,也可以省略花括号:
627
628```yuescript
629my_function dance: "探戈", partner: "无"
630
631y = type: "狗", legs: 4, tails: 1
632```
633
634<YueDisplay>
635
636```yue
637my_function dance: "探戈", partner: "无"
638
639y = type: "狗", legs: 4, tails: 1
640```
641
642</YueDisplay>
643
644&emsp;&emsp;表格字面量的键可以使用 Lua 语言的关键字,而无需转义:
645
646```yuescript
647tbl = {
648 do: "某事"
649 end: "饥饿"
650}
651```
652
653<YueDisplay>
654
655```yue
656tbl = {
657 do: "某事"
658 end: "饥饿"
659}
660```
661
662</YueDisplay>
663
664&emsp;&emsp;如果你要构造一个由变量组成的表,并希望键与变量名相同,那么可以使用 **:** 前缀操作符:
665
666```yuescript
667hair = "金色"
668height = 200
669person = { :hair, :height, shoe_size: 40 }
670
671print_table :hair, :height
672```
673
674<YueDisplay>
675
676```yue
677hair = "金色"
678height = 200
679person = { :hair, :height, shoe_size: 40 }
680
681print_table :hair, :height
682```
683
684</YueDisplay>
685
686&emsp;&emsp;如果你希望表中字段的键是某个表达式的结果,那么可以用 **[ ]** 包裹它,就像在 Lua 中一样。如果键中有任何特殊字符,也可以直接使用字符串字面量作为键,省略方括号。
687
688```yuescript
689t = {
690 [1 + 2]: "你好"
691 "你好 世界": true
692}
693```
694
695<YueDisplay>
696
697```yue
698t = {
699 [1 + 2]: "你好"
700 "你好 世界": true
701}
702```
703
704</YueDisplay>
705
706&emsp;&emsp;Lua 的表同时具有数组部分和哈希部分,但有时候你会希望在书写 Lua 表时,对 Lua 表做数组和哈希不同用法的语义区分。然后你可以用 **[ ]** 而不是 **{ }** 来编写表示数组的 Lua 表,并且不允许在数组 Lua 表中写入任何键值对。
707
708```yuescript
709some_values = [ 1, 2, 3, 4 ]
710list_with_one_element = [ 1, ]
711```
712
713<YueDisplay>
714
715```yue
716some_values = [ 1, 2, 3, 4 ]
717list_with_one_element = [ 1, ]
718```
719
720</YueDisplay>
721
722# 推导式
723
724&emsp;&emsp;推导式为我们提供了一种便捷的语法,通过遍历现有对象并对其值应用表达式来构造出新的表格。月之脚本有两种推导式:列表推导式和表格推导式。它们最终都是产生 Lua 表格;列表推导式将值累积到类似数组的表格中,而表格推导式允许你在每次遍历时设置新表格的键和值。
725
726## 列表推导式
727
728&emsp;&emsp;以下操作创建了一个 items 表的副本,但所有包含的值都翻倍了。
729
730```yuescript
731items = [1, 2, 3, 4]
732doubled = [item * 2 for i, item in ipairs items]
733```
734
735<YueDisplay>
736
737```yue
738items = [1, 2, 3, 4]
739doubled = [item * 2 for i, item in ipairs items]
740```
741
742</YueDisplay>
743
744&emsp;&emsp;可以使用 `when` 子句筛选新表中包含的项目:
745
746```yuescript
747slice = [item for i, item in ipairs items when i > 1 and i < 3]
748```
749
750<YueDisplay>
751
752```yue
753slice = [item for i, item in ipairs items when i > 1 and i < 3]
754```
755
756</YueDisplay>
757
758&emsp;&emsp;因为我们常常需要迭代数值索引表的值,所以引入了 **\*** 操作符来做语法简化。doubled 示例可以重写为:
759
760```yuescript
761doubled = [item * 2 for item in *items]
762```
763
764<YueDisplay>
765
766```yue
767doubled = [item * 2 for item in *items]
768```
769
770</YueDisplay>
771
772&emsp;&emsp;在列表推导式中,你还可以使用展开操作符 `...` 来实现对列表嵌套层级进行扁平化的处理:
773
774```yuescript
775data =
776 a: [1, 2, 3]
777 b: [4, 5, 6]
778
779flat = [...v for k,v in pairs data]
780-- flat 现在为 [1, 2, 3, 4, 5, 6]
781```
782
783<YueDisplay>
784
785```yue
786data =
787 a: [1, 2, 3]
788 b: [4, 5, 6]
789
790flat = [...v for k,v in pairs data]
791-- flat 现在为 [1, 2, 3, 4, 5, 6]
792```
793
794</YueDisplay>
795
796&emsp;&emsp;for 和 when 子句可以根据需要进行链式操作。唯一的要求是推导式中至少要有一个 for 子句。
797
798&emsp;&emsp;使用多个 for 子句与使用多重循环的效果相同:
799
800```yuescript
801x_coords = [4, 5, 6, 7]
802y_coords = [9, 2, 3]
803
804points = [ [x, y] for x in *x_coords \
805for y in *y_coords]
806```
807
808<YueDisplay>
809
810```yue
811x_coords = [4, 5, 6, 7]
812y_coords = [9, 2, 3]
813
814points = [ [x, y] for x in *x_coords \
815for y in *y_coords]
816```
817
818</YueDisplay>
819
820&emsp;&emsp;在推导式中也可以使用简单的数值 for 循环:
821
822```yuescript
823evens = [i for i = 1, 100 when i % 2 == 0]
824```
825
826<YueDisplay>
827
828```yue
829evens = [i for i = 1, 100 when i % 2 == 0]
830```
831
832</YueDisplay>
833
834## 表格推导式
835
836&emsp;&emsp;表格推导式和列表推导式的语法非常相似,只是要使用 **{** 和 **}** 并从每次迭代中取两个值。
837
838&emsp;&emsp;以下示例生成了表格 thing 的副本:
839
840```yuescript
841thing = {
842 color: "red"
843 name: "fast"
844 width: 123
845}
846
847thing_copy = {k, v for k, v in pairs thing}
848```
849
850<YueDisplay>
851
852```yue
853thing = {
854 color: "red"
855 name: "fast"
856 width: 123
857}
858
859thing_copy = {k, v for k, v in pairs thing}
860```
861
862</YueDisplay>
863
864```yuescript
865no_color = {k, v for k, v in pairs thing when k != "color"}
866```
867
868<YueDisplay>
869
870```yue
871no_color = {k, v for k, v in pairs thing when k != "color"}
872```
873
874</YueDisplay>
875
876&emsp;&emsp;**\*** 操作符在表格推导式中能使用。在下面的例子里,我们为几个数字创建了一个平方根查找表。
877
878```yuescript
879numbers = [1, 2, 3, 4]
880sqrts = {i, math.sqrt i for i in *numbers}
881```
882
883<YueDisplay>
884
885```yue
886numbers = [1, 2, 3, 4]
887sqrts = {i, math.sqrt i for i in *numbers}
888```
889
890</YueDisplay>
891
892&emsp;&emsp;表格推导式中的键值元组也可以来自单个表达式,在这种情况下,表达式在计算后应返回两个值。第一个用作键,第二个用作值:
893
894&emsp;&emsp;在下面的示例中,我们将一些数组转换为一个表,其中每个数组里的第一项是键,第二项是值。
895
896```yuescript
897tuples = [ ["hello", "world"], ["foo", "bar"]]
898tbl = {unpack tuple for tuple in *tuples}
899```
900
901<YueDisplay>
902
903```yue
904tuples = [ ["hello", "world"], ["foo", "bar"]]
905tbl = {unpack tuple for tuple in *tuples}
906```
907
908</YueDisplay>
909
910## 切片
911
912&emsp;&emsp;当使用 **\*** 操作符时,月之脚本还提供了一种特殊的语法来限制要遍历的列表范围。这个语法也相当于在 for 循环中设置迭代边界和步长。
913
914&emsp;&emsp;下面的案例中,我们在切片中设置最小和最大边界,取索引在 1 到 5 之间(包括 1 和 5)的所有项目:
915
916```yuescript
917slice = [item for item in *items[1, 5]]
918```
919
920<YueDisplay>
921
922```yue
923slice = [item for item in *items[1, 5]]
924```
925
926</YueDisplay>
927
928&emsp;&emsp;切片的任意参数都可以省略,并会使用默认值。在如下示例中,如果省略了最大索引边界,它默认为表的长度。使下面的代码取除第一个元素之外的所有元素:
929
930```yuescript
931slice = [item for item in *items[2,]]
932```
933
934<YueDisplay>
935
936```yue
937slice = [item for item in *items[2,]]
938```
939
940</YueDisplay>
941
942&emsp;&emsp;如果省略了最小边界,便默认会设置为 1。这里我们只提供一个步长,并留下其他边界为空。这样会使得代码取出所有奇数索引的项目:(1, 3, 5, …)
943
944```yuescript
945slice = [item for item in *items[,,2]]
946```
947
948<YueDisplay>
949
950```yue
951slice = [item for item in *items[,,2]]
952```
953
954</YueDisplay>
955
956&emsp;&emsp;最小和最大边界都可以是负数,使用负数意味着边界是从表的末尾开始计算的。
957
958```yuescript
959-- 取最后4个元素
960slice = [item for item in *items[-4,-1]]
961```
962
963<YueDisplay>
964
965```yue
966-- 取最后4个元素
967slice = [item for item in *items[-4,-1]]
968```
969
970</YueDisplay>
971
972&emsp;&emsp;切片的步长也可以是负数,这意味着元素会以相反的顺序被取出。
973
974```yuescript
975reverse_slice = [item for item in *items[-1,1,-1]]
976```
977
978<YueDisplay>
979
980```yue
981reverse_slice = [item for item in *items[-1,1,-1]]
982```
983
984</YueDisplay>
985
986### 切片表达式
987
988&emsp;&emsp;切片也可以作为表达式来使用。可以用于获取一个表包含的子列表。
989
990```yuescript
991-- 取第2和第4个元素作为新的列表
992sub_list = items[2, 4]
993
994-- 取最后4个元素作为新的列表
995last_four_items = items[-4, -1]
996```
997
998<YueDisplay>
999
1000```yue
1001-- 取第2和第4个元素作为新的列表
1002sub_list = items[2, 4]
1003
1004-- 取最后4个元素作为新的列表
1005last_four_items = items[-4, -1]
1006```
1007
1008</YueDisplay>
1009
1010# 面向对象编程
1011
1012&emsp;&emsp;在以下的示例中,月之脚本生成的 Lua 代码可能看起来会很复杂。所以最好主要关注月之脚本代码层面的意义,然后如果你想知道关于面向对象功能的实现细节,再查看 Lua 代码。
1013
1014&emsp;&emsp;一个简单的类:
1015
1016```yuescript
1017class Inventory
1018 new: =>
1019 @items = {}
1020
1021 add_item: (name) =>
1022 if @items[name]
1023 @items[name] += 1
1024 else
1025 @items[name] = 1
1026```
1027
1028<YueDisplay>
1029
1030```yue
1031class Inventory
1032 new: =>
1033 @items = {}
1034
1035 add_item: (name) =>
1036 if @items[name]
1037 @items[name] += 1
1038 else
1039 @items[name] = 1
1040```
1041
1042</YueDisplay>
1043
1044&emsp;&emsp;在月之脚本中采用面向对象的编程方式时,通常会使用类声明语句结合 Lua 表格字面量来做类定义。这个类的定义包含了它的所有方法和属性。在这种结构中,键名为 “new” 的成员扮演了一个重要的角色,是作为构造函数来使用。
1045
1046&emsp;&emsp;值得注意的是,类中的方法都采用了粗箭头函数语法。当在类的实例上调用方法时,该实例会自动作为第一个参数被传入,因此粗箭头函数用于生成一个名为 “self” 的参数。
1047
1048&emsp;&emsp;此外,“@” 前缀在变量名上起到了简化作用,代表 “self”。例如,`@items` 就等同于 `self.items`。
1049
1050&emsp;&emsp;为了创建类的一个新实例,可以将类名当作一个函数来调用,这样就可以生成并返回一个新的实例。
1051
1052```yuescript
1053inv = Inventory!
1054inv\add_item "t-shirt"
1055inv\add_item "pants"
1056```
1057
1058<YueDisplay>
1059
1060```yue
1061inv = Inventory!
1062inv\add_item "t-shirt"
1063inv\add_item "pants"
1064```
1065
1066</YueDisplay>
1067
1068&emsp;&emsp;在月之脚本的类中,由于需要将类的实例作为参数传入到调用的方法中,因此使用了 **\\** 操作符做类的成员函数调用。
1069
1070&emsp;&emsp;需要特别注意的是,类的所有属性在其实例之间是共享的。这对于函数类型的成员属性通常不会造成问题,但对于其他类型的属性,可能会导致意外的结果。
1071
1072&emsp;&emsp;例如,在下面的示例中,clothes 属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影响到其他所有实例。
1073
1074```yuescript
1075class Person
1076 clothes: []
1077 give_item: (name) =>
1078 table.insert @clothes, name
1079
1080a = Person!
1081b = Person!
1082
1083a\give_item "pants"
1084b\give_item "shirt"
1085
1086-- 会同时打印出裤子和衬衫
1087print item for item in *a.clothes
1088```
1089
1090<YueDisplay>
1091
1092```yue
1093class Person
1094 clothes: []
1095 give_item: (name) =>
1096 table.insert @clothes, name
1097
1098a = Person!
1099b = Person!
1100
1101a\give_item "pants"
1102b\give_item "shirt"
1103
1104-- 会同时打印出裤子和衬衫
1105print item for item in *a.clothes
1106```
1107
1108</YueDisplay>
1109
1110&emsp;&emsp;避免这个问题的正确方法是在构造函数中创建对象的可变状态:
1111
1112```yuescript
1113class Person
1114 new: =>
1115 @clothes = []
1116```
1117
1118<YueDisplay>
1119
1120```yue
1121class Person
1122 new: =>
1123 @clothes = []
1124```
1125
1126</YueDisplay>
1127
1128## 继承
1129
1130&emsp;&emsp;`extends` 关键字可以在类声明中使用,以继承另一个类的属性和方法。
1131
1132```yuescript
1133class BackPack extends Inventory
1134 size: 10
1135 add_item: (name) =>
1136 if #@items > size then error "背包已满"
1137 super name
1138```
1139
1140<YueDisplay>
1141
1142```yue
1143class BackPack extends Inventory
1144 size: 10
1145 add_item: (name) =>
1146 if #@items > size then error "背包已满"
1147 super name
1148```
1149
1150</YueDisplay>
1151
1152&emsp;&emsp;在这一部分,我们对月之脚本中的 `Inventory` 类进行了扩展,加入了对可以携带物品数量的限制。
1153
1154&emsp;&emsp;在这个特定的例子中,子类并没有定义自己的构造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在子类中定义了构造函数,我们可以利用 `super` 方法来调用并执行父类的构造函数。
1155
1156&emsp;&emsp;此外,当一个类继承自另一个类时,它会尝试调用父类上的 `__inherited` 方法(如果这个方法存在的话),以此来向父类发送通知。这个 `__inherited` 函数接受两个参数:被继承的父类和继承的子类。
1157
1158```yuescript
1159class Shelf
1160 @__inherited: (child) =>
1161 print @__name, "被", child.__name, "继承"
1162
1163-- 将打印: Shelf 被 Cupboard 继承
1164class Cupboard extends Shelf
1165```
1166
1167<YueDisplay>
1168
1169```yue
1170class Shelf
1171 @__inherited: (child) =>
1172 print @__name, "被", child.__name, "继承"
1173
1174-- 将打印: Shelf 被 Cupboard 继承
1175class Cupboard extends Shelf
1176```
1177
1178</YueDisplay>
1179
1180## super 关键字
1181
1182&emsp;&emsp;`super` 是一个特别的关键字,它有两种不同的使用方式:既可以当作一个对象来看待,也可以像调用函数那样使用。它仅在类的内部使用时具有特殊的功能。
1183
1184&emsp;&emsp;当 `super` 被作为一个函数调用时,它将调用父类中与之同名的函数。此时,当前的 `self` 会自动作为第一个参数传递,正如上面提到的继承示例所展示的那样。
1185
1186&emsp;&emsp;在将 `super` 当作普通值使用时,它实际上是对父类对象的引用。通过这种方式,我们可以访问父类中可能被子类覆盖的值,就像访问任何普通对象一样。
1187
1188&emsp;&emsp;此外,当使用 `\` 操作符与 `super` 一起使用时,`self`将被插入为第一个参数,而不是使用 `super` 本身的值。而在使用`.`操作符来检索函数时,则会返回父类中的原始函数。
1189
1190&emsp;&emsp;下面是一些使用 `super` 的不同方法的示例:
1191
1192```yuescript
1193class MyClass extends ParentClass
1194 a_method: =>
1195 -- 以下效果相同:
1196 super "你好", "世界"
1197 super\a_method "你好", "世界"
1198 super.a_method self, "你好", "世界"
1199
1200 -- super 作为值等于父类:
1201 assert super == ParentClass
1202```
1203
1204<YueDisplay>
1205
1206```yue
1207class MyClass extends ParentClass
1208 a_method: =>
1209 -- 以下效果相同:
1210 super "你好", "世界"
1211 super\a_method "你好", "世界"
1212 super.a_method self, "你好", "世界"
1213
1214 -- super 作为值等于父类:
1215 assert super == ParentClass
1216```
1217
1218</YueDisplay>
1219
1220&emsp;&emsp;**super** 也可以用在函数存根的左侧。唯一的主要区别是,生成的函数不是绑定到 super 的值,而是绑定到 self。
1221
1222## 类型
1223
1224&emsp;&emsp;每个类的实例都带有它的类型。这存储在特殊的 \_\_class 属性中。此属性会保存类对象。类对象是我们用来构建新实例的对象。我们还可以索引类对象以检索类方法和属性。
1225
1226```yuescript
1227b = BackPack!
1228assert b.__class == BackPack
1229
1230print BackPack.size -- 打印 10
1231```
1232
1233<YueDisplay>
1234
1235```yue
1236b = BackPack!
1237assert b.__class == BackPack
1238
1239print BackPack.size -- 打印 10
1240```
1241
1242</YueDisplay>
1243
1244## 类对象
1245
1246&emsp;&emsp;在月之脚本中,当我们编写类的定义语句时,实际上是在创建一个类对象。这个类对象被保存在一个与该类同名的变量中。
1247
1248&emsp;&emsp;类对象具有函数的特性,可以被调用来创建新的实例。这正是我们在之前示例中所展示的创建类实例的方式。
1249
1250&emsp;&emsp;一个类由两个表构成:类表本身和一个基表。基表作为所有实例的元表。在类声明中列出的所有属性都存放在基表中。
1251
1252&emsp;&emsp;如果在类对象的元表中找不到某个属性,系统会从基表中检索该属性。这就意味着我们可以直接从类本身访问到其方法和属性。
1253
1254&emsp;&emsp;需要特别注意的是,对类对象的赋值并不会影响到基表,因此这不是向实例添加新方法的正确方式。相反,需要直接修改基表。关于这点,可以参考下面的 “\_\_base” 字段。
1255
1256&emsp;&emsp;此外,类对象包含几个特殊的属性:当类被声明时,类的名称会作为一个字符串存储在类对象的 “\_\_name” 字段中。
1257
1258```yuescript
1259print BackPack.__name -- 打印 Backpack
1260```
1261
1262<YueDisplay>
1263
1264```yue
1265print BackPack.__name -- 打印 Backpack
1266```
1267
1268</YueDisplay>
1269
1270&emsp;&emsp;基础对象被保存在一个名为 `__base` 的特殊表中。我们可以编辑这个表,以便为那些已经创建出来的实例和还未创建的实例增加新的功能。
1271
1272&emsp;&emsp;另外,如果一个类是从另一个类派生而来的,那么其父类对象则会被存储在名为 `__parent` 的地方。这种机制允许在类之间实现继承和功能扩展。
1273
1274## 类变量
1275
1276&emsp;&emsp;我们可以直接在类对象中创建变量,而不是在类的基对象中,通过在类声明中的属性名前使用 @。
1277
1278```yuescript
1279class Things
1280 @some_func: => print "Hello from", @__name
1281
1282Things\some_func!
1283
1284-- 类变量在实例中不可见
1285assert Things().some_func == nil
1286```
1287
1288<YueDisplay>
1289
1290```yue
1291class Things
1292 @some_func: => print "Hello from", @__name
1293
1294Things\some_func!
1295
1296-- 类变量在实例中不可见
1297assert Things().some_func == nil
1298```
1299
1300</YueDisplay>
1301
1302&emsp;&emsp;在表达式中,我们可以使用 @@ 来访问存储在 `self.__class` 中的值。因此,`@@hello` 是 `self.__class.hello` 的简写。
1303
1304```yuescript
1305class Counter
1306 @count: 0
1307
1308 new: =>
1309 @@count += 1
1310
1311Counter!
1312Counter!
1313
1314print Counter.count -- 输出 2
1315```
1316
1317<YueDisplay>
1318
1319```yue
1320class Counter
1321 @count: 0
1322
1323 new: =>
1324 @@count += 1
1325
1326Counter!
1327Counter!
1328
1329print Counter.count -- 输出 2
1330```
1331
1332</YueDisplay>
1333
1334&emsp;&emsp;@@ 的调用语义与 @ 类似。调用 @@ 时,会使用 Lua 的冒号语法将类作为第一个参数传入。
1335
1336```yuescript
1337@@hello 1,2,3,4
1338```
1339
1340<YueDisplay>
1341
1342```yue
1343@@hello 1,2,3,4
1344```
1345
1346</YueDisplay>
1347
1348## 类声明语句
1349
1350&emsp;&emsp;在类声明的主体中,除了键/值对外,我们还可以编写普通的表达式。在这种类声明体中的普通代码的上下文中,self 等于类对象,而不是实例对象。
1351
1352&emsp;&emsp;以下是创建类变量的另一种方法:
1353
1354```yuescript
1355class Things
1356 @class_var = "hello world"
1357```
1358
1359<YueDisplay>
1360
1361```yue
1362class Things
1363 @class_var = "hello world"
1364```
1365
1366</YueDisplay>
1367
1368&emsp;&emsp;这些表达式会在所有属性被添加到类的基对象后执行。
1369
1370&emsp;&emsp;在类的主体中声明的所有变量都会限制作用域只在类声明的范围。这对于放置只有类方法可以访问的私有值或辅助函数很方便:
1371
1372```yuescript
1373class MoreThings
1374 secret = 123
1375 log = (msg) -> print "LOG:", msg
1376
1377 some_method: =>
1378 log "hello world: " .. secret
1379```
1380
1381<YueDisplay>
1382
1383```yue
1384class MoreThings
1385 secret = 123
1386 log = (msg) -> print "LOG:", msg
1387
1388 some_method: =>
1389 log "hello world: " .. secret
1390```
1391
1392</YueDisplay>
1393
1394## @ 和 @@ 值
1395
1396&emsp;&emsp;当 @ 和 @@ 前缀在一个名字前时,它们分别代表在 self 和 self.\_\_class 中访问的那个名字。
1397
1398&emsp;&emsp;如果它们单独使用,它们是 self 和 self.\_\_class 的别名。
1399
1400```yuescript
1401assert @ == self
1402assert @@ == self.__class
1403```
1404
1405<YueDisplay>
1406
1407```yue
1408assert @ == self
1409assert @@ == self.__class
1410```
1411
1412</YueDisplay>
1413
1414&emsp;&emsp;例如,使用 @@ 从实例方法快速创建同一类的新实例的方法:
1415
1416```yuescript
1417some_instance_method = (...) => @@ ...
1418```
1419
1420<YueDisplay>
1421
1422```yue
1423some_instance_method = (...) => @@ ...
1424```
1425
1426</YueDisplay>
1427
1428## 构造属性提升
1429
1430&emsp;&emsp;为了减少编写简单值对象定义的代码。你可以这样简单写一个类:
1431
1432```yuescript
1433class Something
1434 new: (@foo, @bar, @@biz, @@baz) =>
1435
1436-- 这是以下声明的简写形式
1437
1438class Something
1439 new: (foo, bar, biz, baz) =>
1440 @foo = foo
1441 @bar = bar
1442 @@biz = biz
1443 @@baz = baz
1444```
1445
1446<YueDisplay>
1447
1448```yue
1449class Something
1450 new: (@foo, @bar, @@biz, @@baz) =>
1451
1452-- 这是以下声明的简写形式
1453
1454class Something
1455 new: (foo, bar, biz, baz) =>
1456 @foo = foo
1457 @bar = bar
1458 @@biz = biz
1459 @@baz = baz
1460```
1461
1462</YueDisplay>
1463
1464&emsp;&emsp;你也可以使用这种语法为一个函数初始化传入对象的字段。
1465
1466```yuescript
1467new = (@fieldA, @fieldB) => @
1468obj = new {}, 123, "abc"
1469print obj
1470```
1471
1472<YueDisplay>
1473
1474```yue
1475new = (@fieldA, @fieldB) => @
1476obj = new {}, 123, "abc"
1477print obj
1478```
1479
1480</YueDisplay>
1481
1482## 类表达式
1483
1484&emsp;&emsp;类声明的语法也可以作为一个表达式使用,可以赋值给一个变量或者被返回语句返回。
1485
1486```yuescript
1487x = class Bucket
1488 drops: 0
1489 add_drop: => @drops += 1
1490```
1491
1492<YueDisplay>
1493
1494```yue
1495x = class Bucket
1496 drops: 0
1497 add_drop: => @drops += 1
1498```
1499
1500</YueDisplay>
1501
1502## 匿名类
1503
1504&emsp;&emsp;声明类时可以省略名称。如果类的表达式不在赋值语句中,\_\_name 属性将为 nil。如果出现在赋值语句中,赋值操作左侧的名称将代替 nil。
1505
1506```yuescript
1507BigBucket = class extends Bucket
1508 add_drop: => @drops += 10
1509
1510assert Bucket.__name == "BigBucket"
1511```
1512
1513<YueDisplay>
1514
1515```yue
1516BigBucket = class extends Bucket
1517 add_drop: => @drops += 10
1518
1519assert Bucket.__name == "BigBucket"
1520```
1521
1522</YueDisplay>
1523
1524&emsp;&emsp;你甚至可以省略掉主体,这意味着你可以这样写一个空白的匿名类:
1525
1526```yuescript
1527x = class
1528```
1529
1530<YueDisplay>
1531
1532```yue
1533x = class
1534```
1535
1536</YueDisplay>
1537
1538## 类混合
1539
1540&emsp;&emsp;你可以通过使用 `using` 关键字来实现类混合。这意味着你可以从一个普通 Lua 表格或已定义的类对象中,复制函数到你创建的新类中。当你使用普通 Lua 表格进行类混合时,你有机会用自己的实现来重写类的索引方法(例如元方法 `__index`)。然而,当你从一个类对象做混合时,需要注意的是该类对象的元方法将不会被复制到新类。
1541
1542```yuescript
1543MyIndex = __index: var: 1
1544
1545class X using MyIndex
1546 func: =>
1547 print 123
1548
1549x = X!
1550print x.var
1551
1552class Y using X
1553
1554y = Y!
1555y\func!
1556
1557assert y.__class.__parent ~= X -- X 不是 Y 的父类
1558```
1559
1560<YueDisplay>
1561
1562```yue
1563MyIndex = __index: var: 1
1564
1565class X using MyIndex
1566 func: =>
1567 print 123
1568
1569x = X!
1570print x.var
1571
1572class Y using X
1573
1574y = Y!
1575y\func!
1576
1577assert y.__class.__parent ~= X -- X 不是 Y 的父类
1578```
1579
1580</YueDisplay>
1581
1582# with 语句
1583
1584在编写 Lua 代码时,我们在创建对象后的常见操作是立即调用这个对象一系列操作函数并设置一系列属性。
1585
1586这导致在代码中多次重复引用对象的名称,增加了不必要的文本噪音。一个常见的解决方案是在创建对象时,在构造函数传入一个表,该表包含要覆盖设置的键和值的集合。这样做的缺点是该对象的构造函数必须支持这种初始化形式。
1587
1588with 块有助于简化编写这样的代码。在 with 块内,我们可以使用以 . 或 \ 开头的特殊语句,这些语句代表我们正在使用的对象的操作。
1589
1590例如,我们可以这样处理一个新创建的对象:
1591
1592```yuescript
1593with Person!
1594 .name = "Oswald"
1595 \add_relative my_dad
1596 \save!
1597 print .name
1598```
1599
1600<YueDisplay>
1601
1602```yue
1603with Person!
1604 .name = "Oswald"
1605 \add_relative my_dad
1606 \save!
1607 print .name
1608```
1609
1610</YueDisplay>
1611
1612with 语句也可以用作一个表达式,并返回它的代码块正在处理的对象。
1613
1614```yuescript
1615file = with File "favorite_foods.txt"
1616 \set_encoding "utf8"
1617```
1618
1619<YueDisplay>
1620
1621```yue
1622file = with File "favorite_foods.txt"
1623 \set_encoding "utf8"
1624```
1625
1626</YueDisplay>
1627
1628`with` 表达式支持 `break` 返回一个值:
1629
1630```yuescript
1631result = with obj
1632 break .value
1633```
1634
1635<YueDisplay>
1636
1637```yue
1638result = with obj
1639 break .value
1640```
1641
1642</YueDisplay>
1643
1644在 `with` 中使用 `break value` 后,`with` 表达式将不再返回其目标对象,而是返回 `break` 给出的值。
1645
1646```yuescript
1647a = with obj
1648 .x = 1
1649-- a 是 obj
1650
1651b = with obj
1652 break .x
1653-- b 是 .x,不是 obj
1654```
1655
1656<YueDisplay>
1657
1658```yue
1659a = with obj
1660 .x = 1
1661-- a 是 obj
1662
1663b = with obj
1664 break .x
1665-- b 是 .x,不是 obj
1666```
1667
1668</YueDisplay>
1669
1670与 `for` / `while` / `repeat` / `do` 不同,`with` 只支持一个 break 返回值。
1671
1672或者…
1673
1674```yuescript
1675create_person = (name, relatives) ->
1676 with Person!
1677 .name = name
1678 \add_relative relative for relative in *relatives
1679
1680me = create_person "Leaf", [dad, mother, sister]
1681```
1682
1683<YueDisplay>
1684
1685```yue
1686create_person = (name, relatives) ->
1687 with Person!
1688 .name = name
1689 \add_relative relative for relative in *relatives
1690
1691me = create_person "Leaf", [dad, mother, sister]
1692```
1693
1694</YueDisplay>
1695
1696在此用法中,with 可以被视为K组合子(k-combinator)的一种特殊形式。
1697
1698如果你想给表达式另外起一个名称的话,with 语句中的表达式也可以是一个赋值语句。
1699
1700```yuescript
1701with str := "你好"
1702 print "原始:", str
1703 print "大写:", \upper!
1704```
1705
1706<YueDisplay>
1707
1708```yue
1709with str := "你好"
1710 print "原始:", str
1711 print "大写:", \upper!
1712```
1713
1714</YueDisplay>
1715
1716你可以在 `with` 语句中使用 `[]` 访问特殊键。
1717
1718```yuescript
1719with tb
1720 [1] = 1
1721 print [2]
1722 with [abc]
1723 [3] = [2]\func!
1724 ["key-name"] = value
1725 [] = "abc" -- 追加到 "tb"
1726```
1727
1728<YueDisplay>
1729
1730```yue
1731with tb
1732 [1] = 1
1733 print [2]
1734 with [abc]
1735 [3] = [2]\func!
1736 ["key-name"] = value
1737 [] = "abc" -- 追加到 "tb"
1738```
1739
1740</YueDisplay>
1741
1742`with?` 是 `with` 语法的一个增强版本,引入了存在性检查,用于在不显式判空的情况下安全访问可能为 nil 的对象。
1743
1744```yuescript
1745with? obj
1746 print obj.name
1747```
1748
1749<YueDisplay>
1750
1751```yue
1752with? obj
1753 print obj.name
1754```
1755
1756</YueDisplay>
1757
1758# 赋值
1759
1760&emsp;&emsp;月之脚本中定义的变量是动态类型的,并默认为局部变量。但你可以通过 **local** 和 **global** 声明来改变声明变量的作用范围。
1761
1762```yuescript
1763hello = "world"
1764a, b, c = 1, 2, 3
1765hello = 123 -- 访问现有的变量
1766```
1767
1768<YueDisplay>
1769
1770```yue
1771hello = "world"
1772a, b, c = 1, 2, 3
1773hello = 123 -- 访问现有的变量
1774```
1775
1776</YueDisplay>
1777
1778## 执行更新
1779
1780&emsp;&emsp;你可以使用各式二进制运算符执行更新赋值。
1781
1782```yuescript
1783x = 1
1784x += 1
1785x -= 1
1786x *= 10
1787x /= 10
1788x %= 10
1789s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量
1790arg or= "默认值"
1791```
1792
1793<YueDisplay>
1794
1795```yue
1796x = 1
1797x += 1
1798x -= 1
1799x *= 10
1800x /= 10
1801x %= 10
1802s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量
1803arg or= "默认值"
1804```
1805
1806</YueDisplay>
1807
1808## 链式赋值
1809
1810&emsp;&emsp;你可以进行链式赋值,将多个项目赋予相同的值。
1811
1812```yuescript
1813a = b = c = d = e = 0
1814x = y = z = f!
1815```
1816
1817<YueDisplay>
1818
1819```yue
1820a = b = c = d = e = 0
1821x = y = z = f!
1822```
1823
1824</YueDisplay>
1825
1826## 显式声明局部变量
1827
1828```yuescript
1829do
1830 local a = 1
1831 local *
1832 print "预先声明后续所有变量为局部变量"
1833 x = -> 1 + y + z
1834 y, z = 2, 3
1835 global instance = Item\new!
1836
1837do
1838 local X = 1
1839 local ^
1840 print "只预先声明后续大写的变量为局部变量"
1841 a = 1
1842 B = 2
1843```
1844
1845<YueDisplay>
1846
1847```yue
1848do
1849 local a = 1
1850 local *
1851 print "预先声明后续所有变量为局部变量"
1852 x = -> 1 + y + z
1853 y, z = 2, 3
1854 global instance = Item\new!
1855
1856do
1857 local X = 1
1858 local ^
1859 print "只预先声明后续大写的变量为局部变量"
1860 a = 1
1861 B = 2
1862```
1863
1864</YueDisplay>
1865
1866## 显式声明全局变量
1867
1868```yuescript
1869do
1870 global a = 1
1871 global *
1872 print "预先声明所有变量为全局变量"
1873 x = -> 1 + y + z
1874 y, z = 2, 3
1875
1876do
1877 global x = 1
1878 global ^
1879 print "只预先声明大写的变量为全局变量"
1880 a = 1
1881 B = 2
1882 local Temp = "一个局部值"
1883```
1884
1885<YueDisplay>
1886
1887```yue
1888do
1889 global a = 1
1890 global *
1891 print "预先声明所有变量为全局变量"
1892 x = -> 1 + y + z
1893 y, z = 2, 3
1894
1895do
1896 global x = 1
1897 global ^
1898 print "只预先声明大写的变量为全局变量"
1899 a = 1
1900 B = 2
1901 local Temp = "一个局部值"
1902```
1903
1904</YueDisplay>
1905
1906# 可变参数赋值
1907
1908&emsp;&emsp;你可以将函数返回的结果赋值给一个可变参数符号 `...`。然后使用 Lua 的方式访问其内容。
1909
1910```yuescript
1911list = [1, 2, 3, 4, 5]
1912fn = (ok) -> ok, table.unpack list
1913ok, ... = fn true
1914count = select '#', ...
1915first = select 1, ...
1916print ok, count, first
1917```
1918
1919<YueDisplay>
1920
1921```yue
1922list = [1, 2, 3, 4, 5]
1923fn = (ok) -> ok, table.unpack list
1924ok, ... = fn true
1925count = select '#', ...
1926first = select 1, ...
1927print ok, count, first
1928```
1929
1930</YueDisplay>
1931
1932# If 赋值
1933
1934&emsp;&emsp;`if` 和 `elseif` 代码块可以在条件表达式的位置进行赋值。在代码执行到要计算条件时,会首先进行赋值计算,并使用赋与的值作为分支判断的条件。赋值的变量仅在条件分支的代码块内有效,这意味着如果值不是真值,那么它就不会被用到。注意,你必须使用“海象运算符” `:=` 而不是 `=` 来做赋值。
1935
1936```yuescript
1937if user := database.find_user "moon"
1938 print user.name
1939```
1940
1941<YueDisplay>
1942
1943```yue
1944if user := database.find_user "moon"
1945 print user.name
1946```
1947
1948</YueDisplay>
1949
1950```yuescript
1951if hello := os.getenv "hello"
1952 print "你有 hello", hello
1953elseif world := os.getenv "world"
1954 print "你有 world", world
1955else
1956 print "什么都没有 :("
1957```
1958
1959<YueDisplay>
1960
1961```yue
1962if hello := os.getenv "hello"
1963 print "你有 hello", hello
1964elseif world := os.getenv "world"
1965 print "你有 world", world
1966else
1967 print "什么都没有 :("
1968```
1969
1970</YueDisplay>
1971
1972&emsp;&emsp;使用多个返回值的 If 赋值。只有第一个值会被检查,其他值都有同样的作用域。
1973
1974```yuescript
1975if success, result := pcall -> "无报错地获取结果"
1976 print result -- 变量 result 是有作用域的
1977print "好的"
1978```
1979
1980<YueDisplay>
1981
1982```yue
1983if success, result := pcall -> "无报错地获取结果"
1984 print result -- 变量 result 是有作用域的
1985print "好的"
1986```
1987
1988</YueDisplay>
1989
1990## While 赋值
1991
1992&emsp;&emsp;你可以在 while 循环中同样使用赋值来获取循环条件的值。
1993
1994```yuescript
1995while byte := stream\read_one!
1996 -- 对 byte 做一些操作
1997 print byte
1998```
1999
2000<YueDisplay>
2001
2002```yue
2003while byte := stream\read_one!
2004 -- 对 byte 做一些操作
2005 print byte
2006```
2007
2008</YueDisplay>
2009
2010# 解构赋值
2011
2012&emsp;&emsp;解构赋值是一种快速从 Lua 表中按名称或基于数组中的位置提取值的方法。
2013
2014&emsp;&emsp;通常当你看到一个字面量的 Lua 表,比如 `{1,2,3}`,它位于赋值的右侧,因为它是一个值。解构赋值语句的写法就是交换了字面量 Lua 表的角色,并将其放在赋值语句的左侧。
2015
2016&emsp;&emsp;最好是通过示例来解释。以下是如何从表格中解包前两个值的方法:
2017
2018```yuescript
2019thing = [1, 2]
2020
2021[a, b] = thing
2022print a, b
2023```
2024
2025<YueDisplay>
2026
2027```yue
2028thing = [1, 2]
2029
2030[a, b] = thing
2031print a, b
2032```
2033
2034</YueDisplay>
2035
2036&emsp;&emsp;在解构表格字面量中,键代表从右侧读取的键,值代表读取的值将被赋予的名称。
2037
2038```yuescript
2039obj = {
2040 hello: "world"
2041 day: "tuesday"
2042 length: 20
2043}
2044
2045{hello: hello, day: the_day} = obj
2046print hello, the_day
2047
2048:day = obj -- 可以不带大括号进行简单的解构
2049```
2050
2051<YueDisplay>
2052
2053```yue
2054obj = {
2055 hello: "world"
2056 day: "tuesday"
2057 length: 20
2058}
2059
2060{hello: hello, day: the_day} = obj
2061print hello, the_day
2062
2063:day = obj -- 可以不带大括号进行简单的解构
2064```
2065
2066</YueDisplay>
2067
2068&emsp;&emsp;这也适用于嵌套的数据结构:
2069
2070```yuescript
2071obj2 = {
2072 numbers: [1,2,3,4]
2073 properties: {
2074 color: "green"
2075 height: 13.5
2076 }
2077}
2078
2079{numbers: [first, second], properties: {color: color}} = obj2
2080print first, second, color
2081```
2082
2083<YueDisplay>
2084
2085```yue
2086obj2 = {
2087 numbers: [1,2,3,4]
2088 properties: {
2089 color: "green"
2090 height: 13.5
2091 }
2092}
2093
2094{numbers: [first, second], properties: {color: color}} = obj2
2095print first, second, color
2096```
2097
2098</YueDisplay>
2099
2100&emsp;&emsp;如果解构语句很复杂,也可以任意将其分散在几行中。稍微复杂一些的示例:
2101
2102```yuescript
2103{
2104 numbers: [first, second]
2105 properties: {
2106 color: color
2107 }
2108} = obj2
2109```
2110
2111<YueDisplay>
2112
2113```yue
2114{
2115 numbers: [first, second]
2116 properties: {
2117 color: color
2118 }
2119} = obj2
2120```
2121
2122</YueDisplay>
2123
2124&emsp;&emsp;有时候我们会需要从 Lua 表中提取值并将它们赋给与键同名的局部变量。为了避免编写重复代码,我们可以使用 **:** 前缀操作符:
2125
2126```yuescript
2127{:concat, :insert} = table
2128```
2129
2130<YueDisplay>
2131
2132```yue
2133{:concat, :insert} = table
2134```
2135
2136</YueDisplay>
2137
2138&emsp;&emsp;这样的用法与导入语法有些相似。但我们可以通过混合语法重命名我们想要提取的字段:
2139
2140```yuescript
2141{:mix, :max, random: rand} = math
2142```
2143
2144<YueDisplay>
2145
2146```yue
2147{:mix, :max, random: rand} = math
2148```
2149
2150</YueDisplay>
2151
2152&emsp;&emsp;在进行解构时,你可以指定默认值,如:
2153
2154```yuescript
2155{:name = "nameless", :job = "jobless"} = person
2156```
2157
2158<YueDisplay>
2159
2160```yue
2161{:name = "nameless", :job = "jobless"} = person
2162```
2163
2164</YueDisplay>
2165
2166&emsp;&emsp;在进行列表解构时,你可以使用`_`作为占位符:
2167
2168```yuescript
2169[_, two, _, four] = items
2170```
2171
2172<YueDisplay>
2173
2174```yue
2175[_, two, _, four] = items
2176```
2177
2178</YueDisplay>
2179
2180## 范围解构
2181
2182&emsp;&emsp;你可以使用展开运算符 `...` 在列表解构中来捕获一个范围的值到子列表中。这在当你想要从列表的开头和结尾提取特定元素,同时收集中间的元素时非常有用。
2183
2184```yuescript
2185orders = ["first", "second", "third", "fourth", "last"]
2186[first, ...bulk, last] = orders
2187print first -- 打印: first
2188print bulk -- 打印: {"second", "third", "fourth"}
2189print last -- 打印: last
2190```
2191
2192<YueDisplay>
2193
2194```yue
2195orders = ["first", "second", "third", "fourth", "last"]
2196[first, ...bulk, last] = orders
2197print first -- 打印: first
2198print bulk -- 打印: {"second", "third", "fourth"}
2199print last -- 打印: last
2200```
2201
2202</YueDisplay>
2203
2204&emsp;&emsp;展开运算符可以用在不同的位置来捕获不同的范围,并且你可以使用 `_` 作为占位符来表示你想跳过对应范围的捕获:
2205
2206```yuescript
2207-- 捕获第一个元素之后的所有元素
2208[first, ...rest] = orders
2209
2210-- 捕获最后一个元素之前的所有元素
2211[...start, last] = orders
2212
2213-- 跳过中间的元素,只捕获第一个和最后一个元素
2214[first, ..._, last] = orders
2215```
2216
2217<YueDisplay>
2218
2219```yue
2220-- 捕获第一个元素之后的所有元素
2221[first, ...rest] = orders
2222
2223-- 捕获最后一个元素之前的所有元素
2224[...start, last] = orders
2225
2226-- 跳过中间的元素,只捕获第一个和最后一个元素
2227[first, ..._, last] = orders
2228```
2229
2230</YueDisplay>
2231
2232## 在其它地方的解构赋值
2233
2234&emsp;&emsp;解构赋值也可以出现在其它隐式进行赋值的地方。一个例子是用在 for 循环中:
2235
2236```yuescript
2237tuples = [
2238 ["hello", "world"]
2239 ["egg", "head"]
2240]
2241
2242for [left, right] in *tuples
2243 print left, right
2244```
2245
2246<YueDisplay>
2247
2248```yue
2249tuples = [
2250 ["hello", "world"]
2251 ["egg", "head"]
2252]
2253
2254for [left, right] in *tuples
2255 print left, right
2256```
2257
2258</YueDisplay>
2259
2260&emsp;&emsp;我们知道数组表中的每个元素都是一个两项的元组,所以我们可以直接在 for 语句的名称子句中使用解构来解包它。
2261
2262# 使用 using 语句:防止破坏性赋值
2263
2264&emsp;&emsp;Lua 的变量作用域是降低代码复杂度的重要工具。然而,随着代码量的增加,维护这些变量可能变得更加困难。比如,看看下面的代码片段:
2265
2266```yuescript
2267i = 100
2268
2269-- 许多代码行...
2270
2271my_func = ->
2272 i = 10
2273 while i > 0
2274 print i
2275 i -= 1
2276
2277my_func!
2278
2279print i -- 将打印 0
2280```
2281
2282<YueDisplay>
2283
2284```yue
2285i = 100
2286
2287-- 许多代码行...
2288
2289my_func = ->
2290 i = 10
2291 while i > 0
2292 print i
2293 i -= 1
2294
2295my_func!
2296
2297print i -- 将打印 0
2298```
2299
2300</YueDisplay>
2301
2302&emsp;&emsp;在 `my_func` 中,我们不小心覆盖了变量 `i` 的值。虽然在这个例子中这个问题很明显,但在一个庞大的或者是由多人共同维护的代码库中,很难追踪每个变量的声明情况。
2303
2304&emsp;&emsp;如果我们可以明确指出哪些变量是我们想在当前作用域内修改的,并且防止我们不小心更改了其他作用域中同名的变量,那将大有裨益。
2305
2306&emsp;&emsp;`using` 语句就是为此而生。`using nil` 确保函数内部的赋值不会意外地影响到外部作用域的变量。我们只需将 `using` 子句放在函数的参数列表之后;若函数没有参数,则直接放在括号内即可。
2307
2308```yuescript
2309i = 100
2310
2311my_func = (using nil) ->
2312 i = "hello" -- 这里创建了一个新的局部变量
2313
2314my_func!
2315print i -- 打印 100,i 没有受到影响
2316```
2317
2318<YueDisplay>
2319
2320```yue
2321i = 100
2322
2323my_func = (using nil) ->
2324 i = "hello" -- 这里创建了一个新的局部变量
2325
2326my_func!
2327print i -- 打印 100,i 没有受到影响
2328```
2329
2330</YueDisplay>
2331
2332&emsp;&emsp;using子句中可以填写多个用逗号分隔名称。指定可以访问和修改的外部变量的名称:
2333
2334```yuescript
2335tmp = 1213
2336i, k = 100, 50
2337
2338my_func = (add using k, i) ->
2339 tmp = tmp + add -- 创建了一个新的局部tmp
2340 i += tmp
2341 k += tmp
2342
2343my_func(22)
2344print i, k -- 这些已经被更新
2345```
2346
2347<YueDisplay>
2348
2349```yue
2350tmp = 1213
2351i, k = 100, 50
2352
2353my_func = (add using k, i) ->
2354 tmp = tmp + add -- 创建了一个新的局部tmp
2355 i += tmp
2356 k += tmp
2357
2358my_func(22)
2359print i, k -- 这些已经被更新
2360```
2361
2362</YueDisplay>
2363
2364# 使用方法
2365
2366## Lua 模块
2367
2368&emsp;&emsp;在 Lua 中使用月之脚本模块:
2369
2370- **用法 1**
2371
2372 &emsp;&emsp;在 Lua 中引入 "你的脚本入口文件.yue"。
2373
2374 ```Lua
2375 require("yue")("你的脚本入口文件")
2376 ```
2377
2378 &emsp;&emsp;当你在同一路径下把 "你的脚本入口文件.yue" 编译成了 "你的脚本入口文件.lua" 时,仍然可以使用这个代码加载 .lua 代码文件。在其余的月之脚本文件中,只需正常使用 **require** 或 **import** 进行脚本引用即可。错误消息中的代码行号也会被正确处理。
2379
2380- **用法 2**
2381
2382 &emsp;&emsp;手动引入月之脚本模块并重写错误消息来帮助调试。
2383
2384 ```lua
2385 local yue = require("yue")
2386 yue.insert_loaders()
2387 local success, result = xpcall(function()
2388 return require("yuescript_module_name")
2389 end, function(err)
2390 return yue.traceback(err)
2391 end)
2392 ```
2393
2394- **用法 3**
2395
2396 &emsp;&emsp;在 Lua 中使用月之脚本编译器功能。
2397
2398 ```lua
2399 local yue = require("yue")
2400 local codes, err, globals = yue.to_lua([[
2401 f = ->
2402 print "hello world"
2403 f!
2404 ]],{
2405 implicit_return_root = true,
2406 reserve_line_number = true,
2407 lint_global = true,
2408 space_over_tab = false,
2409 options = {
2410 target = "5.4",
2411 path = "/script"
2412 }
2413 })
2414 ```
2415
2416## 月之脚本编译工具
2417
2418&emsp;&emsp;使用月之脚本编译工具:
2419
2420```shell
2421> yue -h
2422命令行用法: yue
2423 [选项] [<文件/目录>] ...
2424 yue -e <代码或文件> [参数...]
2425 yue -w [<目录>] [选项]
2426 yue -
2427
2428说明:
2429 - '-' 或 '--' 必须作为唯一且第一个参数,用于读取标准输入。
2430 - '-o/--output' 不能与多个输入文件一起使用。
2431 - '-w/--watch' 仅能用于目录,不能用于单个文件。
2432 - 使用 '-e/--execute' 时,后续的参数将作为脚本参数传递。
2433
2434选项:
2435 -h, --help 显示帮助信息并退出
2436 -e <字符串>, --execute <字符串> 执行文件或原始代码
2437 -m, --minify 生成压缩(最小化)代码
2438 -r, --rewrite 重写输出以匹配原始代码行号
2439 -t <目标路径>, --output-to <目标路径>
2440 指定编译后文件的输出路径
2441 -o <文件>, --output <文件> 将输出写入文件
2442 -p, --print 输出到标准输出
2443 -b, --benchmark 输出编译耗时(不写入文件)
2444 -g, --globals 显示用到的全局变量及其所在的名称、行号、列号
2445 -s, --spaces 用空格代替制表符(tab)输出代码
2446 -l, --line-numbers 输出源代码的行号
2447 -j, --no-implicit-return 禁用文件末尾的隐式返回
2448 -c, --reserve-comments 保留源代码中的注释
2449 -w [<目录>], --watch [<目录>]
2450 监视目录变化并自动编译
2451 -v, --version 显示版本信息
2452 - 从标准输入读取,输出到标准输出(仅能作为唯一参数)
2453 -- 等同于 '-',为兼容旧版本保留
2454
2455 --target <版本> 指定生成代码的 Lua 版本 (只能为 5.1 ~ 5.5)
2456 --path <路径字符串> 附加一个 Lua 搜索路径到 package.path
2457 --<键>=<值> 以 key=value 形式传递编译器选项(保持已有用法)
2458
2459 不带选项直接运行可进入交互模式(REPL),在交互模式里输入单独的符号 '$'
2460 可用于开始或结束多行模式。
2461```
2462
2463&emsp;&emsp;使用案例:
2464
2465&emsp;&emsp;递归编译当前路径下扩展名为 **.yue** 的每个月之脚本文件: **yue .**
2466
2467&emsp;&emsp;编译并将结果保存到目标路径: **yue -t /target/path/ .**
2468
2469&emsp;&emsp;编译并保留调试信息: **yue -l .**
2470
2471&emsp;&emsp;编译并生成压缩代码: **yue -m .**
2472
2473&emsp;&emsp;直接执行代码: **yue -e 'print 123'**
2474
2475&emsp;&emsp;执行一个月之脚本文件: **yue -e main.yue**
2476
2477# 介绍
2478
2479月之脚本(YueScript)是一种动态语言,可以编译为 Lua。它是 [MoonScript](https://github.com/leafo/moonscript) 的方言。用月之脚本编写的代码既有表现力又非常简洁。它适合编写一些更易于维护的代码,并在嵌入 Lua 的环境中运行,如游戏或网站服务器。
2480
2481Yue(月)是中文中“月亮”的名称。
2482
2483## 月之脚本概览
2484
2485```yuescript
2486-- 导入语法
2487import p, to_lua from "yue"
2488
2489-- 隐式对象
2490inventory =
2491 equipment:
2492 - "sword"
2493 - "shield"
2494 items:
2495 - name: "potion"
2496 count: 10
2497 - name: "bread"
2498 count: 3
2499
2500-- 列表推导
2501map = (arr, action) ->
2502 [action item for item in *arr]
2503
2504filter = (arr, cond) ->
2505 [item for item in *arr when cond item]
2506
2507reduce = (arr, init, action): init ->
2508 init = action init, item for item in *arr
2509
2510-- 管道操作符
2511[1, 2, 3]
2512 |> map (x) -> x * 2
2513 |> filter (x) -> x > 4
2514 |> reduce 0, (a, b) -> a + b
2515 |> print
2516
2517-- 元表操作
2518apple =
2519 size: 15
2520 <index>:
2521 color: 0x00ffff
2522
2523with apple
2524 p .size, .color, .<index> if .<>?
2525
2526-- 类似js的导出语法
2527export 🌛 = "月之脚本"
2528```
2529
2530<YueDisplay>
2531
2532```yue
2533-- 导入语法
2534import p, to_lua from "yue"
2535
2536-- 隐式对象
2537inventory =
2538 equipment:
2539 - "sword"
2540 - "shield"
2541 items:
2542 - name: "potion"
2543 count: 10
2544 - name: "bread"
2545 count: 3
2546
2547-- 列表推导
2548map = (arr, action) ->
2549 [action item for item in *arr]
2550
2551filter = (arr, cond) ->
2552 [item for item in *arr when cond item]
2553
2554reduce = (arr, init, action): init ->
2555 init = action init, item for item in *arr
2556
2557-- 管道操作符
2558[1, 2, 3]
2559 |> map (x) -> x * 2
2560 |> filter (x) -> x > 4
2561 |> reduce 0, (a, b) -> a + b
2562 |> print
2563
2564-- 元表操作
2565apple =
2566 size: 15
2567 <index>:
2568 color: 0x00ffff
2569
2570with apple
2571 p .size, .color, .<index> if .<>?
2572
2573-- 类似js的导出语法
2574export 🌛 = "月之脚本"
2575```
2576
2577</YueDisplay>
2578
2579## 关于 Dora SSR
2580
2581月之脚本是与开源游戏引擎 [Dora SSR](https://github.com/Dora-SSR/Dora-SSR) 一起开发和维护的。它已被用于创建引擎工具、游戏原型和演示,在实际的游戏项目中验证其能力,同时它也帮助增强了 Dora SSR 游戏引擎的开发体验。
2582
2583# 安装
2584
2585## Lua 模块
2586
2587&emsp;安装 [luarocks](https://luarocks.org),一个 Lua 模块的包管理器。然后作为 Lua 模块和可执行文件安装它:
2588
2589```shell
2590luarocks install yuescript
2591```
2592
2593&emsp;或者你可以自己构建 `yue.so` 文件:
2594
2595```shell
2596make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua
2597```
2598
2599&emsp;然后从路径 **bin/shared/yue.so** 获取二进制文件。
2600
2601## 构建二进制工具
2602
2603&emsp;克隆项目仓库,然后构建并安装可执行文件:
2604
2605```shell
2606make install
2607```
2608
2609&emsp;构建不带宏功能的月之脚本编译工具:
2610
2611```shell
2612make install NO_MACRO=true
2613```
2614
2615&emsp;构建不带内置Lua二进制文件的月之脚本编译工具:
2616
2617```shell
2618make install NO_LUA=true
2619```
2620
2621## 下载预编译的二进制程序
2622
2623&emsp;你可以下载预编译的二进制程序,包括兼容不同 Lua 版本的二进制可执行文件和库文件。
2624
2625&emsp;在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程序。
2626
2627# 条件语句
2628
2629```yuescript
2630have_coins = false
2631if have_coins
2632 print "有硬币"
2633else
2634 print "没有硬币"
2635```
2636
2637<YueDisplay>
2638
2639```yue
2640have_coins = false
2641if have_coins
2642 print "有硬币"
2643else
2644 print "没有硬币"
2645```
2646
2647</YueDisplay>
2648
2649&emsp;&emsp;对于简单的语句,也可以使用简短的语法:
2650
2651```yuescript
2652have_coins = false
2653if have_coins then print "有硬币" else print "没有硬币"
2654```
2655
2656<YueDisplay>
2657
2658```yue
2659have_coins = false
2660if have_coins then print "有硬币" else print "没有硬币"
2661```
2662
2663</YueDisplay>
2664
2665&emsp;&emsp;因为 if 语句可以用作表达式,所以也可以这样写:
2666
2667```yuescript
2668have_coins = false
2669print if have_coins then "有硬币" else "没有硬币"
2670```
2671
2672<YueDisplay>
2673
2674```yue
2675have_coins = false
2676print if have_coins then "有硬币" else "没有硬币"
2677```
2678
2679</YueDisplay>
2680
2681&emsp;&emsp;条件语句也可以作为表达式用在返回语句和赋值语句中:
2682
2683```yuescript
2684is_tall = (name) ->
2685 if name == "Rob"
2686 true
2687 else
2688 false
2689
2690message = if is_tall "Rob"
2691 "我很高"
2692else
2693 "我不是很高"
2694
2695print message -- 打印: 我很高
2696```
2697
2698<YueDisplay>
2699
2700```yue
2701is_tall = (name) ->
2702 if name == "Rob"
2703 true
2704 else
2705 false
2706
2707message = if is_tall "Rob"
2708 "我很高"
2709else
2710 "我不是很高"
2711
2712print message -- 打印: 我很高
2713```
2714
2715</YueDisplay>
2716
2717&emsp;&emsp;if 的反义词是 unless(相当于 if not,正如“如果”对应“除非”):
2718
2719```yuescript
2720unless os.date("%A") == "Monday"
2721 print "今天不是星期一!"
2722```
2723
2724<YueDisplay>
2725
2726```yue
2727unless os.date("%A") == "Monday"
2728 print "今天不是星期一!"
2729```
2730
2731</YueDisplay>
2732
2733```yuescript
2734print "你真幸运!" unless math.random! > 0.1
2735```
2736
2737<YueDisplay>
2738
2739```yue
2740print "你真幸运!" unless math.random! > 0.1
2741```
2742
2743</YueDisplay>
2744
2745## 范围表达式
2746
2747&emsp;&emsp;你可以使用范围表达式来编写进行范围检查的代码。
2748
2749```yuescript
2750a = 5
2751
2752if a in [1, 3, 5, 7]
2753 print "检查离散值的相等性"
2754
2755if a in list
2756 print "检查`a`是否在列表中"
2757```
2758
2759<YueDisplay>
2760
2761```yue
2762a = 5
2763
2764if a in [1, 3, 5, 7]
2765 print "检查离散值的相等性"
2766
2767if a in list
2768 print "检查`a`是否在列表中"
2769```
2770
2771</YueDisplay>
2772
2773# for 循环
2774
2775&emsp;&emsp;Lua 中有两种 for 循环形式,数字型和通用型:
2776
2777```yuescript
2778for i = 10, 20
2779 print i
2780
2781for k = 1, 15, 2 -- 提供了一个遍历的步长
2782 print k
2783
2784for key, value in pairs object
2785 print key, value
2786```
2787
2788<YueDisplay>
2789
2790```yue
2791for i = 10, 20
2792 print i
2793
2794for k = 1, 15, 2 -- 提供了一个遍历的步长
2795 print k
2796
2797for key, value in pairs object
2798 print key, value
2799```
2800
2801</YueDisplay>
2802
2803&emsp;&emsp;可以使用切片和 **\*** 操作符,就像在列表推导中一样:
2804
2805```yuescript
2806for item in *items[2, 4]
2807 print item
2808```
2809
2810<YueDisplay>
2811
2812```yue
2813for item in *items[2, 4]
2814 print item
2815```
2816
2817</YueDisplay>
2818
2819&emsp;&emsp;当代码语句只有一行时,循环语句也都可以写作更短的语法:
2820
2821```yuescript
2822for item in *items do print item
2823
2824for j = 1, 10, 3 do print j
2825```
2826
2827<YueDisplay>
2828
2829```yue
2830for item in *items do print item
2831
2832for j = 1, 10, 3 do print j
2833```
2834
2835</YueDisplay>
2836
2837&emsp;&emsp;for 循环也可以用作表达式。for 循环主体中的最后一条语句会被强制转换为一个返回值的表达式,并会将表达式计算结果的值追加到一个作为结果的数组表中。
2838
2839&emsp;&emsp;将每个偶数加倍:
2840
2841```yuescript
2842doubled_evens = for i = 1, 20
2843 if i % 2 == 0
2844 i * 2
2845 else
2846 i
2847```
2848
2849<YueDisplay>
2850
2851```yue
2852doubled_evens = for i = 1, 20
2853 if i % 2 == 0
2854 i * 2
2855 else
2856 i
2857```
2858
2859</YueDisplay>
2860
2861&emsp;&emsp;此外,for 循环还支持带返回值的 break 语句,这样循环本身就可以作为一个表达式,在满足条件时提前退出并返回有意义的结果。for 循环表达式支持 `break` 返回多个值。
2862
2863&emsp;&emsp;例如,查找第一个大于 10 的数字:
2864
2865```yuescript
2866first_large = for n in *numbers
2867 break n if n > 10
2868```
2869
2870<YueDisplay>
2871
2872```yue
2873first_large = for n in *numbers
2874 break n if n > 10
2875```
2876
2877</YueDisplay>
2878
2879```yuescript
2880key, score = for k, v in pairs data
2881 break k, v * 10 if k == "target"
2882```
2883
2884<YueDisplay>
2885
2886```yue
2887key, score = for k, v in pairs data
2888 break k, v * 10 if k == "target"
2889```
2890
2891</YueDisplay>
2892
2893&emsp;&emsp;你还可以结合 for 循环表达式与 continue 语句来过滤值。
2894
2895&emsp;&emsp;注意出现在函数体末尾的 for 循环,不会被当作是一个表达式并将循环结果累积到一个列表中作为返回值(相反,函数将返回 nil)。如果要函数末尾的循环转换为列表表达式,可以显式地使用返回语句加 for 循环表达式。
2896
2897```yuescript
2898func_a = -> for i = 1, 10 do print i
2899func_b = -> return for i = 1, 10 do i
2900
2901print func_a! -- 打印 nil
2902print func_b! -- 打印 table 对象
2903```
2904
2905<YueDisplay>
2906
2907```yue
2908func_a = -> for i = 1, 10 do print i
2909func_b = -> return for i = 1, 10 do i
2910
2911print func_a! -- 打印 nil
2912print func_b! -- 打印 table 对象
2913```
2914
2915</YueDisplay>
2916
2917&emsp;&emsp;这样做是为了避免在不需要返回循环结果的函数,创建无效的返回值表格。
2918
2919# continue 语句
2920
2921&emsp;&emsp;继续语句可以用来跳出当前的循环迭代。
2922
2923```yuescript
2924i = 0
2925while i < 10
2926 i += 1
2927 continue if i % 2 == 0
2928 print i
2929```
2930
2931<YueDisplay>
2932
2933```yue
2934i = 0
2935while i < 10
2936 i += 1
2937 continue if i % 2 == 0
2938 print i
2939```
2940
2941</YueDisplay>
2942
2943&emsp;&emsp;继续语句也可以与各种循环表达式一起使用,以防止当前的循环迭代结果累积到结果列表中。以下示例将数组表过滤为仅包含偶数的数组:
2944
2945```yuescript
2946my_numbers = [1, 2, 3, 4, 5, 6]
2947odds = for x in *my_numbers
2948 continue if x % 2 == 1
2949 x
2950```
2951
2952<YueDisplay>
2953
2954```yue
2955my_numbers = [1, 2, 3, 4, 5, 6]
2956odds = for x in *my_numbers
2957 continue if x % 2 == 1
2958 x
2959```
2960
2961</YueDisplay>
2962
2963# switch 语句
2964
2965&emsp;&emsp;switch 语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和 if 语句一样,switch 语句在最后可以接一个 else 代码块来处理没有匹配的情况。在生成的 Lua 代码中,进行比较是使用 == 操作符完成的。switch 语句中也可以使用赋值表达式来储存临时变量值。
2966
2967```yuescript
2968switch name := "Dan"
2969 when "Robert"
2970 print "你是Robert"
2971 when "Dan", "Daniel"
2972 print "你的名字是Dan"
2973 else
2974 print "我不认识你,你的名字是#{name}"
2975```
2976
2977<YueDisplay>
2978
2979```yue
2980switch name := "Dan"
2981 when "Robert"
2982 print "你是Robert"
2983 when "Dan", "Daniel"
2984 print "你的名字是Dan"
2985 else
2986 print "我不认识你,你的名字是#{name}"
2987```
2988
2989</YueDisplay>
2990
2991&emsp;&emsp;switch 语句的 when 子句中可以通过使用逗号分隔的列表来匹配多个值。
2992
2993&emsp;&emsp;switch 语句也可以作为表达式使用,下面我们可以将 switch 语句返回的结果分配给一个变量:
2994
2995```yuescript
2996b = 1
2997next_number = switch b
2998 when 1
2999 2
3000 when 2
3001 3
3002 else
3003 error "数字数得太大了!"
3004```
3005
3006<YueDisplay>
3007
3008```yue
3009b = 1
3010next_number = switch b
3011 when 1
3012 2
3013 when 2
3014 3
3015 else
3016 error "数字数得太大了!"
3017```
3018
3019</YueDisplay>
3020
3021&emsp;&emsp;我们可以使用 then 关键字在 when 子句的同一行上编写处理代码。else 代码块的后续代码中要写在同一行上不需要额外的关键字。
3022
3023```yuescript
3024msg = switch math.random(1, 5)
3025 when 1 then "你很幸运"
3026 when 2 then "你差点很幸运"
3027 else "不太幸运"
3028```
3029
3030<YueDisplay>
3031
3032```yue
3033msg = switch math.random(1, 5)
3034 when 1 then "你很幸运"
3035 when 2 then "你差点很幸运"
3036 else "不太幸运"
3037```
3038
3039</YueDisplay>
3040
3041&emsp;&emsp;如果在编写 switch 语句时希望少写一个缩进,那么你可以把第一个 when 子句放在 switch 开始语句的第一行,然后后续的子语句就都可以都少写一个缩进。
3042
3043```yuescript
3044switch math.random(1, 5)
3045 when 1
3046 print "你很幸运" -- 两个缩进级别
3047 else
3048 print "不太幸运"
3049
3050switch math.random(1, 5) when 1
3051 print "你很幸运" -- 一个缩进级别
3052else
3053 print "不太幸运"
3054```
3055
3056<YueDisplay>
3057
3058```yue
3059switch math.random(1, 5)
3060 when 1
3061 print "你很幸运" -- 两个缩进级别
3062 else
3063 print "不太幸运"
3064
3065switch math.random(1, 5) when 1
3066 print "你很幸运" -- 一个缩进级别
3067else
3068 print "不太幸运"
3069```
3070
3071</YueDisplay>
3072
3073&emsp;&emsp;值得注意的是,在生成 Lua 代码时,我们要做检查的目标变量会放在 == 表达式的右侧。当你希望给 when 子句的比较对象定义一个 \_\_eq 元方法来重载判断逻辑时,可能会有用。
3074
3075## 表格匹配
3076
3077&emsp;&emsp;在 switch 的 when 子句中,如果期待检查目标是一个表格,且可以通过特定的结构进行解构并获得非 nil 值,那么你可以尝试使用表格匹配的语法。
3078
3079```yuescript
3080items =
3081 * x: 100
3082 y: 200
3083 * width: 300
3084 height: 400
3085
3086for item in *items
3087 switch item
3088 when :x, :y
3089 print "Vec2 #{x}, #{y}"
3090 when :width, :height
3091 print "尺寸 #{width}, #{height}"
3092```
3093
3094<YueDisplay>
3095
3096```yue
3097items =
3098 * x: 100
3099 y: 200
3100 * width: 300
3101 height: 400
3102
3103for item in *items
3104 switch item
3105 when :x, :y
3106 print "Vec2 #{x}, #{y}"
3107 when :width, :height
3108 print "尺寸 #{width}, #{height}"
3109```
3110
3111</YueDisplay>
3112
3113&emsp;&emsp;你可以使用默认值来选择性地解构表格的某些字段。
3114
3115```yuescript
3116item = {}
3117
3118{pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos')
3119
3120switch item
3121 when {pos: {:x = 50, :y = 200}}
3122 print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过
3123```
3124
3125<YueDisplay>
3126
3127```yue
3128item = {}
3129
3130{pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos')
3131
3132switch item
3133 when {pos: {:x = 50, :y = 200}}
3134 print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过
3135```
3136
3137</YueDisplay>
3138
3139&emsp;&emsp;你也可以匹配数组元素、表格字段,甚至使用数组或表格字面量来匹配嵌套的结构。
3140
3141&emsp;&emsp;匹配数组元素。
3142
3143```yuescript
3144switch tb
3145 when [1, 2, 3]
3146 print "1, 2, 3"
3147 when [1, b, 3]
3148 print "1, #{b}, 3"
3149 when [1, 2, b = 3] -- 变量b有默认值
3150 print "1, 2, #{b}"
3151```
3152
3153<YueDisplay>
3154
3155```yue
3156switch tb
3157 when [1, 2, 3]
3158 print "1, 2, 3"
3159 when [1, b, 3]
3160 print "1, #{b}, 3"
3161 when [1, 2, b = 3] -- 变量b有默认值
3162 print "1, 2, #{b}"
3163```
3164
3165</YueDisplay>
3166
3167&emsp;&emsp;匹配表格字段。
3168
3169```yuescript
3170switch tb
3171 when success: true, :result
3172 print "成功", result
3173 when success: false
3174 print "失败", result
3175 else
3176 print "无效值"
3177```
3178
3179<YueDisplay>
3180
3181```yue
3182switch tb
3183 when success: true, :result
3184 print "成功", result
3185 when success: false
3186 print "失败", result
3187 else
3188 print "无效值"
3189```
3190
3191</YueDisplay>
3192
3193&emsp;&emsp;匹配嵌套的表格结构。
3194
3195```yuescript
3196switch tb
3197 when data: {type: "success", :content}
3198 print "成功", content
3199 when data: {type: "error", :content}
3200 print "失败", content
3201 else
3202 print "无效值"
3203```
3204
3205<YueDisplay>
3206
3207```yue
3208switch tb
3209 when data: {type: "success", :content}
3210 print "成功", content
3211 when data: {type: "error", :content}
3212 print "失败", content
3213 else
3214 print "无效值"
3215```
3216
3217</YueDisplay>
3218
3219&emsp;&emsp;匹配表格数组。
3220
3221```yuescript
3222switch tb
3223 when [
3224 {a: 1, b: 2}
3225 {a: 3, b: 4}
3226 {a: 5, b: 6}
3227 fourth
3228 ]
3229 print "匹配成功", fourth
3230```
3231
3232<YueDisplay>
3233
3234```yue
3235switch tb
3236 when [
3237 {a: 1, b: 2}
3238 {a: 3, b: 4}
3239 {a: 5, b: 6}
3240 fourth
3241 ]
3242 print "匹配成功", fourth
3243```
3244
3245</YueDisplay>
3246
3247&emsp;&emsp;匹配一个列表并捕获特定范围内的元素。
3248
3249```yuescript
3250segments = ["admin", "users", "logs", "view"]
3251switch segments
3252 when [...groups, resource, action]
3253 print "Group:", groups -- 打印: {"admin", "users"}
3254 print "Resource:", resource -- 打印: "logs"
3255 print "Action:", action -- 打印: "view"
3256```
3257
3258<YueDisplay>
3259
3260```yue
3261segments = ["admin", "users", "logs", "view"]
3262switch segments
3263 when [...groups, resource, action]
3264 print "Group:", groups -- 打印: {"admin", "users"}
3265 print "Resource:", resource -- 打印: "logs"
3266 print "Action:", action -- 打印: "view"
3267```
3268
3269</YueDisplay>
3270
3271# while 循环
3272
3273&emsp;&emsp;在月之脚本中的 while 循环支持几种不同的写法:
3274
3275```yuescript
3276i = 10
3277while i > 0
3278 print i
3279 i -= 1
3280
3281while running == true do my_function!
3282```
3283
3284<YueDisplay>
3285
3286```yue
3287i = 10
3288while i > 0
3289 print i
3290 i -= 1
3291
3292while running == true do my_function!
3293```
3294
3295</YueDisplay>
3296
3297```yuescript
3298i = 10
3299until i == 0
3300 print i
3301 i -= 1
3302
3303until running == false do my_function!
3304```
3305
3306<YueDisplay>
3307
3308```yue
3309i = 10
3310until i == 0
3311 print i
3312 i -= 1
3313until running == false do my_function!
3314```
3315
3316</YueDisplay>
3317
3318&emsp;&emsp;像 for 循环的语法一样,while 循环也可以作为一个表达式使用。while / until 循环表达式支持 `break` 返回多个值。
3319
3320```yuescript
3321value, doubled = while true
3322 n = get_next!
3323 break n, n * 2 if n > 10
3324```
3325
3326<YueDisplay>
3327
3328```yue
3329value, doubled = while true
3330 n = get_next!
3331 break n, n * 2 if n > 10
3332```
3333
3334</YueDisplay>
3335
3336&emsp;&emsp;为了使函数返回 while 循环的累积列表值,必须明确使用返回语句返回 while 循环表达式。
3337
3338## repeat 循环
3339
3340&emsp;&emsp;repeat 循环是从 Lua 语言中搬过来的相似语法:
3341
3342```yuescript
3343i = 10
3344repeat
3345 print i
3346 i -= 1
3347until i == 0
3348```
3349
3350<YueDisplay>
3351
3352```yue
3353i = 10
3354repeat
3355 print i
3356 i -= 1
3357until i == 0
3358```
3359
3360</YueDisplay>
3361
3362&emsp;&emsp;repeat 循环表达式同样支持 `break` 返回多个值:
3363
3364```yuescript
3365i = 1
3366value, scaled = repeat
3367 break i, i * 100 if i > 3
3368 i += 1
3369until false
3370```
3371
3372<YueDisplay>
3373
3374```yue
3375i = 1
3376value, scaled = repeat
3377 break i, i * 100 if i > 3
3378 i += 1
3379until false
3380```
3381
3382</YueDisplay>
3383
3384# 函数存根
3385
3386&emsp;&emsp;在编程中,将对象的方法作为函数类型的值进行传递是一种常见做法,尤其是在将实例方法作为回调函数传递给其他函数的情形中。当目标函数需要将该对象作为其第一个参数时,我们需要找到一种方式将对象和函数绑定在一起,以便能够正确地调用该函数。
3387
3388&emsp;&emsp;函数存根(stub)语法提供了一种便捷的方法来创建一个新的闭包函数,这个函数将对象和原函数绑定在一起。这样,当调用这个新创建的函数时,它会在正确的对象上下文中执行原有的函数。
3389
3390&emsp;&emsp;这种语法类似于使用 \ 操作符调用实例方法的方式,区别在于,这里不需要在 \ 操作符后面附加参数列表。
3391
3392```yuescript
3393my_object = {
3394 value: 1000
3395 write: => print "值为:", @value
3396}
3397
3398run_callback = (func) ->
3399 print "运行回调..."
3400 func!
3401
3402-- 这样写不起作用:
3403-- 函数没有引用my_object
3404run_callback my_object.write
3405
3406-- 函数存根语法
3407-- 让我们把对象捆绑到一个新函数中
3408run_callback my_object\write
3409```
3410
3411<YueDisplay>
3412
3413```yue
3414my_object = {
3415 value: 1000
3416 write: => print "值为:", @value
3417}
3418
3419run_callback = (func) ->
3420 print "运行回调..."
3421 func!
3422
3423-- 这样写不起作用:
3424-- 函数没有引用my_object
3425run_callback my_object.write
3426
3427-- 函数存根语法
3428-- 让我们把对象捆绑到一个新函数中
3429run_callback my_object\write
3430```
3431
3432</YueDisplay>
3433
3434# 反向回调
3435
3436&emsp;&emsp;反向回调用于减少函数回调的嵌套。它们使用指向左侧的箭头,并且默认会被定义为传入后续函数调用的最后一个参数。它的语法大部分与常规箭头函数相同,只是它指向另一方向,并且后续的函数体不需要进行缩进。
3437
3438```yuescript
3439x <- f
3440print "hello" .. x
3441```
3442
3443<YueDisplay>
3444
3445```yue
3446x <- f
3447print "hello" .. x
3448```
3449
3450</YueDisplay>
3451
3452&emsp;&emsp;月之脚本也提供了粗箭头反向回调函数。
3453
3454```yuescript
3455<= f
3456print @value
3457```
3458
3459<YueDisplay>
3460
3461```yue
3462<= f
3463print @value
3464```
3465
3466</YueDisplay>
3467
3468&emsp;&emsp;你可以通过一个占位符指定回调函数的传参位置。
3469
3470```yuescript
3471(x) <- map _, [1, 2, 3]
3472x * 2
3473```
3474
3475<YueDisplay>
3476
3477```yue
3478(x) <- map _, [1, 2, 3]
3479x * 2
3480```
3481
3482</YueDisplay>
3483
3484&emsp;&emsp;如果你希望在反向回调处理后继续编写更多其它的代码,可以使用 do 语句将不属于反向回调的代码分隔开。对于非粗箭头函数的反向回调,回调返回值的括号也是可以省略的。
3485
3486```yuescript
3487result, msg = do
3488 data <- readAsync "文件名.txt"
3489 print data
3490 info <- processAsync data
3491 check info
3492print result, msg
3493```
3494
3495<YueDisplay>
3496
3497```yue
3498result, msg = do
3499 data <- readAsync "文件名.txt"
3500 print data
3501 info <- processAsync data
3502 check info
3503print result, msg
3504```
3505
3506</YueDisplay>
3507
3508# 函数字面量
3509
3510&emsp;&emsp;所有函数都是使用月之脚本的函数表达式创建的。一个简单的函数可以用箭头表示为:**->**。
3511
3512```yuescript
3513my_function = ->
3514my_function() -- 调用空函数
3515```
3516
3517<YueDisplay>
3518
3519```yue
3520my_function = ->
3521my_function() -- 调用空函数
3522```
3523
3524</YueDisplay>
3525
3526&emsp;&emsp;函数体可以是紧跟在箭头后的一个语句,或者是在后面的行上使用同样缩进的一系列语句:
3527
3528```yuescript
3529func_a = -> print "你好,世界"
3530
3531func_b = ->
3532 value = 100
3533 print "这个值是:", value
3534```
3535
3536<YueDisplay>
3537
3538```yue
3539func_a = -> print "你好,世界"
3540
3541func_b = ->
3542 value = 100
3543 print "这个值是:", value
3544```
3545
3546</YueDisplay>
3547
3548&emsp;&emsp;如果一个函数没有参数,可以使用 **\!** 操作符调用它,而不是空括号。使用 **\!** 调用没有参数的函数是推荐的写法。
3549
3550```yuescript
3551func_a!
3552func_b()
3553```
3554
3555<YueDisplay>
3556
3557```yue
3558func_a!
3559func_b()
3560```
3561
3562</YueDisplay>
3563
3564&emsp;&emsp;带有参数的函数可以通过在箭头前加上括号中的参数名列表来进行创建:
3565
3566```yuescript
3567sum = (x, y) -> print "数字的和", x + y
3568```
3569
3570<YueDisplay>
3571
3572```yue
3573sum = (x, y) -> print "数字的和", x + y
3574```
3575
3576</YueDisplay>
3577
3578&emsp;&emsp;函数可以通过在函数名后列出参数来调用。当对函数做嵌套的调用时,后面列出的参数会应用于左侧最近的函数。
3579
3580```yuescript
3581sum 10, 20
3582print sum 10, 20
3583
3584a b c "a", "b", "c"
3585```
3586
3587<YueDisplay>
3588
3589```yue
3590sum 10, 20
3591print sum 10, 20
3592
3593a b c "a", "b", "c"
3594```
3595
3596</YueDisplay>
3597
3598&emsp;&emsp;为了避免在调用函数时产生歧义,也可以使用括号将参数括起来。比如在以下的例子中是必需的,这样才能确保参数被传入到正确的函数。
3599
3600```yuescript
3601print "x:", sum(10, 20), "y:", sum(30, 40)
3602```
3603
3604<YueDisplay>
3605
3606```yue
3607print "x:", sum(10, 20), "y:", sum(30, 40)
3608```
3609
3610</YueDisplay>
3611
3612&emsp;&emsp;注意:函数名与开始括号之间不能有任何空格。
3613
3614&emsp;&emsp;函数会将函数体中的最后一个语句强制转换为返回语句,这被称作隐式返回:
3615
3616```yuescript
3617sum = (x, y) -> x + y
3618print "数字的和是", sum 10, 20
3619```
3620
3621<YueDisplay>
3622
3623```yue
3624sum = (x, y) -> x + y
3625print "数字的和是", sum 10, 20
3626```
3627
3628</YueDisplay>
3629
3630&emsp;&emsp;如果你需要做显式返回,可以使用 return 关键字:
3631
3632```yuescript
3633sum = (x, y) -> return x + y
3634```
3635
3636<YueDisplay>
3637
3638```yue
3639sum = (x, y) -> return x + y
3640```
3641
3642</YueDisplay>
3643
3644&emsp;&emsp;就像在Lua中一样,函数可以返回多个值。最后一个语句必须是由逗号分隔的值列表:
3645
3646```yuescript
3647mystery = (x, y) -> x + y, x - y
3648a, b = mystery 10, 20
3649```
3650
3651<YueDisplay>
3652
3653```yue
3654mystery = (x, y) -> x + y, x - y
3655a, b = mystery 10, 20
3656```
3657
3658</YueDisplay>
3659
3660## 粗箭头
3661
3662&emsp;&emsp;因为在 Lua 中调用方法时,经常习惯将对象作为第一个参数传入,所以月之脚本提供了一种特殊的语法来创建自动包含 self 参数的函数。
3663
3664```yuescript
3665func = (num) => @value + num
3666```
3667
3668<YueDisplay>
3669
3670```yue
3671func = (num) => @value + num
3672```
3673
3674</YueDisplay>
3675
3676## 参数默认值
3677
3678&emsp;&emsp;可以为函数的参数提供默认值。如果参数的值为 nil,则确定该参数为空。任何具有默认值的 nil 参数在函数体运行之前都会被替换。
3679
3680```yuescript
3681my_function = (name = "某物", height = 100) ->
3682 print "你好,我是", name
3683 print "我的高度是", height
3684```
3685
3686<YueDisplay>
3687
3688```yue
3689my_function = (name = "某物", height = 100) ->
3690 print "你好,我是", name
3691 print "我的高度是", height
3692```
3693
3694</YueDisplay>
3695
3696&emsp;&emsp;函数参数的默认值表达式在函数体中会按参数声明的顺序进行计算。因此,在默认值的表达式中可以访问先前声明的参数。
3697
3698```yuescript
3699some_args = (x = 100, y = x + 1000) ->
3700 print x + y
3701```
3702
3703<YueDisplay>
3704
3705```yue
3706some_args = (x = 100, y = x + 1000) ->
3707 print x + y
3708```
3709
3710</YueDisplay>
3711
3712## 注意事项
3713
3714&emsp;&emsp;由于月之脚本支持无需括号的表达式式函数调用,因此为了避免因空白字符造成的解析歧义,需要进行一些限制。
3715
3716&emsp;&emsp;减号(-)在表达式中既可以作为一元取反操作符,也可以作为二元减法操作符。请注意下面这些示例的编译方式:
3717
3718```yuescript
3719a = x - 10
3720b = x-10
3721c = x -y
3722d = x- z
3723```
3724
3725<YueDisplay>
3726
3727```yue
3728a = x - 10
3729b = x-10
3730c = x -y
3731d = x- z
3732```
3733
3734</YueDisplay>
3735
3736&emsp;&emsp;当函数调用的第一个参数是字符串字面量时,可以通过空白控制其优先级。在 Lua 中,常见的写法是调用仅有一个字符串或表字面量参数的函数时省略括号。
3737
3738&emsp;&emsp;当变量名和字符串字面量之间没有空格时,函数的调用优先级高于后续表达式,因此此时无法再传入其他参数。
3739
3740&emsp;&emsp;当变量名和字符串字面量之间有空格时,字符串字面量会作为后续表达式(如果存在)的参数,这样可以传递参数列表。
3741
3742```yuescript
3743x = func"hello" + 100
3744y = func "hello" + 100
3745```
3746
3747<YueDisplay>
3748
3749```yue
3750x = func"hello" + 100
3751y = func "hello" + 100
3752```
3753
3754</YueDisplay>
3755
3756## 多行参数
3757
3758&emsp;&emsp;当调用接收大量参数的函数时,将参数列表分成多行是很方便的。由于月之脚本语言对空白字符的敏感性,做参数列表的分割时务必要小心。
3759
3760&emsp;&emsp;如果要将参数列表写到下一行,那么当前行必须以逗号结束。并且下一行的缩进必须比当前的缩进多。一旦做了参数的缩进,所有其他参数列表的行必须保持相同的缩进级别,以成为参数列表的一部分。
3761
3762```yuescript
3763my_func 5, 4, 3,
3764 8, 9, 10
3765
3766cool_func 1, 2,
3767 3, 4,
3768 5, 6,
3769 7, 8
3770```
3771
3772<YueDisplay>
3773
3774```yue
3775my_func 5, 4, 3,
3776 8, 9, 10
3777
3778cool_func 1, 2,
3779 3, 4,
3780 5, 6,
3781 7, 8
3782```
3783
3784</YueDisplay>
3785
3786&emsp;&emsp;这种调用方式可以做嵌套。并通过缩进级别来确定参数属于哪一个函数。
3787
3788```yuescript
3789my_func 5, 6, 7,
3790 6, another_func 6, 7, 8,
3791 9, 1, 2,
3792 5, 4
3793```
3794
3795<YueDisplay>
3796
3797```yue
3798my_func 5, 6, 7,
3799 6, another_func 6, 7, 8,
3800 9, 1, 2,
3801 5, 4
3802```
3803
3804</YueDisplay>
3805
3806&emsp;&emsp;因为 Lua 表也使用逗号作为分隔符,这种缩进语法有助于让值成为参数列表的一部分,而不是 Lua 表的一部分。
3807
3808```yuescript
3809x = [
3810 1, 2, 3, 4, a_func 4, 5,
3811 5, 6,
3812 8, 9, 10
3813]
3814```
3815
3816<YueDisplay>
3817
3818```yue
3819x = [
3820 1, 2, 3, 4, a_func 4, 5,
3821 5, 6,
3822 8, 9, 10
3823]
3824```
3825
3826</YueDisplay>
3827
3828&emsp;&emsp;有个不常见的写法可以注意一下,如果我们将在后面使用较低的缩进,我们可以为函数参数提供更深的缩进来区分列表的归属。
3829
3830```yuescript
3831y = [ my_func 1, 2, 3,
3832 4, 5,
3833 5, 6, 7
3834]
3835```
3836
3837<YueDisplay>
3838
3839```yue
3840y = [ my_func 1, 2, 3,
3841 4, 5,
3842 5, 6, 7
3843]
3844```
3845
3846</YueDisplay>
3847
3848&emsp;&emsp;对于其它有代码块跟随的语句,比如条件语句,也可以通过小心安排缩进来做类似的事。比如我们可以通过调整缩进级别来控制一些值归属于哪个语句:
3849
3850```yuescript
3851if func 1, 2, 3,
3852 "你好",
3853 "世界"
3854 print "你好"
3855 print "我在if内部"
3856
3857if func 1, 2, 3,
3858 "你好",
3859 "世界"
3860 print "hello"
3861 print "我在if内部"
3862```
3863
3864<YueDisplay>
3865
3866```yue
3867if func 1, 2, 3,
3868 "你好",
3869 "世界"
3870 print "你好"
3871 print "我在if内部"
3872
3873if func 1, 2, 3,
3874 "你好",
3875 "世界"
3876 print "你好"
3877 print "我在if内部"
3878```
3879
3880</YueDisplay>
3881
3882## 参数解构
3883
3884&emsp;&emsp;月之脚本支持在函数形参位置对传入对象进行解构。适用两类解构表子面量:
3885
3886- 使用 {} 包裹的字面量/对象形参,支持提供获得空字段时的默认值(例如 {:a, :b}、{a: a1 = 123})。
3887
3888- 无 {} 包裹、以键值/简写键序列开头,直至遇到其它表达式终止(例如 :a, b: b1, :c),表示从同一个对象中解构多个字段。
3889
3890```yuescript
3891f1 = (:a, :b, :c) ->
3892 print a, b, c
3893
3894f1 a: 1, b: "2", c: {}
3895
3896f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3897 print a1, b, c
3898
3899arg1 = {a: 0}
3900f2 arg1, arg2
3901```
3902
3903<YueDisplay>
3904
3905```yue
3906f1 = (:a, :b, :c) ->
3907 print a, b, c
3908
3909f1 a: 1, b: "2", c: {}
3910
3911f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
3912 print a1, b, c
3913
3914arg1 = {a: 0}
3915f2 arg1, arg2
3916```
3917
3918</YueDisplay>
3919
3920## 前置返回表达式
3921
3922&emsp;&emsp;在深度嵌套的函数体中,为了提升返回值的可读性及编写便利性,我们新增了 “前置返回表达式” 语法。其形式如下:
3923
3924```yuescript
3925findFirstEven = (list): nil ->
3926 for item in *list
3927 if type(item) == "table"
3928 for sub in *item
3929 if sub % 2 == 0
3930 return sub
3931```
3932
3933<YueDisplay>
3934
3935```yue
3936findFirstEven = (list): nil ->
3937 for item in *list
3938 if type(item) == "table"
3939 for sub in *item
3940 if sub % 2 == 0
3941 return sub
3942```
3943
3944</YueDisplay>
3945
3946&emsp;&emsp;这个写法等价于:
3947
3948```yuescript
3949findFirstEven = (list) ->
3950 for item in *list
3951 if type(item) == "table"
3952 for sub in *item
3953 if sub % 2 == 0
3954 return sub
3955 nil
3956```
3957
3958<YueDisplay>
3959
3960```yue
3961findFirstEven = (list) ->
3962 for item in *list
3963 if type(item) == "table"
3964 for sub in *item
3965 if sub % 2 == 0
3966 return sub
3967 nil
3968```
3969
3970</YueDisplay>
3971
3972&emsp;&emsp;唯一的区别在于:你可以将函数的返回值表达式提前写在 `->` 或 `=>` 前,用以指示该函数应隐式返回该表达式的值。这样即使在多层循环或条件判断的场景下,也无需编写尾行悬挂的返回表达式,逻辑结构会更加直观清晰。
3973
3974## 命名变长参数
3975
3976&emsp;&emsp;你可以使用 `(...t) ->` 语法来将变长参数自动存储到一个命名表中。这个表会包含所有传入的参数(包括 `nil` 值),并且会在表的 `n` 字段中存储实际传入的参数个数(包括 `nil` 值在内的个数)。
3977
3978```yuescript
3979f = (...t) ->
3980 print "参数个数:", t.n
3981 print "表长度:", #t
3982 for i = 1, t.n
3983 print t[i]
3984
3985f 1, 2, 3
3986f "a", "b", "c", "d"
3987f!
3988
3989-- 处理包含 nil 的情况
3990process = (...args) ->
3991 sum = 0
3992 for i = 1, args.n
3993 if args[i] != nil and type(args[i]) == "number"
3994 sum += args[i]
3995 sum
3996
3997process 1, nil, 3, nil, 5
3998```
3999
4000<YueDisplay>
4001
4002```yue
4003f = (...t) ->
4004 print "参数个数:", t.n
4005 print "表长度:", #t
4006 for i = 1, t.n
4007 print t[i]
4008
4009f 1, 2, 3
4010f "a", "b", "c", "d"
4011f!
4012
4013-- 处理包含 nil 的情况
4014process = (...args) ->
4015 sum = 0
4016 for i = 1, args.n
4017 if args[i] != nil and type(args[i]) == "number"
4018 sum += args[i]
4019 sum
4020
4021process 1, nil, 3, nil, 5
4022```
4023
4024</YueDisplay>
4025
4026# 空白
4027
4028&emsp;&emsp;月之脚本是一个对空白敏感的语言。你必须在相同的缩进中使用空格 **' '** 或制表符 **'\t'** 来编写一些代码块,如函数体、值列表和一些控制块。包含不同空白的表达式可能意味着不同的事情。制表符被视为4个空格,但最好不要混合使用空格和制表符。
4029
4030## 语句分隔符
4031
4032&emsp;&emsp;一条语句通常以换行结束。你也可以使用分号 `;` 显式结束一条语句,从而在同一行中编写多条语句:
4033
4034```yuescript
4035a = 1; b = 2; print a + b
4036```
4037
4038<YueDisplay>
4039
4040```yue
4041a = 1; b = 2; print a + b
4042```
4043
4044</YueDisplay>
4045
4046## 多行链式调用
4047
4048&emsp;&emsp;你可以使用相同的缩进来编写多行链式函数调用。
4049
4050```yuescript
4051Rx.Observable
4052 .fromRange 1, 8
4053 \filter (x) -> x % 2 == 0
4054 \concat Rx.Observable.of 'who do we appreciate'
4055 \map (value) -> value .. '!'
4056 \subscribe print
4057```
4058
4059<YueDisplay>
4060
4061```yue
4062Rx.Observable
4063 .fromRange 1, 8
4064 \filter (x) -> x % 2 == 0
4065 \concat Rx.Observable.of 'who do we appreciate'
4066 \map (value) -> value .. '!'
4067 \subscribe print
4068```
4069
4070</YueDisplay>
4071
4072# 注释
4073
4074```yuescript
4075-- 我是一个注释
4076
4077str = --[[
4078这是一个多行注释。
4079没问题。
4080]] strA \ -- 注释 1
4081 .. strB \ -- 注释 2
4082 .. strC
4083
4084func --[[端口]] 3000, --[[ip]] "192.168.1.1"
4085```
4086
4087<YueDisplay>
4088
4089```yue
4090-- 我是一个注释
4091
4092str = --[[
4093这是一个多行注释。
4094没问题。
4095]] strA \ -- 注释 1
4096 .. strB \ -- 注释 2
4097 .. strC
4098
4099func --[[端口]] 3000, --[[ip]] "192.168.1.1"
4100```
4101
4102</YueDisplay>
4103
4104# 属性
4105
4106&emsp;&emsp;月之脚本现在提供了 Lua 5.4 新增的叫做属性的语法支持。在月之脚本编译到的 Lua 目标版本低于 5.4 时,你仍然可以同时使用`const` 和 `close` 的属性声明语法,并获得常量检查和作用域回调的功能。
4107
4108```yuescript
4109const a = 123
4110close _ = <close>: -> print "超出范围。"
4111```
4112
4113<YueDisplay>
4114
4115```yue
4116const a = 123
4117close _ = <close>: -> print "超出范围。"
4118```
4119
4120</YueDisplay>
4121
4122&emsp;&emsp;你可以对进行解构得到的变量标记为常量。
4123
4124```yuescript
4125const {:a, :b, c, d} = tb
4126-- a = 1
4127```
4128
4129<YueDisplay>
4130
4131```yue
4132const {:a, :b, c, d} = tb
4133-- a = 1
4134```
4135
4136</YueDisplay>
4137
4138&emsp;&emsp;你也可以声明全局变量为常量。
4139
4140```yuescript
4141global const Constant = 123
4142-- Constant = 1
4143```
4144
4145<YueDisplay>
4146
4147```yue
4148global const Constant = 123
4149-- Constant = 1
4150```
4151
4152</YueDisplay>
4153
4154# 操作符
4155
4156&emsp;&emsp;Lua 的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\** 或 **::** 均可用于编写链式函数调用,如写作 `tb\func!` 或 `tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。
4157
4158```yuescript
4159tb\func! if tb ~= nil
4160tb::func! if tb != nil
4161```
4162
4163<YueDisplay>
4164
4165```yue
4166tb\func! if tb ~= nil
4167tb::func! if tb != nil
4168```
4169
4170</YueDisplay>
4171
4172## 链式比较
4173
4174&emsp;&emsp;你可以在月之脚本中进行比较表达式的链式书写:
4175
4176```yuescript
4177print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4178-- 输出:true
4179
4180a = 5
4181print 1 <= a <= 10
4182-- 输出:true
4183```
4184
4185<YueDisplay>
4186
4187```yue
4188print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
4189-- 输出:true
4190
4191a = 5
4192print 1 <= a <= 10
4193-- 输出:true
4194```
4195
4196</YueDisplay>
4197
4198&emsp;&emsp;可以注意一下链式比较表达式的求值行为:
4199
4200```yuescript
4201v = (x) ->
4202 print x
4203 x
4204
4205print v(1) < v(2) <= v(3)
4206--[[
4207 输出:
4208 2
4209 1
4210 3
4211 true
4212]]
4213
4214print v(1) > v(2) <= v(3)
4215--[[
4216 输出:
4217 2
4218 1
4219 false
4220]]
4221```
4222
4223<YueDisplay>
4224
4225```yue
4226v = (x) ->
4227 print x
4228 x
4229
4230print v(1) < v(2) <= v(3)
4231--[[
4232 输出:
4233 2
4234 1
4235 3
4236 true
4237]]
4238
4239print v(1) > v(2) <= v(3)
4240--[[
4241 输出:
4242 2
4243 1
4244 false
4245]]
4246```
4247
4248</YueDisplay>
4249
4250&emsp;&emsp;在上面的例子里,中间的表达式 `v(2)` 仅被计算一次,如果把表达式写成 `v(1) < v(2) and v(2) <= v(3)` 的方式,中间的 `v(2)` 才会被计算两次。在链式比较中,求值的顺序往往是未定义的。所以强烈建议不要在链式比较中使用具有副作用(比如做打印操作)的表达式。如果需要使用有副作用的函数,应明确使用短路 `and` 运算符来做连接。
4251
4252## 表追加
4253
4254&emsp;&emsp;**[] =** 操作符用于向 Lua 表的最后插入值。
4255
4256```yuescript
4257tab = []
4258tab[] = "Value"
4259```
4260
4261<YueDisplay>
4262
4263```yue
4264tab = []
4265tab[] = "Value"
4266```
4267
4268</YueDisplay>
4269
4270&emsp;&emsp;你还可以使用展开操作符 `...` 来将一个列表中的所有元素追加到另一个列表中:
4271
4272```yuescript
4273tbA = [1, 2, 3]
4274tbB = [4, 5, 6]
4275tbA[] = ...tbB
4276-- tbA 现在为 [1, 2, 3, 4, 5, 6]
4277```
4278
4279<YueDisplay>
4280
4281```yue
4282tbA = [1, 2, 3]
4283tbB = [4, 5, 6]
4284tbA[] = ...tbB
4285-- tbA 现在为 [1, 2, 3, 4, 5, 6]
4286```
4287
4288</YueDisplay>
4289
4290## 表扩展
4291
4292&emsp;&emsp;你可以使用前置 `...` 操作符在 Lua 表中插入数组表或哈希表。
4293
4294```yuescript
4295parts =
4296 * "shoulders"
4297 * "knees"
4298lyrics =
4299 * "head"
4300 * ...parts
4301 * "and"
4302 * "toes"
4303
4304copy = {...other}
4305
4306a = {1, 2, 3, x: 1}
4307b = {4, 5, y: 1}
4308merge = {...a, ...b}
4309```
4310
4311<YueDisplay>
4312
4313```yue
4314parts =
4315 * "shoulders"
4316 * "knees"
4317lyrics =
4318 * "head"
4319 * ...parts
4320 * "and"
4321 * "toes"
4322
4323copy = {...other}
4324
4325a = {1, 2, 3, x: 1}
4326b = {4, 5, y: 1}
4327merge = {...a, ...b}
4328```
4329
4330</YueDisplay>
4331
4332## 表反向索引
4333
4334&emsp;&emsp;你可以使用 **#** 操作符来反向索引表中的元素。
4335
4336```yuescript
4337last = data.items[#]
4338second_last = data.items[#-1]
4339data.items[#] = 1
4340```
4341
4342<YueDisplay>
4343
4344```yue
4345last = data.items[#]
4346second_last = data.items[#-1]
4347data.items[#] = 1
4348```
4349
4350</YueDisplay>
4351
4352## 元表
4353
4354&emsp;&emsp;**<>** 操作符可提供元表操作的快捷方式。
4355
4356### 元表创建
4357
4358&emsp;&emsp;使用空括号 **<>** 或被 **<>** 包围的元方法键创建普通的 Lua 表。
4359
4360```yuescript
4361mt = {}
4362add = (right) => <>: mt, value: @value + right.value
4363mt.__add = add
4364
4365a = <>: mt, value: 1
4366-- 使用与临时变量名相同的字段名,将临时变量赋值给元表
4367b = :<add>, value: 2
4368c = <add>: mt.__add, value: 3
4369
4370d = a + b + c
4371print d.value
4372
4373close _ = <close>: -> print "超出范围"
4374```
4375
4376<YueDisplay>
4377
4378```yue
4379mt = {}
4380add = (right) => <>: mt, value: @value + right.value
4381mt.__add = add
4382
4383a = <>: mt, value: 1
4384-- 使用与临时变量名相同的字段名,将临时变量赋值给元表
4385b = :<add>, value: 2
4386c = <add>: mt.__add, value: 3
4387
4388d = a + b + c
4389print d.value
4390
4391close _ = <close>: -> print "超出范围"
4392```
4393
4394</YueDisplay>
4395
4396### 元表访问
4397
4398&emsp;&emsp;使用 **<>** 或被 **<>** 包围的元方法名或在 **<>** 中编写某些表达式来访问元表。
4399
4400```yuescript
4401-- 使用包含字段 "value" 的元表创建
4402tb = <"value">: 123
4403tb.<index> = tb.<>
4404print tb.value
4405
4406tb.<> = __index: {item: "hello"}
4407print tb.item
4408```
4409
4410<YueDisplay>
4411
4412```yue
4413-- 使用包含字段 "value" 的元表创建
4414tb = <"value">: 123
4415tb.<index> = tb.<>
4416print tb.value
4417tb.<> = __index: {item: "hello"}
4418print tb.item
4419```
4420
4421</YueDisplay>
4422
4423### 元表解构
4424
4425&emsp;&emsp;使用被 **<>** 包围的元方法键解构元表。
4426
4427```yuescript
4428{item, :new, :<close>, <index>: getter} = tb
4429print item, new, close, getter
4430```
4431
4432<YueDisplay>
4433
4434```yue
4435{item, :new, :<close>, <index>: getter} = tb
4436print item, new, close, getter
4437```
4438
4439</YueDisplay>
4440
4441## 存在性
4442
4443&emsp;&emsp;**?** 运算符可以在多种上下文中用来检查存在性。
4444
4445```yuescript
4446func?!
4447print abc?["你好 世界"]?.xyz
4448
4449x = tab?.value
4450len = utf8?.len or string?.len or (o) -> #o
4451
4452if print and x?
4453 print x
4454
4455with? io.open "test.txt", "w"
4456 \write "你好"
4457 \close!
4458```
4459
4460<YueDisplay>
4461
4462```yue
4463func?!
4464print abc?["你好 世界"]?.xyz
4465
4466x = tab?.value
4467len = utf8?.len or string?.len or (o) -> #o
4468
4469if print and x?
4470 print x
4471
4472with? io.open "test.txt", "w"
4473 \write "你好"
4474 \close!
4475```
4476
4477</YueDisplay>
4478
4479## 管道
4480
4481&emsp;&emsp;与其使用一系列嵌套的函数调用,你还可以考虑使用运算符 **|>** 来传递值。
4482
4483```yuescript
4484"你好" |> print
44851 |> print 2 -- 将管道项作为第一个参数插入
44862 |> print 1, _, 3 -- 带有占位符的管道
4487
4488-- 多行的管道表达式
4489readFile "example.txt"
4490 |> extract language, {}
4491 |> parse language
4492 |> emit
4493 |> render
4494 |> print
4495```
4496
4497<YueDisplay>
4498
4499```yue
4500"你好" |> print
45011 |> print 2 -- 将管道项作为第一个参数插入
45022 |> print 1, _, 3 -- 带有占位符的管道
4503-- 多行的管道表达式
4504readFile "example.txt"
4505 |> extract language, {}
4506 |> parse language
4507 |> emit
4508 |> render
4509 |> print
4510```
4511
4512</YueDisplay>
4513
4514## 空值合并
4515
4516&emsp;&emsp;如果其左操作数不是 **nil**,则nil合并运算符 **??** 返回其左操作数的值;否则,它将计算右操作数并返回其结果。如果左操作数计算结果为非 nil 的值,**??** 运算符将不再计算其右操作数。
4517
4518```yuescript
4519local a, b, c, d
4520a = b ?? c ?? d
4521func a ?? {}
4522
4523a ??= false
4524```
4525
4526<YueDisplay>
4527
4528```yue
4529local a, b, c, d
4530a = b ?? c ?? d
4531func a ?? {}
4532a ??= false
4533```
4534
4535</YueDisplay>
4536
4537## 隐式对象
4538
4539&emsp;&emsp;你可以在表格块内使用符号 **\*** 或是 **-** 开始编写一系列隐式结构。如果你正在创建隐式对象,对象的字段必须具有相同的缩进。
4540
4541```yuescript
4542-- 赋值时使用隐式对象
4543list =
4544 * 1
4545 * 2
4546 * 3
4547
4548-- 函数调用时使用隐式对象
4549func
4550 * 1
4551 * 2
4552 * 3
4553
4554-- 返回时使用隐式对象
4555f = ->
4556 return
4557 * 1
4558 * 2
4559 * 3
4560
4561-- 表格时使用隐式对象
4562tb =
4563 name: "abc"
4564
4565 values:
4566 - "a"
4567 - "b"
4568 - "c"
4569
4570 objects:
4571 - name: "a"
4572 value: 1
4573 func: => @value + 1
4574 tb:
4575 fieldA: 1
4576
4577 - name: "b"
4578 value: 2
4579 func: => @value + 2
4580 tb: { }
4581```
4582
4583<YueDisplay>
4584
4585```yue
4586-- 赋值时使用隐式对象
4587list =
4588 * 1
4589 * 2
4590 * 3
4591
4592-- 函数调用时使用隐式对象
4593func
4594 * 1
4595 * 2
4596 * 3
4597
4598-- 返回时使用隐式对象
4599f = ->
4600 return
4601 * 1
4602 * 2
4603 * 3
4604
4605-- 表格时使用隐式对象
4606tb =
4607 name: "abc"
4608
4609 values:
4610 - "a"
4611 - "b"
4612 - "c"
4613
4614 objects:
4615 - name: "a"
4616 value: 1
4617 func: => @value + 1
4618 tb:
4619 fieldA: 1
4620
4621 - name: "b"
4622 value: 2
4623 func: => @value + 2
4624 tb: { }
4625```
4626
4627</YueDisplay>
4628
4629# 字面量
4630
4631&emsp;&emsp;Lua 中的所有基本字面量都可以在月之脚本中使用。包括数字、字符串、布尔值和 **nil**。
4632
4633&emsp;&emsp;但与 Lua 不同的是,单引号和双引号字符串内部允许有换行:
4634
4635```yuescript
4636some_string = "这是一个字符串
4637 并包括一个换行。"
4638
4639-- 使用#{}语法可以将表达式插入到字符串字面量中。
4640-- 字符串插值只在双引号字符串中可用。
4641print "我有#{math.random! * 100}%的把握。"
4642```
4643
4644<YueDisplay>
4645
4646```yue
4647some_string = "这是一个字符串
4648 并包括一个换行。"
4649
4650-- 使用#{}语法可以将表达式插入到字符串字面量中。
4651-- 字符串插值只在双引号字符串中可用。
4652print "我有#{math.random! * 100}%的把握。"
4653```
4654
4655</YueDisplay>
4656
4657## 数字字面量
4658
4659&emsp;&emsp;你可以在数字字面量中使用下划线来增加可读性。
4660
4661```yuescript
4662integer = 1_000_000
4663hex = 0xEF_BB_BF
4664binary = 0B10011
4665```
4666
4667<YueDisplay>
4668
4669```yue
4670integer = 1_000_000
4671hex = 0xEF_BB_BF
4672binary = 0B10011
4673```
4674
4675</YueDisplay>
4676
4677## YAML 风格字符串
4678
4679&emsp;&emsp;使用 `|` 前缀标记一个多行 YAML 风格字符串:
4680
4681```yuescript
4682str = |
4683 key: value
4684 list:
4685 - item1
4686 - #{expr}
4687```
4688
4689<YueDisplay>
4690
4691```yue
4692str = |
4693 key: value
4694 list:
4695 - item1
4696 - #{expr}
4697```
4698
4699</YueDisplay>
4700
4701&emsp;&emsp;其效果类似于原生 Lua 的多行拼接,所有文本(含换行)将被保留下来,并支持 `#{...}` 语法,通过 `tostring(expr)` 插入表达式结果。
4702
4703&emsp;&emsp;YAML 风格的多行字符串会自动检测首行后最小的公共缩进,并从所有行中删除该前缀空白字符。这让你可以在代码中对齐文本,但输出字符串不会带多余缩进。
4704
4705```yuescript
4706fn = ->
4707 str = |
4708 foo:
4709 bar: baz
4710 return str
4711```
4712
4713<YueDisplay>
4714
4715```yue
4716fn = ->
4717 str = |
4718 foo:
4719 bar: baz
4720 return str
4721```
4722
4723</YueDisplay>
4724
4725&emsp;&emsp;输出字符串中的 foo: 对齐到行首,不会带有函数缩进空格。保留内部缩进的相对结构,适合书写结构化嵌套样式的内容。
4726
4727&emsp;&emsp;支持自动处理字符中的引号、反斜杠等特殊符号,无需手动转义:
4728
4729```yuescript
4730str = |
4731 path: "C:\Program Files\App"
4732 note: 'He said: "#{Hello}!"'
4733```
4734
4735<YueDisplay>
4736
4737```yue
4738str = |
4739 path: "C:\Program Files\App"
4740 note: 'He said: "#{Hello}!"'
4741```
4742
4743</YueDisplay>
4744
4745# 模块
4746
4747## 导入
4748
4749&emsp;&emsp;导入语句是一个语法糖,用于需要引入一个模块或者从已导入的模块中提取子项目。从模块导入的变量默认为不可修改的常量。
4750
4751```yuescript
4752-- 用作表解构
4753do
4754 import insert, concat from table
4755 -- 当给 insert, concat 变量赋值时,编译器会报告错误
4756 import C, Ct, Cmt from require "lpeg"
4757 -- 快捷写法引入模块的子项
4758 import x, y, z from 'mymodule'
4759 -- 使用Python风格的导入
4760 from 'module' import a, b, c
4761
4762-- 快捷地导入一个模块
4763do
4764 import 'module'
4765 import 'module_x'
4766 import "d-a-s-h-e-s"
4767 import "module.part"
4768
4769-- 导入模块后起一个别名使用,或是进行导入模块表的解构
4770do
4771 import "player" as PlayerModule
4772 import "lpeg" as :C, :Ct, :Cmt
4773 import "export" as {one, two, Something:{umm:{ch}}}
4774```
4775
4776<YueDisplay>
4777
4778```yue
4779-- 用作表解构
4780do
4781 import insert, concat from table
4782 -- 当给 insert, concat 变量赋值时,编译器会报告错误
4783 import C, Ct, Cmt from require "lpeg"
4784 -- 快捷写法引入模块的子项
4785 import x, y, z from 'mymodule'
4786 -- 使用Python风格的导入
4787 from 'module' import a, b, c
4788
4789-- 快捷地导入一个模块
4790do
4791 import 'module'
4792 import 'module_x'
4793 import "d-a-s-h-e-s"
4794 import "module.part"
4795
4796-- 导入模块后起一个别名使用,或是进行导入模块表的解构
4797do
4798 import "player" as PlayerModule
4799 import "lpeg" as :C, :Ct, :Cmt
4800 import "export" as {one, two, Something:{umm:{ch}}}
4801```
4802
4803</YueDisplay>
4804
4805## 导入全局变量
4806
4807&emsp;&emsp;你可以使用 `import` 将指定的全局变量导入到本地变量中。当导入一系列对全局变量的链式访问时,最后一个访问的字段将被赋值给本地变量。
4808
4809```yuescript
4810do
4811 import tostring
4812 import table.concat
4813 print concat ["a", tostring 1]
4814```
4815
4816<YueDisplay>
4817
4818```yue
4819do
4820 import tostring
4821 import table.concat
4822 print concat ["a", tostring 1]
4823```
4824
4825</YueDisplay>
4826
4827### 自动全局变量导入
4828
4829&emsp;&emsp;在一个代码块的顶部写 `import global`,会将当前作用域中尚未显式声明或赋值过的变量名,自动导入为本地常量,并在该语句的位置绑定到同名的全局变量。
4830
4831&emsp;&emsp;但是在同一作用域中被显式声明为全局的变量不会被自动导入,因此可以继续进行赋值操作。
4832
4833```yuescript
4834do
4835 import global
4836 print "hello"
4837 math.random 3
4838 -- print = nil -- 报错:自动导入的全局变量为常量
4839
4840do
4841 -- 被显式声明为全局的变量不会被自动导入
4842 import global
4843 global FLAG
4844 print FLAG
4845 FLAG = 123
4846```
4847
4848<YueDisplay>
4849
4850```yue
4851do
4852 import global
4853 print "hello"
4854 math.random 3
4855 -- print = nil -- 报错:自动导入的全局变量是常量
4856
4857do
4858 -- 被显式声明为全局的变量不会被自动导入
4859 import global
4860 global FLAG
4861 print FLAG
4862 FLAG = 123
4863```
4864
4865</YueDisplay>
4866
4867## 导出
4868
4869&emsp;&emsp;导出语句提供了一种简洁的方式来定义当前的模块。
4870
4871### 命名导出
4872
4873&emsp;&emsp;带命名的导出将定义一个局部变量,并在导出的表中添加一个同名的字段。
4874
4875```yuescript
4876export a, b, c = 1, 2, 3
4877export cool = "cat"
4878
4879export What = if this
4880 "abc"
4881else
4882 "def"
4883
4884export y = ->
4885 hallo = 3434
4886
4887export class Something
4888 umm: "cool"
4889```
4890
4891<YueDisplay>
4892
4893```yue
4894export a, b, c = 1, 2, 3
4895export cool = "cat"
4896
4897export What = if this
4898 "abc"
4899else
4900 "def"
4901
4902export y = ->
4903 hallo = 3434
4904
4905export class Something
4906 umm: "cool"
4907```
4908
4909</YueDisplay>
4910
4911&emsp;&emsp;使用解构进行命名导出。
4912
4913```yuescript
4914export :loadstring, to_lua: tolua = yue
4915export {itemA: {:fieldA = '默认值'}} = tb
4916```
4917
4918<YueDisplay>
4919
4920```yue
4921export :loadstring, to_lua: tolua = yue
4922export {itemA: {:fieldA = '默认值'}} = tb
4923```
4924
4925</YueDisplay>
4926
4927&emsp;&emsp;从模块导出命名项目时,可以不用创建局部变量。
4928
4929```yuescript
4930export.itemA = tb
4931export.<index> = items
4932export["a-b-c"] = 123
4933```
4934
4935<YueDisplay>
4936
4937```yue
4938export.itemA = tb
4939export.<index> = items
4940export["a-b-c"] = 123
4941```
4942
4943</YueDisplay>
4944
4945### 未命名导出
4946
4947&emsp;&emsp;未命名导出会将要导出的目标项目添加到导出表的数组部分。
4948
4949```yuescript
4950d, e, f = 3, 2, 1
4951export d, e, f
4952
4953export if this
4954 123
4955else
4956 456
4957
4958export with tmp
4959 j = 2000
4960```
4961
4962<YueDisplay>
4963
4964```yue
4965d, e, f = 3, 2, 1
4966export d, e, f
4967
4968export if this
4969 123
4970else
4971 456
4972
4973export with tmp
4974 j = 2000
4975```
4976
4977</YueDisplay>
4978
4979### 默认导出
4980
4981&emsp;&emsp;在导出语句中使用 **default** 关键字,来替换导出的表为一个目标的对象。
4982
4983```yuescript
4984export default ->
4985 print "你好"
4986 123
4987```
4988
4989<YueDisplay>
4990
4991```yue
4992export default ->
4993 print "你好"
4994 123
4995```
4996
4997</YueDisplay>
4998
4999# MIT 许可证
5000
5001版权 (c) 2017-2026 李瑾 \<dragon-fly@qq.com\>
5002
5003特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,以及再授权被配发了本软件的人如上的权利,须在下列条件下:
5004上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
5005本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
5006
5007# 月之脚本语言库
5008
5009在 Lua 中使用 `local yue = require("yue")` 来访问。
5010
5011## yue
5012
5013**描述:**
5014
5015月之脚本语言库。
5016
5017### version
5018
5019**类型:** 成员变量。
5020
5021**描述:**
5022
5023月之脚本版本。
5024
5025**签名:**
5026
5027```lua
5028version: string
5029```
5030
5031### dirsep
5032
5033**类型:** 成员变量。
5034
5035**描述:**
5036
5037当前平台的文件分隔符。
5038
5039**签名:**
5040
5041```lua
5042dirsep: string
5043```
5044
5045### yue_compiled
5046
5047**类型:** 成员变量。
5048
5049**描述:**
5050
5051编译模块代码缓存。
5052
5053**签名:**
5054
5055```lua
5056yue_compiled: {string: string}
5057```
5058
5059### to_lua
5060
5061**类型:** 函数。
5062
5063**描述:**
5064
5065月之脚本的编译函数。它将 YueScript 代码编译为 Lua 代码。
5066
5067**签名:**
5068
5069```lua
5070to_lua: function(code: string, config?: Config):
5071 --[[codes]] string | nil,
5072 --[[error]] string | nil,
5073 --[[globals]] {{string, integer, integer}} | nil
5074```
5075
5076**参数:**
5077
5078| 参数名 | 类型 | 描述 |
5079| ------ | ------ | ------------------- |
5080| code | string | YueScript 代码。 |
5081| config | Config | [可选] 编译器选项。 |
5082
5083**返回值:**
5084
5085| 返回类型 | 描述 |
5086| ----------------------------------- | ------------------------------------------------------------------------------------------ |
5087| string \| nil | 编译后的 Lua 代码,如果编译失败则为 nil。 |
5088| string \| nil | 错误消息,如果编译成功则为 nil。 |
5089| {{string, integer, integer}} \| nil | 代码中出现的全局变量(带有名称、行和列),如果编译器选项 `lint_global` 为 false 则为 nil。 |
5090
5091### file_exist
5092
5093**类型:** 函数。
5094
5095**描述:**
5096
5097检查源文件是否存在的函数。可以覆盖该函数以自定义行为。
5098
5099**签名:**
5100
5101```lua
5102file_exist: function(filename: string): boolean
5103```
5104
5105**参数:**
5106
5107| 参数名 | 类型 | 描述 |
5108| -------- | ------ | -------- |
5109| filename | string | 文件名。 |
5110
5111**返回值:**
5112
5113| 返回类型 | 描述 |
5114| -------- | -------------- |
5115| boolean | 文件是否存在。 |
5116
5117### read_file
5118
5119**类型:** 函数。
5120
5121**描述:**
5122
5123读取源文件的函数。可以覆盖该函数以自定义行为。
5124
5125**签名:**
5126
5127```lua
5128read_file: function(filename: string): string
5129```
5130
5131**参数:**
5132
5133| 参数名 | 类型 | 描述 |
5134| -------- | ------ | -------- |
5135| filename | string | 文件名。 |
5136
5137**返回值:**
5138
5139| 返回类型 | 描述 |
5140| -------- | ---------- |
5141| string | 文件内容。 |
5142
5143### insert_loader
5144
5145**类型:** 函数。
5146
5147**描述:**
5148
5149将 YueScript 加载器插入到 Lua 包加载器(搜索器)中。
5150
5151**签名:**
5152
5153```lua
5154insert_loader: function(pos?: integer): boolean
5155```
5156
5157**参数:**
5158
5159| 参数名 | 类型 | 描述 |
5160| ------ | ------- | ------------------------------------- |
5161| pos | integer | [可选] 要插入加载器的位置。默认为 3。 |
5162
5163**返回值:**
5164
5165| 返回类型 | 描述 |
5166| -------- | ---------------------------------------------------- |
5167| boolean | 是否成功插入加载器。如果加载器已经插入,则返回失败。 |
5168
5169### remove_loader
5170
5171**类型:** 函数。
5172
5173**描述:**
5174
5175从 Lua 包加载器(搜索器)中移除 YueScript 加载器。
5176
5177**签名:**
5178
5179```lua
5180remove_loader: function(): boolean
5181```
5182
5183**返回值:**
5184
5185| 返回类型 | 描述 |
5186| -------- | -------------------------------------------------- |
5187| boolean | 是否成功移除加载器。如果加载器未插入,则返回失败。 |
5188
5189### loadstring
5190
5191**类型:** 函数。
5192
5193**描述:**
5194
5195将 YueScript 代码字符串加载为一个函数。
5196
5197**签名:**
5198
5199```lua
5200loadstring: function(input: string, chunkname: string, env: table, config?: Config):
5201 --[[loaded function]] nil | function(...: any): (any...),
5202 --[[error]] string | nil
5203```
5204
5205**参数:**
5206
5207| 参数名 | 类型 | 描述 |
5208| --------- | ------ | ------------------- |
5209| input | string | YueScript 代码。 |
5210| chunkname | string | 代码块的名称。 |
5211| env | table | 环境表。 |
5212| config | Config | [可选] 编译器选项。 |
5213
5214**返回值:**
5215
5216| 返回类型 | 描述 |
5217| --------------- | ---------------------------------- |
5218| function \| nil | 加载的函数,如果加载失败则为 nil。 |
5219| string \| nil | 错误消息,如果加载成功则为 nil。 |
5220
5221### loadstring
5222
5223**类型:** 函数。
5224
5225**描述:**
5226
5227将 YueScript 代码字符串加载为一个函数。
5228
5229**签名:**
5230
5231```lua
5232loadstring: function(input: string, chunkname: string, config?: Config):
5233 --[[loaded function]] nil | function(...: any): (any...),
5234 --[[error]] string | nil
5235```
5236
5237**参数:**
5238
5239| 参数名 | 类型 | 描述 |
5240| --------- | ------ | ------------------- |
5241| input | string | YueScript 代码。 |
5242| chunkname | string | 代码块的名称。 |
5243| config | Config | [可选] 编译器选项。 |
5244
5245**返回值:**
5246
5247| 返回类型 | 描述 |
5248| --------------- | ---------------------------------- |
5249| function \| nil | 加载的函数,如果加载失败则为 nil。 |
5250| string \| nil | 错误消息,如果加载成功则为 nil。 |
5251
5252### loadstring
5253
5254**类型:** 函数。
5255
5256**描述:**
5257
5258将 YueScript 代码字符串加载为一个函数。
5259
5260**签名:**
5261
5262```lua
5263loadstring: function(input: string, config?: Config):
5264 --[[loaded function]] nil | function(...: any): (any...),
5265 --[[error]] string | nil
5266```
5267
5268**参数:**
5269
5270| 参数名 | 类型 | 描述 |
5271| ------ | ------ | ------------------- |
5272| input | string | YueScript 代码。 |
5273| config | Config | [可选] 编译器选项。 |
5274
5275**返回值:**
5276
5277| 返回类型 | 描述 |
5278| --------------- | ---------------------------------- |
5279| function \| nil | 加载的函数,如果加载失败则为 nil。 |
5280| string \| nil | 错误消息,如果加载成功则为 nil。 |
5281
5282### loadfile
5283
5284**类型:** 函数。
5285
5286**描述:**
5287
5288将 YueScript 代码文件加载为一个函数。
5289
5290**签名:**
5291
5292```lua
5293loadfile: function(filename: string, env: table, config?: Config):
5294 nil | function(...: any): (any...),
5295 string | nil
5296```
5297
5298**参数:**
5299
5300| 参数名 | 类型 | 描述 |
5301| -------- | ------ | ------------------- |
5302| filename | string | 文件名。 |
5303| env | table | 环境表。 |
5304| config | Config | [可选] 编译器选项。 |
5305
5306**返回值:**
5307
5308| 返回类型 | 描述 |
5309| --------------- | ---------------------------------- |
5310| function \| nil | 加载的函数,如果加载失败则为 nil。 |
5311| string \| nil | 错误消息,如果加载成功则为 nil。 |
5312
5313### loadfile
5314
5315**类型:** 函数。
5316
5317**描述:**
5318
5319将 YueScript 代码文件加载为一个函数。
5320
5321**签名:**
5322
5323```lua
5324loadfile: function(filename: string, config?: Config):
5325 nil | function(...: any): (any...),
5326 string | nil
5327```
5328
5329**参数:**
5330
5331| 参数名 | 类型 | 描述 |
5332| -------- | ------ | ------------------- |
5333| filename | string | 文件名。 |
5334| config | Config | [可选] 编译器选项。 |
5335
5336**返回值:**
5337
5338| 返回类型 | 描述 |
5339| --------------- | ---------------------------------- |
5340| function \| nil | 加载的函数,如果加载失败则为 nil。 |
5341| string \| nil | 错误消息,如果加载成功则为 nil。 |
5342
5343### dofile
5344
5345**类型:** 函数。
5346
5347**描述:**
5348
5349将 YueScript 代码文件加载为一个函数并执行。
5350
5351**签名:**
5352
5353```lua
5354dofile: function(filename: string, env: table, config?: Config): any...
5355```
5356
5357**参数:**
5358
5359| 参数名 | 类型 | 描述 |
5360| -------- | ------ | ------------------- |
5361| filename | string | 文件名。 |
5362| env | table | 环境表。 |
5363| config | Config | [可选] 编译器选项。 |
5364
5365**返回值:**
5366
5367| 返回类型 | 描述 |
5368| -------- | -------------------------- |
5369| any... | 加载的函数执行后的返回值。 |
5370
5371### dofile
5372
5373**类型:** 函数。
5374
5375**描述:**
5376
5377将 YueScript 代码文件加载为一个函数并执行。
5378
5379**签名:**
5380
5381```lua
5382dofile: function(filename: string, config?: Config): any...
5383```
5384
5385**参数:**
5386
5387| 参数名 | 类型 | 描述 |
5388| -------- | ------ | ------------------- |
5389| filename | string | 文件名。 |
5390| config | Config | [可选] 编译器选项。 |
5391
5392**返回值:**
5393
5394| 返回类型 | 描述 |
5395| -------- | -------------------------- |
5396| any... | 加载的函数执行后的返回值。 |
5397
5398### find_modulepath
5399
5400**类型:** 函数。
5401
5402**描述:**
5403
5404将 YueScript 模块名解析为文件路径。
5405
5406**签名:**
5407
5408```lua
5409find_modulepath: function(name: string): string
5410```
5411
5412**参数:**
5413
5414| 参数名 | 类型 | 描述 |
5415| ------ | ------ | -------- |
5416| name | string | 模块名。 |
5417
5418**返回值:**
5419
5420| 返回类型 | 描述 |
5421| -------- | ---------- |
5422| string | 文件路径。 |
5423
5424### pcall
5425
5426**类型:** 函数。
5427
5428**描述:**
5429
5430在保护模式下调用一个函数。
5431会捕获任何错误,执行成功则返回成功状态和结果,否则为失败状态和错误信息。
5432当发生错误时,将错误信息中的代码行号重写为 YueScript 代码中的原始行号。
5433
5434**签名:**
5435
5436```lua
5437pcall: function(f: function, ...: any): boolean, any...
5438```
5439
5440**参数:**
5441
5442| 参数名 | 类型 | 描述 |
5443| ------ | -------- | -------------------- |
5444| f | function | 要调用的函数。 |
5445| ... | any | 要传递给函数的参数。 |
5446
5447**返回值:**
5448
5449| 返回类型 | 描述 |
5450| ------------ | ---------------------------- |
5451| boolean, ... | 状态码和函数结果或错误信息。 |
5452
5453### require
5454
5455**类型:** 函数。
5456
5457**描述:**
5458
5459加载给定的模块。可以是 Lua 模块或 YueScript 模块。
5460如果模块是 YueScript 模块且加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。
5461
5462**签名:**
5463
5464```lua
5465require: function(name: string): any...
5466```
5467
5468**参数:**
5469
5470| 参数名 | 类型 | 描述 |
5471| ------- | ------ | ---------------- |
5472| modname | string | 要加载的模块名。 |
5473
5474**返回值:**
5475
5476| 返回类型 | 描述 |
5477| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
5478| any | 如果模块已经加载,则返回 package.loaded[modname] 中存储的值。否则,尝试查找加载器并返回 package.loaded[modname] 的最终值和加载器数据作为第二个结果。 |
5479
5480### p
5481
5482**类型:** 函数。
5483
5484**描述:**
5485
5486检查传递的值的内部结构,并打印值出它的字符串表示。
5487
5488**签名:**
5489
5490```lua
5491p: function(...: any)
5492```
5493
5494**参数:**
5495
5496| 参数名 | 类型 | 描述 |
5497| ------ | ---- | ------------ |
5498| ... | any | 要检查的值。 |
5499
5500### options
5501
5502**类型:** 成员变量。
5503
5504**描述:**
5505
5506当前编译器选项。
5507
5508**签名:**
5509
5510```lua
5511options: Config.Options
5512```
5513
5514### traceback
5515
5516**类型:** 函数。
5517
5518**描述:**
5519
5520重写堆栈跟踪中的行号为 YueScript 代码中的原始行号的 traceback 函数。
5521
5522**签名:**
5523
5524```lua
5525traceback: function(message: string): string
5526```
5527
5528**参数:**
5529
5530| 参数名 | 类型 | 描述 |
5531| ------- | ------ | -------------- |
5532| message | string | 堆栈跟踪消息。 |
5533
5534**返回值:**
5535
5536| 返回类型 | 描述 |
5537| -------- | ---------------------- |
5538| string | 重写后的堆栈跟踪消息。 |
5539
5540### is_ast
5541
5542**类型:** 函数。
5543
5544**描述:**
5545
5546检查代码是否匹配指定的 AST。
5547
5548**签名:**
5549
5550```lua
5551is_ast: function(astName: string, code: string): boolean
5552```
5553
5554**参数:**
5555
5556| 参数名 | 类型 | 描述 |
5557| ------- | ------ | ---------- |
5558| astName | string | AST 名称。 |
5559| code | string | 代码。 |
5560
5561**返回值:**
5562
5563| 返回类型 | 描述 |
5564| -------- | ------------------ |
5565| boolean | 代码是否匹配 AST。 |
5566
5567### AST
5568
5569**类型:** 成员变量。
5570
5571**描述:**
5572
5573AST 类型定义,带有名称、行、列和子节点。
5574
5575**签名:**
5576
5577```lua
5578type AST = {string, integer, integer, any}
5579```
5580
5581### to_ast
5582
5583**类型:** 函数。
5584
5585**描述:**
5586
5587将代码转换为 AST。
5588
5589**签名:**
5590
5591```lua
5592to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
5593 --[[AST]] AST | nil,
5594 --[[error]] nil | string
5595```
5596
5597**参数:**
5598
5599| 参数名 | 类型 | 描述 |
5600| -------------- | ------- | ------------------------------------------------------------------------------ |
5601| code | string | 代码。 |
5602| flattenLevel | integer | [可选] 扁平化级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 |
5603| astName | string | [可选] AST 名称。默认为 "File"。 |
5604| reserveComment | boolean | [可选] 是否保留原始注释。默认为 false。 |
5605
5606**返回值:**
5607
5608| 返回类型 | 描述 |
5609| ------------- | -------------------------------- |
5610| AST \| nil | AST,如果转换失败则为 nil。 |
5611| string \| nil | 错误消息,如果转换成功则为 nil。 |
5612
5613### format
5614
5615**类型:** 函数。
5616
5617**描述:**
5618
5619格式化 YueScript 代码。
5620
5621**签名:**
5622
5623```lua
5624format: function(code: string, tabSize?: number, reserveComment?: boolean): string
5625```
5626
5627**参数:**
5628
5629| 参数名 | 类型 | 描述 |
5630| -------------- | ------- | -------------------------------------- |
5631| code | string | 代码。 |
5632| tabSize | integer | [可选] 制表符大小。默认为 4。 |
5633| reserveComment | boolean | [可选] 是否保留原始注释。默认为 true。 |
5634
5635**返回值:**
5636
5637| 返回类型 | 描述 |
5638| -------- | ---------------- |
5639| string | 格式化后的代码。 |
5640
5641### \_\_call
5642
5643**类型:** 元方法。
5644
5645**描述:**
5646
5647导入 YueScript 模块。
5648如果发生加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。
5649
5650**签名:**
5651
5652```lua
5653metamethod __call: function(self: yue, module: string): any...
5654```
5655
5656**参数:**
5657
5658| 参数名 | 类型 | 描述 |
5659| ------ | ------ | -------- |
5660| module | string | 模块名。 |
5661
5662**返回值:**
5663
5664| 返回类型 | 描述 |
5665| -------- | -------- |
5666| any | 模块值。 |
5667
5668## Config
5669
5670**描述:**
5671
5672编译器编译选项。
5673
5674### lint_global
5675
5676**类型:** 成员变量。
5677
5678**描述:**
5679
5680编译器是否应该收集代码中出现的全局变量。
5681
5682**签名:**
5683
5684```lua
5685lint_global: boolean
5686```
5687
5688### implicit_return_root
5689
5690**类型:** 成员变量。
5691
5692**描述:**
5693
5694编译器是否应该对根层级的代码块进行隐式的表达式返回。
5695
5696**签名:**
5697
5698```lua
5699implicit_return_root: boolean
5700```
5701
5702### reserve_line_number
5703
5704**类型:** 成员变量。
5705
5706**描述:**
5707
5708编译器是否应该在编译后的代码中保留原始行号。
5709
5710**签名:**
5711
5712```lua
5713reserve_line_number: boolean
5714```
5715
5716### reserve_comment
5717
5718**类型:** 成员变量。
5719
5720**描述:**
5721
5722编译器是否应该在编译后的代码中保留原始注释。
5723
5724**签名:**
5725
5726```lua
5727reserve_comment: boolean
5728```
5729
5730### space_over_tab
5731
5732**类型:** 成员变量。
5733
5734**描述:**
5735
5736编译器是否应该在编译后的代码中使用空格字符而不是制表符字符。
5737
5738**签名:**
5739
5740```lua
5741space_over_tab: boolean
5742```
5743
5744### same_module
5745
5746**类型:** 成员变量。
5747
5748**描述:**
5749
5750编译器是否应该将要编译的代码视为当前正在编译的模块。仅供编译器内部使用。
5751
5752**签名:**
5753
5754```lua
5755same_module: boolean
5756```
5757
5758### line_offset
5759
5760**类型:** 成员变量。
5761
5762**描述:**
5763
5764编译器错误消息是否应该包含行号偏移量。仅供编译器内部使用。
5765
5766**签名:**
5767
5768```lua
5769line_offset: integer
5770```
5771
5772### yue.Config.LuaTarget
5773
5774**类型:** 枚举。
5775
5776**描述:**
5777
5778目标 Lua 版本枚举。
5779
5780**签名:**
5781
5782```lua
5783enum LuaTarget
5784 "5.1"
5785 "5.2"
5786 "5.3"
5787 "5.4"
5788 "5.5"
5789end
5790```
5791
5792### options
5793
5794**类型:** 成员变量。
5795
5796**描述:**
5797
5798要传递给编译函数的额外选项。
5799
5800**签名:**
5801
5802```lua
5803options: Options
5804```
5805
5806## Options
5807
5808**描述:**
5809
5810额外编译器选项定义。
5811
5812### target
5813
5814**类型:** 成员变量。
5815
5816**描述:**
5817
5818编译目标 Lua 版本。
5819
5820**签名:**
5821
5822```lua
5823target: LuaTarget
5824```
5825
5826### path
5827
5828**类型:** 成员变量。
5829
5830**描述:**
5831
5832额外模块搜索路径。
5833
5834**签名:**
5835
5836```lua
5837path: string
5838```
5839
5840### dump_locals
5841
5842**类型:** 成员变量。
5843
5844**描述:**
5845
5846是否在回溯错误消息中输出代码块的局部变量。默认为 false。
5847
5848**签名:**
5849
5850```lua
5851dump_locals: boolean
5852```
5853
5854### simplified
5855
5856**类型:** 成员变量。
5857
5858**描述:**
5859
5860是否简化输出的错误消息。默认为 true。
5861
5862**签名:**
5863
5864```lua
5865simplified: boolean
5866```
diff --git a/makefile b/makefile
index 99028e4..8cf9854 100644
--- a/makefile
+++ b/makefile
@@ -33,6 +33,7 @@ INSTALL_PREFIX = usr/local
33TEST_INPUT = ./spec/inputs 33TEST_INPUT = ./spec/inputs
34TEST_OUTPUT = ./spec/generated 34TEST_OUTPUT = ./spec/generated
35GEN_OUTPUT = ./spec/outputs 35GEN_OUTPUT = ./spec/outputs
36DOC_OUTPUT = ./doc
36 37
37PLAT = macos 38PLAT = macos
38 39
@@ -439,7 +440,7 @@ test: debug
439 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(TEST_OUTPUT)/5.1/import_global.lua --target 5.1 440 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(TEST_OUTPUT)/5.1/import_global.lua --target 5.1
440 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target 5.1 441 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target 5.1
441 @./$(BIN_NAME) $(TEST_INPUT)/test/try_catch_spec.yue -o $(TEST_OUTPUT)/5.1/test/try_catch_spec.lua --target 5.1 442 @./$(BIN_NAME) $(TEST_INPUT)/test/try_catch_spec.yue -o $(TEST_OUTPUT)/5.1/test/try_catch_spec.lua --target 5.1
442 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT) 443 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT) $(DOC_OUTPUT)
443 @echo -en "Compile time: " 444 @echo -en "Compile time: "
444 @$(END_TIME) 445 @$(END_TIME)
445 @./$(BIN_NAME) -e "$$(printf "r = io.popen('git diff --no-index $(TEST_OUTPUT) $(GEN_OUTPUT) | head -5')\\\\read '*a'\nif r ~= ''\n print r\n os.exit 1")" 446 @./$(BIN_NAME) -e "$$(printf "r = io.popen('git diff --no-index $(TEST_OUTPUT) $(GEN_OUTPUT) | head -5')\\\\read '*a'\nif r ~= ''\n print r\n os.exit 1")"
@@ -466,7 +467,7 @@ gen: release
466 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(GEN_OUTPUT)/5.1/import_global.lua --target 5.1 467 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(GEN_OUTPUT)/5.1/import_global.lua --target 5.1
467 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target 5.1 468 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target 5.1
468 @./$(BIN_NAME) $(TEST_INPUT)/test/try_catch_spec.yue -o $(GEN_OUTPUT)/5.1/test/try_catch_spec.lua --target 5.1 469 @./$(BIN_NAME) $(TEST_INPUT)/test/try_catch_spec.yue -o $(GEN_OUTPUT)/5.1/test/try_catch_spec.lua --target 5.1
469 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT) 470 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT) $(DOC_OUTPUT)
470 @echo -en "Compile time: " 471 @echo -en "Compile time: "
471 @$(END_TIME) 472 @$(END_TIME)
472 473
diff --git a/spec/inputs/compile_doc.yue b/spec/inputs/compile_doc.yue
index ab621f8..f6a8d49 100644
--- a/spec/inputs/compile_doc.yue
+++ b/spec/inputs/compile_doc.yue
@@ -1,4 +1,4 @@
1outputFolder = ... 1[outputFolder, docFolder] = {...}
2 2
3getFiles = (locale) -> 3getFiles = (locale) ->
4 locale = if locale == "en" then "" else "#{locale}/" 4 locale = if locale == "en" then "" else "#{locale}/"
@@ -37,13 +37,15 @@ getFiles = (locale) ->
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/reference/the-yuescript-library.md"
39 ] 39 ]
40docs = [ ["codes_from_doc_#{locale}.lua", 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, docFiles] in *docs 41for [compiledFile, docFile, docFiles] in *docs
42 codes = [] 42 codes = []
43 docTexts = []
43 for docFile in *docFiles 44 for docFile in *docFiles
44 close input = with? io.open docFile 45 close input = with? io.open docFile
45 import "yue" as :to_lua 46 import "yue" as :to_lua
46 text = \read "*a" 47 text = \read "*a"
48 docTexts[] = text
47 for code in text\gmatch "```yuescript[\r\n]+(.-)```[^%w]" 49 for code in text\gmatch "```yuescript[\r\n]+(.-)```[^%w]"
48 if result, err := to_lua code, implicit_return_root: false, reserve_line_number: false 50 if result, err := to_lua code, implicit_return_root: false, reserve_line_number: false
49 codes[] = result 51 codes[] = result
@@ -58,4 +60,6 @@ for [compiledFile, docFiles] in *docs
58 os.exit 1 60 os.exit 1
59 close output = with io.open "#{outputFolder}/#{compiledFile}", "w+" 61 close output = with io.open "#{outputFolder}/#{compiledFile}", "w+"
60 \write table.concat codes 62 \write table.concat codes
63 close output2 = with io.open "#{docFolder}/#{docFile}", "w+"
64 \write table.concat docTexts, "\n"
61 65
diff --git a/spec/outputs/codes_from_doc_de.lua b/spec/outputs/codes_from_doc_de.lua
index 428f788..4c9ba1d 100644
--- a/spec/outputs/codes_from_doc_de.lua
+++ b/spec/outputs/codes_from_doc_de.lua
@@ -2163,6 +2163,18 @@ repeat
2163 result = _with_0.value 2163 result = _with_0.value
2164 break 2164 break
2165until true 2165until true
2166local a
2167do
2168 local _with_0 = obj
2169 _with_0.x = 1
2170 a = _with_0
2171end
2172local b
2173local _with_0 = obj
2174repeat
2175 b = _with_0.x
2176 break
2177until true
2166local create_person 2178local create_person
2167create_person = function(name, relatives) 2179create_person = function(name, relatives)
2168 local _with_0 = Person() 2180 local _with_0 = Person()
@@ -2209,6 +2221,18 @@ repeat
2209 result = _with_0.value 2221 result = _with_0.value
2210 break 2222 break
2211until true 2223until true
2224local a
2225do
2226 local _with_0 = obj
2227 _with_0.x = 1
2228 a = _with_0
2229end
2230local b
2231local _with_0 = obj
2232repeat
2233 b = _with_0.x
2234 break
2235until true
2212local create_person 2236local create_person
2213create_person = function(name, relatives) 2237create_person = function(name, relatives)
2214 local _with_0 = Person() 2238 local _with_0 = Person()
diff --git a/spec/outputs/codes_from_doc_en.lua b/spec/outputs/codes_from_doc_en.lua
index 4006605..6d822e1 100644
--- a/spec/outputs/codes_from_doc_en.lua
+++ b/spec/outputs/codes_from_doc_en.lua
@@ -2163,6 +2163,18 @@ repeat
2163 result = _with_0.value 2163 result = _with_0.value
2164 break 2164 break
2165until true 2165until true
2166local a
2167do
2168 local _with_0 = obj
2169 _with_0.x = 1
2170 a = _with_0
2171end
2172local b
2173local _with_0 = obj
2174repeat
2175 b = _with_0.x
2176 break
2177until true
2166local create_person 2178local create_person
2167create_person = function(name, relatives) 2179create_person = function(name, relatives)
2168 local _with_0 = Person() 2180 local _with_0 = Person()
@@ -2209,6 +2221,18 @@ repeat
2209 result = _with_0.value 2221 result = _with_0.value
2210 break 2222 break
2211until true 2223until true
2224local a
2225do
2226 local _with_0 = obj
2227 _with_0.x = 1
2228 a = _with_0
2229end
2230local b
2231local _with_0 = obj
2232repeat
2233 b = _with_0.x
2234 break
2235until true
2212local create_person 2236local create_person
2213create_person = function(name, relatives) 2237create_person = function(name, relatives)
2214 local _with_0 = Person() 2238 local _with_0 = Person()
diff --git a/spec/outputs/codes_from_doc_id-id.lua b/spec/outputs/codes_from_doc_id-id.lua
index 7d95eaa..4026240 100644
--- a/spec/outputs/codes_from_doc_id-id.lua
+++ b/spec/outputs/codes_from_doc_id-id.lua
@@ -2163,6 +2163,18 @@ repeat
2163 result = _with_0.value 2163 result = _with_0.value
2164 break 2164 break
2165until true 2165until true
2166local a
2167do
2168 local _with_0 = obj
2169 _with_0.x = 1
2170 a = _with_0
2171end
2172local b
2173local _with_0 = obj
2174repeat
2175 b = _with_0.x
2176 break
2177until true
2166local create_person 2178local create_person
2167create_person = function(name, relatives) 2179create_person = function(name, relatives)
2168 local _with_0 = Person() 2180 local _with_0 = Person()
@@ -2209,6 +2221,18 @@ repeat
2209 result = _with_0.value 2221 result = _with_0.value
2210 break 2222 break
2211until true 2223until true
2224local a
2225do
2226 local _with_0 = obj
2227 _with_0.x = 1
2228 a = _with_0
2229end
2230local b
2231local _with_0 = obj
2232repeat
2233 b = _with_0.x
2234 break
2235until true
2212local create_person 2236local create_person
2213create_person = function(name, relatives) 2237create_person = function(name, relatives)
2214 local _with_0 = Person() 2238 local _with_0 = Person()
diff --git a/spec/outputs/codes_from_doc_pt-br.lua b/spec/outputs/codes_from_doc_pt-br.lua
index caa15d6..0d0c76f 100644
--- a/spec/outputs/codes_from_doc_pt-br.lua
+++ b/spec/outputs/codes_from_doc_pt-br.lua
@@ -2163,6 +2163,18 @@ repeat
2163 result = _with_0.value 2163 result = _with_0.value
2164 break 2164 break
2165until true 2165until true
2166local a
2167do
2168 local _with_0 = obj
2169 _with_0.x = 1
2170 a = _with_0
2171end
2172local b
2173local _with_0 = obj
2174repeat
2175 b = _with_0.x
2176 break
2177until true
2166local create_person 2178local create_person
2167create_person = function(name, relatives) 2179create_person = function(name, relatives)
2168 local _with_0 = Person() 2180 local _with_0 = Person()
@@ -2209,6 +2221,18 @@ repeat
2209 result = _with_0.value 2221 result = _with_0.value
2210 break 2222 break
2211until true 2223until true
2224local a
2225do
2226 local _with_0 = obj
2227 _with_0.x = 1
2228 a = _with_0
2229end
2230local b
2231local _with_0 = obj
2232repeat
2233 b = _with_0.x
2234 break
2235until true
2212local create_person 2236local create_person
2213create_person = function(name, relatives) 2237create_person = function(name, relatives)
2214 local _with_0 = Person() 2238 local _with_0 = Person()
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index 4ff3866..c847841 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -2163,6 +2163,18 @@ repeat
2163 result = _with_0.value 2163 result = _with_0.value
2164 break 2164 break
2165until true 2165until true
2166local a
2167do
2168 local _with_0 = obj
2169 _with_0.x = 1
2170 a = _with_0
2171end
2172local b
2173local _with_0 = obj
2174repeat
2175 b = _with_0.x
2176 break
2177until true
2166local create_person 2178local create_person
2167create_person = function(name, relatives) 2179create_person = function(name, relatives)
2168 local _with_0 = Person() 2180 local _with_0 = Person()
@@ -2209,6 +2221,18 @@ repeat
2209 result = _with_0.value 2221 result = _with_0.value
2210 break 2222 break
2211until true 2223until true
2224local a
2225do
2226 local _with_0 = obj
2227 _with_0.x = 1
2228 a = _with_0
2229end
2230local b
2231local _with_0 = obj
2232repeat
2233 b = _with_0.x
2234 break
2235until true
2212local create_person 2236local create_person
2213create_person = function(name, relatives) 2237create_person = function(name, relatives)
2214 local _with_0 = Person() 2238 local _with_0 = Person()
diff --git a/spec/outputs/compile_doc.lua b/spec/outputs/compile_doc.lua
index 8d5c11a..f661bbd 100644
--- a/spec/outputs/compile_doc.lua
+++ b/spec/outputs/compile_doc.lua
@@ -1,4 +1,10 @@
1local outputFolder = ... 1local outputFolder, docFolder
2do
3 local _obj_0 = {
4 ...
5 }
6 outputFolder, docFolder = _obj_0[1], _obj_0[2]
7end
2local getFiles 8local getFiles
3getFiles = function(locale) 9getFiles = function(locale)
4 if locale == "en" then 10 if locale == "en" then
@@ -57,6 +63,7 @@ do
57 local locale = _list_0[_index_0] 63 local locale = _list_0[_index_0]
58 _accum_0[_len_0] = { 64 _accum_0[_len_0] = {
59 "codes_from_doc_" .. tostring(locale) .. ".lua", 65 "codes_from_doc_" .. tostring(locale) .. ".lua",
66 "yue-" .. tostring(locale) .. ".md",
60 getFiles(locale) 67 getFiles(locale)
61 } 68 }
62 _len_0 = _len_0 + 1 69 _len_0 = _len_0 + 1
@@ -65,8 +72,9 @@ do
65end 72end
66for _index_0 = 1, #docs do 73for _index_0 = 1, #docs do
67 local _des_0 = docs[_index_0] 74 local _des_0 = docs[_index_0]
68 local compiledFile, docFiles = _des_0[1], _des_0[2] 75 local compiledFile, docFile, docFiles = _des_0[1], _des_0[2], _des_0[3]
69 local codes = { } 76 local codes = { }
77 local docTexts = { }
70 for _index_1 = 1, #docFiles do 78 for _index_1 = 1, #docFiles do
71 local docFile = docFiles[_index_1] 79 local docFile = docFiles[_index_1]
72 local input 80 local input
@@ -74,6 +82,7 @@ for _index_0 = 1, #docs do
74 if _with_0 ~= nil then 82 if _with_0 ~= nil then
75 local to_lua = require("yue").to_lua 83 local to_lua = require("yue").to_lua
76 local text = _with_0:read("*a") 84 local text = _with_0:read("*a")
85 docTexts[#docTexts + 1] = text
77 for code in text:gmatch("```yuescript[\r\n]+(.-)```[^%w]") do 86 for code in text:gmatch("```yuescript[\r\n]+(.-)```[^%w]") do
78 local result, err = to_lua(code, { 87 local result, err = to_lua(code, {
79 implicit_return_root = false, 88 implicit_return_root = false,
@@ -103,8 +112,15 @@ for _index_0 = 1, #docs do
103 local _close_0 <close> = input 112 local _close_0 <close> = input
104 end 113 end
105 local output 114 local output
106 local _with_0 = io.open(tostring(outputFolder) .. "/" .. tostring(compiledFile), "w+") 115 do
107 _with_0:write(table.concat(codes)) 116 local _with_0 = io.open(tostring(outputFolder) .. "/" .. tostring(compiledFile), "w+")
108 output = _with_0 117 _with_0:write(table.concat(codes))
118 output = _with_0
119 end
109 local _close_0 <close> = output 120 local _close_0 <close> = output
121 local output2
122 local _with_0 = io.open(tostring(docFolder) .. "/" .. tostring(docFile), "w+")
123 _with_0:write(table.concat(docTexts, "\n"))
124 output2 = _with_0
125 local _close_1 <close> = output2
110end 126end