aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-04-20 15:32:16 +0800
committerLi Jin <dragon-fly@qq.com>2021-04-20 15:32:16 +0800
commit54abdf0fc51ea5df7e16660a8edbd254b42d0c36 (patch)
treeada6f0cbb6337d8a402f5a2bc03648ff0dc7e6de
parentd5d44e5b038b899a7eb2e182edd7f0aa9013a69d (diff)
downloadyuescript-54abdf0fc51ea5df7e16660a8edbd254b42d0c36.tar.gz
yuescript-54abdf0fc51ea5df7e16660a8edbd254b42d0c36.tar.bz2
yuescript-54abdf0fc51ea5df7e16660a8edbd254b42d0c36.zip
update docs.
-rw-r--r--LICENSE2
-rw-r--r--README.md2
-rwxr-xr-xdoc/docs/.vuepress/components/YueCompiler.vue5
-rw-r--r--doc/docs/.vuepress/theme/styles/code.styl4
-rwxr-xr-xdoc/docs/README.md3
-rwxr-xr-xdoc/docs/doc/README.md2074
6 files changed, 2074 insertions, 16 deletions
diff --git a/LICENSE b/LICENSE
index 6c2fbc6..12fe1df 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
1MIT License 1MIT License
2 2
3Copyright (c) 2020 Li Jin 3Copyright (c) 2021 Li Jin
4 4
5Permission is hereby granted, free of charge, to any person obtaining a copy 5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal 6of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 2bbd979..641b3d4 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
1# YueScript 1# YueScript
2 2
3<img src="doc/docs/.vuepress/public/image/yuescript.svg" width="300" height="300" alt="logo"/>
4
3[![Ubuntu](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml) [![Windows](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml) [![macOS](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml) 5[![Ubuntu](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml) [![Windows](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml) [![macOS](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml)
4 6
5Yuescript is a Moonscript dialect. It is derived from [Moonscript language](https://github.com/leafo/moonscript) 0.5.0 and continuously adopting new features to be more up to date. 7Yuescript is a Moonscript dialect. It is derived from [Moonscript language](https://github.com/leafo/moonscript) 0.5.0 and continuously adopting new features to be more up to date.
diff --git a/doc/docs/.vuepress/components/YueCompiler.vue b/doc/docs/.vuepress/components/YueCompiler.vue
index 4d72b92..9c09297 100755
--- a/doc/docs/.vuepress/components/YueCompiler.vue
+++ b/doc/docs/.vuepress/components/YueCompiler.vue
@@ -146,7 +146,7 @@
146 } 146 }
147 .childTitle { 147 .childTitle {
148 width: 100%; 148 width: 100%;
149 font-size: 1.5em; 149 font-size: 1.2em;
150 color: #b7ae8f; 150 color: #b7ae8f;
151 text-align: center; 151 text-align: center;
152 padding: 0.2em; 152 padding: 0.2em;
@@ -195,8 +195,7 @@
195 hyphens: none; 195 hyphens: none;
196 background: #f5f7ff; 196 background: #f5f7ff;
197 color: #5e6687; 197 color: #5e6687;
198 font-size: 1em; 198 font-size: 15px;
199 overflow: scroll;
200 } 199 }
201 200
202 .my-editor >>> .prism-editor__textarea:focus { 201 .my-editor >>> .prism-editor__textarea:focus {
diff --git a/doc/docs/.vuepress/theme/styles/code.styl b/doc/docs/.vuepress/theme/styles/code.styl
index 0cb4081..a89c18e 100644
--- a/doc/docs/.vuepress/theme/styles/code.styl
+++ b/doc/docs/.vuepress/theme/styles/code.styl
@@ -10,7 +10,7 @@ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/b
10code[class*="language-"], 10code[class*="language-"],
11pre[class*="language-"] { 11pre[class*="language-"] {
12 font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace; 12 font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace;
13 font-size: 1em; 13 font-size: 15px;
14 line-height: 1.375; 14 line-height: 1.375;
15 direction: ltr; 15 direction: ltr;
16 text-align: left; 16 text-align: left;
@@ -29,7 +29,7 @@ pre[class*="language-"] {
29} 29}
30 30
31pre > code[class*="language-"] { 31pre > code[class*="language-"] {
32 font-size: 1em; 32 font-size: 15px;
33} 33}
34 34
35pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 35pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
diff --git a/doc/docs/README.md b/doc/docs/README.md
index dfc01d1..f98df6c 100755
--- a/doc/docs/README.md
+++ b/doc/docs/README.md
@@ -4,5 +4,6 @@ heroImage: ./image/yuescript.svg
4tagline: A language that compiles to Lua 4tagline: A language that compiles to Lua
5actionText: Quick Start → 5actionText: Quick Start →
6actionLink: /doc/ 6actionLink: /doc/
7footer: Made by Jin with ❤️ 7footer: MIT Licensed | Copyright © 2021 Li Jin
8--- 8---
9
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index 0d43d04..ec76612 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -2,14 +2,12 @@
2sidebar: auto 2sidebar: auto
3--- 3---
4 4
5<CompilerModal />
6
7# Yuescript 5# Yuescript
8<img src="/image/yuescript.svg" width="300" height="300" alt="logo"/> 6<img src="/image/yuescript.svg" width="300" height="300" alt="logo"/>
9 7
10## Introduction 8## Introduction
11 9
12Yuescript is a dynamic language that compiles to Lua. 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. 10Yuescript 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.
13 11
14Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. 12Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ].
15 13
@@ -232,8 +230,8 @@ macro luaFunc = (var)-> {
232$luaFunc funcB 230$luaFunc funcB
233funcB = -> "assign the Lua defined variable" 231funcB = -> "assign the Lua defined variable"
234 232
235macro lua = (code)-> { 233macro lua = (codes)-> {
236 :code 234 :codes
237 type: "lua" 235 type: "lua"
238} 236}
239 237
@@ -261,8 +259,8 @@ macro luaFunc = (var)-> {
261$luaFunc funcB 259$luaFunc funcB
262funcB = -> "assign the Lua defined variable" 260funcB = -> "assign the Lua defined variable"
263 261
264macro lua = (code)-> { 262macro lua = (codes)-> {
265 :code 263 :codes
266 type: "lua" 264 type: "lua"
267} 265}
268 266
@@ -313,7 +311,9 @@ import "utils" as {
313</pre> 311</pre>
314</YueDisplay> 312</YueDisplay>
315 313
316## Special Operator 314## Operator
315
316All of Lua’s binary and unary operators are available. Additionally **!=** is as an alias for **~=**. And Yuescipt offers some special operator to write more expressive codes.
317 317
318### Metatable 318### Metatable
319 319
@@ -591,4 +591,2060 @@ export default ->
591 print "hello" 591 print "hello"
592 123 592 123
593</pre> 593</pre>
594</YueDisplay> \ No newline at end of file 594</YueDisplay>
595
596## Whitespace
597
598Yuescript 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.
599
600## Assignment
601
602The variable is dynamic typed and is defined as local by default. But you can change the scope of declaration by **local** and **global** statement.
603
604* **Common Use**
605```moonscript
606hello = "world"
607a, b, c = 1, 2, 3
608hello = 123 -- uses the existing variable
609
610-- update Assignment
611x = 0
612x += 10
613
614s = "hello "
615s ..= "world"
616
617arg or= "default value"
618```
619<YueDisplay>
620<pre>
621hello = "world"
622a, b, c = 1, 2, 3
623hello = 123 -- uses the existing variable
624
625-- update Assignment
626x = 0
627x += 10
628
629s = "hello "
630s ..= "world"
631
632arg or= "default value"
633</pre>
634</YueDisplay>
635
636* **Explicit Locals**
637```moonscript
638do
639 local *
640 print "forward declare all variables as locals"
641 x = -> 1 + y + z
642 y, z = 2, 3
643 global instance = Item\new!
644
645do
646 local ^
647 print "only forward declare upper case variables"
648 a = 1
649 B = 2
650```
651<YueDisplay>
652<pre>
653do
654 local *
655 print "forward declare all variables as locals"
656 x = -> 1 + y + z
657 y, z = 2, 3
658 global instance = Item\new!
659
660do
661 local ^
662 print "only forward declare upper case variables"
663 a = 1
664 B = 2
665</pre>
666</YueDisplay>
667
668* **Explicit Globals**
669```moonscript
670do
671 global *
672 print "declare all variables as globals"
673 x = -> 1 + y + z
674 y, z = 2, 3
675
676do
677 global ^
678 print "only declare upper case variables as globals"
679 a = 1
680 B = 2
681 local Temp = "a local value"
682```
683<YueDisplay>
684<pre>
685do
686 global *
687 print "declare all variables as globals"
688 x = -> 1 + y + z
689 y, z = 2, 3
690
691do
692 global ^
693 print "only declare upper case variables as globals"
694 a = 1
695 B = 2
696 local Temp = "a local value"
697</pre>
698</YueDisplay>
699
700## Comment
701```moonscript
702-- I am a comment
703
704str = --[[
705This is a multi-line comment.
706It's OK.
707]] strA \ -- comment 1
708 .. strB \ -- comment 2
709 .. strC
710
711func --[[port]] 3000, --[[ip]] "192.168.1.1"
712```
713<YueDisplay>
714<pre>
715-- I am a comment
716
717str = --[[
718This is a multi-line comment.
719It's OK.
720]] strA \ -- comment 1
721 .. strB \ -- comment 2
722 .. strC
723
724func --[[port]] 3000, --[[ip]] "192.168.1.1"
725</pre>
726</YueDisplay>
727
728::: warning NOTICE
729The rest of the document is describing mostly the same syntax taken from Moonscript. So you may as well refer to the [Moonscript Reference](http://moonscript.org/reference) to get the same explanation.
730:::
731
732## Literals
733
734All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**.
735
736Unlike Lua, Line breaks are allowed inside of single and double quote strings without an escape sequence:
737
738```moonscript
739some_string = "Here is a string
740 that has a line break in it."
741
742-- You can mix expressions into string literals using #{} syntax.
743print "I am #{math.random! * 100}% sure."
744```
745<YueDisplay>
746<pre>
747some_string = "Here is a string
748 that has a line break in it."
749
750-- You can mix expressions into string literals using #{} syntax.
751print "I am #{math.random! * 100}% sure."
752</pre>
753</YueDisplay>
754
755## Function Literals
756
757All functions are created using a function expression. A simple function is denoted using the arrow: **->**.
758
759```moonscript
760my_function = ->
761my_function() -- call the empty function
762```
763<YueDisplay>
764<pre>
765my_function = ->
766my_function() -- call the empty function
767</pre>
768</YueDisplay>
769
770The 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:
771
772```moonscript
773func_a = -> print "hello world"
774
775func_b = ->
776 value = 100
777 print "The value:", value
778```
779<YueDisplay>
780<pre>
781func_a = -> print "hello world"
782
783func_b = ->
784 value = 100
785 print "The value:", value
786</pre>
787</YueDisplay>
788
789If 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.
790
791```moonscript
792func_a!
793func_b()
794```
795<YueDisplay>
796<pre>
797func_a!
798func_b()
799</pre>
800</YueDisplay>
801
802Functions with arguments can be created by preceding the arrow with a list of argument names in parentheses:
803
804```moonscript
805sum = (x, y)-> print "sum", x + y
806```
807<YueDisplay>
808<pre>
809sum = (x, y)-> print "sum", x + y
810</pre>
811</YueDisplay>
812
813Functions 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.
814
815```moonscript
816sum 10, 20
817print sum 10, 20
818
819a b c "a", "b", "c"
820```
821<YueDisplay>
822<pre>
823sum 10, 20
824print sum 10, 20
825
826a b c "a", "b", "c"
827</pre>
828</YueDisplay>
829
830In 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.
831
832```moonscript
833print "x:", sum(10, 20), "y:", sum(30, 40)
834```
835<YueDisplay>
836<pre>
837print "x:", sum(10, 20), "y:", sum(30, 40)
838</pre>
839</YueDisplay>
840
841There must not be any space between the opening parenthesis and the function.
842
843Functions will coerce the last statement in their body into a return statement, this is called implicit return:
844
845```moonscript
846sum = (x, y)-> x + y
847print "The sum is ", sum 10, 20
848```
849<YueDisplay>
850<pre>
851sum = (x, y) -> x + y
852print "The sum is ", sum 10, 20
853</pre>
854</YueDisplay>
855
856And if you need to explicitly return, you can use the return keyword:
857
858```moonscript
859sum = (x, y)-> return x + y
860```
861<YueDisplay>
862<pre>
863sum = (x, y)-> return x + y
864</pre>
865</YueDisplay>
866
867Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas:
868
869```moonscript
870mystery = (x, y)-> x + y, x - y
871a, b = mystery 10, 20
872```
873<YueDisplay>
874<pre>
875mystery = (x, y)-> x + y, x - y
876a, b = mystery 10, 20
877</pre>
878</YueDisplay>
879
880### Fat Arrows
881
882Because 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.
883
884```moonscript
885func = (num)=> @value + num
886```
887<YueDisplay>
888<pre>
889func = (num)=> @value + num
890</pre>
891</YueDisplay>
892
893### Argument Defaults
894
895It 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.
896
897```moonscript
898my_function = (name = "something", height = 100)->
899 print "Hello I am", name
900 print "My height is", height
901```
902<YueDisplay>
903<pre>
904my_function = (name = "something", height = 100)->
905 print "Hello I am", name
906 print "My height is", height
907</pre>
908</YueDisplay>
909
910An 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.
911
912```moonscript
913some_args = (x = 100, y = x + 1000)->
914 print x + y
915```
916<YueDisplay>
917<pre>
918some_args = (x = 100, y = x + 1000)->
919 print x + y
920</pre>
921</YueDisplay>
922
923### Considerations
924
925Because of the expressive parentheses-less way of calling functions, some restrictions must be put in place to avoid parsing ambiguity involving whitespace.
926
927The minus sign plays two roles, a unary negation operator and a binary subtraction operator. Consider how the following examples compile:
928
929```moonscript
930a = x - 10
931b = x-10
932c = x -y
933d = x- z
934```
935<YueDisplay>
936<pre>
937a = x - 10
938b = x-10
939c = x -y
940d = x- z
941</pre>
942</YueDisplay>
943
944The 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.
945
946When 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.
947
948Where 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.
949
950```moonscript
951x = func"hello" + 100
952y = func "hello" + 100
953```
954<YueDisplay>
955<pre>
956x = func"hello" + 100
957y = func "hello" + 100
958</pre>
959</YueDisplay>
960
961### Multi-line arguments
962
963When 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.
964
965If 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
966
967```moonscript
968my_func 5, 4, 3,
969 8, 9, 10
970
971cool_func 1, 2,
972 3, 4,
973 5, 6,
974 7, 8
975```
976<YueDisplay>
977<pre>
978my_func 5, 4, 3,
979 8, 9, 10
980
981cool_func 1, 2,
982 3, 4,
983 5, 6,
984 7, 8
985</pre>
986</YueDisplay>
987
988This type of invocation can be nested. The level of indentation is used to determine to which function the arguments belong to.
989
990```moonscript
991my_func 5, 6, 7,
992 6, another_func 6, 7, 8,
993 9, 1, 2,
994 5, 4
995```
996<YueDisplay>
997<pre>
998my_func 5, 6, 7,
999 6, another_func 6, 7, 8,
1000 9, 1, 2,
1001 5, 4
1002</pre>
1003</YueDisplay>
1004
1005Because 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.
1006
1007```moonscript
1008x = {
1009 1, 2, 3, 4, a_func 4, 5,
1010 5, 6,
1011 8, 9, 10
1012}
1013```
1014<YueDisplay>
1015<pre>
1016x = {
1017 1, 2, 3, 4, a_func 4, 5,
1018 5, 6,
1019 8, 9, 10
1020}
1021</pre>
1022</YueDisplay>
1023
1024Although uncommon, notice how we can give a deeper indentation for function arguments if we know we will be using a lower indentation further on.
1025
1026```moonscript
1027y = { my_func 1, 2, 3,
1028 4, 5,
1029 5, 6, 7
1030}
1031```
1032<YueDisplay>
1033<pre>
1034y = { my_func 1, 2, 3,
1035 4, 5,
1036 5, 6, 7
1037}
1038</pre>
1039</YueDisplay>
1040
1041The 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:
1042
1043```moonscript
1044if func 1, 2, 3,
1045 "hello",
1046 "world"
1047 print "hello"
1048 print "I am inside if"
1049
1050if func 1, 2, 3,
1051 "hello",
1052 "world"
1053 print "hello"
1054 print "I am inside if"
1055```
1056<YueDisplay>
1057<pre>
1058if func 1, 2, 3,
1059 "hello",
1060 "world"
1061 print "hello"
1062 print "I am inside if"
1063
1064if func 1, 2, 3,
1065 "hello",
1066 "world"
1067 print "hello"
1068 print "I am inside if"
1069</pre>
1070</YueDisplay>
1071
1072## Table Literals
1073
1074Like in Lua, tables are delimited in curly braces.
1075
1076```moonscript
1077some_values = { 1, 2, 3, 4 }
1078```
1079<YueDisplay>
1080<pre>
1081some_values = { 1, 2, 3, 4 }
1082</pre>
1083</YueDisplay>
1084
1085Unlike Lua, assigning a value to a key in a table is done with **:** (instead of **=**).
1086
1087```moonscript
1088some_values = {
1089 name: "Bill",
1090 age: 200,
1091 ["favorite food"]: "rice"
1092}
1093```
1094<YueDisplay>
1095<pre>
1096some_values = {
1097 name: "Bill",
1098 age: 200,
1099 ["favorite food"]: "rice"
1100}
1101</pre>
1102</YueDisplay>
1103
1104The curly braces can be left off if a single table of key value pairs is being assigned.
1105
1106```moonscript
1107profile =
1108 height: "4 feet",
1109 shoe_size: 13,
1110 favorite_foods: {"ice cream", "donuts"}
1111```
1112<YueDisplay>
1113<pre>
1114profile =
1115 height: "4 feet",
1116 shoe_size: 13,
1117 favorite_foods: {"ice cream", "donuts"}
1118</pre>
1119</YueDisplay>
1120
1121Newlines can be used to delimit values instead of a comma (or both):
1122
1123```moonscript
1124values = {
1125 1, 2, 3, 4
1126 5, 6, 7, 8
1127 name: "superman"
1128 occupation: "crime fighting"
1129}
1130```
1131<YueDisplay>
1132<pre>
1133values = {
1134 1, 2, 3, 4
1135 5, 6, 7, 8
1136 name: "superman"
1137 occupation: "crime fighting"
1138}
1139</pre>
1140</YueDisplay>
1141
1142When creating a single line table literal, the curly braces can also be left off:
1143
1144```moonscript
1145my_function dance: "Tango", partner: "none"
1146
1147y = type: "dog", legs: 4, tails: 1
1148```
1149<YueDisplay>
1150<pre>
1151my_function dance: "Tango", partner: "none"
1152
1153y = type: "dog", legs: 4, tails: 1
1154</pre>
1155</YueDisplay>
1156
1157The keys of a table literal can be language keywords without being escaped:
1158
1159```moonscript
1160tbl = {
1161 do: "something"
1162 end: "hunger"
1163}
1164```
1165<YueDisplay>
1166<pre>
1167tbl = {
1168 do: "something"
1169 end: "hunger"
1170}
1171</pre>
1172</YueDisplay>
1173
1174If 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:
1175
1176```moonscript
1177hair = "golden"
1178height = 200
1179person = { :hair, :height, shoe_size: 40 }
1180
1181print_table :hair, :height
1182```
1183<YueDisplay>
1184<pre>
1185hair = "golden"
1186height = 200
1187person = { :hair, :height, shoe_size: 40 }
1188
1189print_table :hair, :height
1190</pre>
1191</YueDisplay>
1192
1193If 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.
1194
1195```moonscript
1196t = {
1197 [1 + 2]: "hello"
1198 "hello world": true
1199}
1200```
1201<YueDisplay>
1202<pre>
1203t = {
1204 [1 + 2]: "hello"
1205 "hello world": true
1206}
1207</pre>
1208</YueDisplay>
1209
1210## Comprehensions
1211
1212Comprehensions 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.
1213
1214### List Comprehensions
1215
1216The following creates a copy of the items table but with all the values doubled.
1217
1218```moonscript
1219items = { 1, 2, 3, 4 }
1220doubled = [item * 2 for i, item in ipairs items]
1221```
1222<YueDisplay>
1223<pre>
1224items = { 1, 2, 3, 4 }
1225doubled = [item * 2 for i, item in ipairs items]
1226</pre>
1227</YueDisplay>
1228
1229The items included in the new table can be restricted with a when clause:
1230
1231```moonscript
1232iter = ipairs items
1233slice = [item for i, item in iter when i > 1 and i < 3]
1234```
1235<YueDisplay>
1236<pre>
1237iter = ipairs items
1238slice = [item for i, item in iter when i > 1 and i < 3]
1239</pre>
1240</YueDisplay>
1241
1242Because it is common to iterate over the values of a numerically indexed table, an **\*** operator is introduced. The doubled example can be rewritten as:
1243
1244```moonscript
1245doubled = [item * 2 for item in *items]
1246```
1247<YueDisplay>
1248<pre>
1249doubled = [item * 2 for item in *items]
1250</pre>
1251</YueDisplay>
1252
1253The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause.
1254
1255Using multiple for clauses is the same as using nested loops:
1256
1257```moonscript
1258x_coords = {4, 5, 6, 7}
1259y_coords = {9, 2, 3}
1260
1261points = [{x, y} for x in *x_coords \
1262for y in *y_coords]
1263```
1264<YueDisplay>
1265<pre>
1266x_coords = {4, 5, 6, 7}
1267y_coords = {9, 2, 3}
1268
1269points = [{x, y} for x in *x_coords \
1270for y in *y_coords]
1271</pre>
1272</YueDisplay>
1273
1274Numeric for loops can also be used in comprehensions:
1275
1276```moonscript
1277evens = [i for i = 1, 100 when i % 2 == 0]
1278```
1279<YueDisplay>
1280<pre>
1281evens = [i for i = 1, 100 when i % 2 == 0]
1282</pre>
1283</YueDisplay>
1284
1285### Table Comprehensions
1286
1287The syntax for table comprehensions is very similar, only differing by using **{** and **}** and taking two values from each iteration.
1288
1289This example makes a copy of the tablething:
1290
1291```moonscript
1292thing = {
1293 color: "red"
1294 name: "fast"
1295 width: 123
1296}
1297
1298thing_copy = {k, v for k, v in pairs thing}
1299```
1300<YueDisplay>
1301<pre>
1302thing = {
1303 color: "red"
1304 name: "fast"
1305 width: 123
1306}
1307
1308thing_copy = {k, v for k, v in pairs thing}
1309</pre>
1310</YueDisplay>
1311
1312```moonscript
1313no_color = {k, v for k, v in pairs thing when k != "color"}
1314```
1315<YueDisplay>
1316<pre>
1317no_color = {k, v for k, v in pairs thing when k != "color"}
1318</pre>
1319</YueDisplay>
1320
1321The **\*** operator is also supported. Here we create a square root look up table for a few numbers.
1322
1323```moonscript
1324numbers = {1, 2, 3, 4}
1325sqrts = {i, math.sqrt i for i in *numbers}
1326```
1327<YueDisplay>
1328<pre>
1329numbers = {1, 2, 3, 4}
1330sqrts = {i, math.sqrt i for i in *numbers}
1331</pre>
1332</YueDisplay>
1333
1334The 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:
1335
1336In 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.
1337
1338```moonscript
1339tuples = {{"hello", "world"}, {"foo", "bar"}}
1340tbl = {unpack tuple for tuple in *tuples}
1341```
1342<YueDisplay>
1343<pre>
1344tuples = { {"hello", "world"}, {"foo", "bar"} }
1345tbl = {unpack tuple for tuple in *tuples}
1346</pre>
1347</YueDisplay>
1348
1349### Slicing
1350
1351A 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.
1352
1353Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive:
1354
1355```moonscript
1356slice = [item for item in *items[1, 5]]
1357```
1358<YueDisplay>
1359<pre>
1360slice = [item for item in *items[1, 5]]
1361</pre>
1362</YueDisplay>
1363
1364Any 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:
1365
1366```moonscript
1367slice = [item for item in *items[2,]]
1368```
1369<YueDisplay>
1370<pre>
1371slice = [item for item in *items[2,]]
1372</pre>
1373</YueDisplay>
1374
1375If 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, …)
1376
1377```moonscript
1378slice = [item for item in *items[,,2]]
1379```
1380<YueDisplay>
1381<pre>
1382slice = [item for item in *items[,,2]]
1383</pre>
1384</YueDisplay>
1385
1386## For Loop
1387
1388There are two for loop forms, just like in Lua. A numeric one and a generic one:
1389
1390```moonscript
1391for i = 10, 20
1392 print i
1393
1394for k = 1, 15, 2 -- an optional step provided
1395 print k
1396
1397for key, value in pairs object
1398 print key, value
1399```
1400<YueDisplay>
1401<pre>
1402for i = 10, 20
1403 print i
1404
1405for k = 1, 15, 2 -- an optional step provided
1406 print k
1407
1408for key, value in pairs object
1409 print key, value
1410</pre>
1411</YueDisplay>
1412
1413The slicing and **\*** operators can be used, just like with comprehensions:
1414
1415```moonscript
1416for item in *items[2, 4]
1417 print item
1418```
1419<YueDisplay>
1420<pre>
1421for item in *items[2, 4]
1422 print item
1423</pre>
1424</YueDisplay>
1425
1426A shorter syntax is also available for all variations when the body is only a single line:
1427
1428```moonscript
1429for item in *items do print item
1430
1431for j = 1, 10, 3 do print j
1432```
1433<YueDisplay>
1434<pre>
1435for item in *items do print item
1436
1437for j = 1, 10, 3 do print j
1438</pre>
1439</YueDisplay>
1440
1441A 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.
1442
1443Doubling every even number:
1444
1445```moonscript
1446doubled_evens = for i = 1, 20
1447 if i % 2 == 0
1448 i * 2
1449 else
1450 i
1451```
1452<YueDisplay>
1453<pre>
1454doubled_evens = for i = 1, 20
1455 if i % 2 == 0
1456 i * 2
1457 else
1458 i
1459</pre>
1460</YueDisplay>
1461
1462You can also filter values by combining the for loop expression with the continue statement.
1463
1464For 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.
1465
1466```moonscript
1467func_a = -> for i = 1, 10 do print i
1468func_b = -> return for i = 1, 10 do i
1469
1470print func_a! -- prints nil
1471print func_b! -- prints table object
1472```
1473<YueDisplay>
1474<pre>
1475func_a = -> for i = 1, 10 do print i
1476func_b = -> return for i = 1, 10 do i
1477
1478print func_a! -- prints nil
1479print func_b! -- prints table object
1480</pre>
1481</YueDisplay>
1482
1483This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop.
1484
1485## While Loop
1486
1487The while loop also comes in two variations:
1488
1489```moonscript
1490i = 10
1491while i > 0
1492 print i
1493 i -= 1
1494
1495while running == true do my_function!
1496```
1497<YueDisplay>
1498<pre>
1499i = 10
1500while i > 0
1501 print i
1502 i -= 1
1503
1504while running == true do my_function!
1505</pre>
1506</YueDisplay>
1507
1508Like for loops, the while loop can also be used an expression. Additionally, for a function to return the accumulated value of a while loop, the statement must be explicitly returned.
1509
1510## Continue
1511
1512A continue statement can be used to skip the current iteration in a loop.
1513
1514```moonscript
1515i = 0
1516while i < 10
1517 i += 1
1518 continue if i % 2 == 0
1519 print i
1520```
1521<YueDisplay>
1522<pre>
1523i = 0
1524while i < 10
1525 i += 1
1526 continue if i % 2 == 0
1527 print i
1528</pre>
1529</YueDisplay>
1530
1531continue 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:
1532
1533```moonscript
1534my_numbers = {1, 2, 3, 4, 5, 6}
1535odds = for x in *my_numbers
1536 continue if x % 2 == 1
1537 x
1538```
1539<YueDisplay>
1540<pre>
1541my_numbers = {1, 2, 3, 4, 5, 6}
1542odds = for x in *my_numbers
1543 continue if x % 2 == 1
1544 x
1545</pre>
1546</YueDisplay>
1547
1548## Conditionals
1549
1550```moonscript
1551have_coins = false
1552if have_coins
1553 print "Got coins"
1554else
1555 print "No coins"
1556```
1557<YueDisplay>
1558<pre>
1559have_coins = false
1560if have_coins
1561 print "Got coins"
1562else
1563 print "No coins"
1564</pre>
1565</YueDisplay>
1566
1567A short syntax for single statements can also be used:
1568
1569```moonscript
1570have_coins = false
1571if have_coins then print "Got coins" else print "No coins"
1572```
1573<YueDisplay>
1574<pre>
1575have_coins = false
1576if have_coins then print "Got coins" else print "No coins"
1577</pre>
1578</YueDisplay>
1579
1580Because if statements can be used as expressions, this can also be written as:
1581
1582```moonscript
1583have_coins = false
1584print if have_coins then "Got coins" else "No coins"
1585```
1586<YueDisplay>
1587<pre>
1588have_coins = false
1589print if have_coins then "Got coins" else "No coins"
1590</pre>
1591</YueDisplay>
1592
1593Conditionals can also be used in return statements and assignments:
1594
1595```moonscript
1596is_tall = (name) ->
1597 if name == "Rob"
1598 true
1599 else
1600 false
1601
1602message = if is_tall "Rob"
1603 "I am very tall"
1604else
1605 "I am not so tall"
1606
1607print message -- prints: I am very tall
1608```
1609<YueDisplay>
1610<pre>
1611is_tall = (name) ->
1612 if name == "Rob"
1613 true
1614 else
1615 false
1616
1617message = if is_tall "Rob"
1618 "I am very tall"
1619else
1620 "I am not so tall"
1621
1622print message -- prints: I am very tall
1623</pre>
1624</YueDisplay>
1625
1626The opposite of if is unless:
1627
1628```moonscript
1629unless os.date("%A") == "Monday"
1630 print "it is not Monday!"
1631```
1632<YueDisplay>
1633<pre>
1634unless os.date("%A") == "Monday"
1635 print "it is not Monday!"
1636</pre>
1637</YueDisplay>
1638
1639```moonscript
1640print "You're lucky!" unless math.random! > 0.1
1641```
1642<YueDisplay>
1643<pre>
1644print "You're lucky!" unless math.random! > 0.1
1645</pre>
1646</YueDisplay>
1647
1648## If Assignment
1649
1650if 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.
1651
1652```moonscript
1653if user = database.find_user "moon"
1654 print user.name
1655```
1656<YueDisplay>
1657<pre>
1658if user = database.find_user "moon"
1659 print user.name
1660</pre>
1661</YueDisplay>
1662
1663```moonscript
1664if hello = os.getenv "hello"
1665 print "You have hello", hello
1666elseif world = os.getenv "world"
1667 print "you have world", world
1668else
1669 print "nothing :("
1670```
1671<YueDisplay>
1672<pre>
1673if hello = os.getenv "hello"
1674 print "You have hello", hello
1675elseif world = os.getenv "world"
1676 print "you have world", world
1677else
1678 print "nothing :("
1679</pre>
1680</YueDisplay>
1681
1682## Line Decorators
1683
1684For convenience, the for loop and if statement can be applied to single statements at the end of the line:
1685
1686```moonscript
1687print "hello world" if name == "Rob"
1688```
1689<YueDisplay>
1690<pre>
1691print "hello world" if name == "Rob"
1692</pre>
1693</YueDisplay>
1694
1695And with basic loops:
1696
1697```moonscript
1698print "item: ", item for item in *items
1699```
1700<YueDisplay>
1701<pre>
1702print "item: ", item for item in *items
1703</pre>
1704</YueDisplay>
1705
1706## Switch
1707
1708The 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.
1709
1710```moonscript
1711name = "Dan"
1712switch name
1713 when "Robert"
1714 print "You are Robert"
1715 when "Dan", "Daniel"
1716 print "Your name, it's Dan"
1717 else
1718 print "I don't know about your name"
1719```
1720<YueDisplay>
1721<pre>
1722name = "Dan"
1723switch name
1724 when "Robert"
1725 print "You are Robert"
1726 when "Dan", "Daniel"
1727 print "Your name, it's Dan"
1728 else
1729 print "I don't know about your name"
1730</pre>
1731</YueDisplay>
1732
1733A switch when clause can match against multiple values by listing them out comma separated.
1734
1735Switches can be used as expressions as well, here we can assign the result of the switch to a variable:
1736
1737```moonscript
1738b = 1
1739next_number = switch b
1740 when 1
1741 2
1742 when 2
1743 3
1744 else
1745 error "can't count that high!"
1746```
1747<YueDisplay>
1748<pre>
1749b = 1
1750next_number = switch b
1751 when 1
1752 2
1753 when 2
1754 3
1755 else
1756 error "can't count that high!"
1757</pre>
1758</YueDisplay>
1759
1760We 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.
1761
1762```moonscript
1763msg = switch math.random(1, 5)
1764 when 1 then "you are lucky"
1765 when 2 then "you are almost lucky"
1766 else "not so lucky"
1767```
1768<YueDisplay>
1769<pre>
1770msg = switch math.random(1, 5)
1771 when 1 then "you are lucky"
1772 when 2 then "you are almost lucky"
1773 else "not so lucky"
1774</pre>
1775</YueDisplay>
1776
1777It 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.
1778
1779## Object Oriented Programming
1780
1781In 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.
1782
1783A simple class:
1784
1785```moonscript
1786class Inventory
1787 new: =>
1788 @items = {}
1789
1790 add_item: (name)=>
1791 if @items[name]
1792 @items[name] += 1
1793 else
1794 @items[name] = 1
1795```
1796<YueDisplay>
1797<pre>
1798class Inventory
1799 new: =>
1800 @items = {}
1801
1802 add_item: (name)=>
1803 if @items[name]
1804 @items[name] += 1
1805 else
1806 @items[name] = 1
1807</pre>
1808</YueDisplay>
1809
1810A class is declared with a class statement followed by a table-like declaration where all of the methods and properties are listed.
1811
1812The new property is special in that it will become the constructor.
1813
1814Notice 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.
1815
1816The @ prefix on a variable name is shorthand for self.. @items becomes self.items.
1817
1818Creating an instance of the class is done by calling the name of the class as a function.
1819
1820```moonscript
1821inv = Inventory!
1822inv\add_item "t-shirt"
1823inv\add_item "pants"
1824```
1825<YueDisplay>
1826<pre>
1827inv = Inventory!
1828inv\add_item "t-shirt"
1829inv\add_item "pants"
1830</pre>
1831</YueDisplay>
1832
1833Because the instance of the class needs to be sent to the methods when they are called, the \ operator is used.
1834
1835All properties of a class are shared among the instances. This is fine for functions, but for other types of objects, undesired results may occur.
1836
1837Consider the example below, the clothes property is shared amongst all instances, so modifications to it in one instance will show up in another:
1838
1839```moonscript
1840class Person
1841 clothes: {}
1842 give_item: (name)=>
1843 table.insert @clothes, name
1844
1845a = Person!
1846b = Person!
1847
1848a\give_item "pants"
1849b\give_item "shirt"
1850
1851-- will print both pants and shirt
1852print item for item in *a.clothes
1853```
1854<YueDisplay>
1855<pre>
1856class Person
1857 clothes: {}
1858 give_item: (name)=>
1859 table.insert @clothes, name
1860
1861a = Person!
1862b = Person!
1863
1864a\give_item "pants"
1865b\give_item "shirt"
1866
1867-- will print both pants and shirt
1868print item for item in *a.clothes
1869</pre>
1870</YueDisplay>
1871
1872The proper way to avoid this problem is to create the mutable state of the object in the constructor:
1873
1874```moonscript
1875class Person
1876 new: =>
1877 @clothes = {}
1878```
1879<YueDisplay>
1880<pre>
1881class Person
1882 new: =>
1883 @clothes = {}
1884</pre>
1885</YueDisplay>
1886
1887### Inheritance
1888
1889The extends keyword can be used in a class declaration to inherit the properties and methods from another class.
1890
1891```moonscript
1892class BackPack extends Inventory
1893 size: 10
1894 add_item: (name)=>
1895 if #@items > size then error "backpack is full"
1896 super name
1897```
1898<YueDisplay>
1899<pre>
1900class BackPack extends Inventory
1901 size: 10
1902 add_item: (name)=>
1903 if #@items > size then error "backpack is full"
1904 super name
1905</pre>
1906</YueDisplay>
1907
1908Here we extend our Inventory class, and limit the amount of items it can carry.
1909
1910In 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.
1911
1912Whenever 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.
1913
1914```moonscript
1915class Shelf
1916 @__inherited: (child)=>
1917 print @__name, "was inherited by", child.__name
1918
1919-- will print: Shelf was inherited by Cupboard
1920class Cupboard extends Shelf
1921```
1922<YueDisplay>
1923<pre>
1924class Shelf
1925 @__inherited: (child)=>
1926 print @__name, "was inherited by", child.__name
1927
1928-- will print: Shelf was inherited by Cupboard
1929class Cupboard extends Shelf
1930</pre>
1931</YueDisplay>
1932
1933### Super
1934
1935**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.
1936
1937When 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)
1938
1939When super is used as a normal value, it is a reference to the parent class object.
1940
1941It 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.
1942
1943When 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.
1944
1945A few examples of using super in different ways:
1946
1947```moonscript
1948class MyClass extends ParentClass
1949 a_method: =>
1950 -- the following have the same effect:
1951 super "hello", "world"
1952 super\a_method "hello", "world"
1953 super.a_method self, "hello", "world"
1954
1955 -- super as a value is equal to the parent class:
1956 assert super == ParentClass
1957```
1958<YueDisplay>
1959<pre>
1960class MyClass extends ParentClass
1961 a_method: =>
1962 -- the following have the same effect:
1963 super "hello", "world"
1964 super\a_method "hello", "world"
1965 super.a_method self, "hello", "world"
1966
1967 -- super as a value is equal to the parent class:
1968 assert super == ParentClass
1969</pre>
1970</YueDisplay>
1971
1972**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.
1973
1974### Types
1975
1976Every 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.
1977
1978```moonscript
1979b = BackPack!
1980assert b.__class == BackPack
1981
1982print BackPack.size -- prints 10
1983```
1984<YueDisplay>
1985<pre>
1986b = BackPack!
1987assert b.__class == BackPack
1988
1989print BackPack.size -- prints 10
1990</pre>
1991</YueDisplay>
1992
1993### Class Objects
1994
1995The 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.
1996
1997The 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.
1998
1999A 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.
2000
2001The 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.
2002
2003It 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.
2004
2005The class object has a couple special properties:
2006
2007The name of the class as when it was declared is stored as a string in the __name field of the class object.
2008
2009```moonscript
2010print BackPack.__name -- prints Backpack
2011```
2012<YueDisplay>
2013<pre>
2014print BackPack.__name -- prints Backpack
2015</pre>
2016</YueDisplay>
2017
2018The 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.
2019
2020If the class extends from anything, the parent class object is stored in __parent.
2021
2022### Class Variables
2023
2024We 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.
2025
2026```moonscript
2027class Things
2028 @some_func: => print "Hello from", @__name
2029
2030Things\some_func!
2031
2032-- class variables not visible in instances
2033assert Things().some_func == nil
2034```
2035<YueDisplay>
2036<pre>
2037class Things
2038 @some_func: => print "Hello from", @__name
2039
2040Things\some_func!
2041
2042-- class variables not visible in instances
2043assert Things().some_func == nil
2044</pre>
2045</YueDisplay>
2046
2047In expressions, we can use @@ to access a value that is stored in the __class of self. Thus, @@hello is shorthand for self.__class.hello.
2048
2049```moonscript
2050class Counter
2051 @count: 0
2052
2053 new: =>
2054 @@count += 1
2055
2056Counter!
2057Counter!
2058
2059print Counter.count -- prints 2
2060```
2061<YueDisplay>
2062<pre>
2063class Counter
2064 @count: 0
2065
2066 new: =>
2067 @@count += 1
2068
2069Counter!
2070Counter!
2071
2072print Counter.count -- prints 2
2073</pre>
2074</YueDisplay>
2075
2076The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax.
2077
2078```moonscript
2079@@hello 1,2,3,4
2080```
2081<YueDisplay>
2082<pre>
2083@@hello 1,2,3,4
2084</pre>
2085</YueDisplay>
2086
2087### Class Declaration Statements
2088
2089In 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.
2090
2091Here is an alternative way to create a class variable compared to what’s described above:
2092
2093```moonscript
2094class Things
2095 @class_var = "hello world"
2096```
2097<YueDisplay>
2098<pre>
2099class Things
2100 @class_var = "hello world"
2101</pre>
2102</YueDisplay>
2103
2104These expressions are executed after all the properties have been added to the base.
2105
2106All 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:
2107
2108```moonscript
2109class MoreThings
2110 secret = 123
2111 log = (msg)-> print "LOG:", msg
2112
2113 some_method: =>
2114 log "hello world: " .. secret
2115```
2116<YueDisplay>
2117<pre>
2118class MoreThings
2119 secret = 123
2120 log = (msg)-> print "LOG:", msg
2121
2122 some_method: =>
2123 log "hello world: " .. secret
2124</pre>
2125</YueDisplay>
2126
2127### @ and @@ Values
2128
2129When @ and @@ are prefixed in front of a name they represent, respectively, that name accessed in self and self.__class.
2130
2131If they are used all by themselves, they are aliases for self and self.__class.
2132
2133```moonscript
2134assert @ == self
2135assert @@ == self.__class
2136```
2137<YueDisplay>
2138<pre>
2139assert @ == self
2140assert @@ == self.__class
2141</pre>
2142</YueDisplay>
2143
2144For example, a quick way to create a new instance of the same class from an instance method using @@:
2145
2146```moonscript
2147some_instance_method = (...)=> @@ ...
2148```
2149<YueDisplay>
2150<pre>
2151some_instance_method = (...)=> @@ ...
2152</pre>
2153</YueDisplay>
2154
2155### Class Expressions
2156
2157The class syntax can also be used as an expression which can be assigned to a variable or explicitly returned.
2158
2159```moonscript
2160x = class Bucket
2161 drops: 0
2162 add_drop: => @drops += 1
2163```
2164<YueDisplay>
2165<pre>
2166x = class Bucket
2167 drops: 0
2168 add_drop: => @drops += 1
2169</pre>
2170</YueDisplay>
2171
2172### Anonymous classes
2173
2174The 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.
2175
2176```moonscript
2177BigBucket = class extends Bucket
2178 add_drop: => @drops += 10
2179
2180assert Bucket.__name == "BigBucket"
2181```
2182<YueDisplay>
2183<pre>
2184BigBucket = class extends Bucket
2185 add_drop: => @drops += 10
2186
2187assert Bucket.__name == "BigBucket"
2188</pre>
2189</YueDisplay>
2190
2191You can even leave off the body, meaning you can write a blank anonymous class like this:
2192
2193```moonscript
2194x = class
2195```
2196<YueDisplay>
2197<pre>
2198x = class
2199</pre>
2200</YueDisplay>
2201
2202## With Statement
2203
2204A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it.
2205
2206This 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.
2207
2208The 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.
2209
2210For example, we work with a newly created object:
2211
2212```moonscript
2213with Person!
2214 .name = "Oswald"
2215 \add_relative my_dad
2216 \save!
2217 print .name
2218```
2219<YueDisplay>
2220<pre>
2221with Person!
2222 .name = "Oswald"
2223 \add_relative my_dad
2224 \save!
2225 print .name
2226</pre>
2227</YueDisplay>
2228
2229The with statement can also be used as an expression which returns the value it has been giving access to.
2230
2231```moonscript
2232file = with File "favorite_foods.txt"
2233 \set_encoding "utf8"
2234```
2235<YueDisplay>
2236<pre>
2237file = with File "favorite_foods.txt"
2238 \set_encoding "utf8"
2239</pre>
2240</YueDisplay>
2241
2242Or…
2243
2244```moonscript
2245create_person = (name, relatives)->
2246 with Person!
2247 .name = name
2248 \add_relative relative for relative in *relatives
2249
2250me = create_person "Leaf", {dad, mother, sister}
2251```
2252<YueDisplay>
2253<pre>
2254create_person = (name, relatives)->
2255 with Person!
2256 .name = name
2257 \add_relative relative for relative in *relatives
2258
2259me = create_person "Leaf", {dad, mother, sister}
2260</pre>
2261</YueDisplay>
2262
2263In this usage, with can be seen as a special form of the K combinator.
2264
2265The expression in the with statement can also be an assignment, if you want to give a name to the expression.
2266
2267```moonscript
2268with str = "Hello"
2269 print "original:", str
2270 print "upper:", \upper!
2271```
2272<YueDisplay>
2273<pre>
2274with str = "Hello"
2275 print "original:", str
2276 print "upper:", \upper!
2277</pre>
2278</YueDisplay>
2279
2280## Do
2281
2282When used as a statement, do works just like it does in Lua.
2283
2284```moonscript
2285do
2286 var = "hello"
2287 print var
2288print var -- nil here
2289```
2290<YueDisplay>
2291<pre>
2292do
2293 var = "hello"
2294 print var
2295print var -- nil here
2296</pre>
2297</YueDisplay>
2298
2299Yuescript’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.
2300
2301```moonscript
2302counter = do
2303 i = 0
2304 ->
2305 i += 1
2306 i
2307
2308print counter!
2309print counter!
2310```
2311<YueDisplay>
2312<pre>
2313counter = do
2314 i = 0
2315 ->
2316 i += 1
2317 i
2318
2319print counter!
2320print counter!
2321</pre>
2322</YueDisplay>
2323
2324```moonscript
2325tbl = {
2326 key: do
2327 print "assigning key!"
2328 1234
2329}
2330```
2331<YueDisplay>
2332<pre>
2333tbl = {
2334 key: do
2335 print "assigning key!"
2336 1234
2337}
2338</pre>
2339</YueDisplay>
2340
2341## Destructuring Assignment
2342
2343Destructuring assignment is a way to quickly extract values from a table by their name or position in array based tables.
2344
2345Typically 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.
2346
2347This is best explained with examples. Here is how you would unpack the first two values from a table:
2348
2349```moonscript
2350thing = {1, 2}
2351
2352{a, b} = thing
2353print a, b
2354```
2355<YueDisplay>
2356<pre>
2357thing = {1, 2}
2358
2359{a, b} = thing
2360print a, b
2361</pre>
2362</YueDisplay>
2363
2364In 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.
2365
2366```moonscript
2367obj = {
2368 hello: "world"
2369 day: "tuesday"
2370 length: 20
2371}
2372
2373{hello: hello, day: the_day} = obj
2374print hello, the_day
2375```
2376<YueDisplay>
2377<pre>
2378obj = {
2379 hello: "world"
2380 day: "tuesday"
2381 length: 20
2382}
2383
2384{hello: hello, day: the_day} = obj
2385print hello, the_day
2386</pre>
2387</YueDisplay>
2388
2389This also works with nested data structures as well:
2390
2391```moonscript
2392obj2 = {
2393 numbers: {1,2,3,4}
2394 properties: {
2395 color: "green"
2396 height: 13.5
2397 }
2398}
2399
2400{numbers: {first, second}} = obj2
2401print first, second, color
2402```
2403<YueDisplay>
2404<pre>
2405obj2 = {
2406 numbers: {1,2,3,4}
2407 properties: {
2408 color: "green"
2409 height: 13.5
2410 }
2411}
2412
2413{numbers: {first, second}} = obj2
2414print first, second, color
2415</pre>
2416</YueDisplay>
2417
2418If the destructuring statement is complicated, feel free to spread it out over a few lines. A slightly more complicated example:
2419
2420```moonscript
2421{
2422 numbers: {first, second}
2423 properties: {
2424 color: color
2425 }
2426} = obj2
2427```
2428<YueDisplay>
2429<pre>
2430{
2431 numbers: {first, second}
2432 properties: {
2433 color: color
2434 }
2435} = obj2
2436</pre>
2437</YueDisplay>
2438
2439It’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:
2440
2441```moonscript
2442{:concat, :insert} = table
2443```
2444<YueDisplay>
2445<pre>
2446{:concat, :insert} = table
2447</pre>
2448</YueDisplay>
2449
2450This is effectively the same as import, but we can rename fields we want to extract by mixing the syntax:
2451
2452```moonscript
2453{:mix, :max, random: rand} = math
2454```
2455<YueDisplay>
2456<pre>
2457{:mix, :max, random: rand} = math
2458</pre>
2459</YueDisplay>
2460
2461### Destructuring In Other Places
2462
2463Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
2464
2465```moonscript
2466tuples = {
2467 {"hello", "world"}
2468 {"egg", "head"}
2469}
2470
2471for {left, right} in *tuples
2472 print left, right
2473```
2474<YueDisplay>
2475<pre>
2476tuples = {
2477 {"hello", "world"}
2478 {"egg", "head"}
2479}
2480
2481for {left, right} in *tuples
2482 print left, right
2483</pre>
2484</YueDisplay>
2485
2486We 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.
2487
2488## Function Stubs
2489
2490It 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.
2491
2492The 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.
2493
2494Its syntax is the same as calling an instance method with the \ operator but with no argument list provided.
2495
2496```moonscript
2497my_object = {
2498 value: 1000
2499 write: => print "the value:", @value
2500}
2501
2502run_callback = (func)->
2503 print "running callback..."
2504 func!
2505
2506-- this will not work:
2507-- the function has to no reference to my_object
2508run_callback my_object.write
2509
2510-- function stub syntax
2511-- lets us bundle the object into a new function
2512run_callback my_object\write
2513```
2514<YueDisplay>
2515<pre>
2516my_object = {
2517 value: 1000
2518 write: => print "the value:", @value
2519}
2520
2521run_callback = (func)->
2522 print "running callback..."
2523 func!
2524
2525-- this will not work:
2526-- the function has to no reference to my_object
2527run_callback my_object.write
2528
2529-- function stub syntax
2530-- lets us bundle the object into a new function
2531run_callback my_object\write
2532</pre>
2533</YueDisplay>
2534
2535## The Using Clause; Controlling Destructive Assignment
2536
2537While 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:
2538
2539```moonscript
2540i = 100
2541
2542-- many lines of code...
2543
2544my_func = ->
2545 i = 10
2546 while i > 0
2547 print i
2548 i -= 1
2549
2550my_func!
2551
2552print i -- will print 0
2553```
2554<YueDisplay>
2555<pre>
2556i = 100
2557
2558-- many lines of code...
2559
2560my_func = ->
2561 i = 10
2562 while i > 0
2563 print i
2564 i -= 1
2565
2566my_func!
2567
2568print i -- will print 0
2569</pre>
2570</YueDisplay>
2571
2572In 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.
2573
2574It 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.
2575
2576The 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.
2577
2578```moonscript
2579i = 100
2580
2581my_func = (using nil)->
2582 i = "hello" -- a new local variable is created here
2583
2584my_func!
2585print i -- prints 100, i is unaffected
2586```
2587<YueDisplay>
2588<pre>
2589i = 100
2590
2591my_func = (using nil)->
2592 i = "hello" -- a new local variable is created here
2593
2594my_func!
2595print i -- prints 100, i is unaffected
2596</pre>
2597</YueDisplay>
2598
2599Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified:
2600
2601```moonscript
2602tmp = 1213
2603i, k = 100, 50
2604
2605my_func = (add using k, i)->
2606 tmp = tmp + add -- a new local tmp is created
2607 i += tmp
2608 k += tmp
2609
2610my_func(22)
2611print i, k -- these have been updated
2612```
2613<YueDisplay>
2614<pre>
2615tmp = 1213
2616i, k = 100, 50
2617
2618my_func = (add using k, i)->
2619 tmp = tmp + add -- a new local tmp is created
2620 i += tmp
2621 k += tmp
2622
2623my_func(22)
2624print i, k -- these have been updated
2625</pre>
2626</YueDisplay>
2627
2628## Licence: MIT
2629
2630Copyright (c) 2021 Li Jin
2631
2632Permission is hereby granted, free of charge, to any person obtaining a copy
2633of this software and associated documentation files (the "Software"), to deal
2634in the Software without restriction, including without limitation the rights
2635to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2636copies of the Software, and to permit persons to whom the Software is
2637furnished to do so, subject to the following conditions:
2638
2639The above copyright notice and this permission notice shall be included in all
2640copies or substantial portions of the Software.
2641
2642THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2643IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2644FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2645AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2646LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2647OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2648SOFTWARE.
2649
2650<CompilerModal /> \ No newline at end of file