diff options
Diffstat (limited to 'doc/docs/doc/README.md')
-rwxr-xr-x | doc/docs/doc/README.md | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md new file mode 100755 index 0000000..0d43d04 --- /dev/null +++ b/doc/docs/doc/README.md | |||
@@ -0,0 +1,594 @@ | |||
1 | --- | ||
2 | sidebar: auto | ||
3 | --- | ||
4 | |||
5 | <CompilerModal /> | ||
6 | |||
7 | # Yuescript | ||
8 | <img src="/image/yuescript.svg" width="300" height="300" alt="logo"/> | ||
9 | |||
10 | ## Introduction | ||
11 | |||
12 | Yuescript 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. | ||
13 | |||
14 | Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. | ||
15 | |||
16 | ### An Overview of Yuescript | ||
17 | ```moonscript | ||
18 | -- import syntax | ||
19 | import "yue" as :p, :to_lua | ||
20 | |||
21 | -- implicit objects | ||
22 | inventory = | ||
23 | equipment: | ||
24 | * "sword" | ||
25 | * "shield" | ||
26 | items: | ||
27 | * name: "potion" | ||
28 | count: 10 | ||
29 | * name: "bread" | ||
30 | count: 3 | ||
31 | |||
32 | -- backcall | ||
33 | {1, 2, 3} | ||
34 | |> map (x)-> x * 2 | ||
35 | |> filter (x)-> x > 4 | ||
36 | |> reduce 0, (a, b)-> a + b | ||
37 | |||
38 | |||
39 | -- metatable manipulation | ||
40 | apple = | ||
41 | size: 15 | ||
42 | index#: {color: 0x00ffff} | ||
43 | p apple.color, apple.#?, apple.index# | ||
44 | |||
45 | -- js-like export syntax | ||
46 | export yuescript = "月之脚本" | ||
47 | ``` | ||
48 | <YueDisplay> | ||
49 | <pre> | ||
50 | -- import syntax | ||
51 | import "yue" as :p, :to_lua | ||
52 | |||
53 | -- implicit objects | ||
54 | inventory = | ||
55 | equipment: | ||
56 | * "sword" | ||
57 | * "shield" | ||
58 | items: | ||
59 | * name: "potion" | ||
60 | count: 10 | ||
61 | * name: "bread" | ||
62 | count: 3 | ||
63 | |||
64 | -- backcall | ||
65 | {1, 2, 3} | ||
66 | |> map (x)-> x * 2 | ||
67 | |> filter (x)-> x > 4 | ||
68 | |> reduce 0, (a, b)-> a + b | ||
69 | |||
70 | |||
71 | -- metatable manipulation | ||
72 | apple = | ||
73 | size: 15 | ||
74 | index#: {color: 0x00ffff} | ||
75 | p apple.color, apple.#?, apple.index# | ||
76 | |||
77 | -- js-like export syntax | ||
78 | export yuescript = "月之脚本" | ||
79 | </pre> | ||
80 | </YueDisplay> | ||
81 | |||
82 | ## Installation | ||
83 | |||
84 | * **Lua Module** | ||
85 | |||
86 |   Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install it as a Lua module and executable with: | ||
87 | |||
88 | ``` | ||
89 | > luarocks install yuescript | ||
90 | ``` | ||
91 | |||
92 |   Or you can build `yue.so` file with: | ||
93 | |||
94 | ``` | ||
95 | > make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
96 | ``` | ||
97 | |||
98 |   Then get the binary file from path **bin/shared/yue.so**. | ||
99 | |||
100 | * **Binary Tool** | ||
101 | |||
102 |   Clone this repo, then build and install executable with: | ||
103 | ``` | ||
104 | > make install | ||
105 | ``` | ||
106 | |||
107 |   Build Yuescript tool without macro feature: | ||
108 | ``` | ||
109 | > make install NO_MACRO=true | ||
110 | ``` | ||
111 | |||
112 |   Build Yuescript tool without built-in Lua binary: | ||
113 | ``` | ||
114 | > make install NO_LUA=true | ||
115 | ``` | ||
116 | |||
117 | ## Usage | ||
118 | |||
119 |   Require the Yuescript module in Lua: | ||
120 | ```Lua | ||
121 | -- require `main.yue` in Lua | ||
122 | require("yue")("main") | ||
123 | |||
124 | -- use the Yuescript compiler in Lua | ||
125 | local yue = require("yue") | ||
126 | local codes, err, globals = yue.to_lua([[ | ||
127 | f = -> | ||
128 | print "hello world" | ||
129 | f! | ||
130 | ]],{ | ||
131 | implicit_return_root = true, | ||
132 | reserve_line_number = true, | ||
133 | lint_global = true | ||
134 | }) | ||
135 | ``` | ||
136 |   Use Yuescript tool with: | ||
137 | ``` | ||
138 | > yue -h | ||
139 | Usage: yue [options|files|directories] ... | ||
140 | |||
141 | -h Print this message | ||
142 | -e str Execute a file or raw codes | ||
143 | -t path Specify where to place compiled files | ||
144 | -o file Write output to file | ||
145 | -s Use spaces in generated codes instead of tabs | ||
146 | -m Generate minified codes | ||
147 | -p Write output to standard out | ||
148 | -b Dump compile time (doesn't write output) | ||
149 | -l Write line numbers from source codes | ||
150 | -v Print version | ||
151 | -- Read from standard in, print to standard out | ||
152 | (Must be first and only argument) | ||
153 | |||
154 | Execute without options to enter REPL, type symbol '$' | ||
155 | in a single line to start/stop multi-line mode | ||
156 | ``` | ||
157 |   Use cases: | ||
158 |   Recursively compile every Yuescript file with extension **.yue** under current path: **yue .** | ||
159 |   Compile and save results to a target path: **yue -t /target/path/ .** | ||
160 |   Compile and reserve debug info: **yue -l .** | ||
161 |   Compile and generate minified codes: **yue -m .** | ||
162 |   Execute raw codes: **yue -e 'print 123'** | ||
163 |   Execute a Yuescript file: **yue -e main.yue** | ||
164 | |||
165 | ## Macro | ||
166 | |||
167 | ### Common Usage | ||
168 | Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation. | ||
169 | |||
170 | ```moonscript | ||
171 | macro config = (debugging)-> | ||
172 | global debugMode = debugging == "true" | ||
173 | "" | ||
174 | |||
175 | macro asserts = (cond)-> | ||
176 | debugMode and "assert #{cond}" or "" | ||
177 | |||
178 | macro assert = (cond)-> | ||
179 | debugMode and "assert #{cond}" or "#{cond}" | ||
180 | |||
181 | $config true | ||
182 | $asserts item ~= nil | ||
183 | |||
184 | $config false | ||
185 | value = $assert item | ||
186 | |||
187 | -- the passed expressions are treated as strings | ||
188 | macro and = (...)-> "#{ table.concat {...}, ' and ' }" | ||
189 | if $and f1!, f2!, f3! | ||
190 | print "OK" | ||
191 | ``` | ||
192 | <YueDisplay> | ||
193 | <pre> | ||
194 | macro config = (debugging)-> | ||
195 | global debugMode = debugging == "true" | ||
196 | "" | ||
197 | |||
198 | macro asserts = (cond)-> | ||
199 | debugMode and "assert #{cond}" or "" | ||
200 | |||
201 | macro assert = (cond)-> | ||
202 | debugMode and "assert #{cond}" or "#{cond}" | ||
203 | |||
204 | $config true | ||
205 | $asserts item ~= nil | ||
206 | |||
207 | $config false | ||
208 | value = $assert item | ||
209 | |||
210 | -- the passed expressions are treated as strings | ||
211 | macro and = (...)-> "#{ table.concat {...}, ' and ' }" | ||
212 | if $and f1!, f2!, f3! | ||
213 | print "OK" | ||
214 | </pre> | ||
215 | </YueDisplay> | ||
216 | |||
217 | ### Insert Raw Codes | ||
218 | |||
219 | A macro function can either return a Yuescript string or a config table containing Lua codes. | ||
220 | ```moonscript | ||
221 | macro yueFunc = (var)-> "local #{var} = ->" | ||
222 | $yueFunc funcA | ||
223 | funcA = -> "assign the Yue defined variable" | ||
224 | |||
225 | -- take care and let Yuescript know the | ||
226 | -- local variables you declared in Lua code | ||
227 | macro luaFunc = (var)-> { | ||
228 | codes: "local function #{var}() end" | ||
229 | type: "lua" | ||
230 | locals: {var} | ||
231 | } | ||
232 | $luaFunc funcB | ||
233 | funcB = -> "assign the Lua defined variable" | ||
234 | |||
235 | macro lua = (code)-> { | ||
236 | :code | ||
237 | type: "lua" | ||
238 | } | ||
239 | |||
240 | -- the raw string leading and ending symbols are auto trimed | ||
241 | $lua[==[ | ||
242 | -- raw Lua codes insertion | ||
243 | if cond then | ||
244 | print("output") | ||
245 | end | ||
246 | ]==] | ||
247 | ``` | ||
248 | <YueDisplay> | ||
249 | <pre> | ||
250 | macro yueFunc = (var)-> "local #{var} = ->" | ||
251 | $yueFunc funcA | ||
252 | funcA = -> "assign the Yue defined variable" | ||
253 | |||
254 | -- take care and let Yuescript know the | ||
255 | -- local variables you declared in Lua codes | ||
256 | macro luaFunc = (var)-> { | ||
257 | codes: "local function #{var}() end" | ||
258 | type: "lua" | ||
259 | locals: {var} | ||
260 | } | ||
261 | $luaFunc funcB | ||
262 | funcB = -> "assign the Lua defined variable" | ||
263 | |||
264 | macro lua = (code)-> { | ||
265 | :code | ||
266 | type: "lua" | ||
267 | } | ||
268 | |||
269 | -- the raw string leading and ending symbols are auto trimed | ||
270 | $lua[==[ | ||
271 | -- raw Lua codes insertion | ||
272 | if cond then | ||
273 | print("output") | ||
274 | end | ||
275 | ]==] | ||
276 | </pre> | ||
277 | </YueDisplay> | ||
278 | |||
279 | ### Export Macro | ||
280 | |||
281 | Macro functions can be exported from a module and get imported in another module. It is recommanded to export macro functions in a single file to speed up compilation. | ||
282 | ```moonscript | ||
283 | -- file: utils.yue | ||
284 | export macro map = (items, action)-> "[#{action} for _ in *#{items}]" | ||
285 | export macro filter = (items, action)-> "[_ for _ in *#{items} when #{action}]" | ||
286 | export macro foreach = (items, action)-> "for _ in *#{items} | ||
287 | #{action}" | ||
288 | |||
289 | -- file main.yue | ||
290 | import "utils" as { | ||
291 | $, -- symbol to import all macros | ||
292 | $foreach: $each -- rename macro $foreach to $each | ||
293 | } | ||
294 | {1, 2, 3} |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
295 | ``` | ||
296 | <YueDisplay> | ||
297 | <pre> | ||
298 | -- file: utils.yue | ||
299 | export macro map = (items, action)-> "[#{action} for _ in *#{items}]" | ||
300 | export macro filter = (items, action)-> "[_ for _ in *#{items} when #{action}]" | ||
301 | export macro foreach = (items, action)-> "for _ in *#{items} | ||
302 | #{action}" | ||
303 | |||
304 | -- file main.yue | ||
305 | -- import function is not available in browser, try it in a real environment | ||
306 | --[[ | ||
307 | import "utils" as { | ||
308 | $, -- symbol to import all macros | ||
309 | $foreach: $each -- rename macro $foreach to $each | ||
310 | } | ||
311 | {1, 2, 3} |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
312 | ]] | ||
313 | </pre> | ||
314 | </YueDisplay> | ||
315 | |||
316 | ## Special Operator | ||
317 | |||
318 | ### Metatable | ||
319 | |||
320 | The **#** operator can be used as a shortcut for metatable manipulation. | ||
321 | |||
322 | * **Metatable Creation** | ||
323 | Create normal table with key **#** or metamethod key that ends with **#**. | ||
324 | |||
325 | ```moonscript | ||
326 | mt = {} | ||
327 | add = (right)=> #: mt, value: @value + right.value | ||
328 | mt.__add = add | ||
329 | |||
330 | a = #: mt, value: 1 | ||
331 | -- set field with variable of the same name | ||
332 | b = :add#, value: 2 | ||
333 | c = add#: mt.__add, value: 3 | ||
334 | |||
335 | d = a + b + c | ||
336 | print d.value | ||
337 | |||
338 | close _ = close#: -> print "out of scope" | ||
339 | ``` | ||
340 | <YueDisplay> | ||
341 | <pre> | ||
342 | mt = {} | ||
343 | add = (right)=> #: mt, value: @value + right.value | ||
344 | mt.__add = add | ||
345 | |||
346 | a = #: mt, value: 1 | ||
347 | -- set field with variable of the same name | ||
348 | b = :add#, value: 2 | ||
349 | c = add#: mt.__add, value: 3 | ||
350 | |||
351 | d = a + b + c | ||
352 | print d.value | ||
353 | |||
354 | close _ = close#: -> print "out of scope" | ||
355 | </pre> | ||
356 | </YueDisplay> | ||
357 | |||
358 | * **Metatable Accessing** | ||
359 | Accessing metatable with key **#** or metamethod key that ends with **#**. | ||
360 | |||
361 | ```moonscript | ||
362 | -- create with metatable containing field "value" | ||
363 | tb = ["value"]#: 123 | ||
364 | tb.index# = tb.# | ||
365 | print tb.value | ||
366 | |||
367 | tb.# = __index: {item: "hello"} | ||
368 | print tb.item | ||
369 | ``` | ||
370 | <YueDisplay> | ||
371 | <pre> | ||
372 | -- create with metatable containing field "value" | ||
373 | tb = ["value"]#: 123 | ||
374 | tb.index# = tb.# | ||
375 | print tb.value | ||
376 | |||
377 | tb.# = __index: {item: "hello"} | ||
378 | print tb.item | ||
379 | </pre> | ||
380 | </YueDisplay> | ||
381 | |||
382 | * **Metatable Destructure** | ||
383 | Destruct metatable with metamethod key that ends with **#**. | ||
384 | |||
385 | ```moonscript | ||
386 | {item, :new, :close#, index#: getter} = tb | ||
387 | print item, new, close, getter | ||
388 | ``` | ||
389 | <YueDisplay> | ||
390 | <pre> | ||
391 | {item, :new, :close#, index#: getter} = tb | ||
392 | print item, new, close, getter | ||
393 | </pre> | ||
394 | </YueDisplay> | ||
395 | |||
396 | ### Existence | ||
397 | |||
398 | The **?** operator can be used in a variety of contexts to check for existence. | ||
399 | |||
400 | ```moonscript | ||
401 | func?! | ||
402 | print abc?["hello world"]?.xyz | ||
403 | |||
404 | x = tab?.value | ||
405 | len = utf8?.len or string?.len or (o)-> #o | ||
406 | |||
407 | if print and x? | ||
408 | print x | ||
409 | |||
410 | with? io.open "test.txt", "w" | ||
411 | \write "hello" | ||
412 | \close! | ||
413 | ``` | ||
414 | <YueDisplay> | ||
415 | <pre> | ||
416 | func?! | ||
417 | print abc?["hello world"]?.xyz | ||
418 | |||
419 | x = tab?.value | ||
420 | len = utf8?.len or string?.len or (o)-> #o | ||
421 | |||
422 | if print and x? | ||
423 | print x | ||
424 | |||
425 | with? io.open "test.txt", "w" | ||
426 | \write "hello" | ||
427 | \close! | ||
428 | </pre> | ||
429 | </YueDisplay> | ||
430 | |||
431 | ### Piping | ||
432 | |||
433 | Instead of a series of nested function calls, you can pipe values with operator **|>**. | ||
434 | ```moonscript | ||
435 | "hello" |> print | ||
436 | 1 |> print 2 -- insert pipe item as the first argument | ||
437 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
438 | |||
439 | -- pipe expression in multiline | ||
440 | readFile "example.txt" | ||
441 | |> extract language, {} | ||
442 | |> parse language | ||
443 | |> emit | ||
444 | |> render | ||
445 | |||
446 | ``` | ||
447 | <YueDisplay> | ||
448 | <pre> | ||
449 | "hello" |> print | ||
450 | 1 |> print 2 -- insert pipe item as the first argument | ||
451 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
452 | |||
453 | -- pipe expression in multiline | ||
454 | readFile "example.txt" | ||
455 | |> extract language, {} | ||
456 | |> parse language | ||
457 | |> emit | ||
458 | |> render | ||
459 | |||
460 | </pre> | ||
461 | </YueDisplay> | ||
462 | |||
463 | ## Module | ||
464 | |||
465 | ### Import | ||
466 | |||
467 | The import statement is a syntax sugar for requiring a module or help extracting items from an imported module. | ||
468 | |||
469 | ```moonscript | ||
470 | -- used as table destructure | ||
471 | do | ||
472 | import C, Ct, Cmt from require "lpeg" | ||
473 | import insert, concat from table | ||
474 | |||
475 | -- shortcut for requring a module | ||
476 | do | ||
477 | import 'module' | ||
478 | import 'module_x' | ||
479 | import "d-a-s-h-e-s" | ||
480 | import "module.part" | ||
481 | |||
482 | -- requring module with aliasing or table destruction | ||
483 | do | ||
484 | import "player" as PlayerModule | ||
485 | import "lpeg" as :C, :Ct, :Cmt | ||
486 | import "export" as {one, two, Something:{umm:{ch}}} | ||
487 | ``` | ||
488 | <YueDisplay> | ||
489 | <pre> | ||
490 | -- used as table destruction | ||
491 | do | ||
492 | import C, Ct, Cmt from require "lpeg" | ||
493 | import insert, concat from table | ||
494 | |||
495 | -- shortcut for requring a module | ||
496 | do | ||
497 | import 'module' | ||
498 | import 'module_x' | ||
499 | import "d-a-s-h-e-s" | ||
500 | import "module.part" | ||
501 | |||
502 | -- requring module with aliasing or table destruction | ||
503 | do | ||
504 | import "player" as PlayerModule | ||
505 | import "lpeg" as :C, :Ct, :Cmt | ||
506 | import "export" as {one, two, Something:{umm:{ch}}} | ||
507 | </pre> | ||
508 | </YueDisplay> | ||
509 | |||
510 | ### Export | ||
511 | |||
512 | The export statement offers a concise way to define modules. | ||
513 | |||
514 | * **Named Export** | ||
515 | Named export will define a local variable as well as adding a field in the exported table. | ||
516 | |||
517 | ```moonscript | ||
518 | export a, b, c = 1, 2, 3 | ||
519 | export cool = "cat" | ||
520 | |||
521 | export What = if this | ||
522 | "abc" | ||
523 | else | ||
524 | "def" | ||
525 | |||
526 | export y = -> | ||
527 | hallo = 3434 | ||
528 | |||
529 | export class Something | ||
530 | umm: "cool" | ||
531 | ``` | ||
532 | <YueDisplay> | ||
533 | <pre> | ||
534 | export a, b, c = 1, 2, 3 | ||
535 | export cool = "cat" | ||
536 | |||
537 | export What = if this | ||
538 | "abc" | ||
539 | else | ||
540 | "def" | ||
541 | |||
542 | export y = -> | ||
543 | hallo = 3434 | ||
544 | |||
545 | export class Something | ||
546 | umm: "cool" | ||
547 | </pre> | ||
548 | </YueDisplay> | ||
549 | |||
550 | * **Unnamed Export** | ||
551 | Unnamed export will add the target item into the array part of the exported table. | ||
552 | |||
553 | ```moonscript | ||
554 | d, e, f = 3, 2, 1 | ||
555 | export d, e, f | ||
556 | |||
557 | export if this | ||
558 | 123 | ||
559 | else | ||
560 | 456 | ||
561 | |||
562 | export with tmp | ||
563 | j = 2000 | ||
564 | ``` | ||
565 | <YueDisplay> | ||
566 | <pre> | ||
567 | d, e, f = 3, 2, 1 | ||
568 | export d, e, f | ||
569 | |||
570 | export if this | ||
571 | 123 | ||
572 | else | ||
573 | 456 | ||
574 | |||
575 | export with tmp | ||
576 | j = 2000 | ||
577 | </pre> | ||
578 | </YueDisplay> | ||
579 | |||
580 | * **Default Export** | ||
581 | Using the **default** keyword in export statement to replace the exported table with any thing. | ||
582 | |||
583 | ```moonscript | ||
584 | export default -> | ||
585 | print "hello" | ||
586 | 123 | ||
587 | ``` | ||
588 | <YueDisplay> | ||
589 | <pre> | ||
590 | export default -> | ||
591 | print "hello" | ||
592 | 123 | ||
593 | </pre> | ||
594 | </YueDisplay> \ No newline at end of file | ||