diff options
| author | Li Jin <dragon-fly@qq.com> | 2026-02-04 16:18:19 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2026-02-04 16:18:19 +0800 |
| commit | ffa06586ba5b04bf9c223b41fe66cdb813ba1b34 (patch) | |
| tree | 600114d784edb8509fed20f70319ccbb778ba682 /doc/docs | |
| parent | 8d2a049286131ad6920262a96d365813eca8b780 (diff) | |
| download | yuescript-ffa06586ba5b04bf9c223b41fe66cdb813ba1b34.tar.gz yuescript-ffa06586ba5b04bf9c223b41fe66cdb813ba1b34.tar.bz2 yuescript-ffa06586ba5b04bf9c223b41fe66cdb813ba1b34.zip | |
Splited docs.
Diffstat (limited to 'doc/docs')
72 files changed, 11167 insertions, 10968 deletions
diff --git a/doc/docs/.vitepress/config.mts b/doc/docs/.vitepress/config.mts index da3876d..4c20685 100644 --- a/doc/docs/.vitepress/config.mts +++ b/doc/docs/.vitepress/config.mts | |||
| @@ -15,6 +15,140 @@ const moonscriptLanguage = { | |||
| 15 | aliases: ['yue', 'yuescript', 'moon'], | 15 | aliases: ['yue', 'yuescript', 'moon'], |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | // Generate sidebar configuration function | ||
| 19 | function createSidebar(basePath: string, zh: boolean) { | ||
| 20 | return [ | ||
| 21 | { | ||
| 22 | text: zh ? '介绍' : 'Introduction', | ||
| 23 | link: `${basePath}/introduction`, | ||
| 24 | }, | ||
| 25 | { | ||
| 26 | text: zh ? '安装' : 'Installation', | ||
| 27 | link: `${basePath}/installation`, | ||
| 28 | }, | ||
| 29 | { | ||
| 30 | text: zh ? '使用方法' : 'Usage', | ||
| 31 | link: `${basePath}/usage`, | ||
| 32 | }, | ||
| 33 | { | ||
| 34 | text: zh ? '宏' : 'Macro', | ||
| 35 | link: `${basePath}/macro`, | ||
| 36 | }, | ||
| 37 | { | ||
| 38 | text: zh ? '操作符' : 'Operator', | ||
| 39 | link: `${basePath}/operator`, | ||
| 40 | }, | ||
| 41 | { | ||
| 42 | text: zh ? '模块' : 'Module', | ||
| 43 | link: `${basePath}/module`, | ||
| 44 | }, | ||
| 45 | { | ||
| 46 | text: zh ? '赋值' : 'Assignment', | ||
| 47 | link: `${basePath}/assignment`, | ||
| 48 | }, | ||
| 49 | { | ||
| 50 | text: zh ? '解构赋值' : 'Destructuring Assignment', | ||
| 51 | link: `${basePath}/destructuring-assignment`, | ||
| 52 | }, | ||
| 53 | { | ||
| 54 | text: zh ? 'If 赋值' : 'If Assignment', | ||
| 55 | link: `${basePath}/if-assignment`, | ||
| 56 | }, | ||
| 57 | { | ||
| 58 | text: zh ? '可变参数赋值' : 'Varargs Assignment', | ||
| 59 | link: `${basePath}/varargs-assignment`, | ||
| 60 | }, | ||
| 61 | { | ||
| 62 | text: zh ? '空白' : 'Whitespace', | ||
| 63 | link: `${basePath}/whitespace`, | ||
| 64 | }, | ||
| 65 | { | ||
| 66 | text: zh ? '注释' : 'Comment', | ||
| 67 | link: `${basePath}/comment`, | ||
| 68 | }, | ||
| 69 | { | ||
| 70 | text: zh ? '错误处理' : 'Try', | ||
| 71 | link: `${basePath}/try`, | ||
| 72 | }, | ||
| 73 | { | ||
| 74 | text: zh ? '属性' : 'Attributes', | ||
| 75 | link: `${basePath}/attributes`, | ||
| 76 | }, | ||
| 77 | { | ||
| 78 | text: zh ? '字面量' : 'Literals', | ||
| 79 | link: `${basePath}/literals`, | ||
| 80 | }, | ||
| 81 | { | ||
| 82 | text: zh ? '函数字面量' : 'Function Literals', | ||
| 83 | link: `${basePath}/function-literals`, | ||
| 84 | }, | ||
| 85 | { | ||
| 86 | text: zh ? '反向回调' : 'Backcalls', | ||
| 87 | link: `${basePath}/backcalls`, | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | text: zh ? '表格字面量' : 'Table Literals', | ||
| 91 | link: `${basePath}/table-literals`, | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | text: zh ? '推导式' : 'Comprehensions', | ||
| 95 | link: `${basePath}/comprehensions`, | ||
| 96 | }, | ||
| 97 | { | ||
| 98 | text: zh ? 'for 循环' : 'For Loop', | ||
| 99 | link: `${basePath}/for-loop`, | ||
| 100 | }, | ||
| 101 | { | ||
| 102 | text: zh ? 'while 循环' : 'While Loop', | ||
| 103 | link: `${basePath}/while-loop`, | ||
| 104 | }, | ||
| 105 | { | ||
| 106 | text: zh ? 'continue 语句' : 'Continue Statement', | ||
| 107 | link: `${basePath}/continue`, | ||
| 108 | }, | ||
| 109 | { | ||
| 110 | text: zh ? '条件语句' : 'Conditionals', | ||
| 111 | link: `${basePath}/conditionals`, | ||
| 112 | }, | ||
| 113 | { | ||
| 114 | text: zh ? '代码行修饰符' : 'Line Decorators', | ||
| 115 | link: `${basePath}/line-decorators`, | ||
| 116 | }, | ||
| 117 | { | ||
| 118 | text: zh ? 'switch 语句' : 'Switch', | ||
| 119 | link: `${basePath}/switch`, | ||
| 120 | }, | ||
| 121 | { | ||
| 122 | text: zh ? '面向对象编程' : 'Object Oriented Programming', | ||
| 123 | link: `${basePath}/object-oriented-programming`, | ||
| 124 | }, | ||
| 125 | { | ||
| 126 | text: zh ? 'with 语句' : 'With Statement', | ||
| 127 | link: `${basePath}/with-statement`, | ||
| 128 | }, | ||
| 129 | { | ||
| 130 | text: zh ? 'do 语句' : 'Do', | ||
| 131 | link: `${basePath}/do`, | ||
| 132 | }, | ||
| 133 | { | ||
| 134 | text: zh ? '函数存根' : 'Function Stubs', | ||
| 135 | link: `${basePath}/function-stubs`, | ||
| 136 | }, | ||
| 137 | { | ||
| 138 | text: zh ? '使用 using 语句:防止破坏性赋值' : 'The Using Clause; Controlling Destructive Assignment', | ||
| 139 | link: `${basePath}/the-using-clause-controlling-destructive-assignment`, | ||
| 140 | }, | ||
| 141 | { | ||
| 142 | text: zh ? '月之脚本语言库' : 'The YueScript Library', | ||
| 143 | link: `${basePath}/the-yuescript-library`, | ||
| 144 | }, | ||
| 145 | { | ||
| 146 | text: zh ? 'MIT 许可证' : 'Licence: MIT', | ||
| 147 | link: `${basePath}/licence-mit`, | ||
| 148 | }, | ||
| 149 | ] | ||
| 150 | } | ||
| 151 | |||
| 18 | export default defineConfig({ | 152 | export default defineConfig({ |
| 19 | title: 'YueScript', | 153 | title: 'YueScript', |
| 20 | description: 'A language that compiles to Lua', | 154 | description: 'A language that compiles to Lua', |
| @@ -84,7 +218,8 @@ export default defineConfig({ | |||
| 84 | { text: 'Document', link: '/doc/' }, | 218 | { text: 'Document', link: '/doc/' }, |
| 85 | { text: 'Try yue!', link: '/try/' }, | 219 | { text: 'Try yue!', link: '/try/' }, |
| 86 | { text: 'Github', link: 'https://github.com/IppClub/Yuescript' } | 220 | { text: 'Github', link: 'https://github.com/IppClub/Yuescript' } |
| 87 | ] | 221 | ], |
| 222 | sidebar: createSidebar('/doc', false), | ||
| 88 | } | 223 | } |
| 89 | }, | 224 | }, |
| 90 | zh: { | 225 | zh: { |
| @@ -96,7 +231,8 @@ export default defineConfig({ | |||
| 96 | { text: '文档', link: '/zh/doc/' }, | 231 | { text: '文档', link: '/zh/doc/' }, |
| 97 | { text: '试一试!', link: '/zh/try/' }, | 232 | { text: '试一试!', link: '/zh/try/' }, |
| 98 | { text: 'Github', link: 'https://github.com/IppClub/Yuescript' } | 233 | { text: 'Github', link: 'https://github.com/IppClub/Yuescript' } |
| 99 | ] | 234 | ], |
| 235 | sidebar: createSidebar('/zh/doc', true), | ||
| 100 | } | 236 | } |
| 101 | } | 237 | } |
| 102 | } | 238 | } |
diff --git a/doc/docs/.vitepress/theme/components/YueCompiler.vue b/doc/docs/.vitepress/theme/components/YueCompiler.vue index dcea692..13a5524 100755 --- a/doc/docs/.vitepress/theme/components/YueCompiler.vue +++ b/doc/docs/.vitepress/theme/components/YueCompiler.vue | |||
| @@ -46,7 +46,7 @@ const lightPlusTheme = EditorView.theme( | |||
| 46 | height: '100%', | 46 | height: '100%', |
| 47 | backgroundColor: '#FFFFFF', | 47 | backgroundColor: '#FFFFFF', |
| 48 | color: '#000000', | 48 | color: '#000000', |
| 49 | fontSize: '0.8em' | 49 | fontSize: '14px' |
| 50 | }, | 50 | }, |
| 51 | '&.cm-focused': { | 51 | '&.cm-focused': { |
| 52 | outline: 'none' | 52 | outline: 'none' |
| @@ -90,7 +90,7 @@ const darkPlusTheme = EditorView.theme( | |||
| 90 | height: '100%', | 90 | height: '100%', |
| 91 | backgroundColor: '#1E1E1E', | 91 | backgroundColor: '#1E1E1E', |
| 92 | color: '#D4D4D4', | 92 | color: '#D4D4D4', |
| 93 | fontSize: '0.8em' | 93 | fontSize: '14px' |
| 94 | }, | 94 | }, |
| 95 | '&.cm-focused': { | 95 | '&.cm-focused': { |
| 96 | outline: 'none' | 96 | outline: 'none' |
diff --git a/doc/docs/.vitepress/theme/custom.css b/doc/docs/.vitepress/theme/custom.css index 7b4e593..bd89528 100644 --- a/doc/docs/.vitepress/theme/custom.css +++ b/doc/docs/.vitepress/theme/custom.css | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | .code-output code { | 19 | .code-output code { |
| 20 | background: #ffffff; | 20 | background: #ffffff; |
| 21 | color: #000000; | 21 | color: #000000; |
| 22 | font-size: 14px; | ||
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | .dark .code-output, | 25 | .dark .code-output, |
diff --git a/doc/docs/.vitepress/theme/index.ts b/doc/docs/.vitepress/theme/index.ts index 398df17..c4ec3d7 100644 --- a/doc/docs/.vitepress/theme/index.ts +++ b/doc/docs/.vitepress/theme/index.ts | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | import DefaultTheme from 'vitepress/theme' | 1 | import DefaultTheme from 'vitepress/theme' |
| 2 | import type { Theme } from 'vitepress' | 2 | import type { Theme } from 'vitepress' |
| 3 | import { h } from 'vue' | ||
| 3 | import './custom.css' | 4 | import './custom.css' |
| 4 | 5 | ||
| 5 | // @ts-ignore | 6 | // @ts-ignore |
| @@ -11,6 +12,10 @@ import YueDisplay from './components/YueDisplay.vue' | |||
| 11 | 12 | ||
| 12 | const theme: Theme = { | 13 | const theme: Theme = { |
| 13 | extends: DefaultTheme, | 14 | extends: DefaultTheme, |
| 15 | Layout: () => | ||
| 16 | h(DefaultTheme.Layout, null, { | ||
| 17 | 'layout-bottom': () => h(CompilerModal) | ||
| 18 | }), | ||
| 14 | enhanceApp({ app }) { | 19 | enhanceApp({ app }) { |
| 15 | app.component('CompilerModal', CompilerModal) | 20 | app.component('CompilerModal', CompilerModal) |
| 16 | app.component('YueCompiler', YueCompiler) | 21 | app.component('YueCompiler', YueCompiler) |
diff --git a/doc/docs/doc/assignment.md b/doc/docs/doc/assignment.md new file mode 100644 index 0000000..4dac6f4 --- /dev/null +++ b/doc/docs/doc/assignment.md | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | # Assignment | ||
| 2 | |||
| 3 | The variable is dynamic typed and is defined as local by default. But you can change the scope of declaration by **local** and **global** statement. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | hello = "world" | ||
| 7 | a, b, c = 1, 2, 3 | ||
| 8 | hello = 123 -- uses the existing variable | ||
| 9 | ``` | ||
| 10 | <YueDisplay> | ||
| 11 | |||
| 12 | ```yue | ||
| 13 | hello = "world" | ||
| 14 | a, b, c = 1, 2, 3 | ||
| 15 | hello = 123 -- uses the existing variable | ||
| 16 | ``` | ||
| 17 | |||
| 18 | </YueDisplay> | ||
| 19 | |||
| 20 | ## Perform Update | ||
| 21 | |||
| 22 | You can perform update assignment with many binary operators. | ||
| 23 | ```yuescript | ||
| 24 | x = 1 | ||
| 25 | x += 1 | ||
| 26 | x -= 1 | ||
| 27 | x *= 10 | ||
| 28 | x /= 10 | ||
| 29 | x %= 10 | ||
| 30 | s ..= "world" -- will add a new local if local variable is not exist | ||
| 31 | arg or= "default value" | ||
| 32 | ``` | ||
| 33 | <YueDisplay> | ||
| 34 | |||
| 35 | ```yue | ||
| 36 | x = 1 | ||
| 37 | x += 1 | ||
| 38 | x -= 1 | ||
| 39 | x *= 10 | ||
| 40 | x /= 10 | ||
| 41 | x %= 10 | ||
| 42 | s ..= "world" -- will add a new local if local variable is not exist | ||
| 43 | arg or= "default value" | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 | ## Chaining Assignment | ||
| 49 | |||
| 50 | You can do chaining assignment to assign multiple items to hold the same value. | ||
| 51 | ```yuescript | ||
| 52 | a = b = c = d = e = 0 | ||
| 53 | x = y = z = f! | ||
| 54 | ``` | ||
| 55 | <YueDisplay> | ||
| 56 | |||
| 57 | ```yue | ||
| 58 | a = b = c = d = e = 0 | ||
| 59 | x = y = z = f! | ||
| 60 | ``` | ||
| 61 | |||
| 62 | </YueDisplay> | ||
| 63 | |||
| 64 | ## Explicit Locals | ||
| 65 | ```yuescript | ||
| 66 | do | ||
| 67 | local a = 1 | ||
| 68 | local * | ||
| 69 | print "forward declare all variables as locals" | ||
| 70 | x = -> 1 + y + z | ||
| 71 | y, z = 2, 3 | ||
| 72 | global instance = Item\new! | ||
| 73 | |||
| 74 | do | ||
| 75 | local X = 1 | ||
| 76 | local ^ | ||
| 77 | print "only forward declare upper case variables" | ||
| 78 | a = 1 | ||
| 79 | B = 2 | ||
| 80 | ``` | ||
| 81 | <YueDisplay> | ||
| 82 | |||
| 83 | ```yue | ||
| 84 | do | ||
| 85 | local a = 1 | ||
| 86 | local * | ||
| 87 | print "forward declare all variables as locals" | ||
| 88 | x = -> 1 + y + z | ||
| 89 | y, z = 2, 3 | ||
| 90 | global instance = Item\new! | ||
| 91 | |||
| 92 | do | ||
| 93 | local X = 1 | ||
| 94 | local ^ | ||
| 95 | print "only forward declare upper case variables" | ||
| 96 | a = 1 | ||
| 97 | B = 2 | ||
| 98 | ``` | ||
| 99 | |||
| 100 | </YueDisplay> | ||
| 101 | |||
| 102 | ## Explicit Globals | ||
| 103 | ```yuescript | ||
| 104 | do | ||
| 105 | global a = 1 | ||
| 106 | global * | ||
| 107 | print "declare all variables as globals" | ||
| 108 | x = -> 1 + y + z | ||
| 109 | y, z = 2, 3 | ||
| 110 | |||
| 111 | do | ||
| 112 | global X = 1 | ||
| 113 | global ^ | ||
| 114 | print "only declare upper case variables as globals" | ||
| 115 | a = 1 | ||
| 116 | B = 2 | ||
| 117 | local Temp = "a local value" | ||
| 118 | ``` | ||
| 119 | <YueDisplay> | ||
| 120 | |||
| 121 | ```yue | ||
| 122 | do | ||
| 123 | global a = 1 | ||
| 124 | global * | ||
| 125 | print "declare all variables as globals" | ||
| 126 | x = -> 1 + y + z | ||
| 127 | y, z = 2, 3 | ||
| 128 | |||
| 129 | do | ||
| 130 | global X = 1 | ||
| 131 | global ^ | ||
| 132 | print "only declare upper case variables as globals" | ||
| 133 | a = 1 | ||
| 134 | B = 2 | ||
| 135 | local Temp = "a local value" | ||
| 136 | ``` | ||
| 137 | |||
| 138 | </YueDisplay> | ||
diff --git a/doc/docs/doc/attributes.md b/doc/docs/doc/attributes.md new file mode 100644 index 0000000..e6fd5a7 --- /dev/null +++ b/doc/docs/doc/attributes.md | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | # Attributes | ||
| 2 | |||
| 3 | Syntax 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. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | const a = 123 | ||
| 7 | close _ = <close>: -> print "Out of scope." | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | const a = 123 | ||
| 13 | close _ = <close>: -> print "Out of scope." | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | You can do desctructuring with variables attributed as constant. | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | const {:a, :b, c, d} = tb | ||
| 22 | -- a = 1 | ||
| 23 | ``` | ||
| 24 | <YueDisplay> | ||
| 25 | |||
| 26 | ```yue | ||
| 27 | const {:a, :b, c, d} = tb | ||
| 28 | -- a = 1 | ||
| 29 | ``` | ||
| 30 | |||
| 31 | </YueDisplay> | ||
| 32 | |||
| 33 | You can also declare a global variable to be `const`. | ||
| 34 | |||
| 35 | ```yuescript | ||
| 36 | global const Constant = 123 | ||
| 37 | -- Constant = 1 | ||
| 38 | ``` | ||
| 39 | <YueDisplay> | ||
| 40 | |||
| 41 | ```yue | ||
| 42 | global const Constant = 123 | ||
| 43 | -- Constant = 1 | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
diff --git a/doc/docs/doc/backcalls.md b/doc/docs/doc/backcalls.md new file mode 100644 index 0000000..e34331e --- /dev/null +++ b/doc/docs/doc/backcalls.md | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | # Backcalls | ||
| 2 | |||
| 3 | Backcalls 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. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | x <- f | ||
| 7 | print "hello" .. x | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | x <- f | ||
| 13 | print "hello" .. x | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | Fat arrow functions are also available. | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | <= f | ||
| 22 | print @value | ||
| 23 | ``` | ||
| 24 | <YueDisplay> | ||
| 25 | |||
| 26 | ```yue | ||
| 27 | <= f | ||
| 28 | print @value | ||
| 29 | ``` | ||
| 30 | |||
| 31 | </YueDisplay> | ||
| 32 | |||
| 33 | You can specify a placeholder for where you want the backcall function to go as a parameter. | ||
| 34 | |||
| 35 | ```yuescript | ||
| 36 | (x) <- map _, [1, 2, 3] | ||
| 37 | x * 2 | ||
| 38 | ``` | ||
| 39 | <YueDisplay> | ||
| 40 | |||
| 41 | ```yue | ||
| 42 | (x) <- map _, [1, 2, 3] | ||
| 43 | x * 2 | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 | If 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. | ||
| 49 | |||
| 50 | ```yuescript | ||
| 51 | result, msg = do | ||
| 52 | data <- readAsync "filename.txt" | ||
| 53 | print data | ||
| 54 | info <- processAsync data | ||
| 55 | check info | ||
| 56 | print result, msg | ||
| 57 | ``` | ||
| 58 | <YueDisplay> | ||
| 59 | |||
| 60 | ```yue | ||
| 61 | result, msg = do | ||
| 62 | data <- readAsync "filename.txt" | ||
| 63 | print data | ||
| 64 | info <- processAsync data | ||
| 65 | check info | ||
| 66 | print result, msg | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
diff --git a/doc/docs/doc/comment.md b/doc/docs/doc/comment.md new file mode 100644 index 0000000..b67c97d --- /dev/null +++ b/doc/docs/doc/comment.md | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | # Comment | ||
| 2 | |||
| 3 | ```yuescript | ||
| 4 | -- I am a comment | ||
| 5 | |||
| 6 | str = --[[ | ||
| 7 | This is a multi-line comment. | ||
| 8 | It's OK. | ||
| 9 | ]] strA \ -- comment 1 | ||
| 10 | .. strB \ -- comment 2 | ||
| 11 | .. strC | ||
| 12 | |||
| 13 | func --[[port]] 3000, --[[ip]] "192.168.1.1" | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | -- I am a comment | ||
| 19 | |||
| 20 | str = --[[ | ||
| 21 | This is a multi-line comment. | ||
| 22 | It's OK. | ||
| 23 | ]] strA \ -- comment 1 | ||
| 24 | .. strB \ -- comment 2 | ||
| 25 | .. strC | ||
| 26 | |||
| 27 | func --[[port]] 3000, --[[ip]] "192.168.1.1" | ||
| 28 | ``` | ||
| 29 | |||
| 30 | </YueDisplay> | ||
diff --git a/doc/docs/doc/comprehensions.md b/doc/docs/doc/comprehensions.md new file mode 100644 index 0000000..3a92167 --- /dev/null +++ b/doc/docs/doc/comprehensions.md | |||
| @@ -0,0 +1,271 @@ | |||
| 1 | # Comprehensions | ||
| 2 | |||
| 3 | Comprehensions 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. | ||
| 4 | |||
| 5 | ## List Comprehensions | ||
| 6 | |||
| 7 | The following creates a copy of the items table but with all the values doubled. | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | items = [ 1, 2, 3, 4 ] | ||
| 11 | doubled = [item * 2 for i, item in ipairs items] | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | items = [ 1, 2, 3, 4 ] | ||
| 17 | doubled = [item * 2 for i, item in ipairs items] | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 | The items included in the new table can be restricted with a when clause: | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 31 | ``` | ||
| 32 | |||
| 33 | </YueDisplay> | ||
| 34 | |||
| 35 | Because it is common to iterate over the values of a numerically indexed table, an **\*** operator is introduced. The doubled example can be rewritten as: | ||
| 36 | |||
| 37 | ```yuescript | ||
| 38 | doubled = [item * 2 for item in *items] | ||
| 39 | ``` | ||
| 40 | <YueDisplay> | ||
| 41 | |||
| 42 | ```yue | ||
| 43 | doubled = [item * 2 for item in *items] | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 | In list comprehensions, you can also use the spread operator `...` to flatten nested lists, achieving a flat map effect: | ||
| 49 | |||
| 50 | ```yuescript | ||
| 51 | data = | ||
| 52 | a: [1, 2, 3] | ||
| 53 | b: [4, 5, 6] | ||
| 54 | |||
| 55 | flat = [...v for k,v in pairs data] | ||
| 56 | -- flat is now [1, 2, 3, 4, 5, 6] | ||
| 57 | ``` | ||
| 58 | <YueDisplay> | ||
| 59 | |||
| 60 | ```yue | ||
| 61 | data = | ||
| 62 | a: [1, 2, 3] | ||
| 63 | b: [4, 5, 6] | ||
| 64 | |||
| 65 | flat = [...v for k,v in pairs data] | ||
| 66 | -- flat is now [1, 2, 3, 4, 5, 6] | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
| 70 | |||
| 71 | The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause. | ||
| 72 | |||
| 73 | Using multiple for clauses is the same as using nested loops: | ||
| 74 | |||
| 75 | ```yuescript | ||
| 76 | x_coords = [4, 5, 6, 7] | ||
| 77 | y_coords = [9, 2, 3] | ||
| 78 | |||
| 79 | points = [ [x, y] for x in *x_coords \ | ||
| 80 | for y in *y_coords] | ||
| 81 | ``` | ||
| 82 | <YueDisplay> | ||
| 83 | |||
| 84 | ```yue | ||
| 85 | x_coords = [4, 5, 6, 7] | ||
| 86 | y_coords = [9, 2, 3] | ||
| 87 | |||
| 88 | points = [ [x, y] for x in *x_coords \ | ||
| 89 | for y in *y_coords] | ||
| 90 | ``` | ||
| 91 | |||
| 92 | </YueDisplay> | ||
| 93 | |||
| 94 | Numeric for loops can also be used in comprehensions: | ||
| 95 | |||
| 96 | ```yuescript | ||
| 97 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 98 | ``` | ||
| 99 | <YueDisplay> | ||
| 100 | |||
| 101 | ```yue | ||
| 102 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
| 106 | |||
| 107 | ## Table Comprehensions | ||
| 108 | |||
| 109 | The syntax for table comprehensions is very similar, only differing by using **{** and **}** and taking two values from each iteration. | ||
| 110 | |||
| 111 | This example makes a copy of the tablething: | ||
| 112 | |||
| 113 | ```yuescript | ||
| 114 | thing = { | ||
| 115 | color: "red" | ||
| 116 | name: "fast" | ||
| 117 | width: 123 | ||
| 118 | } | ||
| 119 | |||
| 120 | thing_copy = {k, v for k, v in pairs thing} | ||
| 121 | ``` | ||
| 122 | <YueDisplay> | ||
| 123 | |||
| 124 | ```yue | ||
| 125 | thing = { | ||
| 126 | color: "red" | ||
| 127 | name: "fast" | ||
| 128 | width: 123 | ||
| 129 | } | ||
| 130 | |||
| 131 | thing_copy = {k, v for k, v in pairs thing} | ||
| 132 | ``` | ||
| 133 | |||
| 134 | </YueDisplay> | ||
| 135 | |||
| 136 | ```yuescript | ||
| 137 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 138 | ``` | ||
| 139 | <YueDisplay> | ||
| 140 | |||
| 141 | ```yue | ||
| 142 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 143 | ``` | ||
| 144 | |||
| 145 | </YueDisplay> | ||
| 146 | |||
| 147 | The **\*** operator is also supported. Here we create a square root look up table for a few numbers. | ||
| 148 | |||
| 149 | ```yuescript | ||
| 150 | numbers = [1, 2, 3, 4] | ||
| 151 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 152 | ``` | ||
| 153 | <YueDisplay> | ||
| 154 | |||
| 155 | ```yue | ||
| 156 | numbers = [1, 2, 3, 4] | ||
| 157 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 158 | ``` | ||
| 159 | |||
| 160 | </YueDisplay> | ||
| 161 | |||
| 162 | The 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: | ||
| 163 | |||
| 164 | In 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. | ||
| 165 | |||
| 166 | ```yuescript | ||
| 167 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 168 | tbl = {unpack tuple for tuple in *tuples} | ||
| 169 | ``` | ||
| 170 | <YueDisplay> | ||
| 171 | |||
| 172 | ```yue | ||
| 173 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 174 | tbl = {unpack tuple for tuple in *tuples} | ||
| 175 | ``` | ||
| 176 | |||
| 177 | </YueDisplay> | ||
| 178 | |||
| 179 | ## Slicing | ||
| 180 | |||
| 181 | A 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. | ||
| 182 | |||
| 183 | Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive: | ||
| 184 | |||
| 185 | ```yuescript | ||
| 186 | slice = [item for item in *items[1, 5]] | ||
| 187 | ``` | ||
| 188 | <YueDisplay> | ||
| 189 | |||
| 190 | ```yue | ||
| 191 | slice = [item for item in *items[1, 5]] | ||
| 192 | ``` | ||
| 193 | |||
| 194 | </YueDisplay> | ||
| 195 | |||
| 196 | Any 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: | ||
| 197 | |||
| 198 | ```yuescript | ||
| 199 | slice = [item for item in *items[2,]] | ||
| 200 | ``` | ||
| 201 | <YueDisplay> | ||
| 202 | |||
| 203 | ```yue | ||
| 204 | slice = [item for item in *items[2,]] | ||
| 205 | ``` | ||
| 206 | |||
| 207 | </YueDisplay> | ||
| 208 | |||
| 209 | If 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, …) | ||
| 210 | |||
| 211 | ```yuescript | ||
| 212 | slice = [item for item in *items[,,2]] | ||
| 213 | ``` | ||
| 214 | <YueDisplay> | ||
| 215 | |||
| 216 | ```yue | ||
| 217 | slice = [item for item in *items[,,2]] | ||
| 218 | ``` | ||
| 219 | |||
| 220 | </YueDisplay> | ||
| 221 | |||
| 222 | Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table. | ||
| 223 | |||
| 224 | ```yuescript | ||
| 225 | -- take the last 4 items | ||
| 226 | slice = [item for item in *items[-4,-1]] | ||
| 227 | ``` | ||
| 228 | <YueDisplay> | ||
| 229 | |||
| 230 | ```yue | ||
| 231 | -- take the last 4 items | ||
| 232 | slice = [item for item in *items[-4,-1]] | ||
| 233 | ``` | ||
| 234 | |||
| 235 | </YueDisplay> | ||
| 236 | |||
| 237 | The step size can also be negative, which means that the items are taken in reverse order. | ||
| 238 | |||
| 239 | ```yuescript | ||
| 240 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 241 | ``` | ||
| 242 | <YueDisplay> | ||
| 243 | |||
| 244 | ```yue | ||
| 245 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 246 | ``` | ||
| 247 | |||
| 248 | </YueDisplay> | ||
| 249 | |||
| 250 | ### Slicing Expression | ||
| 251 | |||
| 252 | Slicing can also be used as an expression. This is useful for getting a sub-list of a table. | ||
| 253 | |||
| 254 | ```yuescript | ||
| 255 | -- take the 2nd and 4th items as a new list | ||
| 256 | sub_list = items[2, 4] | ||
| 257 | |||
| 258 | -- take the last 4 items | ||
| 259 | last_four_items = items[-4, -1] | ||
| 260 | ``` | ||
| 261 | <YueDisplay> | ||
| 262 | |||
| 263 | ```yue | ||
| 264 | -- take the 2nd and 4th items as a new list | ||
| 265 | sub_list = items[2, 4] | ||
| 266 | |||
| 267 | -- take the last 4 items | ||
| 268 | last_four_items = items[-4, -1] | ||
| 269 | ``` | ||
| 270 | |||
| 271 | </YueDisplay> | ||
diff --git a/doc/docs/doc/conditionals.md b/doc/docs/doc/conditionals.md new file mode 100644 index 0000000..5ba81cf --- /dev/null +++ b/doc/docs/doc/conditionals.md | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | # Conditionals | ||
| 2 | |||
| 3 | ```yuescript | ||
| 4 | have_coins = false | ||
| 5 | if have_coins | ||
| 6 | print "Got coins" | ||
| 7 | else | ||
| 8 | print "No coins" | ||
| 9 | ``` | ||
| 10 | <YueDisplay> | ||
| 11 | |||
| 12 | ```yue | ||
| 13 | have_coins = false | ||
| 14 | if have_coins | ||
| 15 | print "Got coins" | ||
| 16 | else | ||
| 17 | print "No coins" | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 | A short syntax for single statements can also be used: | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | have_coins = false | ||
| 26 | if have_coins then print "Got coins" else print "No coins" | ||
| 27 | ``` | ||
| 28 | <YueDisplay> | ||
| 29 | |||
| 30 | ```yue | ||
| 31 | have_coins = false | ||
| 32 | if have_coins then print "Got coins" else print "No coins" | ||
| 33 | ``` | ||
| 34 | |||
| 35 | </YueDisplay> | ||
| 36 | |||
| 37 | Because if statements can be used as expressions, this can also be written as: | ||
| 38 | |||
| 39 | ```yuescript | ||
| 40 | have_coins = false | ||
| 41 | print if have_coins then "Got coins" else "No coins" | ||
| 42 | ``` | ||
| 43 | <YueDisplay> | ||
| 44 | |||
| 45 | ```yue | ||
| 46 | have_coins = false | ||
| 47 | print if have_coins then "Got coins" else "No coins" | ||
| 48 | ``` | ||
| 49 | |||
| 50 | </YueDisplay> | ||
| 51 | |||
| 52 | Conditionals can also be used in return statements and assignments: | ||
| 53 | |||
| 54 | ```yuescript | ||
| 55 | is_tall = (name) -> | ||
| 56 | if name == "Rob" | ||
| 57 | true | ||
| 58 | else | ||
| 59 | false | ||
| 60 | |||
| 61 | message = if is_tall "Rob" | ||
| 62 | "I am very tall" | ||
| 63 | else | ||
| 64 | "I am not so tall" | ||
| 65 | |||
| 66 | print message -- prints: I am very tall | ||
| 67 | ``` | ||
| 68 | <YueDisplay> | ||
| 69 | |||
| 70 | ```yue | ||
| 71 | is_tall = (name) -> | ||
| 72 | if name == "Rob" | ||
| 73 | true | ||
| 74 | else | ||
| 75 | false | ||
| 76 | |||
| 77 | message = if is_tall "Rob" | ||
| 78 | "I am very tall" | ||
| 79 | else | ||
| 80 | "I am not so tall" | ||
| 81 | |||
| 82 | print message -- prints: I am very tall | ||
| 83 | ``` | ||
| 84 | |||
| 85 | </YueDisplay> | ||
| 86 | |||
| 87 | The opposite of if is unless: | ||
| 88 | |||
| 89 | ```yuescript | ||
| 90 | unless os.date("%A") == "Monday" | ||
| 91 | print "it is not Monday!" | ||
| 92 | ``` | ||
| 93 | <YueDisplay> | ||
| 94 | |||
| 95 | ```yue | ||
| 96 | unless os.date("%A") == "Monday" | ||
| 97 | print "it is not Monday!" | ||
| 98 | ``` | ||
| 99 | |||
| 100 | </YueDisplay> | ||
| 101 | |||
| 102 | ```yuescript | ||
| 103 | print "You're lucky!" unless math.random! > 0.1 | ||
| 104 | ``` | ||
| 105 | <YueDisplay> | ||
| 106 | |||
| 107 | ```yue | ||
| 108 | print "You're lucky!" unless math.random! > 0.1 | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
| 112 | |||
| 113 | ## In Expression | ||
| 114 | |||
| 115 | You can write range checking code with an `in-expression`. | ||
| 116 | |||
| 117 | ```yuescript | ||
| 118 | a = 5 | ||
| 119 | |||
| 120 | if a in [1, 3, 5, 7] | ||
| 121 | print "checking equality with discrete values" | ||
| 122 | |||
| 123 | if a in list | ||
| 124 | print "checking if `a` is in a list" | ||
| 125 | ``` | ||
| 126 | <YueDisplay> | ||
| 127 | |||
| 128 | ```yue | ||
| 129 | a = 5 | ||
| 130 | |||
| 131 | if a in [1, 3, 5, 7] | ||
| 132 | print "checking equality with discrete values" | ||
| 133 | |||
| 134 | if a in list | ||
| 135 | print "checking if `a` is in a list" | ||
| 136 | ``` | ||
| 137 | |||
| 138 | </YueDisplay> | ||
| 139 | |||
| 140 | ```yuescript | ||
| 141 | print "You're lucky!" unless math.random! > 0.1 | ||
| 142 | ``` | ||
| 143 | <YueDisplay> | ||
| 144 | |||
| 145 | ```yue | ||
| 146 | print "You're lucky!" unless math.random! > 0.1 | ||
| 147 | ``` | ||
| 148 | |||
| 149 | </YueDisplay> | ||
diff --git a/doc/docs/doc/continue.md b/doc/docs/doc/continue.md new file mode 100644 index 0000000..b000765 --- /dev/null +++ b/doc/docs/doc/continue.md | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | # Continue | ||
| 2 | |||
| 3 | A continue statement can be used to skip the current iteration in a loop. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 0 | ||
| 7 | while i < 10 | ||
| 8 | i += 1 | ||
| 9 | continue if i % 2 == 0 | ||
| 10 | print i | ||
| 11 | ``` | ||
| 12 | <YueDisplay> | ||
| 13 | |||
| 14 | ```yue | ||
| 15 | i = 0 | ||
| 16 | while i < 10 | ||
| 17 | i += 1 | ||
| 18 | continue if i % 2 == 0 | ||
| 19 | print i | ||
| 20 | ``` | ||
| 21 | |||
| 22 | </YueDisplay> | ||
| 23 | |||
| 24 | continue 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: | ||
| 25 | |||
| 26 | ```yuescript | ||
| 27 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 28 | odds = for x in *my_numbers | ||
| 29 | continue if x % 2 == 1 | ||
| 30 | x | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 36 | odds = for x in *my_numbers | ||
| 37 | continue if x % 2 == 1 | ||
| 38 | x | ||
| 39 | ``` | ||
| 40 | |||
| 41 | </YueDisplay> | ||
diff --git a/doc/docs/doc/destructuring-assignment.md b/doc/docs/doc/destructuring-assignment.md new file mode 100644 index 0000000..8967eb3 --- /dev/null +++ b/doc/docs/doc/destructuring-assignment.md | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | # Destructuring Assignment | ||
| 2 | |||
| 3 | Destructuring assignment is a way to quickly extract values from a table by their name or position in array based tables. | ||
| 4 | |||
| 5 | Typically 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. | ||
| 6 | |||
| 7 | This is best explained with examples. Here is how you would unpack the first two values from a table: | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | thing = [1, 2] | ||
| 11 | |||
| 12 | [a, b] = thing | ||
| 13 | print a, b | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | thing = [1, 2] | ||
| 19 | |||
| 20 | [a, b] = thing | ||
| 21 | print a, b | ||
| 22 | ``` | ||
| 23 | |||
| 24 | </YueDisplay> | ||
| 25 | |||
| 26 | In 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. | ||
| 27 | |||
| 28 | ```yuescript | ||
| 29 | obj = { | ||
| 30 | hello: "world" | ||
| 31 | day: "tuesday" | ||
| 32 | length: 20 | ||
| 33 | } | ||
| 34 | |||
| 35 | {hello: hello, day: the_day} = obj | ||
| 36 | print hello, the_day | ||
| 37 | |||
| 38 | :day = obj -- OK to do simple destructuring without braces | ||
| 39 | ``` | ||
| 40 | <YueDisplay> | ||
| 41 | |||
| 42 | ```yue | ||
| 43 | obj = { | ||
| 44 | hello: "world" | ||
| 45 | day: "tuesday" | ||
| 46 | length: 20 | ||
| 47 | } | ||
| 48 | |||
| 49 | {hello: hello, day: the_day} = obj | ||
| 50 | print hello, the_day | ||
| 51 | |||
| 52 | :day = obj -- OK to do simple destructuring without braces | ||
| 53 | ``` | ||
| 54 | |||
| 55 | </YueDisplay> | ||
| 56 | |||
| 57 | This also works with nested data structures as well: | ||
| 58 | |||
| 59 | ```yuescript | ||
| 60 | obj2 = { | ||
| 61 | numbers: [1, 2, 3, 4] | ||
| 62 | properties: { | ||
| 63 | color: "green" | ||
| 64 | height: 13.5 | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | {numbers: [first, second], properties: {color: color}} = obj2 | ||
| 69 | print first, second, color | ||
| 70 | ``` | ||
| 71 | <YueDisplay> | ||
| 72 | |||
| 73 | ```yue | ||
| 74 | obj2 = { | ||
| 75 | numbers: [1, 2, 3, 4] | ||
| 76 | properties: { | ||
| 77 | color: "green" | ||
| 78 | height: 13.5 | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | {numbers: [first, second]} = obj2 | ||
| 83 | print first, second, color | ||
| 84 | ``` | ||
| 85 | |||
| 86 | </YueDisplay> | ||
| 87 | |||
| 88 | If the destructuring statement is complicated, feel free to spread it out over a few lines. A slightly more complicated example: | ||
| 89 | |||
| 90 | ```yuescript | ||
| 91 | { | ||
| 92 | numbers: [first, second] | ||
| 93 | properties: { | ||
| 94 | color: color | ||
| 95 | } | ||
| 96 | } = obj2 | ||
| 97 | ``` | ||
| 98 | <YueDisplay> | ||
| 99 | |||
| 100 | ```yue | ||
| 101 | { | ||
| 102 | numbers: [first, second] | ||
| 103 | properties: { | ||
| 104 | color: color | ||
| 105 | } | ||
| 106 | } = obj2 | ||
| 107 | ``` | ||
| 108 | |||
| 109 | </YueDisplay> | ||
| 110 | |||
| 111 | It'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: | ||
| 112 | |||
| 113 | ```yuescript | ||
| 114 | {:concat, :insert} = table | ||
| 115 | ``` | ||
| 116 | <YueDisplay> | ||
| 117 | |||
| 118 | ```yue | ||
| 119 | {:concat, :insert} = table | ||
| 120 | ``` | ||
| 121 | |||
| 122 | </YueDisplay> | ||
| 123 | |||
| 124 | This is effectively the same as import, but we can rename fields we want to extract by mixing the syntax: | ||
| 125 | |||
| 126 | ```yuescript | ||
| 127 | {:mix, :max, random: rand} = math | ||
| 128 | ``` | ||
| 129 | <YueDisplay> | ||
| 130 | |||
| 131 | ```yue | ||
| 132 | {:mix, :max, random: rand} = math | ||
| 133 | ``` | ||
| 134 | |||
| 135 | </YueDisplay> | ||
| 136 | |||
| 137 | You can write default values while doing destructuring like: | ||
| 138 | |||
| 139 | ```yuescript | ||
| 140 | {:name = "nameless", :job = "jobless"} = person | ||
| 141 | ``` | ||
| 142 | <YueDisplay> | ||
| 143 | |||
| 144 | ```yue | ||
| 145 | {:name = "nameless", :job = "jobless"} = person | ||
| 146 | ``` | ||
| 147 | |||
| 148 | </YueDisplay> | ||
| 149 | |||
| 150 | You can use `_` as placeholder when doing a list destructuring: | ||
| 151 | |||
| 152 | ```yuescript | ||
| 153 | [_, two, _, four] = items | ||
| 154 | ``` | ||
| 155 | <YueDisplay> | ||
| 156 | |||
| 157 | ```yue | ||
| 158 | [_, two, _, four] = items | ||
| 159 | ``` | ||
| 160 | |||
| 161 | </YueDisplay> | ||
| 162 | |||
| 163 | ## Range Destructuring | ||
| 164 | |||
| 165 | You 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. | ||
| 166 | |||
| 167 | ```yuescript | ||
| 168 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 169 | [first, ...bulk, last] = orders | ||
| 170 | print first -- prints: first | ||
| 171 | print bulk -- prints: {"second", "third", "fourth"} | ||
| 172 | print last -- prints: last | ||
| 173 | ``` | ||
| 174 | <YueDisplay> | ||
| 175 | |||
| 176 | ```yue | ||
| 177 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 178 | [first, ...bulk, last] = orders | ||
| 179 | print first -- prints: first | ||
| 180 | print bulk -- prints: {"second", "third", "fourth"} | ||
| 181 | print last -- prints: last | ||
| 182 | ``` | ||
| 183 | |||
| 184 | </YueDisplay> | ||
| 185 | |||
| 186 | The 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: | ||
| 187 | |||
| 188 | ```yuescript | ||
| 189 | -- Capture everything after first element | ||
| 190 | [first, ...rest] = orders | ||
| 191 | |||
| 192 | -- Capture everything before last element | ||
| 193 | [...start, last] = orders | ||
| 194 | |||
| 195 | -- Capture things except the middle elements | ||
| 196 | [first, ..._, last] = orders | ||
| 197 | ``` | ||
| 198 | <YueDisplay> | ||
| 199 | |||
| 200 | ```yue | ||
| 201 | -- Capture everything after first element | ||
| 202 | [first, ...rest] = orders | ||
| 203 | |||
| 204 | -- Capture everything before last element | ||
| 205 | [...start, last] = orders | ||
| 206 | |||
| 207 | -- Capture things except the middle elements | ||
| 208 | [first, ..._, last] = orders | ||
| 209 | ``` | ||
| 210 | |||
| 211 | </YueDisplay> | ||
| 212 | |||
| 213 | ## Destructuring In Other Places | ||
| 214 | |||
| 215 | Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: | ||
| 216 | |||
| 217 | ```yuescript | ||
| 218 | tuples = [ | ||
| 219 | ["hello", "world"] | ||
| 220 | ["egg", "head"] | ||
| 221 | ] | ||
| 222 | |||
| 223 | for [left, right] in *tuples | ||
| 224 | print left, right | ||
| 225 | ``` | ||
| 226 | <YueDisplay> | ||
| 227 | |||
| 228 | ```yue | ||
| 229 | tuples = [ | ||
| 230 | ["hello", "world"] | ||
| 231 | ["egg", "head"] | ||
| 232 | ] | ||
| 233 | |||
| 234 | for [left, right] in *tuples | ||
| 235 | print left, right | ||
| 236 | ``` | ||
| 237 | |||
| 238 | </YueDisplay> | ||
| 239 | |||
| 240 | We 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. | ||
diff --git a/doc/docs/doc/do.md b/doc/docs/doc/do.md new file mode 100644 index 0000000..4990d6f --- /dev/null +++ b/doc/docs/doc/do.md | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | # Do | ||
| 2 | |||
| 3 | When used as a statement, do works just like it does in Lua. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | do | ||
| 7 | var = "hello" | ||
| 8 | print var | ||
| 9 | print var -- nil here | ||
| 10 | ``` | ||
| 11 | <YueDisplay> | ||
| 12 | |||
| 13 | ```yue | ||
| 14 | do | ||
| 15 | var = "hello" | ||
| 16 | print var | ||
| 17 | print var -- nil here | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 | YueScript'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. | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | counter = do | ||
| 26 | i = 0 | ||
| 27 | -> | ||
| 28 | i += 1 | ||
| 29 | i | ||
| 30 | |||
| 31 | print counter! | ||
| 32 | print counter! | ||
| 33 | ``` | ||
| 34 | <YueDisplay> | ||
| 35 | |||
| 36 | ```yue | ||
| 37 | counter = do | ||
| 38 | i = 0 | ||
| 39 | -> | ||
| 40 | i += 1 | ||
| 41 | i | ||
| 42 | |||
| 43 | print counter! | ||
| 44 | print counter! | ||
| 45 | ``` | ||
| 46 | |||
| 47 | </YueDisplay> | ||
| 48 | |||
| 49 | ```yuescript | ||
| 50 | tbl = { | ||
| 51 | key: do | ||
| 52 | print "assigning key!" | ||
| 53 | 1234 | ||
| 54 | } | ||
| 55 | ``` | ||
| 56 | <YueDisplay> | ||
| 57 | |||
| 58 | ```yue | ||
| 59 | tbl = { | ||
| 60 | key: do | ||
| 61 | print "assigning key!" | ||
| 62 | 1234 | ||
| 63 | } | ||
| 64 | ``` | ||
| 65 | |||
| 66 | </YueDisplay> | ||
diff --git a/doc/docs/doc/for-loop.md b/doc/docs/doc/for-loop.md new file mode 100644 index 0000000..cabcde5 --- /dev/null +++ b/doc/docs/doc/for-loop.md | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | # For Loop | ||
| 2 | |||
| 3 | There are two for loop forms, just like in Lua. A numeric one and a generic one: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | for i = 10, 20 | ||
| 7 | print i | ||
| 8 | |||
| 9 | for k = 1, 15, 2 -- an optional step provided | ||
| 10 | print k | ||
| 11 | |||
| 12 | for key, value in pairs object | ||
| 13 | print key, value | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | for i = 10, 20 | ||
| 19 | print i | ||
| 20 | |||
| 21 | for k = 1, 15, 2 -- an optional step provided | ||
| 22 | print k | ||
| 23 | |||
| 24 | for key, value in pairs object | ||
| 25 | print key, value | ||
| 26 | ``` | ||
| 27 | |||
| 28 | </YueDisplay> | ||
| 29 | |||
| 30 | The slicing and **\*** operators can be used, just like with comprehensions: | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | for item in *items[2, 4] | ||
| 34 | print item | ||
| 35 | ``` | ||
| 36 | <YueDisplay> | ||
| 37 | |||
| 38 | ```yue | ||
| 39 | for item in *items[2, 4] | ||
| 40 | print item | ||
| 41 | ``` | ||
| 42 | |||
| 43 | </YueDisplay> | ||
| 44 | |||
| 45 | A shorter syntax is also available for all variations when the body is only a single line: | ||
| 46 | |||
| 47 | ```yuescript | ||
| 48 | for item in *items do print item | ||
| 49 | |||
| 50 | for j = 1, 10, 3 do print j | ||
| 51 | ``` | ||
| 52 | <YueDisplay> | ||
| 53 | |||
| 54 | ```yue | ||
| 55 | for item in *items do print item | ||
| 56 | |||
| 57 | for j = 1, 10, 3 do print j | ||
| 58 | ``` | ||
| 59 | |||
| 60 | </YueDisplay> | ||
| 61 | |||
| 62 | A 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. | ||
| 63 | |||
| 64 | Doubling every even number: | ||
| 65 | |||
| 66 | ```yuescript | ||
| 67 | doubled_evens = for i = 1, 20 | ||
| 68 | if i % 2 == 0 | ||
| 69 | i * 2 | ||
| 70 | else | ||
| 71 | i | ||
| 72 | ``` | ||
| 73 | <YueDisplay> | ||
| 74 | |||
| 75 | ```yue | ||
| 76 | doubled_evens = for i = 1, 20 | ||
| 77 | if i % 2 == 0 | ||
| 78 | i * 2 | ||
| 79 | else | ||
| 80 | i | ||
| 81 | ``` | ||
| 82 | |||
| 83 | </YueDisplay> | ||
| 84 | |||
| 85 | In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result. | ||
| 86 | |||
| 87 | For example, to find the first number greater than 10: | ||
| 88 | |||
| 89 | ```yuescript | ||
| 90 | first_large = for n in *numbers | ||
| 91 | break n if n > 10 | ||
| 92 | ``` | ||
| 93 | <YueDisplay> | ||
| 94 | |||
| 95 | ```yue | ||
| 96 | first_large = for n in *numbers | ||
| 97 | break n if n > 10 | ||
| 98 | ``` | ||
| 99 | |||
| 100 | </YueDisplay> | ||
| 101 | |||
| 102 | This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions. | ||
| 103 | |||
| 104 | You can also filter values by combining the for loop expression with the continue statement. | ||
| 105 | |||
| 106 | For 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. | ||
| 107 | |||
| 108 | ```yuescript | ||
| 109 | func_a = -> for i = 1, 10 do print i | ||
| 110 | func_b = -> return for i = 1, 10 do i | ||
| 111 | |||
| 112 | print func_a! -- prints nil | ||
| 113 | print func_b! -- prints table object | ||
| 114 | ``` | ||
| 115 | <YueDisplay> | ||
| 116 | |||
| 117 | ```yue | ||
| 118 | func_a = -> for i = 1, 10 do print i | ||
| 119 | func_b = -> return for i = 1, 10 do i | ||
| 120 | |||
| 121 | print func_a! -- prints nil | ||
| 122 | print func_b! -- prints table object | ||
| 123 | ``` | ||
| 124 | |||
| 125 | </YueDisplay> | ||
| 126 | |||
| 127 | This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop. | ||
diff --git a/doc/docs/doc/function-literals.md b/doc/docs/doc/function-literals.md new file mode 100644 index 0000000..316e07c --- /dev/null +++ b/doc/docs/doc/function-literals.md | |||
| @@ -0,0 +1,494 @@ | |||
| 1 | # Function Literals | ||
| 2 | |||
| 3 | All functions are created using a function expression. A simple function is denoted using the arrow: **->**. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | my_function = -> | ||
| 7 | my_function() -- call the empty function | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | my_function = -> | ||
| 13 | my_function() -- call the empty function | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | The 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: | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | func_a = -> print "hello world" | ||
| 22 | |||
| 23 | func_b = -> | ||
| 24 | value = 100 | ||
| 25 | print "The value:", value | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | func_a = -> print "hello world" | ||
| 31 | |||
| 32 | func_b = -> | ||
| 33 | value = 100 | ||
| 34 | print "The value:", value | ||
| 35 | ``` | ||
| 36 | |||
| 37 | </YueDisplay> | ||
| 38 | |||
| 39 | If 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. | ||
| 40 | |||
| 41 | ```yuescript | ||
| 42 | func_a! | ||
| 43 | func_b() | ||
| 44 | ``` | ||
| 45 | <YueDisplay> | ||
| 46 | |||
| 47 | ```yue | ||
| 48 | func_a! | ||
| 49 | func_b() | ||
| 50 | ``` | ||
| 51 | |||
| 52 | </YueDisplay> | ||
| 53 | |||
| 54 | Functions with arguments can be created by preceding the arrow with a list of argument names in parentheses: | ||
| 55 | |||
| 56 | ```yuescript | ||
| 57 | sum = (x, y) -> print "sum", x + y | ||
| 58 | ``` | ||
| 59 | <YueDisplay> | ||
| 60 | |||
| 61 | ```yue | ||
| 62 | sum = (x, y) -> print "sum", x + y | ||
| 63 | ``` | ||
| 64 | |||
| 65 | </YueDisplay> | ||
| 66 | |||
| 67 | Functions 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. | ||
| 68 | |||
| 69 | ```yuescript | ||
| 70 | sum 10, 20 | ||
| 71 | print sum 10, 20 | ||
| 72 | |||
| 73 | a b c "a", "b", "c" | ||
| 74 | ``` | ||
| 75 | <YueDisplay> | ||
| 76 | |||
| 77 | ```yue | ||
| 78 | sum 10, 20 | ||
| 79 | print sum 10, 20 | ||
| 80 | |||
| 81 | a b c "a", "b", "c" | ||
| 82 | ``` | ||
| 83 | |||
| 84 | </YueDisplay> | ||
| 85 | |||
| 86 | In 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. | ||
| 87 | |||
| 88 | ```yuescript | ||
| 89 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 90 | ``` | ||
| 91 | <YueDisplay> | ||
| 92 | |||
| 93 | ```yue | ||
| 94 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 95 | ``` | ||
| 96 | |||
| 97 | </YueDisplay> | ||
| 98 | |||
| 99 | There must not be any space between the opening parenthesis and the function. | ||
| 100 | |||
| 101 | Functions will coerce the last statement in their body into a return statement, this is called implicit return: | ||
| 102 | |||
| 103 | ```yuescript | ||
| 104 | sum = (x, y) -> x + y | ||
| 105 | print "The sum is ", sum 10, 20 | ||
| 106 | ``` | ||
| 107 | <YueDisplay> | ||
| 108 | |||
| 109 | ```yue | ||
| 110 | sum = (x, y) -> x + y | ||
| 111 | print "The sum is ", sum 10, 20 | ||
| 112 | ``` | ||
| 113 | |||
| 114 | </YueDisplay> | ||
| 115 | |||
| 116 | And if you need to explicitly return, you can use the return keyword: | ||
| 117 | |||
| 118 | ```yuescript | ||
| 119 | sum = (x, y) -> return x + y | ||
| 120 | ``` | ||
| 121 | <YueDisplay> | ||
| 122 | |||
| 123 | ```yue | ||
| 124 | sum = (x, y) -> return x + y | ||
| 125 | ``` | ||
| 126 | |||
| 127 | </YueDisplay> | ||
| 128 | |||
| 129 | Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas: | ||
| 130 | |||
| 131 | ```yuescript | ||
| 132 | mystery = (x, y) -> x + y, x - y | ||
| 133 | a, b = mystery 10, 20 | ||
| 134 | ``` | ||
| 135 | <YueDisplay> | ||
| 136 | |||
| 137 | ```yue | ||
| 138 | mystery = (x, y) -> x + y, x - y | ||
| 139 | a, b = mystery 10, 20 | ||
| 140 | ``` | ||
| 141 | |||
| 142 | </YueDisplay> | ||
| 143 | |||
| 144 | ## Fat Arrows | ||
| 145 | |||
| 146 | Because 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. | ||
| 147 | |||
| 148 | ```yuescript | ||
| 149 | func = (num) => @value + num | ||
| 150 | ``` | ||
| 151 | <YueDisplay> | ||
| 152 | |||
| 153 | ```yue | ||
| 154 | func = (num) => @value + num | ||
| 155 | ``` | ||
| 156 | |||
| 157 | </YueDisplay> | ||
| 158 | |||
| 159 | ## Argument Defaults | ||
| 160 | |||
| 161 | It 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. | ||
| 162 | |||
| 163 | ```yuescript | ||
| 164 | my_function = (name = "something", height = 100) -> | ||
| 165 | print "Hello I am", name | ||
| 166 | print "My height is", height | ||
| 167 | ``` | ||
| 168 | <YueDisplay> | ||
| 169 | |||
| 170 | ```yue | ||
| 171 | my_function = (name = "something", height = 100) -> | ||
| 172 | print "Hello I am", name | ||
| 173 | print "My height is", height | ||
| 174 | ``` | ||
| 175 | |||
| 176 | </YueDisplay> | ||
| 177 | |||
| 178 | An 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. | ||
| 179 | |||
| 180 | ```yuescript | ||
| 181 | some_args = (x = 100, y = x + 1000) -> | ||
| 182 | print x + y | ||
| 183 | ``` | ||
| 184 | <YueDisplay> | ||
| 185 | |||
| 186 | ```yue | ||
| 187 | some_args = (x = 100, y = x + 1000) -> | ||
| 188 | print x + y | ||
| 189 | ``` | ||
| 190 | |||
| 191 | </YueDisplay> | ||
| 192 | |||
| 193 | ## Considerations | ||
| 194 | |||
| 195 | Because of the expressive parentheses-less way of calling functions, some restrictions must be put in place to avoid parsing ambiguity involving whitespace. | ||
| 196 | |||
| 197 | The minus sign plays two roles, a unary negation operator and a binary subtraction operator. Consider how the following examples compile: | ||
| 198 | |||
| 199 | ```yuescript | ||
| 200 | a = x - 10 | ||
| 201 | b = x-10 | ||
| 202 | c = x -y | ||
| 203 | d = x- z | ||
| 204 | ``` | ||
| 205 | <YueDisplay> | ||
| 206 | |||
| 207 | ```yue | ||
| 208 | a = x - 10 | ||
| 209 | b = x-10 | ||
| 210 | c = x -y | ||
| 211 | d = x- z | ||
| 212 | ``` | ||
| 213 | |||
| 214 | </YueDisplay> | ||
| 215 | |||
| 216 | The 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. | ||
| 217 | |||
| 218 | When 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. | ||
| 219 | |||
| 220 | Where 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. | ||
| 221 | |||
| 222 | ```yuescript | ||
| 223 | x = func"hello" + 100 | ||
| 224 | y = func "hello" + 100 | ||
| 225 | ``` | ||
| 226 | <YueDisplay> | ||
| 227 | |||
| 228 | ```yue | ||
| 229 | x = func"hello" + 100 | ||
| 230 | y = func "hello" + 100 | ||
| 231 | ``` | ||
| 232 | |||
| 233 | </YueDisplay> | ||
| 234 | |||
| 235 | ## Multi-line arguments | ||
| 236 | |||
| 237 | When 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. | ||
| 238 | |||
| 239 | If 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 | ||
| 240 | |||
| 241 | ```yuescript | ||
| 242 | my_func 5, 4, 3, | ||
| 243 | 8, 9, 10 | ||
| 244 | |||
| 245 | cool_func 1, 2, | ||
| 246 | 3, 4, | ||
| 247 | 5, 6, | ||
| 248 | 7, 8 | ||
| 249 | ``` | ||
| 250 | <YueDisplay> | ||
| 251 | |||
| 252 | ```yue | ||
| 253 | my_func 5, 4, 3, | ||
| 254 | 8, 9, 10 | ||
| 255 | |||
| 256 | cool_func 1, 2, | ||
| 257 | 3, 4, | ||
| 258 | 5, 6, | ||
| 259 | 7, 8 | ||
| 260 | ``` | ||
| 261 | |||
| 262 | </YueDisplay> | ||
| 263 | |||
| 264 | This type of invocation can be nested. The level of indentation is used to determine to which function the arguments belong to. | ||
| 265 | |||
| 266 | ```yuescript | ||
| 267 | my_func 5, 6, 7, | ||
| 268 | 6, another_func 6, 7, 8, | ||
| 269 | 9, 1, 2, | ||
| 270 | 5, 4 | ||
| 271 | ``` | ||
| 272 | <YueDisplay> | ||
| 273 | |||
| 274 | ```yue | ||
| 275 | my_func 5, 6, 7, | ||
| 276 | 6, another_func 6, 7, 8, | ||
| 277 | 9, 1, 2, | ||
| 278 | 5, 4 | ||
| 279 | ``` | ||
| 280 | |||
| 281 | </YueDisplay> | ||
| 282 | |||
| 283 | Because 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. | ||
| 284 | |||
| 285 | ```yuescript | ||
| 286 | x = [ | ||
| 287 | 1, 2, 3, 4, a_func 4, 5, | ||
| 288 | 5, 6, | ||
| 289 | 8, 9, 10 | ||
| 290 | ] | ||
| 291 | ``` | ||
| 292 | <YueDisplay> | ||
| 293 | |||
| 294 | ```yue | ||
| 295 | x = [ | ||
| 296 | 1, 2, 3, 4, a_func 4, 5, | ||
| 297 | 5, 6, | ||
| 298 | 8, 9, 10 | ||
| 299 | ] | ||
| 300 | ``` | ||
| 301 | |||
| 302 | </YueDisplay> | ||
| 303 | |||
| 304 | Although uncommon, notice how we can give a deeper indentation for function arguments if we know we will be using a lower indentation further on. | ||
| 305 | |||
| 306 | ```yuescript | ||
| 307 | y = [ my_func 1, 2, 3, | ||
| 308 | 4, 5, | ||
| 309 | 5, 6, 7 | ||
| 310 | ] | ||
| 311 | ``` | ||
| 312 | <YueDisplay> | ||
| 313 | |||
| 314 | ```yue | ||
| 315 | y = [ my_func 1, 2, 3, | ||
| 316 | 4, 5, | ||
| 317 | 5, 6, 7 | ||
| 318 | ] | ||
| 319 | ``` | ||
| 320 | |||
| 321 | </YueDisplay> | ||
| 322 | |||
| 323 | The 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: | ||
| 324 | |||
| 325 | ```yuescript | ||
| 326 | if func 1, 2, 3, | ||
| 327 | "hello", | ||
| 328 | "world" | ||
| 329 | print "hello" | ||
| 330 | print "I am inside if" | ||
| 331 | |||
| 332 | if func 1, 2, 3, | ||
| 333 | "hello", | ||
| 334 | "world" | ||
| 335 | print "hello" | ||
| 336 | print "I am inside if" | ||
| 337 | ``` | ||
| 338 | <YueDisplay> | ||
| 339 | |||
| 340 | ```yue | ||
| 341 | if func 1, 2, 3, | ||
| 342 | "hello", | ||
| 343 | "world" | ||
| 344 | print "hello" | ||
| 345 | print "I am inside if" | ||
| 346 | |||
| 347 | if func 1, 2, 3, | ||
| 348 | "hello", | ||
| 349 | "world" | ||
| 350 | print "hello" | ||
| 351 | print "I am inside if" | ||
| 352 | ``` | ||
| 353 | |||
| 354 | </YueDisplay> | ||
| 355 | |||
| 356 | ## Parameter Destructuring | ||
| 357 | |||
| 358 | YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available: | ||
| 359 | |||
| 360 | * **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`). | ||
| 361 | |||
| 362 | * **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. | ||
| 363 | |||
| 364 | ```yuescript | ||
| 365 | f1 = (:a, :b, :c) -> | ||
| 366 | print a, b, c | ||
| 367 | |||
| 368 | f1 a: 1, b: "2", c: {} | ||
| 369 | |||
| 370 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 371 | print a1, b, c | ||
| 372 | |||
| 373 | arg1 = {a: 0} | ||
| 374 | f2 arg1, arg2 | ||
| 375 | ``` | ||
| 376 | <YueDisplay> | ||
| 377 | |||
| 378 | ```yue | ||
| 379 | f1 = (:a, :b, :c) -> | ||
| 380 | print a, b, c | ||
| 381 | |||
| 382 | f1 a: 1, b: "2", c: {} | ||
| 383 | |||
| 384 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 385 | print a1, b, c | ||
| 386 | |||
| 387 | arg1 = {a: 0} | ||
| 388 | f2 arg1, arg2 | ||
| 389 | ``` | ||
| 390 | |||
| 391 | </YueDisplay> | ||
| 392 | |||
| 393 | ## Prefixed Return Expression | ||
| 394 | |||
| 395 | When 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: | ||
| 396 | |||
| 397 | ```yuescript | ||
| 398 | findFirstEven = (list): nil -> | ||
| 399 | for item in *list | ||
| 400 | if type(item) == "table" | ||
| 401 | for sub in *item | ||
| 402 | if sub % 2 == 0 | ||
| 403 | return sub | ||
| 404 | ``` | ||
| 405 | <YueDisplay> | ||
| 406 | |||
| 407 | ```yue | ||
| 408 | findFirstEven = (list): nil -> | ||
| 409 | for item in *list | ||
| 410 | if type(item) == "table" | ||
| 411 | for sub in *item | ||
| 412 | if sub % 2 == 0 | ||
| 413 | return sub | ||
| 414 | ``` | ||
| 415 | |||
| 416 | </YueDisplay> | ||
| 417 | |||
| 418 | This is equivalent to: | ||
| 419 | |||
| 420 | ```yuescript | ||
| 421 | findFirstEven = (list) -> | ||
| 422 | for item in *list | ||
| 423 | if type(item) == "table" | ||
| 424 | for sub in *item | ||
| 425 | if sub % 2 == 0 | ||
| 426 | return sub | ||
| 427 | nil | ||
| 428 | ``` | ||
| 429 | <YueDisplay> | ||
| 430 | |||
| 431 | ```yue | ||
| 432 | findFirstEven = (list) -> | ||
| 433 | for item in *list | ||
| 434 | if type(item) == "table" | ||
| 435 | for sub in *item | ||
| 436 | if sub % 2 == 0 | ||
| 437 | return sub | ||
| 438 | nil | ||
| 439 | ``` | ||
| 440 | |||
| 441 | </YueDisplay> | ||
| 442 | |||
| 443 | The 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. | ||
| 444 | |||
| 445 | ## Named Varargs | ||
| 446 | |||
| 447 | You 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). | ||
| 448 | |||
| 449 | ```yuescript | ||
| 450 | f = (...t) -> | ||
| 451 | print "argument count:", t.n | ||
| 452 | print "table length:", #t | ||
| 453 | for i = 1, t.n | ||
| 454 | print t[i] | ||
| 455 | |||
| 456 | f 1, 2, 3 | ||
| 457 | f "a", "b", "c", "d" | ||
| 458 | f! | ||
| 459 | |||
| 460 | -- Handling cases with nil values | ||
| 461 | process = (...args) -> | ||
| 462 | sum = 0 | ||
| 463 | for i = 1, args.n | ||
| 464 | if args[i] != nil and type(args[i]) == "number" | ||
| 465 | sum += args[i] | ||
| 466 | sum | ||
| 467 | |||
| 468 | process 1, nil, 3, nil, 5 | ||
| 469 | ``` | ||
| 470 | <YueDisplay> | ||
| 471 | |||
| 472 | ```yue | ||
| 473 | f = (...t) -> | ||
| 474 | print "argument count:", t.n | ||
| 475 | print "table length:", #t | ||
| 476 | for i = 1, t.n | ||
| 477 | print t[i] | ||
| 478 | |||
| 479 | f 1, 2, 3 | ||
| 480 | f "a", "b", "c", "d" | ||
| 481 | f! | ||
| 482 | |||
| 483 | -- Handling cases with nil values | ||
| 484 | process = (...args) -> | ||
| 485 | sum = 0 | ||
| 486 | for i = 1, args.n | ||
| 487 | if args[i] != nil and type(args[i]) == "number" | ||
| 488 | sum += args[i] | ||
| 489 | sum | ||
| 490 | |||
| 491 | process 1, nil, 3, nil, 5 | ||
| 492 | ``` | ||
| 493 | |||
| 494 | </YueDisplay> | ||
diff --git a/doc/docs/doc/function-stubs.md b/doc/docs/doc/function-stubs.md new file mode 100644 index 0000000..57a8b0c --- /dev/null +++ b/doc/docs/doc/function-stubs.md | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | # Function Stubs | ||
| 2 | |||
| 3 | It 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. | ||
| 4 | |||
| 5 | The 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. | ||
| 6 | |||
| 7 | Its syntax is the same as calling an instance method with the \ operator but with no argument list provided. | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | my_object = { | ||
| 11 | value: 1000 | ||
| 12 | write: => print "the value:", @value | ||
| 13 | } | ||
| 14 | |||
| 15 | run_callback = (func) -> | ||
| 16 | print "running callback..." | ||
| 17 | func! | ||
| 18 | |||
| 19 | -- this will not work: | ||
| 20 | -- the function has to no reference to my_object | ||
| 21 | run_callback my_object.write | ||
| 22 | |||
| 23 | -- function stub syntax | ||
| 24 | -- lets us bundle the object into a new function | ||
| 25 | run_callback my_object\write | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | my_object = { | ||
| 31 | value: 1000 | ||
| 32 | write: => print "the value:", @value | ||
| 33 | } | ||
| 34 | |||
| 35 | run_callback = (func) -> | ||
| 36 | print "running callback..." | ||
| 37 | func! | ||
| 38 | |||
| 39 | -- this will not work: | ||
| 40 | -- the function has to no reference to my_object | ||
| 41 | run_callback my_object.write | ||
| 42 | |||
| 43 | -- function stub syntax | ||
| 44 | -- lets us bundle the object into a new function | ||
| 45 | run_callback my_object\write | ||
| 46 | ``` | ||
| 47 | |||
| 48 | </YueDisplay> | ||
diff --git a/doc/docs/doc/if-assignment.md b/doc/docs/doc/if-assignment.md new file mode 100644 index 0000000..02984e8 --- /dev/null +++ b/doc/docs/doc/if-assignment.md | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | # If Assignment | ||
| 2 | |||
| 3 | `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. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | if user := database.find_user "moon" | ||
| 7 | print user.name | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | if user := database.find_user "moon" | ||
| 13 | print user.name | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | if hello := os.getenv "hello" | ||
| 20 | print "You have hello", hello | ||
| 21 | elseif world := os.getenv "world" | ||
| 22 | print "you have world", world | ||
| 23 | else | ||
| 24 | print "nothing :(" | ||
| 25 | ``` | ||
| 26 | <YueDisplay> | ||
| 27 | |||
| 28 | ```yue | ||
| 29 | if hello := os.getenv "hello" | ||
| 30 | print "You have hello", hello | ||
| 31 | elseif world := os.getenv "world" | ||
| 32 | print "you have world", world | ||
| 33 | else | ||
| 34 | print "nothing :(" | ||
| 35 | ``` | ||
| 36 | |||
| 37 | </YueDisplay> | ||
| 38 | |||
| 39 | If assignment with multiple return values. Only the first value is getting checked, other values are scoped. | ||
| 40 | ```yuescript | ||
| 41 | if success, result := pcall -> "get result without problems" | ||
| 42 | print result -- variable result is scoped | ||
| 43 | print "OK" | ||
| 44 | ``` | ||
| 45 | <YueDisplay> | ||
| 46 | |||
| 47 | ```yue | ||
| 48 | if success, result := pcall -> "get result without problems" | ||
| 49 | print result -- variable result is scoped | ||
| 50 | print "OK" | ||
| 51 | ``` | ||
| 52 | |||
| 53 | </YueDisplay> | ||
| 54 | |||
| 55 | ## While Assignment | ||
| 56 | |||
| 57 | You can also use if assignment in a while loop to get the value as the loop condition. | ||
| 58 | |||
| 59 | ```yuescript | ||
| 60 | while byte := stream\read_one! | ||
| 61 | -- do something with the byte | ||
| 62 | print byte | ||
| 63 | ``` | ||
| 64 | <YueDisplay> | ||
| 65 | |||
| 66 | ```yue | ||
| 67 | while byte := stream\read_one! | ||
| 68 | -- do something with the byte | ||
| 69 | print byte | ||
| 70 | ``` | ||
| 71 | |||
| 72 | </YueDisplay> | ||
diff --git a/doc/docs/doc/index.md b/doc/docs/doc/index.md index 6de2ce7..b7f609b 100755 --- a/doc/docs/doc/index.md +++ b/doc/docs/doc/index.md | |||
| @@ -1,5520 +1,11 @@ | |||
| 1 | --- | 1 | --- |
| 2 | sidebar: auto | ||
| 3 | title: Reference | 2 | title: Reference |
| 4 | --- | 3 | --- |
| 5 | 4 | ||
| 6 | # YueScript | 5 | # YueScript Documentation |
| 7 | 6 | ||
| 8 | <img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em;"/> | 7 | <img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em; padding-bottom: 2em;"/> |
| 9 | 8 | ||
| 10 | ## Introduction | 9 | Welcome to the <b>YueScript</b> official documentation!<br/> |
| 11 | 10 | Here you can find the language features, usage, reference examples and resources.<br/> | |
| 12 | YueScript 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. | 11 | Please select a chapter from the sidebar to start learning about YueScript. |
| 13 | |||
| 14 | Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. | ||
| 15 | |||
| 16 | ### An Overview of YueScript | ||
| 17 | ```yuescript | ||
| 18 | -- import syntax | ||
| 19 | import p, to_lua from "yue" | ||
| 20 | |||
| 21 | -- object literals | ||
| 22 | inventory = | ||
| 23 | equipment: | ||
| 24 | - "sword" | ||
| 25 | - "shield" | ||
| 26 | items: | ||
| 27 | - name: "potion" | ||
| 28 | count: 10 | ||
| 29 | - name: "bread" | ||
| 30 | count: 3 | ||
| 31 | |||
| 32 | -- list comprehension | ||
| 33 | map = (arr, action) -> | ||
| 34 | [action item for item in *arr] | ||
| 35 | |||
| 36 | filter = (arr, cond) -> | ||
| 37 | [item for item in *arr when cond item] | ||
| 38 | |||
| 39 | reduce = (arr, init, action): init -> | ||
| 40 | init = action init, item for item in *arr | ||
| 41 | |||
| 42 | -- pipe operator | ||
| 43 | [1, 2, 3] | ||
| 44 | |> map (x) -> x * 2 | ||
| 45 | |> filter (x) -> x > 4 | ||
| 46 | |> reduce 0, (a, b) -> a + b | ||
| 47 | |||
| 48 | |||
| 49 | -- metatable manipulation | ||
| 50 | apple = | ||
| 51 | size: 15 | ||
| 52 | <index>: | ||
| 53 | color: 0x00ffff | ||
| 54 | |||
| 55 | with apple | ||
| 56 | p .size, .color, .<index> if .<>? | ||
| 57 | |||
| 58 | -- js-like export syntax | ||
| 59 | export 🌛 = "月之脚本" | ||
| 60 | ``` | ||
| 61 | |||
| 62 | <YueDisplay> | ||
| 63 | |||
| 64 | ```yue | ||
| 65 | -- import syntax | ||
| 66 | import p, to_lua from "yue" | ||
| 67 | |||
| 68 | -- object literals | ||
| 69 | inventory = | ||
| 70 | equipment: | ||
| 71 | - "sword" | ||
| 72 | - "shield" | ||
| 73 | items: | ||
| 74 | - name: "potion" | ||
| 75 | count: 10 | ||
| 76 | - name: "bread" | ||
| 77 | count: 3 | ||
| 78 | |||
| 79 | -- list comprehension | ||
| 80 | map = (arr, action) -> | ||
| 81 | [action item for item in *arr] | ||
| 82 | |||
| 83 | filter = (arr, cond) -> | ||
| 84 | [item for item in *arr when cond item] | ||
| 85 | |||
| 86 | reduce = (arr, init, action): init -> | ||
| 87 | init = action init, item for item in *arr | ||
| 88 | |||
| 89 | -- pipe operator | ||
| 90 | [1, 2, 3] | ||
| 91 | |> map (x) -> x * 2 | ||
| 92 | |> filter (x) -> x > 4 | ||
| 93 | |> reduce 0, (a, b) -> a + b | ||
| 94 | |||
| 95 | |||
| 96 | -- metatable manipulation | ||
| 97 | apple = | ||
| 98 | size: 15 | ||
| 99 | <index>: | ||
| 100 | color: 0x00ffff | ||
| 101 | |||
| 102 | with apple | ||
| 103 | p .size, .color, .<index> if .<>? | ||
| 104 | |||
| 105 | -- js-like export syntax | ||
| 106 | export 🌛 = "月之脚本" | ||
| 107 | ``` | ||
| 108 | |||
| 109 | </YueDisplay> | ||
| 110 | |||
| 111 | ## Installation | ||
| 112 | |||
| 113 | * **Lua Module** | ||
| 114 | |||
| 115 |  Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install it as a Lua module and executable with: | ||
| 116 | |||
| 117 | ``` | ||
| 118 | > luarocks install yuescript | ||
| 119 | ``` | ||
| 120 | |||
| 121 |  Or you can build `yue.so` file with: | ||
| 122 | |||
| 123 | ``` | ||
| 124 | > make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
| 125 | ``` | ||
| 126 | |||
| 127 |  Then get the binary file from path **bin/shared/yue.so**. | ||
| 128 | |||
| 129 | * **Build Binary Tool** | ||
| 130 | |||
| 131 |  Clone this repo, then build and install executable with: | ||
| 132 | ``` | ||
| 133 | > make install | ||
| 134 | ``` | ||
| 135 | |||
| 136 |  Build YueScript tool without macro feature: | ||
| 137 | ``` | ||
| 138 | > make install NO_MACRO=true | ||
| 139 | ``` | ||
| 140 | |||
| 141 |  Build YueScript tool without built-in Lua binary: | ||
| 142 | ``` | ||
| 143 | > make install NO_LUA=true | ||
| 144 | ``` | ||
| 145 | |||
| 146 | * **Download Precompiled Binary** | ||
| 147 | |||
| 148 |  You can download precompiled binary files, including binary executable files compatible with different Lua versions and library files. | ||
| 149 | |||
| 150 |  Download precompiled binary files from [here](https://github.com/IppClub/YueScript/releases). | ||
| 151 | |||
| 152 | ## Usage | ||
| 153 | |||
| 154 | ### Lua Module | ||
| 155 | |||
| 156 |  Use YueScript module in Lua: | ||
| 157 | |||
| 158 | * **Case 1** | ||
| 159 | Require "your_yuescript_entry.yue" in Lua. | ||
| 160 | ```Lua | ||
| 161 | require("yue")("your_yuescript_entry") | ||
| 162 | ``` | ||
| 163 |  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. | ||
| 164 | |||
| 165 | * **Case 2** | ||
| 166 | Require YueScript module and rewite message by hand. | ||
| 167 | ```lua | ||
| 168 | local yue = require("yue") | ||
| 169 | yue.insert_loader() | ||
| 170 | local success, result = xpcall(function() | ||
| 171 | return require("yuescript_module_name") | ||
| 172 | end, function(err) | ||
| 173 | return yue.traceback(err) | ||
| 174 | end) | ||
| 175 | ``` | ||
| 176 | |||
| 177 | * **Case 3** | ||
| 178 | Use the YueScript compiler function in Lua. | ||
| 179 | ```lua | ||
| 180 | local yue = require("yue") | ||
| 181 | local codes, err, globals = yue.to_lua([[ | ||
| 182 | f = -> | ||
| 183 | print "hello world" | ||
| 184 | f! | ||
| 185 | ]],{ | ||
| 186 | implicit_return_root = true, | ||
| 187 | reserve_line_number = true, | ||
| 188 | lint_global = true, | ||
| 189 | space_over_tab = false, | ||
| 190 | options = { | ||
| 191 | target = "5.4", | ||
| 192 | path = "/script" | ||
| 193 | } | ||
| 194 | }) | ||
| 195 | ``` | ||
| 196 | |||
| 197 | ### YueScript Tool | ||
| 198 | |||
| 199 |  Use YueScript tool with: | ||
| 200 | ```sh | ||
| 201 | > yue -h | ||
| 202 | Usage: yue | ||
| 203 | [options] [<file/directory>] ... | ||
| 204 | yue -e <code_or_file> [args...] | ||
| 205 | yue -w [<directory>] [options] | ||
| 206 | yue - | ||
| 207 | |||
| 208 | Notes: | ||
| 209 | - '-' / '--' must be the first and only argument. | ||
| 210 | - '-o/--output' can not be used with multiple input files. | ||
| 211 | - '-w/--watch' can not be used with file input (directory only). | ||
| 212 | - with '-e/--execute', remaining tokens are treated as script args. | ||
| 213 | |||
| 214 | Options: | ||
| 215 | -h, --help Show this help message and exit. | ||
| 216 | -e <str>, --execute <str> Execute a file or raw codes | ||
| 217 | -m, --minify Generate minified codes | ||
| 218 | -r, --rewrite Rewrite output to match original line numbers | ||
| 219 | -t <output_to>, --output-to <output_to> | ||
| 220 | Specify where to place compiled files | ||
| 221 | -o <file>, --output <file> Write output to file | ||
| 222 | -p, --print Write output to standard out | ||
| 223 | -b, --benchmark Dump compile time (doesn't write output) | ||
| 224 | -g, --globals Dump global variables used in NAME LINE COLUMN | ||
| 225 | -s, --spaces Use spaces in generated codes instead of tabs | ||
| 226 | -l, --line-numbers Write line numbers from source codes | ||
| 227 | -j, --no-implicit-return Disable implicit return at end of file | ||
| 228 | -c, --reserve-comments Reserve comments before statement from source codes | ||
| 229 | -w [<dir>], --watch [<dir>] | ||
| 230 | Watch changes and compile every file under directory | ||
| 231 | -v, --version Print version | ||
| 232 | - Read from standard in, print to standard out | ||
| 233 | (Must be first and only argument) | ||
| 234 | -- Same as '-' (kept for backward compatibility) | ||
| 235 | |||
| 236 | --target <version> Specify the Lua version that codes will be generated to | ||
| 237 | (version can only be 5.1 to 5.5) | ||
| 238 | --path <path_str> Append an extra Lua search path string to package.path | ||
| 239 | --<key>=<value> Pass compiler option in key=value form (existing behavior) | ||
| 240 | |||
| 241 | Execute without options to enter REPL, type symbol '$' | ||
| 242 | in a single line to start/stop multi-line mode | ||
| 243 | ``` | ||
| 244 |   Use cases: | ||
| 245 | |||
| 246 |   Recursively compile every YueScript file with extension **.yue** under current path: **yue .** | ||
| 247 | |||
| 248 |   Compile and save results to a target path: **yue -t /target/path/ .** | ||
| 249 | |||
| 250 |   Compile and reserve debug info: **yue -l .** | ||
| 251 | |||
| 252 |   Compile and generate minified codes: **yue -m .** | ||
| 253 | |||
| 254 |   Execute raw codes: **yue -e 'print 123'** | ||
| 255 | |||
| 256 |   Execute a YueScript file: **yue -e main.yue** | ||
| 257 | |||
| 258 | ## Macro | ||
| 259 | |||
| 260 | ### Common Usage | ||
| 261 | |||
| 262 | Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation. | ||
| 263 | |||
| 264 | ```yuescript | ||
| 265 | macro PI2 = -> math.pi * 2 | ||
| 266 | area = $PI2 * 5 | ||
| 267 | |||
| 268 | macro HELLO = -> "'hello world'" | ||
| 269 | print $HELLO | ||
| 270 | |||
| 271 | macro config = (debugging) -> | ||
| 272 | global debugMode = debugging == "true" | ||
| 273 | "" | ||
| 274 | |||
| 275 | macro asserts = (cond) -> | ||
| 276 | debugMode and "assert #{cond}" or "" | ||
| 277 | |||
| 278 | macro assert = (cond) -> | ||
| 279 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 280 | |||
| 281 | $config true | ||
| 282 | $asserts item ~= nil | ||
| 283 | |||
| 284 | $config false | ||
| 285 | value = $assert item | ||
| 286 | |||
| 287 | -- the passed expressions are treated as strings | ||
| 288 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 289 | if $and f1!, f2!, f3! | ||
| 290 | print "OK" | ||
| 291 | ``` | ||
| 292 | <YueDisplay> | ||
| 293 | |||
| 294 | ```yue | ||
| 295 | macro PI2 = -> math.pi * 2 | ||
| 296 | area = $PI2 * 5 | ||
| 297 | |||
| 298 | macro HELLO = -> "'hello world'" | ||
| 299 | print $HELLO | ||
| 300 | |||
| 301 | macro config = (debugging) -> | ||
| 302 | global debugMode = debugging == "true" | ||
| 303 | "" | ||
| 304 | |||
| 305 | macro asserts = (cond) -> | ||
| 306 | debugMode and "assert #{cond}" or "" | ||
| 307 | |||
| 308 | macro assert = (cond) -> | ||
| 309 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 310 | |||
| 311 | $config true | ||
| 312 | $asserts item ~= nil | ||
| 313 | |||
| 314 | $config false | ||
| 315 | value = $assert item | ||
| 316 | |||
| 317 | -- the passed expressions are treated as strings | ||
| 318 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 319 | if $and f1!, f2!, f3! | ||
| 320 | print "OK" | ||
| 321 | ``` | ||
| 322 | |||
| 323 | </YueDisplay> | ||
| 324 | |||
| 325 | ### Insert Raw Codes | ||
| 326 | |||
| 327 | A macro function can either return a YueScript string or a config table containing Lua codes. | ||
| 328 | ```yuescript | ||
| 329 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 330 | $yueFunc funcA | ||
| 331 | funcA = -> "fail to assign to the Yue macro defined variable" | ||
| 332 | |||
| 333 | macro luaFunc = (var) -> { | ||
| 334 | code: "local function #{var}() end" | ||
| 335 | type: "lua" | ||
| 336 | } | ||
| 337 | $luaFunc funcB | ||
| 338 | funcB = -> "fail to assign to the Lua macro defined variable" | ||
| 339 | |||
| 340 | macro lua = (code) -> { | ||
| 341 | :code | ||
| 342 | type: "lua" | ||
| 343 | } | ||
| 344 | |||
| 345 | -- the raw string leading and ending symbols are auto trimed | ||
| 346 | $lua[==[ | ||
| 347 | -- raw Lua codes insertion | ||
| 348 | if cond then | ||
| 349 | print("output") | ||
| 350 | end | ||
| 351 | ]==] | ||
| 352 | ``` | ||
| 353 | <YueDisplay> | ||
| 354 | |||
| 355 | ```yue | ||
| 356 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 357 | $yueFunc funcA | ||
| 358 | funcA = -> "fail to assign to the Yue macro defined variable" | ||
| 359 | |||
| 360 | macro luaFunc = (var) -> { | ||
| 361 | code: "local function #{var}() end" | ||
| 362 | type: "lua" | ||
| 363 | } | ||
| 364 | $luaFunc funcB | ||
| 365 | funcB = -> "fail to assign to the Lua macro defined variable" | ||
| 366 | |||
| 367 | macro lua = (code) -> { | ||
| 368 | :code | ||
| 369 | type: "lua" | ||
| 370 | } | ||
| 371 | |||
| 372 | -- the raw string leading and ending symbols are auto trimed | ||
| 373 | $lua[==[ | ||
| 374 | -- raw Lua codes insertion | ||
| 375 | if cond then | ||
| 376 | print("output") | ||
| 377 | end | ||
| 378 | ]==] | ||
| 379 | ``` | ||
| 380 | |||
| 381 | </YueDisplay> | ||
| 382 | |||
| 383 | ### Export Macro | ||
| 384 | |||
| 385 | Macro 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. | ||
| 386 | ```yuescript | ||
| 387 | -- file: utils.yue | ||
| 388 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 389 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 390 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 391 | #{action}" | ||
| 392 | |||
| 393 | -- file main.yue | ||
| 394 | import "utils" as { | ||
| 395 | $, -- symbol to import all macros | ||
| 396 | $foreach: $each -- rename macro $foreach to $each | ||
| 397 | } | ||
| 398 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 399 | ``` | ||
| 400 | <YueDisplay> | ||
| 401 | |||
| 402 | ```yue | ||
| 403 | -- file: utils.yue | ||
| 404 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 405 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 406 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 407 | #{action}" | ||
| 408 | -- file main.yue | ||
| 409 | -- import function is not available in browser, try it in a real environment | ||
| 410 | --[[ | ||
| 411 | import "utils" as { | ||
| 412 | $, -- symbol to import all macros | ||
| 413 | $foreach: $each -- rename macro $foreach to $each | ||
| 414 | } | ||
| 415 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 416 | ]] | ||
| 417 | ``` | ||
| 418 | |||
| 419 | </YueDisplay> | ||
| 420 | |||
| 421 | ### Builtin Macro | ||
| 422 | |||
| 423 | There are some builtin macros but you can override them by declaring macros with the same names. | ||
| 424 | ```yuescript | ||
| 425 | print $FILE -- get string of current module name | ||
| 426 | print $LINE -- get number 2 | ||
| 427 | ``` | ||
| 428 | <YueDisplay> | ||
| 429 | |||
| 430 | ```yue | ||
| 431 | print $FILE -- get string of current module name | ||
| 432 | print $LINE -- get number 2 | ||
| 433 | ``` | ||
| 434 | |||
| 435 | </YueDisplay> | ||
| 436 | |||
| 437 | ### Generating Macros with Macros | ||
| 438 | |||
| 439 | In 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. | ||
| 440 | |||
| 441 | ```yuescript | ||
| 442 | macro Enum = (...) -> | ||
| 443 | items = {...} | ||
| 444 | itemSet = {item, true for item in *items} | ||
| 445 | (item) -> | ||
| 446 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 447 | "\"#{item}\"" | ||
| 448 | |||
| 449 | macro BodyType = $Enum( | ||
| 450 | Static | ||
| 451 | Dynamic | ||
| 452 | Kinematic | ||
| 453 | ) | ||
| 454 | |||
| 455 | print "Valid enum type:", $BodyType Static | ||
| 456 | -- print "Compilation error with enum type:", $BodyType Unknown | ||
| 457 | ``` | ||
| 458 | |||
| 459 | <YueDisplay> | ||
| 460 | |||
| 461 | ```yue | ||
| 462 | macro Enum = (...) -> | ||
| 463 | items = {...} | ||
| 464 | itemSet = {item, true for item in *items} | ||
| 465 | (item) -> | ||
| 466 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 467 | "\"#{item}\"" | ||
| 468 | |||
| 469 | macro BodyType = $Enum( | ||
| 470 | Static | ||
| 471 | Dynamic | ||
| 472 | Kinematic | ||
| 473 | ) | ||
| 474 | |||
| 475 | print "Valid enum type:", $BodyType Static | ||
| 476 | -- print "Compilation error with enum type:", $BodyType Unknown | ||
| 477 | ``` | ||
| 478 | |||
| 479 | </YueDisplay> | ||
| 480 | |||
| 481 | ### Argument Validation | ||
| 482 | |||
| 483 | You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time. | ||
| 484 | |||
| 485 | ```yuescript | ||
| 486 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 487 | print( | ||
| 488 | #{num} | ||
| 489 | #{str} | ||
| 490 | ) | ||
| 491 | |||
| 492 | $printNumAndStr 123, "hello" | ||
| 493 | ``` | ||
| 494 | <YueDisplay> | ||
| 495 | |||
| 496 | ```yue | ||
| 497 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 498 | print( | ||
| 499 | #{num} | ||
| 500 | #{str} | ||
| 501 | ) | ||
| 502 | |||
| 503 | $printNumAndStr 123, "hello" | ||
| 504 | ``` | ||
| 505 | |||
| 506 | </YueDisplay> | ||
| 507 | |||
| 508 | If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place. | ||
| 509 | |||
| 510 | ```yuescript | ||
| 511 | macro printNumAndStr = (num, str) -> | ||
| 512 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 513 | error "expected String as second argument" unless $is_ast String, str | ||
| 514 | "print(#{num}, #{str})" | ||
| 515 | |||
| 516 | $printNumAndStr 123, "hello" | ||
| 517 | ``` | ||
| 518 | <YueDisplay> | ||
| 519 | |||
| 520 | ```yue | ||
| 521 | macro printNumAndStr = (num, str) -> | ||
| 522 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 523 | error "expected String as second argument" unless $is_ast String, str | ||
| 524 | "print(#{num}, #{str})" | ||
| 525 | |||
| 526 | $printNumAndStr 123, "hello" | ||
| 527 | ``` | ||
| 528 | |||
| 529 | </YueDisplay> | ||
| 530 | |||
| 531 | For 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). | ||
| 532 | |||
| 533 | ## Operator | ||
| 534 | |||
| 535 | All 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. | ||
| 536 | |||
| 537 | ```yuescript | ||
| 538 | tb\func! if tb ~= nil | ||
| 539 | tb::func! if tb != nil | ||
| 540 | ``` | ||
| 541 | <YueDisplay> | ||
| 542 | |||
| 543 | ```yue | ||
| 544 | tb\func! if tb ~= nil | ||
| 545 | tb::func! if tb != nil | ||
| 546 | ``` | ||
| 547 | |||
| 548 | </YueDisplay> | ||
| 549 | |||
| 550 | ### Chaining Comparisons | ||
| 551 | |||
| 552 | Comparisons can be arbitrarily chained: | ||
| 553 | |||
| 554 | ```yuescript | ||
| 555 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 556 | -- output: true | ||
| 557 | |||
| 558 | a = 5 | ||
| 559 | print 1 <= a <= 10 | ||
| 560 | -- output: true | ||
| 561 | ``` | ||
| 562 | <YueDisplay> | ||
| 563 | |||
| 564 | ```yue | ||
| 565 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 566 | -- output: true | ||
| 567 | |||
| 568 | a = 5 | ||
| 569 | print 1 <= a <= 10 | ||
| 570 | -- output: true | ||
| 571 | ``` | ||
| 572 | |||
| 573 | </YueDisplay> | ||
| 574 | |||
| 575 | Note the evaluation behavior of chained comparisons: | ||
| 576 | |||
| 577 | ```yuescript | ||
| 578 | v = (x) -> | ||
| 579 | print x | ||
| 580 | x | ||
| 581 | |||
| 582 | print v(1) < v(2) <= v(3) | ||
| 583 | --[[ | ||
| 584 | output: | ||
| 585 | 2 | ||
| 586 | 1 | ||
| 587 | 3 | ||
| 588 | true | ||
| 589 | ]] | ||
| 590 | |||
| 591 | print v(1) > v(2) <= v(3) | ||
| 592 | --[[ | ||
| 593 | output: | ||
| 594 | 2 | ||
| 595 | 1 | ||
| 596 | false | ||
| 597 | ]] | ||
| 598 | ``` | ||
| 599 | <YueDisplay> | ||
| 600 | |||
| 601 | ```yue | ||
| 602 | v = (x) -> | ||
| 603 | print x | ||
| 604 | x | ||
| 605 | |||
| 606 | print v(1) < v(2) <= v(3) | ||
| 607 | --[[ | ||
| 608 | output: | ||
| 609 | 2 | ||
| 610 | 1 | ||
| 611 | 3 | ||
| 612 | true | ||
| 613 | ]] | ||
| 614 | |||
| 615 | print v(1) > v(2) <= v(3) | ||
| 616 | --[[ | ||
| 617 | output: | ||
| 618 | 2 | ||
| 619 | 1 | ||
| 620 | false | ||
| 621 | ]] | ||
| 622 | ``` | ||
| 623 | |||
| 624 | </YueDisplay> | ||
| 625 | |||
| 626 | The 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. | ||
| 627 | |||
| 628 | ### Table Appending | ||
| 629 | The **[] =** operator is used to append values to tables. | ||
| 630 | |||
| 631 | ```yuescript | ||
| 632 | tab = [] | ||
| 633 | tab[] = "Value" | ||
| 634 | ``` | ||
| 635 | <YueDisplay> | ||
| 636 | |||
| 637 | ```yue | ||
| 638 | tab = [] | ||
| 639 | tab[] = "Value" | ||
| 640 | ``` | ||
| 641 | |||
| 642 | </YueDisplay> | ||
| 643 | |||
| 644 | You can also use the spread operator `...` to append all elements from one list to another: | ||
| 645 | |||
| 646 | ```yuescript | ||
| 647 | tbA = [1, 2, 3] | ||
| 648 | tbB = [4, 5, 6] | ||
| 649 | tbA[] = ...tbB | ||
| 650 | -- tbA is now [1, 2, 3, 4, 5, 6] | ||
| 651 | ``` | ||
| 652 | <YueDisplay> | ||
| 653 | |||
| 654 | ```yue | ||
| 655 | tbA = [1, 2, 3] | ||
| 656 | tbB = [4, 5, 6] | ||
| 657 | tbA[] = ...tbB | ||
| 658 | -- tbA is now [1, 2, 3, 4, 5, 6] | ||
| 659 | ``` | ||
| 660 | |||
| 661 | </YueDisplay> | ||
| 662 | |||
| 663 | ### Table Spreading | ||
| 664 | |||
| 665 | You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals. | ||
| 666 | |||
| 667 | ```yuescript | ||
| 668 | parts = | ||
| 669 | * "shoulders" | ||
| 670 | * "knees" | ||
| 671 | lyrics = | ||
| 672 | * "head" | ||
| 673 | * ...parts | ||
| 674 | * "and" | ||
| 675 | * "toes" | ||
| 676 | |||
| 677 | copy = {...other} | ||
| 678 | |||
| 679 | a = {1, 2, 3, x: 1} | ||
| 680 | b = {4, 5, y: 1} | ||
| 681 | merge = {...a, ...b} | ||
| 682 | ``` | ||
| 683 | <YueDisplay> | ||
| 684 | |||
| 685 | ```yue | ||
| 686 | parts = | ||
| 687 | * "shoulders" | ||
| 688 | * "knees" | ||
| 689 | lyrics = | ||
| 690 | * "head" | ||
| 691 | * ...parts | ||
| 692 | * "and" | ||
| 693 | * "toes" | ||
| 694 | |||
| 695 | copy = {...other} | ||
| 696 | |||
| 697 | a = {1, 2, 3, x: 1} | ||
| 698 | b = {4, 5, y: 1} | ||
| 699 | merge = {...a, ...b} | ||
| 700 | ``` | ||
| 701 | |||
| 702 | </YueDisplay> | ||
| 703 | |||
| 704 | ### Table Reversed Indexing | ||
| 705 | |||
| 706 | You can use the **#** operator to get the last elements of a table. | ||
| 707 | |||
| 708 | ```yuescript | ||
| 709 | last = data.items[#] | ||
| 710 | second_last = data.items[#-1] | ||
| 711 | data.items[#] = 1 | ||
| 712 | ``` | ||
| 713 | <YueDisplay> | ||
| 714 | |||
| 715 | ```yue | ||
| 716 | last = data.items[#] | ||
| 717 | second_last = data.items[#-1] | ||
| 718 | data.items[#] = 1 | ||
| 719 | ``` | ||
| 720 | |||
| 721 | </YueDisplay> | ||
| 722 | |||
| 723 | ### Metatable | ||
| 724 | |||
| 725 | The **<>** operator can be used as a shortcut for metatable manipulation. | ||
| 726 | |||
| 727 | * **Metatable Creation** | ||
| 728 | Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. | ||
| 729 | |||
| 730 | ```yuescript | ||
| 731 | mt = {} | ||
| 732 | add = (right) => <>: mt, value: @value + right.value | ||
| 733 | mt.__add = add | ||
| 734 | |||
| 735 | a = <>: mt, value: 1 | ||
| 736 | -- set field with variable of the same name | ||
| 737 | b = :<add>, value: 2 | ||
| 738 | c = <add>: mt.__add, value: 3 | ||
| 739 | |||
| 740 | d = a + b + c | ||
| 741 | print d.value | ||
| 742 | |||
| 743 | close _ = <close>: -> print "out of scope" | ||
| 744 | ``` | ||
| 745 | <YueDisplay> | ||
| 746 | |||
| 747 | ```yue | ||
| 748 | mt = {} | ||
| 749 | add = (right) => <>: mt, value: @value + right.value | ||
| 750 | mt.__add = add | ||
| 751 | |||
| 752 | a = <>: mt, value: 1 | ||
| 753 | -- set field with variable of the same name | ||
| 754 | b = :<add>, value: 2 | ||
| 755 | c = <add>: mt.__add, value: 3 | ||
| 756 | |||
| 757 | d = a + b + c | ||
| 758 | print d.value | ||
| 759 | |||
| 760 | close _ = <close>: -> print "out of scope" | ||
| 761 | ``` | ||
| 762 | |||
| 763 | </YueDisplay> | ||
| 764 | |||
| 765 | * **Metatable Accessing** | ||
| 766 | Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. | ||
| 767 | |||
| 768 | ```yuescript | ||
| 769 | -- create with metatable containing field "value" | ||
| 770 | tb = <"value">: 123 | ||
| 771 | tb.<index> = tb.<> | ||
| 772 | print tb.value | ||
| 773 | |||
| 774 | tb.<> = __index: {item: "hello"} | ||
| 775 | print tb.item | ||
| 776 | ``` | ||
| 777 | <YueDisplay> | ||
| 778 | |||
| 779 | ```yue | ||
| 780 | -- create with metatable containing field "value" | ||
| 781 | tb = <"value">: 123 | ||
| 782 | tb.<index> = tb.<> | ||
| 783 | print tb.value | ||
| 784 | tb.<> = __index: {item: "hello"} | ||
| 785 | print tb.item | ||
| 786 | ``` | ||
| 787 | |||
| 788 | </YueDisplay> | ||
| 789 | |||
| 790 | * **Metatable Destructure** | ||
| 791 | Destruct metatable with metamethod key surrounded by **<>**. | ||
| 792 | |||
| 793 | ```yuescript | ||
| 794 | {item, :new, :<close>, <index>: getter} = tb | ||
| 795 | print item, new, close, getter | ||
| 796 | ``` | ||
| 797 | <YueDisplay> | ||
| 798 | |||
| 799 | ```yue | ||
| 800 | {item, :new, :<close>, <index>: getter} = tb | ||
| 801 | print item, new, close, getter | ||
| 802 | ``` | ||
| 803 | |||
| 804 | </YueDisplay> | ||
| 805 | |||
| 806 | ### Existence | ||
| 807 | |||
| 808 | The **?** operator can be used in a variety of contexts to check for existence. | ||
| 809 | |||
| 810 | ```yuescript | ||
| 811 | func?! | ||
| 812 | print abc?["hello world"]?.xyz | ||
| 813 | |||
| 814 | x = tab?.value | ||
| 815 | len = utf8?.len or string?.len or (o) -> #o | ||
| 816 | |||
| 817 | if print and x? | ||
| 818 | print x | ||
| 819 | |||
| 820 | with? io.open "test.txt", "w" | ||
| 821 | \write "hello" | ||
| 822 | \close! | ||
| 823 | ``` | ||
| 824 | <YueDisplay> | ||
| 825 | |||
| 826 | ```yue | ||
| 827 | func?! | ||
| 828 | print abc?["hello world"]?.xyz | ||
| 829 | |||
| 830 | x = tab?.value | ||
| 831 | len = utf8?.len or string?.len or (o) -> #o | ||
| 832 | |||
| 833 | if print and x? | ||
| 834 | print x | ||
| 835 | |||
| 836 | with? io.open "test.txt", "w" | ||
| 837 | \write "hello" | ||
| 838 | \close! | ||
| 839 | ``` | ||
| 840 | |||
| 841 | </YueDisplay> | ||
| 842 | |||
| 843 | ### Piping | ||
| 844 | |||
| 845 | Instead of a series of nested function calls, you can pipe values with operator **|>**. | ||
| 846 | |||
| 847 | ```yuescript | ||
| 848 | "hello" |> print | ||
| 849 | 1 |> print 2 -- insert pipe item as the first argument | ||
| 850 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
| 851 | |||
| 852 | -- pipe expression in multiline | ||
| 853 | readFile "example.txt" | ||
| 854 | |> extract language, {} | ||
| 855 | |> parse language | ||
| 856 | |> emit | ||
| 857 | |> render | ||
| 858 | |||
| 859 | ``` | ||
| 860 | <YueDisplay> | ||
| 861 | |||
| 862 | ```yue | ||
| 863 | "hello" |> print | ||
| 864 | 1 |> print 2 -- insert pipe item as the first argument | ||
| 865 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
| 866 | -- pipe expression in multiline | ||
| 867 | readFile "example.txt" | ||
| 868 | |> extract language, {} | ||
| 869 | |> parse language | ||
| 870 | |> emit | ||
| 871 | |> render | ||
| 872 | |||
| 873 | ``` | ||
| 874 | |||
| 875 | </YueDisplay> | ||
| 876 | |||
| 877 | ### Nil Coalescing | ||
| 878 | |||
| 879 | The 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. | ||
| 880 | ```yuescript | ||
| 881 | local a, b, c, d | ||
| 882 | a = b ?? c ?? d | ||
| 883 | func a ?? {} | ||
| 884 | |||
| 885 | a ??= false | ||
| 886 | ``` | ||
| 887 | <YueDisplay> | ||
| 888 | |||
| 889 | ```yue | ||
| 890 | local a, b, c, d | ||
| 891 | a = b ?? c ?? d | ||
| 892 | func a ?? {} | ||
| 893 | a ??= false | ||
| 894 | ``` | ||
| 895 | |||
| 896 | </YueDisplay> | ||
| 897 | |||
| 898 | ### Implicit Object | ||
| 899 | |||
| 900 | You 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. | ||
| 901 | |||
| 902 | ```yuescript | ||
| 903 | -- assignment with implicit object | ||
| 904 | list = | ||
| 905 | * 1 | ||
| 906 | * 2 | ||
| 907 | * 3 | ||
| 908 | |||
| 909 | -- function call with implicit object | ||
| 910 | func | ||
| 911 | * 1 | ||
| 912 | * 2 | ||
| 913 | * 3 | ||
| 914 | |||
| 915 | -- return with implicit object | ||
| 916 | f = -> | ||
| 917 | return | ||
| 918 | * 1 | ||
| 919 | * 2 | ||
| 920 | * 3 | ||
| 921 | |||
| 922 | -- table with implicit object | ||
| 923 | tb = | ||
| 924 | name: "abc" | ||
| 925 | |||
| 926 | values: | ||
| 927 | - "a" | ||
| 928 | - "b" | ||
| 929 | - "c" | ||
| 930 | |||
| 931 | objects: | ||
| 932 | - name: "a" | ||
| 933 | value: 1 | ||
| 934 | func: => @value + 1 | ||
| 935 | tb: | ||
| 936 | fieldA: 1 | ||
| 937 | |||
| 938 | - name: "b" | ||
| 939 | value: 2 | ||
| 940 | func: => @value + 2 | ||
| 941 | tb: { } | ||
| 942 | |||
| 943 | ``` | ||
| 944 | <YueDisplay> | ||
| 945 | |||
| 946 | ```yue | ||
| 947 | -- assignment with implicit object | ||
| 948 | list = | ||
| 949 | * 1 | ||
| 950 | * 2 | ||
| 951 | * 3 | ||
| 952 | |||
| 953 | -- function call with implicit object | ||
| 954 | func | ||
| 955 | * 1 | ||
| 956 | * 2 | ||
| 957 | * 3 | ||
| 958 | |||
| 959 | -- return with implicit object | ||
| 960 | f = -> | ||
| 961 | return | ||
| 962 | * 1 | ||
| 963 | * 2 | ||
| 964 | * 3 | ||
| 965 | |||
| 966 | -- table with implicit object | ||
| 967 | tb = | ||
| 968 | name: "abc" | ||
| 969 | |||
| 970 | values: | ||
| 971 | - "a" | ||
| 972 | - "b" | ||
| 973 | - "c" | ||
| 974 | |||
| 975 | objects: | ||
| 976 | - name: "a" | ||
| 977 | value: 1 | ||
| 978 | func: => @value + 1 | ||
| 979 | tb: | ||
| 980 | fieldA: 1 | ||
| 981 | |||
| 982 | - name: "b" | ||
| 983 | value: 2 | ||
| 984 | func: => @value + 2 | ||
| 985 | tb: { } | ||
| 986 | ``` | ||
| 987 | |||
| 988 | </YueDisplay> | ||
| 989 | |||
| 990 | ## Module | ||
| 991 | |||
| 992 | ### Import | ||
| 993 | |||
| 994 | The 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. | ||
| 995 | |||
| 996 | ```yuescript | ||
| 997 | -- used as table destructuring | ||
| 998 | do | ||
| 999 | import insert, concat from table | ||
| 1000 | -- report error when assigning to insert, concat | ||
| 1001 | import C, Ct, Cmt from require "lpeg" | ||
| 1002 | -- shortcut for implicit requiring | ||
| 1003 | import x, y, z from 'mymodule' | ||
| 1004 | -- import with Python style | ||
| 1005 | from 'module' import a, b, c | ||
| 1006 | |||
| 1007 | -- shortcut for requring a module | ||
| 1008 | do | ||
| 1009 | import 'module' | ||
| 1010 | import 'module_x' | ||
| 1011 | import "d-a-s-h-e-s" | ||
| 1012 | import "module.part" | ||
| 1013 | |||
| 1014 | -- requring module with aliasing or table destructuring | ||
| 1015 | do | ||
| 1016 | import "player" as PlayerModule | ||
| 1017 | import "lpeg" as :C, :Ct, :Cmt | ||
| 1018 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 1019 | ``` | ||
| 1020 | <YueDisplay> | ||
| 1021 | |||
| 1022 | ```yue | ||
| 1023 | -- used as table destructuring | ||
| 1024 | do | ||
| 1025 | import insert, concat from table | ||
| 1026 | -- report error when assigning to insert, concat | ||
| 1027 | import C, Ct, Cmt from require "lpeg" | ||
| 1028 | -- shortcut for implicit requiring | ||
| 1029 | import x, y, z from 'mymodule' | ||
| 1030 | -- import with Python style | ||
| 1031 | from 'module' import a, b, c | ||
| 1032 | |||
| 1033 | -- shortcut for requring a module | ||
| 1034 | do | ||
| 1035 | import 'module' | ||
| 1036 | import 'module_x' | ||
| 1037 | import "d-a-s-h-e-s" | ||
| 1038 | import "module.part" | ||
| 1039 | |||
| 1040 | -- requring module with aliasing or table destructuring | ||
| 1041 | do | ||
| 1042 | import "player" as PlayerModule | ||
| 1043 | import "lpeg" as :C, :Ct, :Cmt | ||
| 1044 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 1045 | ``` | ||
| 1046 | |||
| 1047 | </YueDisplay> | ||
| 1048 | |||
| 1049 | ### Import Global | ||
| 1050 | |||
| 1051 | You 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. | ||
| 1052 | |||
| 1053 | ```yuescript | ||
| 1054 | do | ||
| 1055 | import tostring | ||
| 1056 | import table.concat | ||
| 1057 | print concat ["a", tostring 1] | ||
| 1058 | ``` | ||
| 1059 | <YueDisplay> | ||
| 1060 | |||
| 1061 | ```yue | ||
| 1062 | do | ||
| 1063 | import tostring | ||
| 1064 | import table.concat | ||
| 1065 | print concat ["a", tostring 1] | ||
| 1066 | ``` | ||
| 1067 | |||
| 1068 | </YueDisplay> | ||
| 1069 | |||
| 1070 | #### Automatic Import | ||
| 1071 | |||
| 1072 | You 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. | ||
| 1073 | |||
| 1074 | Names that are explicitly declared as globals in the same scope will not be imported, so you can still assign to them. | ||
| 1075 | |||
| 1076 | ```yuescript | ||
| 1077 | do | ||
| 1078 | import global | ||
| 1079 | print "hello" | ||
| 1080 | math.random 3 | ||
| 1081 | -- print = nil -- error: imported globals are const | ||
| 1082 | |||
| 1083 | do | ||
| 1084 | -- explicit global variable will not be imported | ||
| 1085 | import global | ||
| 1086 | global FLAG | ||
| 1087 | print FLAG | ||
| 1088 | FLAG = 123 | ||
| 1089 | ``` | ||
| 1090 | <YueDisplay> | ||
| 1091 | |||
| 1092 | ```yue | ||
| 1093 | do | ||
| 1094 | import global | ||
| 1095 | print "hello" | ||
| 1096 | math.random 3 | ||
| 1097 | -- print = nil -- error: imported globals are const | ||
| 1098 | |||
| 1099 | do | ||
| 1100 | -- explicit global variable will not be imported | ||
| 1101 | import global | ||
| 1102 | global FLAG | ||
| 1103 | print FLAG | ||
| 1104 | FLAG = 123 | ||
| 1105 | ``` | ||
| 1106 | |||
| 1107 | </YueDisplay> | ||
| 1108 | |||
| 1109 | ### Export | ||
| 1110 | |||
| 1111 | The export statement offers a concise way to define modules. | ||
| 1112 | |||
| 1113 | * **Named Export** | ||
| 1114 | Named export will define a local variable as well as adding a field in the exported table. | ||
| 1115 | |||
| 1116 | ```yuescript | ||
| 1117 | export a, b, c = 1, 2, 3 | ||
| 1118 | export cool = "cat" | ||
| 1119 | |||
| 1120 | export What = if this | ||
| 1121 | "abc" | ||
| 1122 | else | ||
| 1123 | "def" | ||
| 1124 | |||
| 1125 | export y = -> | ||
| 1126 | hallo = 3434 | ||
| 1127 | |||
| 1128 | export class Something | ||
| 1129 | umm: "cool" | ||
| 1130 | ``` | ||
| 1131 | <YueDisplay> | ||
| 1132 | |||
| 1133 | ```yue | ||
| 1134 | export a, b, c = 1, 2, 3 | ||
| 1135 | export cool = "cat" | ||
| 1136 | |||
| 1137 | export What = if this | ||
| 1138 | "abc" | ||
| 1139 | else | ||
| 1140 | "def" | ||
| 1141 | |||
| 1142 | export y = -> | ||
| 1143 | hallo = 3434 | ||
| 1144 | |||
| 1145 | export class Something | ||
| 1146 | umm: "cool" | ||
| 1147 | ``` | ||
| 1148 | |||
| 1149 | </YueDisplay> | ||
| 1150 | |||
| 1151 | Doing named export with destructuring. | ||
| 1152 | |||
| 1153 | ```yuescript | ||
| 1154 | export :loadstring, to_lua: tolua = yue | ||
| 1155 | export {itemA: {:fieldA = 'default'}} = tb | ||
| 1156 | ``` | ||
| 1157 | <YueDisplay> | ||
| 1158 | |||
| 1159 | ```yue | ||
| 1160 | export :loadstring, to_lua: tolua = yue | ||
| 1161 | export {itemA: {:fieldA = 'default'}} = tb | ||
| 1162 | ``` | ||
| 1163 | |||
| 1164 | </YueDisplay> | ||
| 1165 | |||
| 1166 | Export named items from module without creating local variables. | ||
| 1167 | |||
| 1168 | ```yuescript | ||
| 1169 | export.itemA = tb | ||
| 1170 | export.<index> = items | ||
| 1171 | export["a-b-c"] = 123 | ||
| 1172 | ``` | ||
| 1173 | <YueDisplay> | ||
| 1174 | |||
| 1175 | ```yue | ||
| 1176 | export.itemA = tb | ||
| 1177 | export.<index> = items | ||
| 1178 | export["a-b-c"] = 123 | ||
| 1179 | ``` | ||
| 1180 | |||
| 1181 | </YueDisplay> | ||
| 1182 | |||
| 1183 | * **Unnamed Export** | ||
| 1184 | Unnamed export will add the target item into the array part of the exported table. | ||
| 1185 | |||
| 1186 | ```yuescript | ||
| 1187 | d, e, f = 3, 2, 1 | ||
| 1188 | export d, e, f | ||
| 1189 | |||
| 1190 | export if this | ||
| 1191 | 123 | ||
| 1192 | else | ||
| 1193 | 456 | ||
| 1194 | |||
| 1195 | export with tmp | ||
| 1196 | j = 2000 | ||
| 1197 | ``` | ||
| 1198 | <YueDisplay> | ||
| 1199 | |||
| 1200 | ```yue | ||
| 1201 | d, e, f = 3, 2, 1 | ||
| 1202 | export d, e, f | ||
| 1203 | |||
| 1204 | export if this | ||
| 1205 | 123 | ||
| 1206 | else | ||
| 1207 | 456 | ||
| 1208 | |||
| 1209 | export with tmp | ||
| 1210 | j = 2000 | ||
| 1211 | ``` | ||
| 1212 | |||
| 1213 | </YueDisplay> | ||
| 1214 | |||
| 1215 | * **Default Export** | ||
| 1216 | Using the **default** keyword in export statement to replace the exported table with any thing. | ||
| 1217 | |||
| 1218 | ```yuescript | ||
| 1219 | export default -> | ||
| 1220 | print "hello" | ||
| 1221 | 123 | ||
| 1222 | ``` | ||
| 1223 | <YueDisplay> | ||
| 1224 | |||
| 1225 | ```yue | ||
| 1226 | export default -> | ||
| 1227 | print "hello" | ||
| 1228 | 123 | ||
| 1229 | ``` | ||
| 1230 | |||
| 1231 | </YueDisplay> | ||
| 1232 | |||
| 1233 | ## Assignment | ||
| 1234 | |||
| 1235 | The variable is dynamic typed and is defined as local by default. But you can change the scope of declaration by **local** and **global** statement. | ||
| 1236 | |||
| 1237 | ```yuescript | ||
| 1238 | hello = "world" | ||
| 1239 | a, b, c = 1, 2, 3 | ||
| 1240 | hello = 123 -- uses the existing variable | ||
| 1241 | ``` | ||
| 1242 | <YueDisplay> | ||
| 1243 | |||
| 1244 | ```yue | ||
| 1245 | hello = "world" | ||
| 1246 | a, b, c = 1, 2, 3 | ||
| 1247 | hello = 123 -- uses the existing variable | ||
| 1248 | ``` | ||
| 1249 | |||
| 1250 | </YueDisplay> | ||
| 1251 | |||
| 1252 | ### Perform Update | ||
| 1253 | |||
| 1254 | You can perform update assignment with many binary operators. | ||
| 1255 | ```yuescript | ||
| 1256 | x = 1 | ||
| 1257 | x += 1 | ||
| 1258 | x -= 1 | ||
| 1259 | x *= 10 | ||
| 1260 | x /= 10 | ||
| 1261 | x %= 10 | ||
| 1262 | s ..= "world" -- will add a new local if local variable is not exist | ||
| 1263 | arg or= "default value" | ||
| 1264 | ``` | ||
| 1265 | <YueDisplay> | ||
| 1266 | |||
| 1267 | ```yue | ||
| 1268 | x = 1 | ||
| 1269 | x += 1 | ||
| 1270 | x -= 1 | ||
| 1271 | x *= 10 | ||
| 1272 | x /= 10 | ||
| 1273 | x %= 10 | ||
| 1274 | s ..= "world" -- will add a new local if local variable is not exist | ||
| 1275 | arg or= "default value" | ||
| 1276 | ``` | ||
| 1277 | |||
| 1278 | </YueDisplay> | ||
| 1279 | |||
| 1280 | ### Chaining Assignment | ||
| 1281 | |||
| 1282 | You can do chaining assignment to assign multiple items to hold the same value. | ||
| 1283 | ```yuescript | ||
| 1284 | a = b = c = d = e = 0 | ||
| 1285 | x = y = z = f! | ||
| 1286 | ``` | ||
| 1287 | <YueDisplay> | ||
| 1288 | |||
| 1289 | ```yue | ||
| 1290 | a = b = c = d = e = 0 | ||
| 1291 | x = y = z = f! | ||
| 1292 | ``` | ||
| 1293 | |||
| 1294 | </YueDisplay> | ||
| 1295 | |||
| 1296 | ### Explicit Locals | ||
| 1297 | ```yuescript | ||
| 1298 | do | ||
| 1299 | local a = 1 | ||
| 1300 | local * | ||
| 1301 | print "forward declare all variables as locals" | ||
| 1302 | x = -> 1 + y + z | ||
| 1303 | y, z = 2, 3 | ||
| 1304 | global instance = Item\new! | ||
| 1305 | |||
| 1306 | do | ||
| 1307 | local X = 1 | ||
| 1308 | local ^ | ||
| 1309 | print "only forward declare upper case variables" | ||
| 1310 | a = 1 | ||
| 1311 | B = 2 | ||
| 1312 | ``` | ||
| 1313 | <YueDisplay> | ||
| 1314 | |||
| 1315 | ```yue | ||
| 1316 | do | ||
| 1317 | local a = 1 | ||
| 1318 | local * | ||
| 1319 | print "forward declare all variables as locals" | ||
| 1320 | x = -> 1 + y + z | ||
| 1321 | y, z = 2, 3 | ||
| 1322 | global instance = Item\new! | ||
| 1323 | |||
| 1324 | do | ||
| 1325 | local X = 1 | ||
| 1326 | local ^ | ||
| 1327 | print "only forward declare upper case variables" | ||
| 1328 | a = 1 | ||
| 1329 | B = 2 | ||
| 1330 | ``` | ||
| 1331 | |||
| 1332 | </YueDisplay> | ||
| 1333 | |||
| 1334 | ### Explicit Globals | ||
| 1335 | ```yuescript | ||
| 1336 | do | ||
| 1337 | global a = 1 | ||
| 1338 | global * | ||
| 1339 | print "declare all variables as globals" | ||
| 1340 | x = -> 1 + y + z | ||
| 1341 | y, z = 2, 3 | ||
| 1342 | |||
| 1343 | do | ||
| 1344 | global X = 1 | ||
| 1345 | global ^ | ||
| 1346 | print "only declare upper case variables as globals" | ||
| 1347 | a = 1 | ||
| 1348 | B = 2 | ||
| 1349 | local Temp = "a local value" | ||
| 1350 | ``` | ||
| 1351 | <YueDisplay> | ||
| 1352 | |||
| 1353 | ```yue | ||
| 1354 | do | ||
| 1355 | global a = 1 | ||
| 1356 | global * | ||
| 1357 | print "declare all variables as globals" | ||
| 1358 | x = -> 1 + y + z | ||
| 1359 | y, z = 2, 3 | ||
| 1360 | |||
| 1361 | do | ||
| 1362 | global X = 1 | ||
| 1363 | global ^ | ||
| 1364 | print "only declare upper case variables as globals" | ||
| 1365 | a = 1 | ||
| 1366 | B = 2 | ||
| 1367 | local Temp = "a local value" | ||
| 1368 | ``` | ||
| 1369 | |||
| 1370 | </YueDisplay> | ||
| 1371 | |||
| 1372 | ## Destructuring Assignment | ||
| 1373 | |||
| 1374 | Destructuring assignment is a way to quickly extract values from a table by their name or position in array based tables. | ||
| 1375 | |||
| 1376 | Typically 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. | ||
| 1377 | |||
| 1378 | This is best explained with examples. Here is how you would unpack the first two values from a table: | ||
| 1379 | |||
| 1380 | ```yuescript | ||
| 1381 | thing = [1, 2] | ||
| 1382 | |||
| 1383 | [a, b] = thing | ||
| 1384 | print a, b | ||
| 1385 | ``` | ||
| 1386 | <YueDisplay> | ||
| 1387 | |||
| 1388 | ```yue | ||
| 1389 | thing = [1, 2] | ||
| 1390 | |||
| 1391 | [a, b] = thing | ||
| 1392 | print a, b | ||
| 1393 | ``` | ||
| 1394 | |||
| 1395 | </YueDisplay> | ||
| 1396 | |||
| 1397 | In 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. | ||
| 1398 | |||
| 1399 | ```yuescript | ||
| 1400 | obj = { | ||
| 1401 | hello: "world" | ||
| 1402 | day: "tuesday" | ||
| 1403 | length: 20 | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | {hello: hello, day: the_day} = obj | ||
| 1407 | print hello, the_day | ||
| 1408 | |||
| 1409 | :day = obj -- OK to do simple destructuring without braces | ||
| 1410 | ``` | ||
| 1411 | <YueDisplay> | ||
| 1412 | |||
| 1413 | ```yue | ||
| 1414 | obj = { | ||
| 1415 | hello: "world" | ||
| 1416 | day: "tuesday" | ||
| 1417 | length: 20 | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | {hello: hello, day: the_day} = obj | ||
| 1421 | print hello, the_day | ||
| 1422 | |||
| 1423 | :day = obj -- OK to do simple destructuring without braces | ||
| 1424 | ``` | ||
| 1425 | |||
| 1426 | </YueDisplay> | ||
| 1427 | |||
| 1428 | This also works with nested data structures as well: | ||
| 1429 | |||
| 1430 | ```yuescript | ||
| 1431 | obj2 = { | ||
| 1432 | numbers: [1, 2, 3, 4] | ||
| 1433 | properties: { | ||
| 1434 | color: "green" | ||
| 1435 | height: 13.5 | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | {numbers: [first, second], properties: {color: color}} = obj2 | ||
| 1440 | print first, second, color | ||
| 1441 | ``` | ||
| 1442 | <YueDisplay> | ||
| 1443 | |||
| 1444 | ```yue | ||
| 1445 | obj2 = { | ||
| 1446 | numbers: [1, 2, 3, 4] | ||
| 1447 | properties: { | ||
| 1448 | color: "green" | ||
| 1449 | height: 13.5 | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | {numbers: [first, second]} = obj2 | ||
| 1454 | print first, second, color | ||
| 1455 | ``` | ||
| 1456 | |||
| 1457 | </YueDisplay> | ||
| 1458 | |||
| 1459 | If the destructuring statement is complicated, feel free to spread it out over a few lines. A slightly more complicated example: | ||
| 1460 | |||
| 1461 | ```yuescript | ||
| 1462 | { | ||
| 1463 | numbers: [first, second] | ||
| 1464 | properties: { | ||
| 1465 | color: color | ||
| 1466 | } | ||
| 1467 | } = obj2 | ||
| 1468 | ``` | ||
| 1469 | <YueDisplay> | ||
| 1470 | |||
| 1471 | ```yue | ||
| 1472 | { | ||
| 1473 | numbers: [first, second] | ||
| 1474 | properties: { | ||
| 1475 | color: color | ||
| 1476 | } | ||
| 1477 | } = obj2 | ||
| 1478 | ``` | ||
| 1479 | |||
| 1480 | </YueDisplay> | ||
| 1481 | |||
| 1482 | It'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: | ||
| 1483 | |||
| 1484 | ```yuescript | ||
| 1485 | {:concat, :insert} = table | ||
| 1486 | ``` | ||
| 1487 | <YueDisplay> | ||
| 1488 | |||
| 1489 | ```yue | ||
| 1490 | {:concat, :insert} = table | ||
| 1491 | ``` | ||
| 1492 | |||
| 1493 | </YueDisplay> | ||
| 1494 | |||
| 1495 | This is effectively the same as import, but we can rename fields we want to extract by mixing the syntax: | ||
| 1496 | |||
| 1497 | ```yuescript | ||
| 1498 | {:mix, :max, random: rand} = math | ||
| 1499 | ``` | ||
| 1500 | <YueDisplay> | ||
| 1501 | |||
| 1502 | ```yue | ||
| 1503 | {:mix, :max, random: rand} = math | ||
| 1504 | ``` | ||
| 1505 | |||
| 1506 | </YueDisplay> | ||
| 1507 | |||
| 1508 | You can write default values while doing destructuring like: | ||
| 1509 | |||
| 1510 | ```yuescript | ||
| 1511 | {:name = "nameless", :job = "jobless"} = person | ||
| 1512 | ``` | ||
| 1513 | <YueDisplay> | ||
| 1514 | |||
| 1515 | ```yue | ||
| 1516 | {:name = "nameless", :job = "jobless"} = person | ||
| 1517 | ``` | ||
| 1518 | |||
| 1519 | </YueDisplay> | ||
| 1520 | |||
| 1521 | You can use `_` as placeholder when doing a list destructuring: | ||
| 1522 | |||
| 1523 | ```yuescript | ||
| 1524 | [_, two, _, four] = items | ||
| 1525 | ``` | ||
| 1526 | <YueDisplay> | ||
| 1527 | |||
| 1528 | ```yue | ||
| 1529 | [_, two, _, four] = items | ||
| 1530 | ``` | ||
| 1531 | |||
| 1532 | </YueDisplay> | ||
| 1533 | |||
| 1534 | ### Range Destructuring | ||
| 1535 | |||
| 1536 | You 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. | ||
| 1537 | |||
| 1538 | ```yuescript | ||
| 1539 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 1540 | [first, ...bulk, last] = orders | ||
| 1541 | print first -- prints: first | ||
| 1542 | print bulk -- prints: {"second", "third", "fourth"} | ||
| 1543 | print last -- prints: last | ||
| 1544 | ``` | ||
| 1545 | <YueDisplay> | ||
| 1546 | |||
| 1547 | ```yue | ||
| 1548 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 1549 | [first, ...bulk, last] = orders | ||
| 1550 | print first -- prints: first | ||
| 1551 | print bulk -- prints: {"second", "third", "fourth"} | ||
| 1552 | print last -- prints: last | ||
| 1553 | ``` | ||
| 1554 | |||
| 1555 | </YueDisplay> | ||
| 1556 | |||
| 1557 | The 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: | ||
| 1558 | |||
| 1559 | ```yuescript | ||
| 1560 | -- Capture everything after first element | ||
| 1561 | [first, ...rest] = orders | ||
| 1562 | |||
| 1563 | -- Capture everything before last element | ||
| 1564 | [...start, last] = orders | ||
| 1565 | |||
| 1566 | -- Capture things except the middle elements | ||
| 1567 | [first, ..._, last] = orders | ||
| 1568 | ``` | ||
| 1569 | <YueDisplay> | ||
| 1570 | |||
| 1571 | ```yue | ||
| 1572 | -- Capture everything after first element | ||
| 1573 | [first, ...rest] = orders | ||
| 1574 | |||
| 1575 | -- Capture everything before last element | ||
| 1576 | [...start, last] = orders | ||
| 1577 | |||
| 1578 | -- Capture things except the middle elements | ||
| 1579 | [first, ..._, last] = orders | ||
| 1580 | ``` | ||
| 1581 | |||
| 1582 | </YueDisplay> | ||
| 1583 | |||
| 1584 | ### Destructuring In Other Places | ||
| 1585 | |||
| 1586 | Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: | ||
| 1587 | |||
| 1588 | ```yuescript | ||
| 1589 | tuples = [ | ||
| 1590 | ["hello", "world"] | ||
| 1591 | ["egg", "head"] | ||
| 1592 | ] | ||
| 1593 | |||
| 1594 | for [left, right] in *tuples | ||
| 1595 | print left, right | ||
| 1596 | ``` | ||
| 1597 | <YueDisplay> | ||
| 1598 | |||
| 1599 | ```yue | ||
| 1600 | tuples = [ | ||
| 1601 | ["hello", "world"] | ||
| 1602 | ["egg", "head"] | ||
| 1603 | ] | ||
| 1604 | |||
| 1605 | for [left, right] in *tuples | ||
| 1606 | print left, right | ||
| 1607 | ``` | ||
| 1608 | |||
| 1609 | </YueDisplay> | ||
| 1610 | |||
| 1611 | We 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. | ||
| 1612 | |||
| 1613 | ## If Assignment | ||
| 1614 | |||
| 1615 | `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. | ||
| 1616 | |||
| 1617 | ```yuescript | ||
| 1618 | if user := database.find_user "moon" | ||
| 1619 | print user.name | ||
| 1620 | ``` | ||
| 1621 | <YueDisplay> | ||
| 1622 | |||
| 1623 | ```yue | ||
| 1624 | if user := database.find_user "moon" | ||
| 1625 | print user.name | ||
| 1626 | ``` | ||
| 1627 | |||
| 1628 | </YueDisplay> | ||
| 1629 | |||
| 1630 | ```yuescript | ||
| 1631 | if hello := os.getenv "hello" | ||
| 1632 | print "You have hello", hello | ||
| 1633 | elseif world := os.getenv "world" | ||
| 1634 | print "you have world", world | ||
| 1635 | else | ||
| 1636 | print "nothing :(" | ||
| 1637 | ``` | ||
| 1638 | <YueDisplay> | ||
| 1639 | |||
| 1640 | ```yue | ||
| 1641 | if hello := os.getenv "hello" | ||
| 1642 | print "You have hello", hello | ||
| 1643 | elseif world := os.getenv "world" | ||
| 1644 | print "you have world", world | ||
| 1645 | else | ||
| 1646 | print "nothing :(" | ||
| 1647 | ``` | ||
| 1648 | |||
| 1649 | </YueDisplay> | ||
| 1650 | |||
| 1651 | If assignment with multiple return values. Only the first value is getting checked, other values are scoped. | ||
| 1652 | ```yuescript | ||
| 1653 | if success, result := pcall -> "get result without problems" | ||
| 1654 | print result -- variable result is scoped | ||
| 1655 | print "OK" | ||
| 1656 | ``` | ||
| 1657 | <YueDisplay> | ||
| 1658 | |||
| 1659 | ```yue | ||
| 1660 | if success, result := pcall -> "get result without problems" | ||
| 1661 | print result -- variable result is scoped | ||
| 1662 | print "OK" | ||
| 1663 | ``` | ||
| 1664 | |||
| 1665 | </YueDisplay> | ||
| 1666 | |||
| 1667 | ### While Assignment | ||
| 1668 | |||
| 1669 | You can also use if assignment in a while loop to get the value as the loop condition. | ||
| 1670 | ```yuescript | ||
| 1671 | while byte := stream\read_one! | ||
| 1672 | -- do something with the byte | ||
| 1673 | print byte | ||
| 1674 | ``` | ||
| 1675 | <YueDisplay> | ||
| 1676 | |||
| 1677 | ```yue | ||
| 1678 | while byte := stream\read_one! | ||
| 1679 | -- do something with the byte | ||
| 1680 | print byte | ||
| 1681 | ``` | ||
| 1682 | |||
| 1683 | </YueDisplay> | ||
| 1684 | |||
| 1685 | ## Varargs Assignment | ||
| 1686 | |||
| 1687 | You can assign the results returned from a function to a varargs symbol `...`. And then access its content using the Lua way. | ||
| 1688 | ```yuescript | ||
| 1689 | list = [1, 2, 3, 4, 5] | ||
| 1690 | fn = (ok) -> ok, table.unpack list | ||
| 1691 | ok, ... = fn true | ||
| 1692 | count = select '#', ... | ||
| 1693 | first = select 1, ... | ||
| 1694 | print ok, count, first | ||
| 1695 | ``` | ||
| 1696 | <YueDisplay> | ||
| 1697 | |||
| 1698 | ```yue | ||
| 1699 | list = [1, 2, 3, 4, 5] | ||
| 1700 | fn = (ok) -> ok, table.unpack list | ||
| 1701 | ok, ... = fn true | ||
| 1702 | count = select '#', ... | ||
| 1703 | first = select 1, ... | ||
| 1704 | print ok, count, first | ||
| 1705 | ``` | ||
| 1706 | |||
| 1707 | </YueDisplay> | ||
| 1708 | |||
| 1709 | ## Whitespace | ||
| 1710 | |||
| 1711 | YueScript 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. | ||
| 1712 | |||
| 1713 | ### Statement Separator | ||
| 1714 | |||
| 1715 | A 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: | ||
| 1716 | |||
| 1717 | ```yuescript | ||
| 1718 | a = 1; b = 2; print a + b | ||
| 1719 | ``` | ||
| 1720 | <YueDisplay> | ||
| 1721 | |||
| 1722 | ```yue | ||
| 1723 | a = 1; b = 2; print a + b | ||
| 1724 | ``` | ||
| 1725 | |||
| 1726 | </YueDisplay> | ||
| 1727 | |||
| 1728 | ### Multiline Chaining | ||
| 1729 | |||
| 1730 | You can write multi-line chaining function calls with a same indent. | ||
| 1731 | ```yuescript | ||
| 1732 | Rx.Observable | ||
| 1733 | .fromRange 1, 8 | ||
| 1734 | \filter (x) -> x % 2 == 0 | ||
| 1735 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 1736 | \map (value) -> value .. '!' | ||
| 1737 | \subscribe print | ||
| 1738 | ``` | ||
| 1739 | <YueDisplay> | ||
| 1740 | |||
| 1741 | ```yue | ||
| 1742 | Rx.Observable | ||
| 1743 | .fromRange 1, 8 | ||
| 1744 | \filter (x) -> x % 2 == 0 | ||
| 1745 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 1746 | \map (value) -> value .. '!' | ||
| 1747 | \subscribe print | ||
| 1748 | ``` | ||
| 1749 | |||
| 1750 | </YueDisplay> | ||
| 1751 | |||
| 1752 | ## Comment | ||
| 1753 | |||
| 1754 | ```yuescript | ||
| 1755 | -- I am a comment | ||
| 1756 | |||
| 1757 | str = --[[ | ||
| 1758 | This is a multi-line comment. | ||
| 1759 | It's OK. | ||
| 1760 | ]] strA \ -- comment 1 | ||
| 1761 | .. strB \ -- comment 2 | ||
| 1762 | .. strC | ||
| 1763 | |||
| 1764 | func --[[port]] 3000, --[[ip]] "192.168.1.1" | ||
| 1765 | ``` | ||
| 1766 | <YueDisplay> | ||
| 1767 | |||
| 1768 | ```yue | ||
| 1769 | -- I am a comment | ||
| 1770 | |||
| 1771 | str = --[[ | ||
| 1772 | This is a multi-line comment. | ||
| 1773 | It's OK. | ||
| 1774 | ]] strA \ -- comment 1 | ||
| 1775 | .. strB \ -- comment 2 | ||
| 1776 | .. strC | ||
| 1777 | |||
| 1778 | func --[[port]] 3000, --[[ip]] "192.168.1.1" | ||
| 1779 | ``` | ||
| 1780 | |||
| 1781 | </YueDisplay> | ||
| 1782 | |||
| 1783 | ## Try | ||
| 1784 | |||
| 1785 | The syntax for Lua error handling in a common form. | ||
| 1786 | |||
| 1787 | ```yuescript | ||
| 1788 | try | ||
| 1789 | func 1, 2, 3 | ||
| 1790 | catch err | ||
| 1791 | print yue.traceback err | ||
| 1792 | |||
| 1793 | success, result = try | ||
| 1794 | func 1, 2, 3 | ||
| 1795 | catch err | ||
| 1796 | yue.traceback err | ||
| 1797 | |||
| 1798 | try func 1, 2, 3 | ||
| 1799 | catch err | ||
| 1800 | print yue.traceback err | ||
| 1801 | |||
| 1802 | success, result = try func 1, 2, 3 | ||
| 1803 | |||
| 1804 | try | ||
| 1805 | print "trying" | ||
| 1806 | func 1, 2, 3 | ||
| 1807 | |||
| 1808 | -- working with if assignment pattern | ||
| 1809 | if success, result := try func 1, 2, 3 | ||
| 1810 | catch err | ||
| 1811 | print yue.traceback err | ||
| 1812 | print result | ||
| 1813 | ``` | ||
| 1814 | <YueDisplay> | ||
| 1815 | |||
| 1816 | ```yue | ||
| 1817 | try | ||
| 1818 | func 1, 2, 3 | ||
| 1819 | catch err | ||
| 1820 | print yue.traceback err | ||
| 1821 | |||
| 1822 | success, result = try | ||
| 1823 | func 1, 2, 3 | ||
| 1824 | catch err | ||
| 1825 | yue.traceback err | ||
| 1826 | |||
| 1827 | try func 1, 2, 3 | ||
| 1828 | catch err | ||
| 1829 | print yue.traceback err | ||
| 1830 | |||
| 1831 | success, result = try func 1, 2, 3 | ||
| 1832 | |||
| 1833 | try | ||
| 1834 | print "trying" | ||
| 1835 | func 1, 2, 3 | ||
| 1836 | |||
| 1837 | -- working with if assignment pattern | ||
| 1838 | if success, result := try func 1, 2, 3 | ||
| 1839 | catch err | ||
| 1840 | print yue.traceback err | ||
| 1841 | print result | ||
| 1842 | ``` | ||
| 1843 | |||
| 1844 | </YueDisplay> | ||
| 1845 | |||
| 1846 | ### Try? | ||
| 1847 | |||
| 1848 | `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. | ||
| 1849 | |||
| 1850 | ```yuescript | ||
| 1851 | a, b, c = try? func! | ||
| 1852 | |||
| 1853 | -- with nil coalescing operator | ||
| 1854 | a = (try? func!) ?? "default" | ||
| 1855 | |||
| 1856 | -- as function argument | ||
| 1857 | f try? func! | ||
| 1858 | |||
| 1859 | -- with catch block | ||
| 1860 | f try? | ||
| 1861 | print 123 | ||
| 1862 | func! | ||
| 1863 | catch e | ||
| 1864 | print e | ||
| 1865 | e | ||
| 1866 | ``` | ||
| 1867 | <YueDisplay> | ||
| 1868 | |||
| 1869 | ```yue | ||
| 1870 | a, b, c = try? func! | ||
| 1871 | |||
| 1872 | -- with nil coalescing operator | ||
| 1873 | a = (try? func!) ?? "default" | ||
| 1874 | |||
| 1875 | -- as function argument | ||
| 1876 | f try? func! | ||
| 1877 | |||
| 1878 | -- with catch block | ||
| 1879 | f try? | ||
| 1880 | print 123 | ||
| 1881 | func! | ||
| 1882 | catch e | ||
| 1883 | print e | ||
| 1884 | e | ||
| 1885 | ``` | ||
| 1886 | |||
| 1887 | </YueDisplay> | ||
| 1888 | |||
| 1889 | ## Attributes | ||
| 1890 | |||
| 1891 | Syntax 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. | ||
| 1892 | |||
| 1893 | ```yuescript | ||
| 1894 | const a = 123 | ||
| 1895 | close _ = <close>: -> print "Out of scope." | ||
| 1896 | ``` | ||
| 1897 | <YueDisplay> | ||
| 1898 | |||
| 1899 | ```yue | ||
| 1900 | const a = 123 | ||
| 1901 | close _ = <close>: -> print "Out of scope." | ||
| 1902 | ``` | ||
| 1903 | |||
| 1904 | </YueDisplay> | ||
| 1905 | |||
| 1906 | You can do desctructuring with variables attributed as constant. | ||
| 1907 | |||
| 1908 | ```yuescript | ||
| 1909 | const {:a, :b, c, d} = tb | ||
| 1910 | -- a = 1 | ||
| 1911 | ``` | ||
| 1912 | <YueDisplay> | ||
| 1913 | |||
| 1914 | ```yue | ||
| 1915 | const {:a, :b, c, d} = tb | ||
| 1916 | -- a = 1 | ||
| 1917 | ``` | ||
| 1918 | |||
| 1919 | </YueDisplay> | ||
| 1920 | |||
| 1921 | You can also declare a global variable to be `const`. | ||
| 1922 | |||
| 1923 | ```yuescript | ||
| 1924 | global const Constant = 123 | ||
| 1925 | -- Constant = 1 | ||
| 1926 | ``` | ||
| 1927 | <YueDisplay> | ||
| 1928 | |||
| 1929 | ```yue | ||
| 1930 | global const Constant = 123 | ||
| 1931 | -- Constant = 1 | ||
| 1932 | ``` | ||
| 1933 | |||
| 1934 | </YueDisplay> | ||
| 1935 | |||
| 1936 | ## Literals | ||
| 1937 | |||
| 1938 | All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. | ||
| 1939 | |||
| 1940 | Unlike Lua, Line breaks are allowed inside of single and double quote strings without an escape sequence: | ||
| 1941 | |||
| 1942 | ```yuescript | ||
| 1943 | some_string = "Here is a string | ||
| 1944 | that has a line break in it." | ||
| 1945 | |||
| 1946 | -- You can mix expressions into string literals using #{} syntax. | ||
| 1947 | -- String interpolation is only available in double quoted strings. | ||
| 1948 | print "I am #{math.random! * 100}% sure." | ||
| 1949 | ``` | ||
| 1950 | <YueDisplay> | ||
| 1951 | |||
| 1952 | ```yue | ||
| 1953 | some_string = "Here is a string | ||
| 1954 | that has a line break in it." | ||
| 1955 | |||
| 1956 | -- You can mix expressions into string literals using #{} syntax. | ||
| 1957 | -- String interpolation is only available in double quoted strings. | ||
| 1958 | print "I am #{math.random! * 100}% sure." | ||
| 1959 | ``` | ||
| 1960 | |||
| 1961 | </YueDisplay> | ||
| 1962 | |||
| 1963 | ### Number Literals | ||
| 1964 | |||
| 1965 | You can use underscores in a number literal to increase readability. | ||
| 1966 | |||
| 1967 | ```yuescript | ||
| 1968 | integer = 1_000_000 | ||
| 1969 | hex = 0xEF_BB_BF | ||
| 1970 | binary = 0B10011 | ||
| 1971 | ``` | ||
| 1972 | <YueDisplay> | ||
| 1973 | |||
| 1974 | ```yue | ||
| 1975 | integer = 1_000_000 | ||
| 1976 | hex = 0xEF_BB_BF | ||
| 1977 | binary = 0B10011 | ||
| 1978 | ``` | ||
| 1979 | |||
| 1980 | </YueDisplay> | ||
| 1981 | |||
| 1982 | ### YAML Multiline String | ||
| 1983 | |||
| 1984 | The `|` prefix introduces a YAML-style multiline string literal: | ||
| 1985 | |||
| 1986 | ```yuescript | ||
| 1987 | str = | | ||
| 1988 | key: value | ||
| 1989 | list: | ||
| 1990 | - item1 | ||
| 1991 | - #{expr} | ||
| 1992 | ``` | ||
| 1993 | <YueDisplay> | ||
| 1994 | |||
| 1995 | ```yue | ||
| 1996 | str = | | ||
| 1997 | key: value | ||
| 1998 | list: | ||
| 1999 | - item1 | ||
| 2000 | - #{expr} | ||
| 2001 | ``` | ||
| 2002 | |||
| 2003 | </YueDisplay> | ||
| 2004 | |||
| 2005 | This 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)`. | ||
| 2006 | |||
| 2007 | YAML 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. | ||
| 2008 | |||
| 2009 | ```yuescript | ||
| 2010 | fn = -> | ||
| 2011 | str = | | ||
| 2012 | foo: | ||
| 2013 | bar: baz | ||
| 2014 | return str | ||
| 2015 | ``` | ||
| 2016 | <YueDisplay> | ||
| 2017 | |||
| 2018 | ```yue | ||
| 2019 | fn = -> | ||
| 2020 | str = | | ||
| 2021 | foo: | ||
| 2022 | bar: baz | ||
| 2023 | return str | ||
| 2024 | ``` | ||
| 2025 | |||
| 2026 | </YueDisplay> | ||
| 2027 | |||
| 2028 | Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures. | ||
| 2029 | |||
| 2030 | All 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. | ||
| 2031 | |||
| 2032 | ```yuescript | ||
| 2033 | str = | | ||
| 2034 | path: "C:\Program Files\App" | ||
| 2035 | note: 'He said: "#{Hello}!"' | ||
| 2036 | ``` | ||
| 2037 | <YueDisplay> | ||
| 2038 | |||
| 2039 | ```yue | ||
| 2040 | str = | | ||
| 2041 | path: "C:\Program Files\App" | ||
| 2042 | note: 'He said: "#{Hello}!"' | ||
| 2043 | ``` | ||
| 2044 | |||
| 2045 | </YueDisplay> | ||
| 2046 | |||
| 2047 | ## Function Literals | ||
| 2048 | |||
| 2049 | All functions are created using a function expression. A simple function is denoted using the arrow: **->**. | ||
| 2050 | |||
| 2051 | ```yuescript | ||
| 2052 | my_function = -> | ||
| 2053 | my_function() -- call the empty function | ||
| 2054 | ``` | ||
| 2055 | <YueDisplay> | ||
| 2056 | |||
| 2057 | ```yue | ||
| 2058 | my_function = -> | ||
| 2059 | my_function() -- call the empty function | ||
| 2060 | ``` | ||
| 2061 | |||
| 2062 | </YueDisplay> | ||
| 2063 | |||
| 2064 | The 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: | ||
| 2065 | |||
| 2066 | ```yuescript | ||
| 2067 | func_a = -> print "hello world" | ||
| 2068 | |||
| 2069 | func_b = -> | ||
| 2070 | value = 100 | ||
| 2071 | print "The value:", value | ||
| 2072 | ``` | ||
| 2073 | <YueDisplay> | ||
| 2074 | |||
| 2075 | ```yue | ||
| 2076 | func_a = -> print "hello world" | ||
| 2077 | |||
| 2078 | func_b = -> | ||
| 2079 | value = 100 | ||
| 2080 | print "The value:", value | ||
| 2081 | ``` | ||
| 2082 | |||
| 2083 | </YueDisplay> | ||
| 2084 | |||
| 2085 | If 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. | ||
| 2086 | |||
| 2087 | ```yuescript | ||
| 2088 | func_a! | ||
| 2089 | func_b() | ||
| 2090 | ``` | ||
| 2091 | <YueDisplay> | ||
| 2092 | |||
| 2093 | ```yue | ||
| 2094 | func_a! | ||
| 2095 | func_b() | ||
| 2096 | ``` | ||
| 2097 | |||
| 2098 | </YueDisplay> | ||
| 2099 | |||
| 2100 | Functions with arguments can be created by preceding the arrow with a list of argument names in parentheses: | ||
| 2101 | |||
| 2102 | ```yuescript | ||
| 2103 | sum = (x, y) -> print "sum", x + y | ||
| 2104 | ``` | ||
| 2105 | <YueDisplay> | ||
| 2106 | |||
| 2107 | ```yue | ||
| 2108 | sum = (x, y) -> print "sum", x + y | ||
| 2109 | ``` | ||
| 2110 | |||
| 2111 | </YueDisplay> | ||
| 2112 | |||
| 2113 | Functions 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. | ||
| 2114 | |||
| 2115 | ```yuescript | ||
| 2116 | sum 10, 20 | ||
| 2117 | print sum 10, 20 | ||
| 2118 | |||
| 2119 | a b c "a", "b", "c" | ||
| 2120 | ``` | ||
| 2121 | <YueDisplay> | ||
| 2122 | |||
| 2123 | ```yue | ||
| 2124 | sum 10, 20 | ||
| 2125 | print sum 10, 20 | ||
| 2126 | |||
| 2127 | a b c "a", "b", "c" | ||
| 2128 | ``` | ||
| 2129 | |||
| 2130 | </YueDisplay> | ||
| 2131 | |||
| 2132 | In 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. | ||
| 2133 | |||
| 2134 | ```yuescript | ||
| 2135 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 2136 | ``` | ||
| 2137 | <YueDisplay> | ||
| 2138 | |||
| 2139 | ```yue | ||
| 2140 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 2141 | ``` | ||
| 2142 | |||
| 2143 | </YueDisplay> | ||
| 2144 | |||
| 2145 | There must not be any space between the opening parenthesis and the function. | ||
| 2146 | |||
| 2147 | Functions will coerce the last statement in their body into a return statement, this is called implicit return: | ||
| 2148 | |||
| 2149 | ```yuescript | ||
| 2150 | sum = (x, y) -> x + y | ||
| 2151 | print "The sum is ", sum 10, 20 | ||
| 2152 | ``` | ||
| 2153 | <YueDisplay> | ||
| 2154 | |||
| 2155 | ```yue | ||
| 2156 | sum = (x, y) -> x + y | ||
| 2157 | print "The sum is ", sum 10, 20 | ||
| 2158 | ``` | ||
| 2159 | |||
| 2160 | </YueDisplay> | ||
| 2161 | |||
| 2162 | And if you need to explicitly return, you can use the return keyword: | ||
| 2163 | |||
| 2164 | ```yuescript | ||
| 2165 | sum = (x, y) -> return x + y | ||
| 2166 | ``` | ||
| 2167 | <YueDisplay> | ||
| 2168 | |||
| 2169 | ```yue | ||
| 2170 | sum = (x, y) -> return x + y | ||
| 2171 | ``` | ||
| 2172 | |||
| 2173 | </YueDisplay> | ||
| 2174 | |||
| 2175 | Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas: | ||
| 2176 | |||
| 2177 | ```yuescript | ||
| 2178 | mystery = (x, y) -> x + y, x - y | ||
| 2179 | a, b = mystery 10, 20 | ||
| 2180 | ``` | ||
| 2181 | <YueDisplay> | ||
| 2182 | |||
| 2183 | ```yue | ||
| 2184 | mystery = (x, y) -> x + y, x - y | ||
| 2185 | a, b = mystery 10, 20 | ||
| 2186 | ``` | ||
| 2187 | |||
| 2188 | </YueDisplay> | ||
| 2189 | |||
| 2190 | ### Fat Arrows | ||
| 2191 | |||
| 2192 | Because 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. | ||
| 2193 | |||
| 2194 | ```yuescript | ||
| 2195 | func = (num) => @value + num | ||
| 2196 | ``` | ||
| 2197 | <YueDisplay> | ||
| 2198 | |||
| 2199 | ```yue | ||
| 2200 | func = (num) => @value + num | ||
| 2201 | ``` | ||
| 2202 | |||
| 2203 | </YueDisplay> | ||
| 2204 | |||
| 2205 | ### Argument Defaults | ||
| 2206 | |||
| 2207 | It 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. | ||
| 2208 | |||
| 2209 | ```yuescript | ||
| 2210 | my_function = (name = "something", height = 100) -> | ||
| 2211 | print "Hello I am", name | ||
| 2212 | print "My height is", height | ||
| 2213 | ``` | ||
| 2214 | <YueDisplay> | ||
| 2215 | |||
| 2216 | ```yue | ||
| 2217 | my_function = (name = "something", height = 100) -> | ||
| 2218 | print "Hello I am", name | ||
| 2219 | print "My height is", height | ||
| 2220 | ``` | ||
| 2221 | |||
| 2222 | </YueDisplay> | ||
| 2223 | |||
| 2224 | An 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. | ||
| 2225 | |||
| 2226 | ```yuescript | ||
| 2227 | some_args = (x = 100, y = x + 1000) -> | ||
| 2228 | print x + y | ||
| 2229 | ``` | ||
| 2230 | <YueDisplay> | ||
| 2231 | |||
| 2232 | ```yue | ||
| 2233 | some_args = (x = 100, y = x + 1000) -> | ||
| 2234 | print x + y | ||
| 2235 | ``` | ||
| 2236 | |||
| 2237 | </YueDisplay> | ||
| 2238 | |||
| 2239 | ### Considerations | ||
| 2240 | |||
| 2241 | Because of the expressive parentheses-less way of calling functions, some restrictions must be put in place to avoid parsing ambiguity involving whitespace. | ||
| 2242 | |||
| 2243 | The minus sign plays two roles, a unary negation operator and a binary subtraction operator. Consider how the following examples compile: | ||
| 2244 | |||
| 2245 | ```yuescript | ||
| 2246 | a = x - 10 | ||
| 2247 | b = x-10 | ||
| 2248 | c = x -y | ||
| 2249 | d = x- z | ||
| 2250 | ``` | ||
| 2251 | <YueDisplay> | ||
| 2252 | |||
| 2253 | ```yue | ||
| 2254 | a = x - 10 | ||
| 2255 | b = x-10 | ||
| 2256 | c = x -y | ||
| 2257 | d = x- z | ||
| 2258 | ``` | ||
| 2259 | |||
| 2260 | </YueDisplay> | ||
| 2261 | |||
| 2262 | The 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. | ||
| 2263 | |||
| 2264 | When 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. | ||
| 2265 | |||
| 2266 | Where 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. | ||
| 2267 | |||
| 2268 | ```yuescript | ||
| 2269 | x = func"hello" + 100 | ||
| 2270 | y = func "hello" + 100 | ||
| 2271 | ``` | ||
| 2272 | <YueDisplay> | ||
| 2273 | |||
| 2274 | ```yue | ||
| 2275 | x = func"hello" + 100 | ||
| 2276 | y = func "hello" + 100 | ||
| 2277 | ``` | ||
| 2278 | |||
| 2279 | </YueDisplay> | ||
| 2280 | |||
| 2281 | ### Multi-line arguments | ||
| 2282 | |||
| 2283 | When 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. | ||
| 2284 | |||
| 2285 | If 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 | ||
| 2286 | |||
| 2287 | ```yuescript | ||
| 2288 | my_func 5, 4, 3, | ||
| 2289 | 8, 9, 10 | ||
| 2290 | |||
| 2291 | cool_func 1, 2, | ||
| 2292 | 3, 4, | ||
| 2293 | 5, 6, | ||
| 2294 | 7, 8 | ||
| 2295 | ``` | ||
| 2296 | <YueDisplay> | ||
| 2297 | |||
| 2298 | ```yue | ||
| 2299 | my_func 5, 4, 3, | ||
| 2300 | 8, 9, 10 | ||
| 2301 | |||
| 2302 | cool_func 1, 2, | ||
| 2303 | 3, 4, | ||
| 2304 | 5, 6, | ||
| 2305 | 7, 8 | ||
| 2306 | ``` | ||
| 2307 | |||
| 2308 | </YueDisplay> | ||
| 2309 | |||
| 2310 | This type of invocation can be nested. The level of indentation is used to determine to which function the arguments belong to. | ||
| 2311 | |||
| 2312 | ```yuescript | ||
| 2313 | my_func 5, 6, 7, | ||
| 2314 | 6, another_func 6, 7, 8, | ||
| 2315 | 9, 1, 2, | ||
| 2316 | 5, 4 | ||
| 2317 | ``` | ||
| 2318 | <YueDisplay> | ||
| 2319 | |||
| 2320 | ```yue | ||
| 2321 | my_func 5, 6, 7, | ||
| 2322 | 6, another_func 6, 7, 8, | ||
| 2323 | 9, 1, 2, | ||
| 2324 | 5, 4 | ||
| 2325 | ``` | ||
| 2326 | |||
| 2327 | </YueDisplay> | ||
| 2328 | |||
| 2329 | Because 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. | ||
| 2330 | |||
| 2331 | ```yuescript | ||
| 2332 | x = [ | ||
| 2333 | 1, 2, 3, 4, a_func 4, 5, | ||
| 2334 | 5, 6, | ||
| 2335 | 8, 9, 10 | ||
| 2336 | ] | ||
| 2337 | ``` | ||
| 2338 | <YueDisplay> | ||
| 2339 | |||
| 2340 | ```yue | ||
| 2341 | x = [ | ||
| 2342 | 1, 2, 3, 4, a_func 4, 5, | ||
| 2343 | 5, 6, | ||
| 2344 | 8, 9, 10 | ||
| 2345 | ] | ||
| 2346 | ``` | ||
| 2347 | |||
| 2348 | </YueDisplay> | ||
| 2349 | |||
| 2350 | Although uncommon, notice how we can give a deeper indentation for function arguments if we know we will be using a lower indentation further on. | ||
| 2351 | |||
| 2352 | ```yuescript | ||
| 2353 | y = [ my_func 1, 2, 3, | ||
| 2354 | 4, 5, | ||
| 2355 | 5, 6, 7 | ||
| 2356 | ] | ||
| 2357 | ``` | ||
| 2358 | <YueDisplay> | ||
| 2359 | |||
| 2360 | ```yue | ||
| 2361 | y = [ my_func 1, 2, 3, | ||
| 2362 | 4, 5, | ||
| 2363 | 5, 6, 7 | ||
| 2364 | ] | ||
| 2365 | ``` | ||
| 2366 | |||
| 2367 | </YueDisplay> | ||
| 2368 | |||
| 2369 | The 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: | ||
| 2370 | |||
| 2371 | ```yuescript | ||
| 2372 | if func 1, 2, 3, | ||
| 2373 | "hello", | ||
| 2374 | "world" | ||
| 2375 | print "hello" | ||
| 2376 | print "I am inside if" | ||
| 2377 | |||
| 2378 | if func 1, 2, 3, | ||
| 2379 | "hello", | ||
| 2380 | "world" | ||
| 2381 | print "hello" | ||
| 2382 | print "I am inside if" | ||
| 2383 | ``` | ||
| 2384 | <YueDisplay> | ||
| 2385 | |||
| 2386 | ```yue | ||
| 2387 | if func 1, 2, 3, | ||
| 2388 | "hello", | ||
| 2389 | "world" | ||
| 2390 | print "hello" | ||
| 2391 | print "I am inside if" | ||
| 2392 | |||
| 2393 | if func 1, 2, 3, | ||
| 2394 | "hello", | ||
| 2395 | "world" | ||
| 2396 | print "hello" | ||
| 2397 | print "I am inside if" | ||
| 2398 | ``` | ||
| 2399 | |||
| 2400 | </YueDisplay> | ||
| 2401 | |||
| 2402 | ### Parameter Destructuring | ||
| 2403 | |||
| 2404 | YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available: | ||
| 2405 | |||
| 2406 | * **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`). | ||
| 2407 | |||
| 2408 | * **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. | ||
| 2409 | |||
| 2410 | ```yuescript | ||
| 2411 | f1 = (:a, :b, :c) -> | ||
| 2412 | print a, b, c | ||
| 2413 | |||
| 2414 | f1 a: 1, b: "2", c: {} | ||
| 2415 | |||
| 2416 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 2417 | print a1, b, c | ||
| 2418 | |||
| 2419 | arg1 = {a: 0} | ||
| 2420 | f2 arg1, arg2 | ||
| 2421 | ``` | ||
| 2422 | <YueDisplay> | ||
| 2423 | |||
| 2424 | ```yue | ||
| 2425 | f1 = (:a, :b, :c) -> | ||
| 2426 | print a, b, c | ||
| 2427 | |||
| 2428 | f1 a: 1, b: "2", c: {} | ||
| 2429 | |||
| 2430 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 2431 | print a1, b, c | ||
| 2432 | |||
| 2433 | arg1 = {a: 0} | ||
| 2434 | f2 arg1, arg2 | ||
| 2435 | ``` | ||
| 2436 | |||
| 2437 | </YueDisplay> | ||
| 2438 | |||
| 2439 | ### Prefixed Return Expression | ||
| 2440 | |||
| 2441 | When 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: | ||
| 2442 | |||
| 2443 | ```yuescript | ||
| 2444 | findFirstEven = (list): nil -> | ||
| 2445 | for item in *list | ||
| 2446 | if type(item) == "table" | ||
| 2447 | for sub in *item | ||
| 2448 | if sub % 2 == 0 | ||
| 2449 | return sub | ||
| 2450 | ``` | ||
| 2451 | <YueDisplay> | ||
| 2452 | |||
| 2453 | ```yue | ||
| 2454 | findFirstEven = (list): nil -> | ||
| 2455 | for item in *list | ||
| 2456 | if type(item) == "table" | ||
| 2457 | for sub in *item | ||
| 2458 | if sub % 2 == 0 | ||
| 2459 | return sub | ||
| 2460 | ``` | ||
| 2461 | |||
| 2462 | </YueDisplay> | ||
| 2463 | |||
| 2464 | This is equivalent to: | ||
| 2465 | |||
| 2466 | ```yuescript | ||
| 2467 | findFirstEven = (list) -> | ||
| 2468 | for item in *list | ||
| 2469 | if type(item) == "table" | ||
| 2470 | for sub in *item | ||
| 2471 | if sub % 2 == 0 | ||
| 2472 | return sub | ||
| 2473 | nil | ||
| 2474 | ``` | ||
| 2475 | <YueDisplay> | ||
| 2476 | |||
| 2477 | ```yue | ||
| 2478 | findFirstEven = (list) -> | ||
| 2479 | for item in *list | ||
| 2480 | if type(item) == "table" | ||
| 2481 | for sub in *item | ||
| 2482 | if sub % 2 == 0 | ||
| 2483 | return sub | ||
| 2484 | nil | ||
| 2485 | ``` | ||
| 2486 | |||
| 2487 | </YueDisplay> | ||
| 2488 | |||
| 2489 | The 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. | ||
| 2490 | |||
| 2491 | ### Named Varargs | ||
| 2492 | |||
| 2493 | You 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). | ||
| 2494 | |||
| 2495 | ```yuescript | ||
| 2496 | f = (...t) -> | ||
| 2497 | print "argument count:", t.n | ||
| 2498 | print "table length:", #t | ||
| 2499 | for i = 1, t.n | ||
| 2500 | print t[i] | ||
| 2501 | |||
| 2502 | f 1, 2, 3 | ||
| 2503 | f "a", "b", "c", "d" | ||
| 2504 | f! | ||
| 2505 | |||
| 2506 | -- Handling cases with nil values | ||
| 2507 | process = (...args) -> | ||
| 2508 | sum = 0 | ||
| 2509 | for i = 1, args.n | ||
| 2510 | if args[i] != nil and type(args[i]) == "number" | ||
| 2511 | sum += args[i] | ||
| 2512 | sum | ||
| 2513 | |||
| 2514 | process 1, nil, 3, nil, 5 | ||
| 2515 | ``` | ||
| 2516 | <YueDisplay> | ||
| 2517 | |||
| 2518 | ```yue | ||
| 2519 | f = (...t) -> | ||
| 2520 | print "argument count:", t.n | ||
| 2521 | print "table length:", #t | ||
| 2522 | for i = 1, t.n | ||
| 2523 | print t[i] | ||
| 2524 | |||
| 2525 | f 1, 2, 3 | ||
| 2526 | f "a", "b", "c", "d" | ||
| 2527 | f! | ||
| 2528 | |||
| 2529 | -- Handling cases with nil values | ||
| 2530 | process = (...args) -> | ||
| 2531 | sum = 0 | ||
| 2532 | for i = 1, args.n | ||
| 2533 | if args[i] != nil and type(args[i]) == "number" | ||
| 2534 | sum += args[i] | ||
| 2535 | sum | ||
| 2536 | |||
| 2537 | process 1, nil, 3, nil, 5 | ||
| 2538 | ``` | ||
| 2539 | |||
| 2540 | </YueDisplay> | ||
| 2541 | |||
| 2542 | ## Backcalls | ||
| 2543 | |||
| 2544 | Backcalls 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. | ||
| 2545 | |||
| 2546 | ```yuescript | ||
| 2547 | <- f | ||
| 2548 | print "hello" | ||
| 2549 | ``` | ||
| 2550 | <YueDisplay> | ||
| 2551 | |||
| 2552 | ```yue | ||
| 2553 | <- f | ||
| 2554 | print "hello" | ||
| 2555 | ``` | ||
| 2556 | |||
| 2557 | </YueDisplay> | ||
| 2558 | |||
| 2559 | Fat arrow functions are also available. | ||
| 2560 | |||
| 2561 | ```yuescript | ||
| 2562 | <= f | ||
| 2563 | print @value | ||
| 2564 | ``` | ||
| 2565 | <YueDisplay> | ||
| 2566 | |||
| 2567 | ```yue | ||
| 2568 | <= f | ||
| 2569 | print @value | ||
| 2570 | ``` | ||
| 2571 | |||
| 2572 | </YueDisplay> | ||
| 2573 | |||
| 2574 | You can specify a placeholder for where you want the backcall function to go as a parameter. | ||
| 2575 | |||
| 2576 | ```yuescript | ||
| 2577 | (x) <- map _, [1, 2, 3] | ||
| 2578 | x * 2 | ||
| 2579 | ``` | ||
| 2580 | <YueDisplay> | ||
| 2581 | |||
| 2582 | ```yue | ||
| 2583 | (x) <- map _, [1, 2, 3] | ||
| 2584 | x * 2 | ||
| 2585 | ``` | ||
| 2586 | |||
| 2587 | </YueDisplay> | ||
| 2588 | |||
| 2589 | If 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. | ||
| 2590 | |||
| 2591 | ```yuescript | ||
| 2592 | result, msg = do | ||
| 2593 | data <- readAsync "filename.txt" | ||
| 2594 | print data | ||
| 2595 | info <- processAsync data | ||
| 2596 | check info | ||
| 2597 | print result, msg | ||
| 2598 | ``` | ||
| 2599 | <YueDisplay> | ||
| 2600 | |||
| 2601 | ```yue | ||
| 2602 | result, msg = do | ||
| 2603 | data <- readAsync "filename.txt" | ||
| 2604 | print data | ||
| 2605 | info <- processAsync data | ||
| 2606 | check info | ||
| 2607 | print result, msg | ||
| 2608 | ``` | ||
| 2609 | |||
| 2610 | </YueDisplay> | ||
| 2611 | |||
| 2612 | ## Table Literals | ||
| 2613 | |||
| 2614 | Like in Lua, tables are delimited in curly braces. | ||
| 2615 | |||
| 2616 | ```yuescript | ||
| 2617 | some_values = [1, 2, 3, 4] | ||
| 2618 | ``` | ||
| 2619 | <YueDisplay> | ||
| 2620 | |||
| 2621 | ```yue | ||
| 2622 | some_values = [1, 2, 3, 4] | ||
| 2623 | ``` | ||
| 2624 | |||
| 2625 | </YueDisplay> | ||
| 2626 | |||
| 2627 | Unlike Lua, assigning a value to a key in a table is done with **:** (instead of **=**). | ||
| 2628 | |||
| 2629 | ```yuescript | ||
| 2630 | some_values = { | ||
| 2631 | name: "Bill", | ||
| 2632 | age: 200, | ||
| 2633 | ["favorite food"]: "rice" | ||
| 2634 | } | ||
| 2635 | ``` | ||
| 2636 | <YueDisplay> | ||
| 2637 | |||
| 2638 | ```yue | ||
| 2639 | some_values = { | ||
| 2640 | name: "Bill", | ||
| 2641 | age: 200, | ||
| 2642 | ["favorite food"]: "rice" | ||
| 2643 | } | ||
| 2644 | ``` | ||
| 2645 | |||
| 2646 | </YueDisplay> | ||
| 2647 | |||
| 2648 | The curly braces can be left off if a single table of key value pairs is being assigned. | ||
| 2649 | |||
| 2650 | ```yuescript | ||
| 2651 | profile = | ||
| 2652 | height: "4 feet", | ||
| 2653 | shoe_size: 13, | ||
| 2654 | favorite_foods: ["ice cream", "donuts"] | ||
| 2655 | ``` | ||
| 2656 | <YueDisplay> | ||
| 2657 | |||
| 2658 | ```yue | ||
| 2659 | profile = | ||
| 2660 | height: "4 feet", | ||
| 2661 | shoe_size: 13, | ||
| 2662 | favorite_foods: ["ice cream", "donuts"] | ||
| 2663 | ``` | ||
| 2664 | |||
| 2665 | </YueDisplay> | ||
| 2666 | |||
| 2667 | Newlines can be used to delimit values instead of a comma (or both): | ||
| 2668 | |||
| 2669 | ```yuescript | ||
| 2670 | values = { | ||
| 2671 | 1, 2, 3, 4 | ||
| 2672 | 5, 6, 7, 8 | ||
| 2673 | name: "superman" | ||
| 2674 | occupation: "crime fighting" | ||
| 2675 | } | ||
| 2676 | ``` | ||
| 2677 | <YueDisplay> | ||
| 2678 | |||
| 2679 | ```yue | ||
| 2680 | values = { | ||
| 2681 | 1, 2, 3, 4 | ||
| 2682 | 5, 6, 7, 8 | ||
| 2683 | name: "superman" | ||
| 2684 | occupation: "crime fighting" | ||
| 2685 | } | ||
| 2686 | ``` | ||
| 2687 | |||
| 2688 | </YueDisplay> | ||
| 2689 | |||
| 2690 | When creating a single line table literal, the curly braces can also be left off: | ||
| 2691 | |||
| 2692 | ```yuescript | ||
| 2693 | my_function dance: "Tango", partner: "none" | ||
| 2694 | |||
| 2695 | y = type: "dog", legs: 4, tails: 1 | ||
| 2696 | ``` | ||
| 2697 | <YueDisplay> | ||
| 2698 | |||
| 2699 | ```yue | ||
| 2700 | my_function dance: "Tango", partner: "none" | ||
| 2701 | |||
| 2702 | y = type: "dog", legs: 4, tails: 1 | ||
| 2703 | ``` | ||
| 2704 | |||
| 2705 | </YueDisplay> | ||
| 2706 | |||
| 2707 | The keys of a table literal can be language keywords without being escaped: | ||
| 2708 | |||
| 2709 | ```yuescript | ||
| 2710 | tbl = { | ||
| 2711 | do: "something" | ||
| 2712 | end: "hunger" | ||
| 2713 | } | ||
| 2714 | ``` | ||
| 2715 | <YueDisplay> | ||
| 2716 | |||
| 2717 | ```yue | ||
| 2718 | tbl = { | ||
| 2719 | do: "something" | ||
| 2720 | end: "hunger" | ||
| 2721 | } | ||
| 2722 | ``` | ||
| 2723 | |||
| 2724 | </YueDisplay> | ||
| 2725 | |||
| 2726 | If 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: | ||
| 2727 | |||
| 2728 | ```yuescript | ||
| 2729 | hair = "golden" | ||
| 2730 | height = 200 | ||
| 2731 | person = { :hair, :height, shoe_size: 40 } | ||
| 2732 | |||
| 2733 | print_table :hair, :height | ||
| 2734 | ``` | ||
| 2735 | <YueDisplay> | ||
| 2736 | |||
| 2737 | ```yue | ||
| 2738 | hair = "golden" | ||
| 2739 | height = 200 | ||
| 2740 | person = { :hair, :height, shoe_size: 40 } | ||
| 2741 | |||
| 2742 | print_table :hair, :height | ||
| 2743 | ``` | ||
| 2744 | |||
| 2745 | </YueDisplay> | ||
| 2746 | |||
| 2747 | If 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. | ||
| 2748 | |||
| 2749 | ```yuescript | ||
| 2750 | t = { | ||
| 2751 | [1 + 2]: "hello" | ||
| 2752 | "hello world": true | ||
| 2753 | } | ||
| 2754 | ``` | ||
| 2755 | <YueDisplay> | ||
| 2756 | |||
| 2757 | ```yue | ||
| 2758 | t = { | ||
| 2759 | [1 + 2]: "hello" | ||
| 2760 | "hello world": true | ||
| 2761 | } | ||
| 2762 | ``` | ||
| 2763 | |||
| 2764 | </YueDisplay> | ||
| 2765 | |||
| 2766 | Lua 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. | ||
| 2767 | |||
| 2768 | ```yuescript | ||
| 2769 | some_values = [1, 2, 3, 4] | ||
| 2770 | list_with_one_element = [1, ] | ||
| 2771 | ``` | ||
| 2772 | <YueDisplay> | ||
| 2773 | |||
| 2774 | ```yue | ||
| 2775 | some_values = [1, 2, 3, 4] | ||
| 2776 | list_with_one_element = [1, ] | ||
| 2777 | ``` | ||
| 2778 | |||
| 2779 | </YueDisplay> | ||
| 2780 | |||
| 2781 | ## Comprehensions | ||
| 2782 | |||
| 2783 | Comprehensions 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. | ||
| 2784 | |||
| 2785 | ### List Comprehensions | ||
| 2786 | |||
| 2787 | The following creates a copy of the items table but with all the values doubled. | ||
| 2788 | |||
| 2789 | ```yuescript | ||
| 2790 | items = [ 1, 2, 3, 4 ] | ||
| 2791 | doubled = [item * 2 for i, item in ipairs items] | ||
| 2792 | ``` | ||
| 2793 | <YueDisplay> | ||
| 2794 | |||
| 2795 | ```yue | ||
| 2796 | items = [ 1, 2, 3, 4 ] | ||
| 2797 | doubled = [item * 2 for i, item in ipairs items] | ||
| 2798 | ``` | ||
| 2799 | |||
| 2800 | </YueDisplay> | ||
| 2801 | |||
| 2802 | The items included in the new table can be restricted with a when clause: | ||
| 2803 | |||
| 2804 | ```yuescript | ||
| 2805 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 2806 | ``` | ||
| 2807 | <YueDisplay> | ||
| 2808 | |||
| 2809 | ```yue | ||
| 2810 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 2811 | ``` | ||
| 2812 | |||
| 2813 | </YueDisplay> | ||
| 2814 | |||
| 2815 | Because it is common to iterate over the values of a numerically indexed table, an **\*** operator is introduced. The doubled example can be rewritten as: | ||
| 2816 | |||
| 2817 | ```yuescript | ||
| 2818 | doubled = [item * 2 for item in *items] | ||
| 2819 | ``` | ||
| 2820 | <YueDisplay> | ||
| 2821 | |||
| 2822 | ```yue | ||
| 2823 | doubled = [item * 2 for item in *items] | ||
| 2824 | ``` | ||
| 2825 | |||
| 2826 | </YueDisplay> | ||
| 2827 | |||
| 2828 | In list comprehensions, you can also use the spread operator `...` to flatten nested lists, achieving a flat map effect: | ||
| 2829 | |||
| 2830 | ```yuescript | ||
| 2831 | data = | ||
| 2832 | a: [1, 2, 3] | ||
| 2833 | b: [4, 5, 6] | ||
| 2834 | |||
| 2835 | flat = [...v for k,v in pairs data] | ||
| 2836 | -- flat is now [1, 2, 3, 4, 5, 6] | ||
| 2837 | ``` | ||
| 2838 | <YueDisplay> | ||
| 2839 | |||
| 2840 | ```yue | ||
| 2841 | data = | ||
| 2842 | a: [1, 2, 3] | ||
| 2843 | b: [4, 5, 6] | ||
| 2844 | |||
| 2845 | flat = [...v for k,v in pairs data] | ||
| 2846 | -- flat is now [1, 2, 3, 4, 5, 6] | ||
| 2847 | ``` | ||
| 2848 | |||
| 2849 | </YueDisplay> | ||
| 2850 | |||
| 2851 | The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause. | ||
| 2852 | |||
| 2853 | Using multiple for clauses is the same as using nested loops: | ||
| 2854 | |||
| 2855 | ```yuescript | ||
| 2856 | x_coords = [4, 5, 6, 7] | ||
| 2857 | y_coords = [9, 2, 3] | ||
| 2858 | |||
| 2859 | points = [ [x, y] for x in *x_coords \ | ||
| 2860 | for y in *y_coords] | ||
| 2861 | ``` | ||
| 2862 | <YueDisplay> | ||
| 2863 | |||
| 2864 | ```yue | ||
| 2865 | x_coords = [4, 5, 6, 7] | ||
| 2866 | y_coords = [9, 2, 3] | ||
| 2867 | |||
| 2868 | points = [ [x, y] for x in *x_coords \ | ||
| 2869 | for y in *y_coords] | ||
| 2870 | ``` | ||
| 2871 | |||
| 2872 | </YueDisplay> | ||
| 2873 | |||
| 2874 | Numeric for loops can also be used in comprehensions: | ||
| 2875 | |||
| 2876 | ```yuescript | ||
| 2877 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 2878 | ``` | ||
| 2879 | <YueDisplay> | ||
| 2880 | |||
| 2881 | ```yue | ||
| 2882 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 2883 | ``` | ||
| 2884 | |||
| 2885 | </YueDisplay> | ||
| 2886 | |||
| 2887 | ### Table Comprehensions | ||
| 2888 | |||
| 2889 | The syntax for table comprehensions is very similar, only differing by using **{** and **}** and taking two values from each iteration. | ||
| 2890 | |||
| 2891 | This example makes a copy of the tablething: | ||
| 2892 | |||
| 2893 | ```yuescript | ||
| 2894 | thing = { | ||
| 2895 | color: "red" | ||
| 2896 | name: "fast" | ||
| 2897 | width: 123 | ||
| 2898 | } | ||
| 2899 | |||
| 2900 | thing_copy = {k, v for k, v in pairs thing} | ||
| 2901 | ``` | ||
| 2902 | <YueDisplay> | ||
| 2903 | |||
| 2904 | ```yue | ||
| 2905 | thing = { | ||
| 2906 | color: "red" | ||
| 2907 | name: "fast" | ||
| 2908 | width: 123 | ||
| 2909 | } | ||
| 2910 | |||
| 2911 | thing_copy = {k, v for k, v in pairs thing} | ||
| 2912 | ``` | ||
| 2913 | |||
| 2914 | </YueDisplay> | ||
| 2915 | |||
| 2916 | ```yuescript | ||
| 2917 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 2918 | ``` | ||
| 2919 | <YueDisplay> | ||
| 2920 | |||
| 2921 | ```yue | ||
| 2922 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 2923 | ``` | ||
| 2924 | |||
| 2925 | </YueDisplay> | ||
| 2926 | |||
| 2927 | The **\*** operator is also supported. Here we create a square root look up table for a few numbers. | ||
| 2928 | |||
| 2929 | ```yuescript | ||
| 2930 | numbers = [1, 2, 3, 4] | ||
| 2931 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 2932 | ``` | ||
| 2933 | <YueDisplay> | ||
| 2934 | |||
| 2935 | ```yue | ||
| 2936 | numbers = [1, 2, 3, 4] | ||
| 2937 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 2938 | ``` | ||
| 2939 | |||
| 2940 | </YueDisplay> | ||
| 2941 | |||
| 2942 | The 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: | ||
| 2943 | |||
| 2944 | In 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. | ||
| 2945 | |||
| 2946 | ```yuescript | ||
| 2947 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 2948 | tbl = {unpack tuple for tuple in *tuples} | ||
| 2949 | ``` | ||
| 2950 | <YueDisplay> | ||
| 2951 | |||
| 2952 | ```yue | ||
| 2953 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 2954 | tbl = {unpack tuple for tuple in *tuples} | ||
| 2955 | ``` | ||
| 2956 | |||
| 2957 | </YueDisplay> | ||
| 2958 | |||
| 2959 | ### Slicing | ||
| 2960 | |||
| 2961 | A 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. | ||
| 2962 | |||
| 2963 | Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive: | ||
| 2964 | |||
| 2965 | ```yuescript | ||
| 2966 | slice = [item for item in *items[1, 5]] | ||
| 2967 | ``` | ||
| 2968 | <YueDisplay> | ||
| 2969 | |||
| 2970 | ```yue | ||
| 2971 | slice = [item for item in *items[1, 5]] | ||
| 2972 | ``` | ||
| 2973 | |||
| 2974 | </YueDisplay> | ||
| 2975 | |||
| 2976 | Any 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: | ||
| 2977 | |||
| 2978 | ```yuescript | ||
| 2979 | slice = [item for item in *items[2,]] | ||
| 2980 | ``` | ||
| 2981 | <YueDisplay> | ||
| 2982 | |||
| 2983 | ```yue | ||
| 2984 | slice = [item for item in *items[2,]] | ||
| 2985 | ``` | ||
| 2986 | |||
| 2987 | </YueDisplay> | ||
| 2988 | |||
| 2989 | If 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, …) | ||
| 2990 | |||
| 2991 | ```yuescript | ||
| 2992 | slice = [item for item in *items[,,2]] | ||
| 2993 | ``` | ||
| 2994 | <YueDisplay> | ||
| 2995 | |||
| 2996 | ```yue | ||
| 2997 | slice = [item for item in *items[,,2]] | ||
| 2998 | ``` | ||
| 2999 | |||
| 3000 | </YueDisplay> | ||
| 3001 | |||
| 3002 | Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table. | ||
| 3003 | |||
| 3004 | ```yuescript | ||
| 3005 | -- take the last 4 items | ||
| 3006 | slice = [item for item in *items[-4,-1]] | ||
| 3007 | ``` | ||
| 3008 | <YueDisplay> | ||
| 3009 | |||
| 3010 | ```yue | ||
| 3011 | -- take the last 4 items | ||
| 3012 | slice = [item for item in *items[-4,-1]] | ||
| 3013 | ``` | ||
| 3014 | |||
| 3015 | </YueDisplay> | ||
| 3016 | |||
| 3017 | The step size can also be negative, which means that the items are taken in reverse order. | ||
| 3018 | |||
| 3019 | ```yuescript | ||
| 3020 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 3021 | ``` | ||
| 3022 | <YueDisplay> | ||
| 3023 | |||
| 3024 | ```yue | ||
| 3025 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 3026 | ``` | ||
| 3027 | |||
| 3028 | </YueDisplay> | ||
| 3029 | |||
| 3030 | #### Slicing Expression | ||
| 3031 | |||
| 3032 | Slicing can also be used as an expression. This is useful for getting a sub-list of a table. | ||
| 3033 | |||
| 3034 | ```yuescript | ||
| 3035 | -- take the 2nd and 4th items as a new list | ||
| 3036 | sub_list = items[2, 4] | ||
| 3037 | ``` | ||
| 3038 | <YueDisplay> | ||
| 3039 | |||
| 3040 | ```yue | ||
| 3041 | -- take the 2nd and 4th items as a new list | ||
| 3042 | sub_list = items[2, 4] | ||
| 3043 | ``` | ||
| 3044 | |||
| 3045 | </YueDisplay> | ||
| 3046 | |||
| 3047 | ## For Loop | ||
| 3048 | |||
| 3049 | There are two for loop forms, just like in Lua. A numeric one and a generic one: | ||
| 3050 | |||
| 3051 | ```yuescript | ||
| 3052 | for i = 10, 20 | ||
| 3053 | print i | ||
| 3054 | |||
| 3055 | for k = 1, 15, 2 -- an optional step provided | ||
| 3056 | print k | ||
| 3057 | |||
| 3058 | for key, value in pairs object | ||
| 3059 | print key, value | ||
| 3060 | ``` | ||
| 3061 | <YueDisplay> | ||
| 3062 | |||
| 3063 | ```yue | ||
| 3064 | for i = 10, 20 | ||
| 3065 | print i | ||
| 3066 | |||
| 3067 | for k = 1, 15, 2 -- an optional step provided | ||
| 3068 | print k | ||
| 3069 | |||
| 3070 | for key, value in pairs object | ||
| 3071 | print key, value | ||
| 3072 | ``` | ||
| 3073 | |||
| 3074 | </YueDisplay> | ||
| 3075 | |||
| 3076 | The slicing and **\*** operators can be used, just like with comprehensions: | ||
| 3077 | |||
| 3078 | ```yuescript | ||
| 3079 | for item in *items[2, 4] | ||
| 3080 | print item | ||
| 3081 | ``` | ||
| 3082 | <YueDisplay> | ||
| 3083 | |||
| 3084 | ```yue | ||
| 3085 | for item in *items[2, 4] | ||
| 3086 | print item | ||
| 3087 | ``` | ||
| 3088 | |||
| 3089 | </YueDisplay> | ||
| 3090 | |||
| 3091 | A shorter syntax is also available for all variations when the body is only a single line: | ||
| 3092 | |||
| 3093 | ```yuescript | ||
| 3094 | for item in *items do print item | ||
| 3095 | |||
| 3096 | for j = 1, 10, 3 do print j | ||
| 3097 | ``` | ||
| 3098 | <YueDisplay> | ||
| 3099 | |||
| 3100 | ```yue | ||
| 3101 | for item in *items do print item | ||
| 3102 | |||
| 3103 | for j = 1, 10, 3 do print j | ||
| 3104 | ``` | ||
| 3105 | |||
| 3106 | </YueDisplay> | ||
| 3107 | |||
| 3108 | A 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. | ||
| 3109 | |||
| 3110 | Doubling every even number: | ||
| 3111 | |||
| 3112 | ```yuescript | ||
| 3113 | doubled_evens = for i = 1, 20 | ||
| 3114 | if i % 2 == 0 | ||
| 3115 | i * 2 | ||
| 3116 | else | ||
| 3117 | i | ||
| 3118 | ``` | ||
| 3119 | <YueDisplay> | ||
| 3120 | |||
| 3121 | ```yue | ||
| 3122 | doubled_evens = for i = 1, 20 | ||
| 3123 | if i % 2 == 0 | ||
| 3124 | i * 2 | ||
| 3125 | else | ||
| 3126 | i | ||
| 3127 | ``` | ||
| 3128 | |||
| 3129 | </YueDisplay> | ||
| 3130 | |||
| 3131 | In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result. | ||
| 3132 | |||
| 3133 | For example, to find the first number greater than 10: | ||
| 3134 | |||
| 3135 | ```yuescript | ||
| 3136 | first_large = for n in *numbers | ||
| 3137 | break n if n > 10 | ||
| 3138 | ``` | ||
| 3139 | <YueDisplay> | ||
| 3140 | |||
| 3141 | ```yue | ||
| 3142 | first_large = for n in *numbers | ||
| 3143 | break n if n > 10 | ||
| 3144 | ``` | ||
| 3145 | |||
| 3146 | </YueDisplay> | ||
| 3147 | |||
| 3148 | This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions. | ||
| 3149 | |||
| 3150 | You can also filter values by combining the for loop expression with the continue statement. | ||
| 3151 | |||
| 3152 | For 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. | ||
| 3153 | |||
| 3154 | ```yuescript | ||
| 3155 | func_a = -> for i = 1, 10 do print i | ||
| 3156 | func_b = -> return for i = 1, 10 do i | ||
| 3157 | |||
| 3158 | print func_a! -- prints nil | ||
| 3159 | print func_b! -- prints table object | ||
| 3160 | ``` | ||
| 3161 | <YueDisplay> | ||
| 3162 | |||
| 3163 | ```yue | ||
| 3164 | func_a = -> for i = 1, 10 do print i | ||
| 3165 | func_b = -> return for i = 1, 10 do i | ||
| 3166 | |||
| 3167 | print func_a! -- prints nil | ||
| 3168 | print func_b! -- prints table object | ||
| 3169 | ``` | ||
| 3170 | |||
| 3171 | </YueDisplay> | ||
| 3172 | |||
| 3173 | This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop. | ||
| 3174 | |||
| 3175 | ## Repeat Loop | ||
| 3176 | |||
| 3177 | The repeat loop comes from Lua: | ||
| 3178 | |||
| 3179 | ```yuescript | ||
| 3180 | i = 10 | ||
| 3181 | repeat | ||
| 3182 | print i | ||
| 3183 | i -= 1 | ||
| 3184 | until i == 0 | ||
| 3185 | ``` | ||
| 3186 | <YueDisplay> | ||
| 3187 | |||
| 3188 | ```yue | ||
| 3189 | i = 10 | ||
| 3190 | repeat | ||
| 3191 | print i | ||
| 3192 | i -= 1 | ||
| 3193 | until i == 0 | ||
| 3194 | ``` | ||
| 3195 | |||
| 3196 | </YueDisplay> | ||
| 3197 | |||
| 3198 | ## While Loop | ||
| 3199 | |||
| 3200 | The while loop also comes in four variations: | ||
| 3201 | |||
| 3202 | ```yuescript | ||
| 3203 | i = 10 | ||
| 3204 | while i > 0 | ||
| 3205 | print i | ||
| 3206 | i -= 1 | ||
| 3207 | |||
| 3208 | while running == true do my_function! | ||
| 3209 | ``` | ||
| 3210 | <YueDisplay> | ||
| 3211 | |||
| 3212 | ```yue | ||
| 3213 | i = 10 | ||
| 3214 | while i > 0 | ||
| 3215 | print i | ||
| 3216 | i -= 1 | ||
| 3217 | |||
| 3218 | while running == true do my_function! | ||
| 3219 | ``` | ||
| 3220 | |||
| 3221 | </YueDisplay> | ||
| 3222 | |||
| 3223 | ```yuescript | ||
| 3224 | i = 10 | ||
| 3225 | until i == 0 | ||
| 3226 | print i | ||
| 3227 | i -= 1 | ||
| 3228 | |||
| 3229 | until running == false do my_function! | ||
| 3230 | ``` | ||
| 3231 | <YueDisplay> | ||
| 3232 | |||
| 3233 | ```yue | ||
| 3234 | i = 10 | ||
| 3235 | until i == 0 | ||
| 3236 | print i | ||
| 3237 | i -= 1 | ||
| 3238 | until running == false do my_function! | ||
| 3239 | ``` | ||
| 3240 | |||
| 3241 | </YueDisplay> | ||
| 3242 | |||
| 3243 | Like 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. | ||
| 3244 | |||
| 3245 | ## Continue | ||
| 3246 | |||
| 3247 | A continue statement can be used to skip the current iteration in a loop. | ||
| 3248 | |||
| 3249 | ```yuescript | ||
| 3250 | i = 0 | ||
| 3251 | while i < 10 | ||
| 3252 | i += 1 | ||
| 3253 | continue if i % 2 == 0 | ||
| 3254 | print i | ||
| 3255 | ``` | ||
| 3256 | <YueDisplay> | ||
| 3257 | |||
| 3258 | ```yue | ||
| 3259 | i = 0 | ||
| 3260 | while i < 10 | ||
| 3261 | i += 1 | ||
| 3262 | continue if i % 2 == 0 | ||
| 3263 | print i | ||
| 3264 | ``` | ||
| 3265 | |||
| 3266 | </YueDisplay> | ||
| 3267 | |||
| 3268 | continue 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: | ||
| 3269 | |||
| 3270 | ```yuescript | ||
| 3271 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 3272 | odds = for x in *my_numbers | ||
| 3273 | continue if x % 2 == 1 | ||
| 3274 | x | ||
| 3275 | ``` | ||
| 3276 | <YueDisplay> | ||
| 3277 | |||
| 3278 | ```yue | ||
| 3279 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 3280 | odds = for x in *my_numbers | ||
| 3281 | continue if x % 2 == 1 | ||
| 3282 | x | ||
| 3283 | ``` | ||
| 3284 | |||
| 3285 | </YueDisplay> | ||
| 3286 | |||
| 3287 | ## Conditionals | ||
| 3288 | |||
| 3289 | ```yuescript | ||
| 3290 | have_coins = false | ||
| 3291 | if have_coins | ||
| 3292 | print "Got coins" | ||
| 3293 | else | ||
| 3294 | print "No coins" | ||
| 3295 | ``` | ||
| 3296 | <YueDisplay> | ||
| 3297 | |||
| 3298 | ```yue | ||
| 3299 | have_coins = false | ||
| 3300 | if have_coins | ||
| 3301 | print "Got coins" | ||
| 3302 | else | ||
| 3303 | print "No coins" | ||
| 3304 | ``` | ||
| 3305 | |||
| 3306 | </YueDisplay> | ||
| 3307 | |||
| 3308 | A short syntax for single statements can also be used: | ||
| 3309 | |||
| 3310 | ```yuescript | ||
| 3311 | have_coins = false | ||
| 3312 | if have_coins then print "Got coins" else print "No coins" | ||
| 3313 | ``` | ||
| 3314 | <YueDisplay> | ||
| 3315 | |||
| 3316 | ```yue | ||
| 3317 | have_coins = false | ||
| 3318 | if have_coins then print "Got coins" else print "No coins" | ||
| 3319 | ``` | ||
| 3320 | |||
| 3321 | </YueDisplay> | ||
| 3322 | |||
| 3323 | Because if statements can be used as expressions, this can also be written as: | ||
| 3324 | |||
| 3325 | ```yuescript | ||
| 3326 | have_coins = false | ||
| 3327 | print if have_coins then "Got coins" else "No coins" | ||
| 3328 | ``` | ||
| 3329 | <YueDisplay> | ||
| 3330 | |||
| 3331 | ```yue | ||
| 3332 | have_coins = false | ||
| 3333 | print if have_coins then "Got coins" else "No coins" | ||
| 3334 | ``` | ||
| 3335 | |||
| 3336 | </YueDisplay> | ||
| 3337 | |||
| 3338 | Conditionals can also be used in return statements and assignments: | ||
| 3339 | |||
| 3340 | ```yuescript | ||
| 3341 | is_tall = (name) -> | ||
| 3342 | if name == "Rob" | ||
| 3343 | true | ||
| 3344 | else | ||
| 3345 | false | ||
| 3346 | |||
| 3347 | message = if is_tall "Rob" | ||
| 3348 | "I am very tall" | ||
| 3349 | else | ||
| 3350 | "I am not so tall" | ||
| 3351 | |||
| 3352 | print message -- prints: I am very tall | ||
| 3353 | ``` | ||
| 3354 | <YueDisplay> | ||
| 3355 | |||
| 3356 | ```yue | ||
| 3357 | is_tall = (name) -> | ||
| 3358 | if name == "Rob" | ||
| 3359 | true | ||
| 3360 | else | ||
| 3361 | false | ||
| 3362 | |||
| 3363 | message = if is_tall "Rob" | ||
| 3364 | "I am very tall" | ||
| 3365 | else | ||
| 3366 | "I am not so tall" | ||
| 3367 | |||
| 3368 | print message -- prints: I am very tall | ||
| 3369 | ``` | ||
| 3370 | |||
| 3371 | </YueDisplay> | ||
| 3372 | |||
| 3373 | The opposite of if is unless: | ||
| 3374 | |||
| 3375 | ```yuescript | ||
| 3376 | unless os.date("%A") == "Monday" | ||
| 3377 | print "it is not Monday!" | ||
| 3378 | ``` | ||
| 3379 | <YueDisplay> | ||
| 3380 | |||
| 3381 | ```yue | ||
| 3382 | unless os.date("%A") == "Monday" | ||
| 3383 | print "it is not Monday!" | ||
| 3384 | ``` | ||
| 3385 | |||
| 3386 | </YueDisplay> | ||
| 3387 | |||
| 3388 | ```yuescript | ||
| 3389 | print "You're lucky!" unless math.random! > 0.1 | ||
| 3390 | ``` | ||
| 3391 | <YueDisplay> | ||
| 3392 | |||
| 3393 | ```yue | ||
| 3394 | print "You're lucky!" unless math.random! > 0.1 | ||
| 3395 | ``` | ||
| 3396 | |||
| 3397 | </YueDisplay> | ||
| 3398 | |||
| 3399 | ### In Expression | ||
| 3400 | |||
| 3401 | You can write range checking code with an `in-expression`. | ||
| 3402 | |||
| 3403 | ```yuescript | ||
| 3404 | a = 5 | ||
| 3405 | |||
| 3406 | if a in [1, 3, 5, 7] | ||
| 3407 | print "checking equality with discrete values" | ||
| 3408 | |||
| 3409 | if a in list | ||
| 3410 | print "checking if `a` is in a list" | ||
| 3411 | ``` | ||
| 3412 | <YueDisplay> | ||
| 3413 | |||
| 3414 | ```yue | ||
| 3415 | a = 5 | ||
| 3416 | |||
| 3417 | if a in [1, 3, 5, 7] | ||
| 3418 | print "checking equality with discrete values" | ||
| 3419 | |||
| 3420 | if a in list | ||
| 3421 | print "checking if `a` is in a list" | ||
| 3422 | ``` | ||
| 3423 | |||
| 3424 | </YueDisplay> | ||
| 3425 | |||
| 3426 | ```yuescript | ||
| 3427 | print "You're lucky!" unless math.random! > 0.1 | ||
| 3428 | ``` | ||
| 3429 | <YueDisplay> | ||
| 3430 | |||
| 3431 | ```yue | ||
| 3432 | print "You're lucky!" unless math.random! > 0.1 | ||
| 3433 | ``` | ||
| 3434 | |||
| 3435 | </YueDisplay> | ||
| 3436 | |||
| 3437 | ## Line Decorators | ||
| 3438 | |||
| 3439 | For convenience, the for loop and if statement can be applied to single statements at the end of the line: | ||
| 3440 | |||
| 3441 | ```yuescript | ||
| 3442 | print "hello world" if name == "Rob" | ||
| 3443 | ``` | ||
| 3444 | <YueDisplay> | ||
| 3445 | |||
| 3446 | ```yue | ||
| 3447 | print "hello world" if name == "Rob" | ||
| 3448 | ``` | ||
| 3449 | |||
| 3450 | </YueDisplay> | ||
| 3451 | |||
| 3452 | And with basic loops: | ||
| 3453 | |||
| 3454 | ```yuescript | ||
| 3455 | print "item: ", item for item in *items | ||
| 3456 | ``` | ||
| 3457 | <YueDisplay> | ||
| 3458 | |||
| 3459 | ```yue | ||
| 3460 | print "item: ", item for item in *items | ||
| 3461 | ``` | ||
| 3462 | |||
| 3463 | </YueDisplay> | ||
| 3464 | |||
| 3465 | And with while loops: | ||
| 3466 | |||
| 3467 | ```yuescript | ||
| 3468 | game\update! while game\isRunning! | ||
| 3469 | |||
| 3470 | reader\parse_line! until reader\eof! | ||
| 3471 | ``` | ||
| 3472 | <YueDisplay> | ||
| 3473 | |||
| 3474 | ```yue | ||
| 3475 | game\update! while game\isRunning! | ||
| 3476 | |||
| 3477 | reader\parse_line! until reader\eof! | ||
| 3478 | ``` | ||
| 3479 | |||
| 3480 | </YueDisplay> | ||
| 3481 | |||
| 3482 | ## Switch | ||
| 3483 | |||
| 3484 | The 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. | ||
| 3485 | |||
| 3486 | ```yuescript | ||
| 3487 | switch name := "Dan" | ||
| 3488 | when "Robert" | ||
| 3489 | print "You are Robert" | ||
| 3490 | when "Dan", "Daniel" | ||
| 3491 | print "Your name, it's Dan" | ||
| 3492 | else | ||
| 3493 | print "I don't know about you with name #{name}" | ||
| 3494 | ``` | ||
| 3495 | <YueDisplay> | ||
| 3496 | |||
| 3497 | ```yue | ||
| 3498 | switch name := "Dan" | ||
| 3499 | when "Robert" | ||
| 3500 | print "You are Robert" | ||
| 3501 | when "Dan", "Daniel" | ||
| 3502 | print "Your name, it's Dan" | ||
| 3503 | else | ||
| 3504 | print "I don't know about you with name #{name}" | ||
| 3505 | ``` | ||
| 3506 | |||
| 3507 | </YueDisplay> | ||
| 3508 | |||
| 3509 | A switch when clause can match against multiple values by listing them out comma separated. | ||
| 3510 | |||
| 3511 | Switches can be used as expressions as well, here we can assign the result of the switch to a variable: | ||
| 3512 | |||
| 3513 | ```yuescript | ||
| 3514 | b = 1 | ||
| 3515 | next_number = switch b | ||
| 3516 | when 1 | ||
| 3517 | 2 | ||
| 3518 | when 2 | ||
| 3519 | 3 | ||
| 3520 | else | ||
| 3521 | error "can't count that high!" | ||
| 3522 | ``` | ||
| 3523 | <YueDisplay> | ||
| 3524 | |||
| 3525 | ```yue | ||
| 3526 | b = 1 | ||
| 3527 | next_number = switch b | ||
| 3528 | when 1 | ||
| 3529 | 2 | ||
| 3530 | when 2 | ||
| 3531 | 3 | ||
| 3532 | else | ||
| 3533 | error "can't count that high!" | ||
| 3534 | ``` | ||
| 3535 | |||
| 3536 | </YueDisplay> | ||
| 3537 | |||
| 3538 | We 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. | ||
| 3539 | |||
| 3540 | ```yuescript | ||
| 3541 | msg = switch math.random(1, 5) | ||
| 3542 | when 1 then "you are lucky" | ||
| 3543 | when 2 then "you are almost lucky" | ||
| 3544 | else "not so lucky" | ||
| 3545 | ``` | ||
| 3546 | <YueDisplay> | ||
| 3547 | |||
| 3548 | ```yue | ||
| 3549 | msg = switch math.random(1, 5) | ||
| 3550 | when 1 then "you are lucky" | ||
| 3551 | when 2 then "you are almost lucky" | ||
| 3552 | else "not so lucky" | ||
| 3553 | ``` | ||
| 3554 | |||
| 3555 | </YueDisplay> | ||
| 3556 | |||
| 3557 | If 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. | ||
| 3558 | |||
| 3559 | ```yuescript | ||
| 3560 | switch math.random(1, 5) | ||
| 3561 | when 1 | ||
| 3562 | print "you are lucky" -- two indents | ||
| 3563 | else | ||
| 3564 | print "not so lucky" | ||
| 3565 | |||
| 3566 | switch math.random(1, 5) when 1 | ||
| 3567 | print "you are lucky" -- one indent | ||
| 3568 | else | ||
| 3569 | print "not so lucky" | ||
| 3570 | ``` | ||
| 3571 | <YueDisplay> | ||
| 3572 | |||
| 3573 | ```yue | ||
| 3574 | switch math.random(1, 5) | ||
| 3575 | when 1 | ||
| 3576 | print "you are lucky" -- two indents | ||
| 3577 | else | ||
| 3578 | print "not so lucky" | ||
| 3579 | |||
| 3580 | switch math.random(1, 5) when 1 | ||
| 3581 | print "you are lucky" -- one indent | ||
| 3582 | else | ||
| 3583 | print "not so lucky" | ||
| 3584 | ``` | ||
| 3585 | |||
| 3586 | </YueDisplay> | ||
| 3587 | |||
| 3588 | It 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. | ||
| 3589 | |||
| 3590 | ### Table Matching | ||
| 3591 | |||
| 3592 | You can do table matching in a switch when clause, if the table can be destructured by a specific structure and get non-nil values. | ||
| 3593 | |||
| 3594 | ```yuescript | ||
| 3595 | items = | ||
| 3596 | * x: 100 | ||
| 3597 | y: 200 | ||
| 3598 | * width: 300 | ||
| 3599 | height: 400 | ||
| 3600 | |||
| 3601 | for item in *items | ||
| 3602 | switch item | ||
| 3603 | when :x, :y | ||
| 3604 | print "Vec2 #{x}, #{y}" | ||
| 3605 | when :width, :height | ||
| 3606 | print "size #{width}, #{height}" | ||
| 3607 | ``` | ||
| 3608 | <YueDisplay> | ||
| 3609 | |||
| 3610 | ```yue | ||
| 3611 | items = | ||
| 3612 | * x: 100 | ||
| 3613 | y: 200 | ||
| 3614 | * width: 300 | ||
| 3615 | height: 400 | ||
| 3616 | |||
| 3617 | for item in *items | ||
| 3618 | switch item | ||
| 3619 | when :x, :y | ||
| 3620 | print "Vec2 #{x}, #{y}" | ||
| 3621 | when :width, :height | ||
| 3622 | print "size #{width}, #{height}" | ||
| 3623 | ``` | ||
| 3624 | |||
| 3625 | </YueDisplay> | ||
| 3626 | |||
| 3627 | You can use default values to optionally destructure the table for some fields. | ||
| 3628 | |||
| 3629 | ```yuescript | ||
| 3630 | item = {} | ||
| 3631 | |||
| 3632 | {pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos') | ||
| 3633 | |||
| 3634 | switch item | ||
| 3635 | when {pos: {:x = 50, :y = 200}} | ||
| 3636 | print "Vec2 #{x}, #{y}" -- table destructuring will still pass | ||
| 3637 | ``` | ||
| 3638 | <YueDisplay> | ||
| 3639 | |||
| 3640 | ```yue | ||
| 3641 | item = {} | ||
| 3642 | |||
| 3643 | {pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos') | ||
| 3644 | |||
| 3645 | switch item | ||
| 3646 | when {pos: {:x = 50, :y = 200}} | ||
| 3647 | print "Vec2 #{x}, #{y}" -- table destructuring will still pass | ||
| 3648 | ``` | ||
| 3649 | |||
| 3650 | </YueDisplay> | ||
| 3651 | |||
| 3652 | You can also match against array elements, table fields, and even nested structures with array or table literals. | ||
| 3653 | |||
| 3654 | Match against array elements. | ||
| 3655 | |||
| 3656 | ```yuescript | ||
| 3657 | switch tb | ||
| 3658 | when [1, 2, 3] | ||
| 3659 | print "1, 2, 3" | ||
| 3660 | when [1, b, 3] | ||
| 3661 | print "1, #{b}, 3" | ||
| 3662 | when [1, 2, b = 3] -- b has a default value | ||
| 3663 | print "1, 2, #{b}" | ||
| 3664 | ``` | ||
| 3665 | <YueDisplay> | ||
| 3666 | |||
| 3667 | ```yue | ||
| 3668 | switch tb | ||
| 3669 | when [1, 2, 3] | ||
| 3670 | print "1, 2, 3" | ||
| 3671 | when [1, b, 3] | ||
| 3672 | print "1, #{b}, 3" | ||
| 3673 | when [1, 2, b = 3] -- b has a default value | ||
| 3674 | print "1, 2, #{b}" | ||
| 3675 | ``` | ||
| 3676 | |||
| 3677 | </YueDisplay> | ||
| 3678 | |||
| 3679 | Match against table fields with destructuring. | ||
| 3680 | |||
| 3681 | ```yuescript | ||
| 3682 | switch tb | ||
| 3683 | when success: true, :result | ||
| 3684 | print "success", result | ||
| 3685 | when success: false | ||
| 3686 | print "failed", result | ||
| 3687 | else | ||
| 3688 | print "invalid" | ||
| 3689 | ``` | ||
| 3690 | <YueDisplay> | ||
| 3691 | |||
| 3692 | ```yue | ||
| 3693 | switch tb | ||
| 3694 | when success: true, :result | ||
| 3695 | print "success", result | ||
| 3696 | when success: false | ||
| 3697 | print "failed", result | ||
| 3698 | else | ||
| 3699 | print "invalid" | ||
| 3700 | ``` | ||
| 3701 | |||
| 3702 | </YueDisplay> | ||
| 3703 | |||
| 3704 | Match against nested table structures. | ||
| 3705 | |||
| 3706 | ```yuescript | ||
| 3707 | switch tb | ||
| 3708 | when data: {type: "success", :content} | ||
| 3709 | print "success", content | ||
| 3710 | when data: {type: "error", :content} | ||
| 3711 | print "failed", content | ||
| 3712 | else | ||
| 3713 | print "invalid" | ||
| 3714 | ``` | ||
| 3715 | <YueDisplay> | ||
| 3716 | |||
| 3717 | ```yue | ||
| 3718 | switch tb | ||
| 3719 | when data: {type: "success", :content} | ||
| 3720 | print "success", content | ||
| 3721 | when data: {type: "error", :content} | ||
| 3722 | print "failed", content | ||
| 3723 | else | ||
| 3724 | print "invalid" | ||
| 3725 | ``` | ||
| 3726 | |||
| 3727 | </YueDisplay> | ||
| 3728 | |||
| 3729 | Match against array of tables. | ||
| 3730 | |||
| 3731 | ```yuescript | ||
| 3732 | switch tb | ||
| 3733 | when [ | ||
| 3734 | {a: 1, b: 2} | ||
| 3735 | {a: 3, b: 4} | ||
| 3736 | {a: 5, b: 6} | ||
| 3737 | fourth | ||
| 3738 | ] | ||
| 3739 | print "matched", fourth | ||
| 3740 | ``` | ||
| 3741 | <YueDisplay> | ||
| 3742 | |||
| 3743 | ```yue | ||
| 3744 | switch tb | ||
| 3745 | when [ | ||
| 3746 | {a: 1, b: 2} | ||
| 3747 | {a: 3, b: 4} | ||
| 3748 | {a: 5, b: 6} | ||
| 3749 | fourth | ||
| 3750 | ] | ||
| 3751 | print "matched", fourth | ||
| 3752 | ``` | ||
| 3753 | |||
| 3754 | </YueDisplay> | ||
| 3755 | |||
| 3756 | Match against a list and capture a range of elements. | ||
| 3757 | |||
| 3758 | ```yuescript | ||
| 3759 | segments = ["admin", "users", "logs", "view"] | ||
| 3760 | switch segments | ||
| 3761 | when [...groups, resource, action] | ||
| 3762 | print "Group:", groups -- prints: {"admin", "users"} | ||
| 3763 | print "Resource:", resource -- prints: "logs" | ||
| 3764 | print "Action:", action -- prints: "view" | ||
| 3765 | ``` | ||
| 3766 | <YueDisplay> | ||
| 3767 | |||
| 3768 | ```yue | ||
| 3769 | segments = ["admin", "users", "logs", "view"] | ||
| 3770 | switch segments | ||
| 3771 | when [...groups, resource, action] | ||
| 3772 | print "Group:", groups -- prints: {"admin", "users"} | ||
| 3773 | print "Resource:", resource -- prints: "logs" | ||
| 3774 | print "Action:", action -- prints: "view" | ||
| 3775 | ``` | ||
| 3776 | |||
| 3777 | </YueDisplay> | ||
| 3778 | |||
| 3779 | ## Object Oriented Programming | ||
| 3780 | |||
| 3781 | In 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. | ||
| 3782 | |||
| 3783 | A simple class: | ||
| 3784 | |||
| 3785 | ```yuescript | ||
| 3786 | class Inventory | ||
| 3787 | new: => | ||
| 3788 | @items = {} | ||
| 3789 | |||
| 3790 | add_item: (name) => | ||
| 3791 | if @items[name] | ||
| 3792 | @items[name] += 1 | ||
| 3793 | else | ||
| 3794 | @items[name] = 1 | ||
| 3795 | ``` | ||
| 3796 | <YueDisplay> | ||
| 3797 | |||
| 3798 | ```yue | ||
| 3799 | class Inventory | ||
| 3800 | new: => | ||
| 3801 | @items = {} | ||
| 3802 | |||
| 3803 | add_item: (name) => | ||
| 3804 | if @items[name] | ||
| 3805 | @items[name] += 1 | ||
| 3806 | else | ||
| 3807 | @items[name] = 1 | ||
| 3808 | ``` | ||
| 3809 | |||
| 3810 | </YueDisplay> | ||
| 3811 | |||
| 3812 | A class is declared with a class statement followed by a table-like declaration where all of the methods and properties are listed. | ||
| 3813 | |||
| 3814 | The new property is special in that it will become the constructor. | ||
| 3815 | |||
| 3816 | Notice 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. | ||
| 3817 | |||
| 3818 | The @ prefix on a variable name is shorthand for self.. @items becomes self.items. | ||
| 3819 | |||
| 3820 | Creating an instance of the class is done by calling the name of the class as a function. | ||
| 3821 | |||
| 3822 | ```yuescript | ||
| 3823 | inv = Inventory! | ||
| 3824 | inv\add_item "t-shirt" | ||
| 3825 | inv\add_item "pants" | ||
| 3826 | ``` | ||
| 3827 | <YueDisplay> | ||
| 3828 | |||
| 3829 | ```yue | ||
| 3830 | inv = Inventory! | ||
| 3831 | inv\add_item "t-shirt" | ||
| 3832 | inv\add_item "pants" | ||
| 3833 | ``` | ||
| 3834 | |||
| 3835 | </YueDisplay> | ||
| 3836 | |||
| 3837 | Because the instance of the class needs to be sent to the methods when they are called, the \ operator is used. | ||
| 3838 | |||
| 3839 | All properties of a class are shared among the instances. This is fine for functions, but for other types of objects, undesired results may occur. | ||
| 3840 | |||
| 3841 | Consider the example below, the clothes property is shared amongst all instances, so modifications to it in one instance will show up in another: | ||
| 3842 | |||
| 3843 | ```yuescript | ||
| 3844 | class Person | ||
| 3845 | clothes: [] | ||
| 3846 | give_item: (name) => | ||
| 3847 | table.insert @clothes, name | ||
| 3848 | |||
| 3849 | a = Person! | ||
| 3850 | b = Person! | ||
| 3851 | |||
| 3852 | a\give_item "pants" | ||
| 3853 | b\give_item "shirt" | ||
| 3854 | |||
| 3855 | -- will print both pants and shirt | ||
| 3856 | print item for item in *a.clothes | ||
| 3857 | ``` | ||
| 3858 | <YueDisplay> | ||
| 3859 | |||
| 3860 | ```yue | ||
| 3861 | class Person | ||
| 3862 | clothes: [] | ||
| 3863 | give_item: (name) => | ||
| 3864 | table.insert @clothes, name | ||
| 3865 | |||
| 3866 | a = Person! | ||
| 3867 | b = Person! | ||
| 3868 | |||
| 3869 | a\give_item "pants" | ||
| 3870 | b\give_item "shirt" | ||
| 3871 | |||
| 3872 | -- will print both pants and shirt | ||
| 3873 | print item for item in *a.clothes | ||
| 3874 | ``` | ||
| 3875 | |||
| 3876 | </YueDisplay> | ||
| 3877 | |||
| 3878 | The proper way to avoid this problem is to create the mutable state of the object in the constructor: | ||
| 3879 | |||
| 3880 | ```yuescript | ||
| 3881 | class Person | ||
| 3882 | new: => | ||
| 3883 | @clothes = [] | ||
| 3884 | ``` | ||
| 3885 | <YueDisplay> | ||
| 3886 | |||
| 3887 | ```yue | ||
| 3888 | class Person | ||
| 3889 | new: => | ||
| 3890 | @clothes = [] | ||
| 3891 | ``` | ||
| 3892 | |||
| 3893 | </YueDisplay> | ||
| 3894 | |||
| 3895 | ### Inheritance | ||
| 3896 | |||
| 3897 | The extends keyword can be used in a class declaration to inherit the properties and methods from another class. | ||
| 3898 | |||
| 3899 | ```yuescript | ||
| 3900 | class BackPack extends Inventory | ||
| 3901 | size: 10 | ||
| 3902 | add_item: (name) => | ||
| 3903 | if #@items > size then error "backpack is full" | ||
| 3904 | super name | ||
| 3905 | ``` | ||
| 3906 | <YueDisplay> | ||
| 3907 | |||
| 3908 | ```yue | ||
| 3909 | class BackPack extends Inventory | ||
| 3910 | size: 10 | ||
| 3911 | add_item: (name) => | ||
| 3912 | if #@items > size then error "backpack is full" | ||
| 3913 | super name | ||
| 3914 | ``` | ||
| 3915 | |||
| 3916 | </YueDisplay> | ||
| 3917 | |||
| 3918 | Here we extend our Inventory class, and limit the amount of items it can carry. | ||
| 3919 | |||
| 3920 | In 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. | ||
| 3921 | |||
| 3922 | Whenever 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. | ||
| 3923 | |||
| 3924 | ```yuescript | ||
| 3925 | class Shelf | ||
| 3926 | @__inherited: (child) => | ||
| 3927 | print @__name, "was inherited by", child.__name | ||
| 3928 | |||
| 3929 | -- will print: Shelf was inherited by Cupboard | ||
| 3930 | class Cupboard extends Shelf | ||
| 3931 | ``` | ||
| 3932 | <YueDisplay> | ||
| 3933 | |||
| 3934 | ```yue | ||
| 3935 | class Shelf | ||
| 3936 | @__inherited: (child) => | ||
| 3937 | print @__name, "was inherited by", child.__name | ||
| 3938 | |||
| 3939 | -- will print: Shelf was inherited by Cupboard | ||
| 3940 | class Cupboard extends Shelf | ||
| 3941 | ``` | ||
| 3942 | |||
| 3943 | </YueDisplay> | ||
| 3944 | |||
| 3945 | ### Super | ||
| 3946 | |||
| 3947 | **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. | ||
| 3948 | |||
| 3949 | When 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) | ||
| 3950 | |||
| 3951 | When super is used as a normal value, it is a reference to the parent class object. | ||
| 3952 | |||
| 3953 | It 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. | ||
| 3954 | |||
| 3955 | When 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. | ||
| 3956 | |||
| 3957 | A few examples of using super in different ways: | ||
| 3958 | |||
| 3959 | ```yuescript | ||
| 3960 | class MyClass extends ParentClass | ||
| 3961 | a_method: => | ||
| 3962 | -- the following have the same effect: | ||
| 3963 | super "hello", "world" | ||
| 3964 | super\a_method "hello", "world" | ||
| 3965 | super.a_method self, "hello", "world" | ||
| 3966 | |||
| 3967 | -- super as a value is equal to the parent class: | ||
| 3968 | assert super == ParentClass | ||
| 3969 | ``` | ||
| 3970 | <YueDisplay> | ||
| 3971 | |||
| 3972 | ```yue | ||
| 3973 | class MyClass extends ParentClass | ||
| 3974 | a_method: => | ||
| 3975 | -- the following have the same effect: | ||
| 3976 | super "hello", "world" | ||
| 3977 | super\a_method "hello", "world" | ||
| 3978 | super.a_method self, "hello", "world" | ||
| 3979 | |||
| 3980 | -- super as a value is equal to the parent class: | ||
| 3981 | assert super == ParentClass | ||
| 3982 | ``` | ||
| 3983 | |||
| 3984 | </YueDisplay> | ||
| 3985 | |||
| 3986 | **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. | ||
| 3987 | |||
| 3988 | ### Types | ||
| 3989 | |||
| 3990 | Every 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. | ||
| 3991 | |||
| 3992 | ```yuescript | ||
| 3993 | b = BackPack! | ||
| 3994 | assert b.__class == BackPack | ||
| 3995 | |||
| 3996 | print BackPack.size -- prints 10 | ||
| 3997 | ``` | ||
| 3998 | <YueDisplay> | ||
| 3999 | |||
| 4000 | ```yue | ||
| 4001 | b = BackPack! | ||
| 4002 | assert b.__class == BackPack | ||
| 4003 | |||
| 4004 | print BackPack.size -- prints 10 | ||
| 4005 | ``` | ||
| 4006 | |||
| 4007 | </YueDisplay> | ||
| 4008 | |||
| 4009 | ### Class Objects | ||
| 4010 | |||
| 4011 | The 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. | ||
| 4012 | |||
| 4013 | The 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. | ||
| 4014 | |||
| 4015 | A 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. | ||
| 4016 | |||
| 4017 | The 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. | ||
| 4018 | |||
| 4019 | It 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. | ||
| 4020 | |||
| 4021 | The class object has a couple special properties: | ||
| 4022 | |||
| 4023 | The name of the class as when it was declared is stored as a string in the __name field of the class object. | ||
| 4024 | |||
| 4025 | ```yuescript | ||
| 4026 | print BackPack.__name -- prints Backpack | ||
| 4027 | ``` | ||
| 4028 | <YueDisplay> | ||
| 4029 | |||
| 4030 | ```yue | ||
| 4031 | print BackPack.__name -- prints Backpack | ||
| 4032 | ``` | ||
| 4033 | |||
| 4034 | </YueDisplay> | ||
| 4035 | |||
| 4036 | The 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. | ||
| 4037 | |||
| 4038 | If the class extends from anything, the parent class object is stored in __parent. | ||
| 4039 | |||
| 4040 | ### Class Variables | ||
| 4041 | |||
| 4042 | We 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. | ||
| 4043 | |||
| 4044 | ```yuescript | ||
| 4045 | class Things | ||
| 4046 | @some_func: => print "Hello from", @__name | ||
| 4047 | |||
| 4048 | Things\some_func! | ||
| 4049 | |||
| 4050 | -- class variables not visible in instances | ||
| 4051 | assert Things().some_func == nil | ||
| 4052 | ``` | ||
| 4053 | <YueDisplay> | ||
| 4054 | |||
| 4055 | ```yue | ||
| 4056 | class Things | ||
| 4057 | @some_func: => print "Hello from", @__name | ||
| 4058 | |||
| 4059 | Things\some_func! | ||
| 4060 | |||
| 4061 | -- class variables not visible in instances | ||
| 4062 | assert Things().some_func == nil | ||
| 4063 | ``` | ||
| 4064 | |||
| 4065 | </YueDisplay> | ||
| 4066 | |||
| 4067 | In expressions, we can use @@ to access a value that is stored in the __class of self. Thus, @@hello is shorthand for self.__class.hello. | ||
| 4068 | |||
| 4069 | ```yuescript | ||
| 4070 | class Counter | ||
| 4071 | @count: 0 | ||
| 4072 | |||
| 4073 | new: => | ||
| 4074 | @@count += 1 | ||
| 4075 | |||
| 4076 | Counter! | ||
| 4077 | Counter! | ||
| 4078 | |||
| 4079 | print Counter.count -- prints 2 | ||
| 4080 | ``` | ||
| 4081 | <YueDisplay> | ||
| 4082 | |||
| 4083 | ```yue | ||
| 4084 | class Counter | ||
| 4085 | @count: 0 | ||
| 4086 | |||
| 4087 | new: => | ||
| 4088 | @@count += 1 | ||
| 4089 | |||
| 4090 | Counter! | ||
| 4091 | Counter! | ||
| 4092 | |||
| 4093 | print Counter.count -- prints 2 | ||
| 4094 | ``` | ||
| 4095 | |||
| 4096 | </YueDisplay> | ||
| 4097 | |||
| 4098 | The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax. | ||
| 4099 | |||
| 4100 | ```yuescript | ||
| 4101 | @@hello 1,2,3,4 | ||
| 4102 | ``` | ||
| 4103 | <YueDisplay> | ||
| 4104 | |||
| 4105 | ```yue | ||
| 4106 | @@hello 1,2,3,4 | ||
| 4107 | ``` | ||
| 4108 | |||
| 4109 | </YueDisplay> | ||
| 4110 | |||
| 4111 | ### Class Declaration Statements | ||
| 4112 | |||
| 4113 | In 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. | ||
| 4114 | |||
| 4115 | Here is an alternative way to create a class variable compared to what's described above: | ||
| 4116 | |||
| 4117 | ```yuescript | ||
| 4118 | class Things | ||
| 4119 | @class_var = "hello world" | ||
| 4120 | ``` | ||
| 4121 | <YueDisplay> | ||
| 4122 | |||
| 4123 | ```yue | ||
| 4124 | class Things | ||
| 4125 | @class_var = "hello world" | ||
| 4126 | ``` | ||
| 4127 | |||
| 4128 | </YueDisplay> | ||
| 4129 | |||
| 4130 | These expressions are executed after all the properties have been added to the base. | ||
| 4131 | |||
| 4132 | All 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: | ||
| 4133 | |||
| 4134 | ```yuescript | ||
| 4135 | class MoreThings | ||
| 4136 | secret = 123 | ||
| 4137 | log = (msg) -> print "LOG:", msg | ||
| 4138 | |||
| 4139 | some_method: => | ||
| 4140 | log "hello world: " .. secret | ||
| 4141 | ``` | ||
| 4142 | <YueDisplay> | ||
| 4143 | |||
| 4144 | ```yue | ||
| 4145 | class MoreThings | ||
| 4146 | secret = 123 | ||
| 4147 | log = (msg) -> print "LOG:", msg | ||
| 4148 | |||
| 4149 | some_method: => | ||
| 4150 | log "hello world: " .. secret | ||
| 4151 | ``` | ||
| 4152 | |||
| 4153 | </YueDisplay> | ||
| 4154 | |||
| 4155 | ### @ and @@ Values | ||
| 4156 | |||
| 4157 | When @ and @@ are prefixed in front of a name they represent, respectively, that name accessed in self and self.__class. | ||
| 4158 | |||
| 4159 | If they are used all by themselves, they are aliases for self and self.__class. | ||
| 4160 | |||
| 4161 | ```yuescript | ||
| 4162 | assert @ == self | ||
| 4163 | assert @@ == self.__class | ||
| 4164 | ``` | ||
| 4165 | <YueDisplay> | ||
| 4166 | |||
| 4167 | ```yue | ||
| 4168 | assert @ == self | ||
| 4169 | assert @@ == self.__class | ||
| 4170 | ``` | ||
| 4171 | |||
| 4172 | </YueDisplay> | ||
| 4173 | |||
| 4174 | For example, a quick way to create a new instance of the same class from an instance method using @@: | ||
| 4175 | |||
| 4176 | ```yuescript | ||
| 4177 | some_instance_method = (...) => @@ ... | ||
| 4178 | ``` | ||
| 4179 | <YueDisplay> | ||
| 4180 | |||
| 4181 | ```yue | ||
| 4182 | some_instance_method = (...) => @@ ... | ||
| 4183 | ``` | ||
| 4184 | |||
| 4185 | </YueDisplay> | ||
| 4186 | |||
| 4187 | ### Constructor Property Promotion | ||
| 4188 | |||
| 4189 | To reduce the boilerplate code for definition of simple value objects. You can write a simple class like: | ||
| 4190 | |||
| 4191 | ```yuescript | ||
| 4192 | class Something | ||
| 4193 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 4194 | |||
| 4195 | -- Which is short for | ||
| 4196 | |||
| 4197 | class Something | ||
| 4198 | new: (foo, bar, biz, baz) => | ||
| 4199 | @foo = foo | ||
| 4200 | @bar = bar | ||
| 4201 | @@biz = biz | ||
| 4202 | @@baz = baz | ||
| 4203 | ``` | ||
| 4204 | <YueDisplay> | ||
| 4205 | |||
| 4206 | ```yue | ||
| 4207 | class Something | ||
| 4208 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 4209 | |||
| 4210 | -- Which is short for | ||
| 4211 | |||
| 4212 | class Something | ||
| 4213 | new: (foo, bar, biz, baz) => | ||
| 4214 | @foo = foo | ||
| 4215 | @bar = bar | ||
| 4216 | @@biz = biz | ||
| 4217 | @@baz = baz | ||
| 4218 | ``` | ||
| 4219 | |||
| 4220 | </YueDisplay> | ||
| 4221 | |||
| 4222 | You can also use this syntax for a common function to initialize a object's fields. | ||
| 4223 | |||
| 4224 | ```yuescript | ||
| 4225 | new = (@fieldA, @fieldB) => @ | ||
| 4226 | obj = new {}, 123, "abc" | ||
| 4227 | print obj | ||
| 4228 | ``` | ||
| 4229 | <YueDisplay> | ||
| 4230 | |||
| 4231 | ```yue | ||
| 4232 | new = (@fieldA, @fieldB) => @ | ||
| 4233 | obj = new {}, 123, "abc" | ||
| 4234 | print obj | ||
| 4235 | ``` | ||
| 4236 | |||
| 4237 | </YueDisplay> | ||
| 4238 | |||
| 4239 | ### Class Expressions | ||
| 4240 | |||
| 4241 | The class syntax can also be used as an expression which can be assigned to a variable or explicitly returned. | ||
| 4242 | |||
| 4243 | ```yuescript | ||
| 4244 | x = class Bucket | ||
| 4245 | drops: 0 | ||
| 4246 | add_drop: => @drops += 1 | ||
| 4247 | ``` | ||
| 4248 | <YueDisplay> | ||
| 4249 | |||
| 4250 | ```yue | ||
| 4251 | x = class Bucket | ||
| 4252 | drops: 0 | ||
| 4253 | add_drop: => @drops += 1 | ||
| 4254 | ``` | ||
| 4255 | |||
| 4256 | </YueDisplay> | ||
| 4257 | |||
| 4258 | ### Anonymous classes | ||
| 4259 | |||
| 4260 | The 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. | ||
| 4261 | |||
| 4262 | ```yuescript | ||
| 4263 | BigBucket = class extends Bucket | ||
| 4264 | add_drop: => @drops += 10 | ||
| 4265 | |||
| 4266 | assert Bucket.__name == "BigBucket" | ||
| 4267 | ``` | ||
| 4268 | <YueDisplay> | ||
| 4269 | |||
| 4270 | ```yue | ||
| 4271 | BigBucket = class extends Bucket | ||
| 4272 | add_drop: => @drops += 10 | ||
| 4273 | |||
| 4274 | assert Bucket.__name == "BigBucket" | ||
| 4275 | ``` | ||
| 4276 | |||
| 4277 | </YueDisplay> | ||
| 4278 | |||
| 4279 | You can even leave off the body, meaning you can write a blank anonymous class like this: | ||
| 4280 | |||
| 4281 | ```yuescript | ||
| 4282 | x = class | ||
| 4283 | ``` | ||
| 4284 | <YueDisplay> | ||
| 4285 | |||
| 4286 | ```yue | ||
| 4287 | x = class | ||
| 4288 | ``` | ||
| 4289 | |||
| 4290 | </YueDisplay> | ||
| 4291 | |||
| 4292 | ### Class Mixing | ||
| 4293 | |||
| 4294 | You 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. | ||
| 4295 | |||
| 4296 | ```yuescript | ||
| 4297 | MyIndex = __index: var: 1 | ||
| 4298 | |||
| 4299 | class X using MyIndex | ||
| 4300 | func: => | ||
| 4301 | print 123 | ||
| 4302 | |||
| 4303 | x = X! | ||
| 4304 | print x.var | ||
| 4305 | |||
| 4306 | class Y using X | ||
| 4307 | |||
| 4308 | y = Y! | ||
| 4309 | y\func! | ||
| 4310 | |||
| 4311 | assert y.__class.__parent ~= X -- X is not parent of Y | ||
| 4312 | ``` | ||
| 4313 | <YueDisplay> | ||
| 4314 | |||
| 4315 | ```yue | ||
| 4316 | MyIndex = __index: var: 1 | ||
| 4317 | |||
| 4318 | class X using MyIndex | ||
| 4319 | func: => | ||
| 4320 | print 123 | ||
| 4321 | |||
| 4322 | x = X! | ||
| 4323 | print x.var | ||
| 4324 | |||
| 4325 | class Y using X | ||
| 4326 | |||
| 4327 | y = Y! | ||
| 4328 | y\func! | ||
| 4329 | |||
| 4330 | assert y.__class.__parent ~= X -- X is not parent of Y | ||
| 4331 | ``` | ||
| 4332 | |||
| 4333 | </YueDisplay> | ||
| 4334 | |||
| 4335 | ## With Statement | ||
| 4336 | |||
| 4337 | A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it. | ||
| 4338 | |||
| 4339 | This 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. | ||
| 4340 | |||
| 4341 | The 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. | ||
| 4342 | |||
| 4343 | For example, we work with a newly created object: | ||
| 4344 | |||
| 4345 | ```yuescript | ||
| 4346 | with Person! | ||
| 4347 | .name = "Oswald" | ||
| 4348 | \add_relative my_dad | ||
| 4349 | \save! | ||
| 4350 | print .name | ||
| 4351 | ``` | ||
| 4352 | <YueDisplay> | ||
| 4353 | |||
| 4354 | ```yue | ||
| 4355 | with Person! | ||
| 4356 | .name = "Oswald" | ||
| 4357 | \add_relative my_dad | ||
| 4358 | \save! | ||
| 4359 | print .name | ||
| 4360 | ``` | ||
| 4361 | |||
| 4362 | </YueDisplay> | ||
| 4363 | |||
| 4364 | The with statement can also be used as an expression which returns the value it has been giving access to. | ||
| 4365 | |||
| 4366 | ```yuescript | ||
| 4367 | file = with File "favorite_foods.txt" | ||
| 4368 | \set_encoding "utf8" | ||
| 4369 | ``` | ||
| 4370 | <YueDisplay> | ||
| 4371 | |||
| 4372 | ```yue | ||
| 4373 | file = with File "favorite_foods.txt" | ||
| 4374 | \set_encoding "utf8" | ||
| 4375 | ``` | ||
| 4376 | |||
| 4377 | </YueDisplay> | ||
| 4378 | |||
| 4379 | Or… | ||
| 4380 | |||
| 4381 | ```yuescript | ||
| 4382 | create_person = (name, relatives) -> | ||
| 4383 | with Person! | ||
| 4384 | .name = name | ||
| 4385 | \add_relative relative for relative in *relatives | ||
| 4386 | |||
| 4387 | me = create_person "Leaf", [dad, mother, sister] | ||
| 4388 | ``` | ||
| 4389 | <YueDisplay> | ||
| 4390 | |||
| 4391 | ```yue | ||
| 4392 | create_person = (name, relatives) -> | ||
| 4393 | with Person! | ||
| 4394 | .name = name | ||
| 4395 | \add_relative relative for relative in *relatives | ||
| 4396 | |||
| 4397 | me = create_person "Leaf", [dad, mother, sister] | ||
| 4398 | ``` | ||
| 4399 | |||
| 4400 | </YueDisplay> | ||
| 4401 | |||
| 4402 | In this usage, with can be seen as a special form of the K combinator. | ||
| 4403 | |||
| 4404 | The expression in the with statement can also be an assignment, if you want to give a name to the expression. | ||
| 4405 | |||
| 4406 | ```yuescript | ||
| 4407 | with str := "Hello" | ||
| 4408 | print "original:", str | ||
| 4409 | print "upper:", \upper! | ||
| 4410 | ``` | ||
| 4411 | <YueDisplay> | ||
| 4412 | |||
| 4413 | ```yue | ||
| 4414 | with str := "Hello" | ||
| 4415 | print "original:", str | ||
| 4416 | print "upper:", \upper! | ||
| 4417 | ``` | ||
| 4418 | |||
| 4419 | </YueDisplay> | ||
| 4420 | |||
| 4421 | You can access special keys with `[]` in a `with` statement. | ||
| 4422 | |||
| 4423 | ```yuescript | ||
| 4424 | with tb | ||
| 4425 | [1] = 1 | ||
| 4426 | print [2] | ||
| 4427 | with [abc] | ||
| 4428 | [3] = [2]\func! | ||
| 4429 | ["key-name"] = value | ||
| 4430 | [] = "abc" -- appending to "tb" | ||
| 4431 | ``` | ||
| 4432 | <YueDisplay> | ||
| 4433 | |||
| 4434 | ```yue | ||
| 4435 | with tb | ||
| 4436 | [1] = 1 | ||
| 4437 | print [2] | ||
| 4438 | with [abc] | ||
| 4439 | [3] = [2]\func! | ||
| 4440 | ["key-name"] = value | ||
| 4441 | [] = "abc" -- appending to "tb" | ||
| 4442 | ``` | ||
| 4443 | |||
| 4444 | </YueDisplay> | ||
| 4445 | |||
| 4446 | `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. | ||
| 4447 | |||
| 4448 | ```yuescript | ||
| 4449 | with? obj | ||
| 4450 | print obj.name | ||
| 4451 | ``` | ||
| 4452 | <YueDisplay> | ||
| 4453 | |||
| 4454 | ```yue | ||
| 4455 | with? obj | ||
| 4456 | print obj.name | ||
| 4457 | ``` | ||
| 4458 | |||
| 4459 | </YueDisplay> | ||
| 4460 | |||
| 4461 | ## Do | ||
| 4462 | |||
| 4463 | When used as a statement, do works just like it does in Lua. | ||
| 4464 | |||
| 4465 | ```yuescript | ||
| 4466 | do | ||
| 4467 | var = "hello" | ||
| 4468 | print var | ||
| 4469 | print var -- nil here | ||
| 4470 | ``` | ||
| 4471 | <YueDisplay> | ||
| 4472 | |||
| 4473 | ```yue | ||
| 4474 | do | ||
| 4475 | var = "hello" | ||
| 4476 | print var | ||
| 4477 | print var -- nil here | ||
| 4478 | ``` | ||
| 4479 | |||
| 4480 | </YueDisplay> | ||
| 4481 | |||
| 4482 | YueScript'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. | ||
| 4483 | |||
| 4484 | ```yuescript | ||
| 4485 | counter = do | ||
| 4486 | i = 0 | ||
| 4487 | -> | ||
| 4488 | i += 1 | ||
| 4489 | i | ||
| 4490 | |||
| 4491 | print counter! | ||
| 4492 | print counter! | ||
| 4493 | ``` | ||
| 4494 | <YueDisplay> | ||
| 4495 | |||
| 4496 | ```yue | ||
| 4497 | counter = do | ||
| 4498 | i = 0 | ||
| 4499 | -> | ||
| 4500 | i += 1 | ||
| 4501 | i | ||
| 4502 | |||
| 4503 | print counter! | ||
| 4504 | print counter! | ||
| 4505 | ``` | ||
| 4506 | |||
| 4507 | </YueDisplay> | ||
| 4508 | |||
| 4509 | ```yuescript | ||
| 4510 | tbl = { | ||
| 4511 | key: do | ||
| 4512 | print "assigning key!" | ||
| 4513 | 1234 | ||
| 4514 | } | ||
| 4515 | ``` | ||
| 4516 | <YueDisplay> | ||
| 4517 | |||
| 4518 | ```yue | ||
| 4519 | tbl = { | ||
| 4520 | key: do | ||
| 4521 | print "assigning key!" | ||
| 4522 | 1234 | ||
| 4523 | } | ||
| 4524 | ``` | ||
| 4525 | |||
| 4526 | </YueDisplay> | ||
| 4527 | |||
| 4528 | ## Function Stubs | ||
| 4529 | |||
| 4530 | It 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. | ||
| 4531 | |||
| 4532 | The 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. | ||
| 4533 | |||
| 4534 | Its syntax is the same as calling an instance method with the \ operator but with no argument list provided. | ||
| 4535 | |||
| 4536 | ```yuescript | ||
| 4537 | my_object = { | ||
| 4538 | value: 1000 | ||
| 4539 | write: => print "the value:", @value | ||
| 4540 | } | ||
| 4541 | |||
| 4542 | run_callback = (func) -> | ||
| 4543 | print "running callback..." | ||
| 4544 | func! | ||
| 4545 | |||
| 4546 | -- this will not work: | ||
| 4547 | -- the function has to no reference to my_object | ||
| 4548 | run_callback my_object.write | ||
| 4549 | |||
| 4550 | -- function stub syntax | ||
| 4551 | -- lets us bundle the object into a new function | ||
| 4552 | run_callback my_object\write | ||
| 4553 | ``` | ||
| 4554 | <YueDisplay> | ||
| 4555 | |||
| 4556 | ```yue | ||
| 4557 | my_object = { | ||
| 4558 | value: 1000 | ||
| 4559 | write: => print "the value:", @value | ||
| 4560 | } | ||
| 4561 | |||
| 4562 | run_callback = (func) -> | ||
| 4563 | print "running callback..." | ||
| 4564 | func! | ||
| 4565 | |||
| 4566 | -- this will not work: | ||
| 4567 | -- the function has to no reference to my_object | ||
| 4568 | run_callback my_object.write | ||
| 4569 | |||
| 4570 | -- function stub syntax | ||
| 4571 | -- lets us bundle the object into a new function | ||
| 4572 | run_callback my_object\write | ||
| 4573 | ``` | ||
| 4574 | |||
| 4575 | </YueDisplay> | ||
| 4576 | |||
| 4577 | ## The Using Clause; Controlling Destructive Assignment | ||
| 4578 | |||
| 4579 | While 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: | ||
| 4580 | |||
| 4581 | ```yuescript | ||
| 4582 | i = 100 | ||
| 4583 | |||
| 4584 | -- many lines of code... | ||
| 4585 | |||
| 4586 | my_func = -> | ||
| 4587 | i = 10 | ||
| 4588 | while i > 0 | ||
| 4589 | print i | ||
| 4590 | i -= 1 | ||
| 4591 | |||
| 4592 | my_func! | ||
| 4593 | |||
| 4594 | print i -- will print 0 | ||
| 4595 | ``` | ||
| 4596 | <YueDisplay> | ||
| 4597 | |||
| 4598 | ```yue | ||
| 4599 | i = 100 | ||
| 4600 | |||
| 4601 | -- many lines of code... | ||
| 4602 | |||
| 4603 | my_func = -> | ||
| 4604 | i = 10 | ||
| 4605 | while i > 0 | ||
| 4606 | print i | ||
| 4607 | i -= 1 | ||
| 4608 | |||
| 4609 | my_func! | ||
| 4610 | |||
| 4611 | print i -- will print 0 | ||
| 4612 | ``` | ||
| 4613 | |||
| 4614 | </YueDisplay> | ||
| 4615 | |||
| 4616 | In 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. | ||
| 4617 | |||
| 4618 | It 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. | ||
| 4619 | |||
| 4620 | The 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. | ||
| 4621 | |||
| 4622 | ```yuescript | ||
| 4623 | i = 100 | ||
| 4624 | |||
| 4625 | my_func = (using nil) -> | ||
| 4626 | i = "hello" -- a new local variable is created here | ||
| 4627 | |||
| 4628 | my_func! | ||
| 4629 | print i -- prints 100, i is unaffected | ||
| 4630 | ``` | ||
| 4631 | <YueDisplay> | ||
| 4632 | |||
| 4633 | ```yue | ||
| 4634 | i = 100 | ||
| 4635 | |||
| 4636 | my_func = (using nil) -> | ||
| 4637 | i = "hello" -- a new local variable is created here | ||
| 4638 | |||
| 4639 | my_func! | ||
| 4640 | print i -- prints 100, i is unaffected | ||
| 4641 | ``` | ||
| 4642 | |||
| 4643 | </YueDisplay> | ||
| 4644 | |||
| 4645 | Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified: | ||
| 4646 | |||
| 4647 | ```yuescript | ||
| 4648 | tmp = 1213 | ||
| 4649 | i, k = 100, 50 | ||
| 4650 | |||
| 4651 | my_func = (add using k, i) -> | ||
| 4652 | tmp = tmp + add -- a new local tmp is created | ||
| 4653 | i += tmp | ||
| 4654 | k += tmp | ||
| 4655 | |||
| 4656 | my_func(22) | ||
| 4657 | print i, k -- these have been updated | ||
| 4658 | ``` | ||
| 4659 | <YueDisplay> | ||
| 4660 | |||
| 4661 | ```yue | ||
| 4662 | tmp = 1213 | ||
| 4663 | i, k = 100, 50 | ||
| 4664 | |||
| 4665 | my_func = (add using k, i) -> | ||
| 4666 | tmp = tmp + add -- a new local tmp is created | ||
| 4667 | i += tmp | ||
| 4668 | k += tmp | ||
| 4669 | |||
| 4670 | my_func(22) | ||
| 4671 | print i, k -- these have been updated | ||
| 4672 | ``` | ||
| 4673 | |||
| 4674 | </YueDisplay> | ||
| 4675 | |||
| 4676 | ## The YueScript Library | ||
| 4677 | |||
| 4678 | Access it by `require("yue")`. | ||
| 4679 | |||
| 4680 | ### yue | ||
| 4681 | |||
| 4682 | **Description:** | ||
| 4683 | |||
| 4684 | The YueScript language library. | ||
| 4685 | |||
| 4686 | #### version | ||
| 4687 | |||
| 4688 | **Type:** Field. | ||
| 4689 | |||
| 4690 | **Description:** | ||
| 4691 | |||
| 4692 | The YueScript version. | ||
| 4693 | |||
| 4694 | **Signature:** | ||
| 4695 | ```lua | ||
| 4696 | version: string | ||
| 4697 | ``` | ||
| 4698 | |||
| 4699 | #### dirsep | ||
| 4700 | |||
| 4701 | **Type:** Field. | ||
| 4702 | |||
| 4703 | **Description:** | ||
| 4704 | |||
| 4705 | The file separator for the current platform. | ||
| 4706 | |||
| 4707 | **Signature:** | ||
| 4708 | ```lua | ||
| 4709 | dirsep: string | ||
| 4710 | ``` | ||
| 4711 | |||
| 4712 | #### yue_compiled | ||
| 4713 | |||
| 4714 | **Type:** Field. | ||
| 4715 | |||
| 4716 | **Description:** | ||
| 4717 | |||
| 4718 | The compiled module code cache. | ||
| 4719 | |||
| 4720 | **Signature:** | ||
| 4721 | ```lua | ||
| 4722 | yue_compiled: {string: string} | ||
| 4723 | ``` | ||
| 4724 | |||
| 4725 | #### to_lua | ||
| 4726 | |||
| 4727 | **Type:** Function. | ||
| 4728 | |||
| 4729 | **Description:** | ||
| 4730 | |||
| 4731 | The YueScript compiling function. It compiles the YueScript code to Lua code. | ||
| 4732 | |||
| 4733 | **Signature:** | ||
| 4734 | ```lua | ||
| 4735 | to_lua: function(code: string, config?: Config): | ||
| 4736 | --[[codes]] string | nil, | ||
| 4737 | --[[error]] string | nil, | ||
| 4738 | --[[globals]] {{string, integer, integer}} | nil | ||
| 4739 | ``` | ||
| 4740 | |||
| 4741 | **Parameters:** | ||
| 4742 | |||
| 4743 | | Parameter | Type | Description | | ||
| 4744 | | --- | --- | --- | | ||
| 4745 | | code | string | The YueScript code. | | ||
| 4746 | | config | Config | [Optional] The compiler options. | | ||
| 4747 | |||
| 4748 | **Returns:** | ||
| 4749 | |||
| 4750 | | Return Type | Description | | ||
| 4751 | | --- | --- | | ||
| 4752 | | string \| nil | The compiled Lua code, or nil if the compilation failed. | | ||
| 4753 | | string \| nil | The error message, or nil if the compilation succeeded. | | ||
| 4754 | | {{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. | | ||
| 4755 | |||
| 4756 | #### file_exist | ||
| 4757 | |||
| 4758 | **Type:** Function. | ||
| 4759 | |||
| 4760 | **Description:** | ||
| 4761 | |||
| 4762 | The source file existence checking function. Can be overridden to customize the behavior. | ||
| 4763 | |||
| 4764 | **Signature:** | ||
| 4765 | ```lua | ||
| 4766 | file_exist: function(filename: string): boolean | ||
| 4767 | ``` | ||
| 4768 | |||
| 4769 | **Parameters:** | ||
| 4770 | |||
| 4771 | | Parameter | Type | Description | | ||
| 4772 | | --- | --- | --- | | ||
| 4773 | | filename | string | The file name. | | ||
| 4774 | |||
| 4775 | **Returns:** | ||
| 4776 | |||
| 4777 | | Return Type | Description | | ||
| 4778 | | --- | --- | | ||
| 4779 | | boolean | Whether the file exists. | | ||
| 4780 | |||
| 4781 | #### read_file | ||
| 4782 | |||
| 4783 | **Type:** Function. | ||
| 4784 | |||
| 4785 | **Description:** | ||
| 4786 | |||
| 4787 | The source file reading function. Can be overridden to customize the behavior. | ||
| 4788 | |||
| 4789 | **Signature:** | ||
| 4790 | ```lua | ||
| 4791 | read_file: function(filename: string): string | ||
| 4792 | ``` | ||
| 4793 | |||
| 4794 | **Parameters:** | ||
| 4795 | |||
| 4796 | | Parameter | Type | Description | | ||
| 4797 | | --- | --- | --- | | ||
| 4798 | | filename | string | The file name. | | ||
| 4799 | |||
| 4800 | **Returns:** | ||
| 4801 | |||
| 4802 | | Return Type | Description | | ||
| 4803 | | --- | --- | | ||
| 4804 | | string | The file content. | | ||
| 4805 | |||
| 4806 | #### insert_loader | ||
| 4807 | |||
| 4808 | **Type:** Function. | ||
| 4809 | |||
| 4810 | **Description:** | ||
| 4811 | |||
| 4812 | Insert the YueScript loader to the package loaders (searchers). | ||
| 4813 | |||
| 4814 | **Signature:** | ||
| 4815 | ```lua | ||
| 4816 | insert_loader: function(pos?: integer): boolean | ||
| 4817 | ``` | ||
| 4818 | |||
| 4819 | **Parameters:** | ||
| 4820 | |||
| 4821 | | Parameter | Type | Description | | ||
| 4822 | | --- | --- | --- | | ||
| 4823 | | pos | integer | [Optional] The position to insert the loader. Default is 3. | | ||
| 4824 | |||
| 4825 | **Returns:** | ||
| 4826 | |||
| 4827 | | Return Type | Description | | ||
| 4828 | | --- | --- | | ||
| 4829 | | boolean | Whether the loader is inserted successfully. It will fail if the loader is already inserted. | | ||
| 4830 | |||
| 4831 | #### remove_loader | ||
| 4832 | |||
| 4833 | **Type:** Function. | ||
| 4834 | |||
| 4835 | **Description:** | ||
| 4836 | |||
| 4837 | Remove the YueScript loader from the package loaders (searchers). | ||
| 4838 | |||
| 4839 | **Signature:** | ||
| 4840 | ```lua | ||
| 4841 | remove_loader: function(): boolean | ||
| 4842 | ``` | ||
| 4843 | |||
| 4844 | **Returns:** | ||
| 4845 | |||
| 4846 | | Return Type | Description | | ||
| 4847 | | --- | --- | | ||
| 4848 | | boolean | Whether the loader is removed successfully. It will fail if the loader is not inserted. | | ||
| 4849 | |||
| 4850 | #### loadstring | ||
| 4851 | |||
| 4852 | **Type:** Function. | ||
| 4853 | |||
| 4854 | **Description:** | ||
| 4855 | |||
| 4856 | Loads YueScript code from a string into a function. | ||
| 4857 | |||
| 4858 | **Signature:** | ||
| 4859 | ```lua | ||
| 4860 | loadstring: function(input: string, chunkname: string, env: table, config?: Config): | ||
| 4861 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4862 | --[[error]] string | nil | ||
| 4863 | ``` | ||
| 4864 | |||
| 4865 | **Parameters:** | ||
| 4866 | |||
| 4867 | | Parameter | Type | Description | | ||
| 4868 | | --- | --- | --- | | ||
| 4869 | | input | string | The YueScript code. | | ||
| 4870 | | chunkname | string | The name of the code chunk. | | ||
| 4871 | | env | table | The environment table. | | ||
| 4872 | | config | Config | [Optional] The compiler options. | | ||
| 4873 | |||
| 4874 | **Returns:** | ||
| 4875 | |||
| 4876 | | Return Type | Description | | ||
| 4877 | | --- | --- | | ||
| 4878 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 4879 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 4880 | |||
| 4881 | #### loadstring | ||
| 4882 | |||
| 4883 | **Type:** Function. | ||
| 4884 | |||
| 4885 | **Description:** | ||
| 4886 | |||
| 4887 | Loads YueScript code from a string into a function. | ||
| 4888 | |||
| 4889 | **Signature:** | ||
| 4890 | ```lua | ||
| 4891 | loadstring: function(input: string, chunkname: string, config?: Config): | ||
| 4892 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4893 | --[[error]] string | nil | ||
| 4894 | ``` | ||
| 4895 | |||
| 4896 | **Parameters:** | ||
| 4897 | |||
| 4898 | | Parameter | Type | Description | | ||
| 4899 | | --- | --- | --- | | ||
| 4900 | | input | string | The YueScript code. | | ||
| 4901 | | chunkname | string | The name of the code chunk. | | ||
| 4902 | | config | Config | [Optional] The compiler options. | | ||
| 4903 | |||
| 4904 | **Returns:** | ||
| 4905 | |||
| 4906 | | Return Type | Description | | ||
| 4907 | | --- | --- | | ||
| 4908 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 4909 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 4910 | |||
| 4911 | #### loadstring | ||
| 4912 | |||
| 4913 | **Type:** Function. | ||
| 4914 | |||
| 4915 | **Description:** | ||
| 4916 | |||
| 4917 | Loads YueScript code from a string into a function. | ||
| 4918 | |||
| 4919 | **Signature:** | ||
| 4920 | ```lua | ||
| 4921 | loadstring: function(input: string, config?: Config): | ||
| 4922 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4923 | --[[error]] string | nil | ||
| 4924 | ``` | ||
| 4925 | |||
| 4926 | **Parameters:** | ||
| 4927 | |||
| 4928 | | Parameter | Type | Description | | ||
| 4929 | | --- | --- | --- | | ||
| 4930 | | input | string | The YueScript code. | | ||
| 4931 | | config | Config | [Optional] The compiler options. | | ||
| 4932 | |||
| 4933 | **Returns:** | ||
| 4934 | |||
| 4935 | | Return Type | Description | | ||
| 4936 | | --- | --- | | ||
| 4937 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 4938 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 4939 | |||
| 4940 | #### loadfile | ||
| 4941 | |||
| 4942 | **Type:** Function. | ||
| 4943 | |||
| 4944 | **Description:** | ||
| 4945 | |||
| 4946 | Loads YueScript code from a file into a function. | ||
| 4947 | |||
| 4948 | **Signature:** | ||
| 4949 | ```lua | ||
| 4950 | loadfile: function(filename: string, env: table, config?: Config): | ||
| 4951 | nil | function(...: any): (any...), | ||
| 4952 | string | nil | ||
| 4953 | ``` | ||
| 4954 | |||
| 4955 | **Parameters:** | ||
| 4956 | |||
| 4957 | | Parameter | Type | Description | | ||
| 4958 | | --- | --- | --- | | ||
| 4959 | | filename | string | The file name. | | ||
| 4960 | | env | table | The environment table. | | ||
| 4961 | | config | Config | [Optional] The compiler options. | | ||
| 4962 | |||
| 4963 | **Returns:** | ||
| 4964 | |||
| 4965 | | Return Type | Description | | ||
| 4966 | | --- | --- | | ||
| 4967 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 4968 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 4969 | |||
| 4970 | #### loadfile | ||
| 4971 | |||
| 4972 | **Type:** Function. | ||
| 4973 | |||
| 4974 | **Description:** | ||
| 4975 | |||
| 4976 | Loads YueScript code from a file into a function. | ||
| 4977 | |||
| 4978 | **Signature:** | ||
| 4979 | ```lua | ||
| 4980 | loadfile: function(filename: string, config?: Config): | ||
| 4981 | nil | function(...: any): (any...), | ||
| 4982 | string | nil | ||
| 4983 | ``` | ||
| 4984 | |||
| 4985 | **Parameters:** | ||
| 4986 | |||
| 4987 | | Parameter | Type | Description | | ||
| 4988 | | --- | --- | --- | | ||
| 4989 | | filename | string | The file name. | | ||
| 4990 | | config | Config | [Optional] The compiler options. | | ||
| 4991 | |||
| 4992 | **Returns:** | ||
| 4993 | |||
| 4994 | | Return Type | Description | | ||
| 4995 | | --- | --- | | ||
| 4996 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 4997 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 4998 | |||
| 4999 | #### dofile | ||
| 5000 | |||
| 5001 | **Type:** Function. | ||
| 5002 | |||
| 5003 | **Description:** | ||
| 5004 | |||
| 5005 | Loads YueScript code from a file into a function and executes it. | ||
| 5006 | |||
| 5007 | **Signature:** | ||
| 5008 | ```lua | ||
| 5009 | dofile: function(filename: string, env: table, config?: Config): any... | ||
| 5010 | ``` | ||
| 5011 | |||
| 5012 | **Parameters:** | ||
| 5013 | |||
| 5014 | | Parameter | Type | Description | | ||
| 5015 | | --- | --- | --- | | ||
| 5016 | | filename | string | The file name. | | ||
| 5017 | | env | table | The environment table. | | ||
| 5018 | | config | Config | [Optional] The compiler options. | | ||
| 5019 | |||
| 5020 | **Returns:** | ||
| 5021 | |||
| 5022 | | Return Type | Description | | ||
| 5023 | | --- | --- | | ||
| 5024 | | any... | The return values of the loaded function. | | ||
| 5025 | |||
| 5026 | #### dofile | ||
| 5027 | |||
| 5028 | **Type:** Function. | ||
| 5029 | |||
| 5030 | **Description:** | ||
| 5031 | |||
| 5032 | Loads YueScript code from a file into a function and executes it. | ||
| 5033 | |||
| 5034 | **Signature:** | ||
| 5035 | ```lua | ||
| 5036 | dofile: function(filename: string, config?: Config): any... | ||
| 5037 | ``` | ||
| 5038 | |||
| 5039 | **Parameters:** | ||
| 5040 | |||
| 5041 | | Parameter | Type | Description | | ||
| 5042 | | --- | --- | --- | | ||
| 5043 | | filename | string | The file name. | | ||
| 5044 | | config | Config | [Optional] The compiler options. | | ||
| 5045 | |||
| 5046 | **Returns:** | ||
| 5047 | |||
| 5048 | | Return Type | Description | | ||
| 5049 | | --- | --- | | ||
| 5050 | | any... | The return values of the loaded function. | | ||
| 5051 | |||
| 5052 | #### find_modulepath | ||
| 5053 | |||
| 5054 | **Type:** Function. | ||
| 5055 | |||
| 5056 | **Description:** | ||
| 5057 | |||
| 5058 | Resolves the YueScript module name to the file path. | ||
| 5059 | |||
| 5060 | **Signature:** | ||
| 5061 | ```lua | ||
| 5062 | find_modulepath: function(name: string): string | ||
| 5063 | ``` | ||
| 5064 | |||
| 5065 | **Parameters:** | ||
| 5066 | |||
| 5067 | | Parameter | Type | Description | | ||
| 5068 | | --- | --- | --- | | ||
| 5069 | | name | string | The module name. | | ||
| 5070 | |||
| 5071 | **Returns:** | ||
| 5072 | |||
| 5073 | | Return Type | Description | | ||
| 5074 | | --- | --- | | ||
| 5075 | | string | The file path. | | ||
| 5076 | |||
| 5077 | #### pcall | ||
| 5078 | |||
| 5079 | **Type:** Function. | ||
| 5080 | |||
| 5081 | **Description:** | ||
| 5082 | |||
| 5083 | Calls a function in protected mode. | ||
| 5084 | Catches any errors and returns a status code and results or error object. | ||
| 5085 | Rewrites the error line number to the original line number in the YueScript code when errors occur. | ||
| 5086 | |||
| 5087 | **Signature:** | ||
| 5088 | ```lua | ||
| 5089 | pcall: function(f: function, ...: any): boolean, any... | ||
| 5090 | ``` | ||
| 5091 | |||
| 5092 | **Parameters:** | ||
| 5093 | |||
| 5094 | | Parameter | Type | Description | | ||
| 5095 | | --- | --- | --- | | ||
| 5096 | | f | function | The function to call. | | ||
| 5097 | | ... | any | Arguments to pass to the function. | | ||
| 5098 | |||
| 5099 | **Returns:** | ||
| 5100 | |||
| 5101 | | Return Type | Description | | ||
| 5102 | | --- | --- | | ||
| 5103 | | boolean, ... | Status code and function results or error object. | | ||
| 5104 | |||
| 5105 | #### require | ||
| 5106 | |||
| 5107 | **Type:** Function. | ||
| 5108 | |||
| 5109 | **Description:** | ||
| 5110 | |||
| 5111 | Loads a given module. Can be either a Lua module or a YueScript module. | ||
| 5112 | Rewrites the error line number to the original line number in the YueScript code if the module is a YueScript module and loading fails. | ||
| 5113 | |||
| 5114 | **Signature:** | ||
| 5115 | ```lua | ||
| 5116 | require: function(name: string): any... | ||
| 5117 | ``` | ||
| 5118 | |||
| 5119 | **Parameters:** | ||
| 5120 | |||
| 5121 | | Parameter | Type | Description | | ||
| 5122 | | --- | --- | --- | | ||
| 5123 | | modname | string | The name of the module to load. | | ||
| 5124 | |||
| 5125 | **Returns:** | ||
| 5126 | |||
| 5127 | | Return Type | Description | | ||
| 5128 | | --- | --- | | ||
| 5129 | | 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. | | ||
| 5130 | |||
| 5131 | #### p | ||
| 5132 | |||
| 5133 | **Type:** Function. | ||
| 5134 | |||
| 5135 | **Description:** | ||
| 5136 | |||
| 5137 | Inspects the structures of the passed values and prints string representations. | ||
| 5138 | |||
| 5139 | **Signature:** | ||
| 5140 | ```lua | ||
| 5141 | p: function(...: any) | ||
| 5142 | ``` | ||
| 5143 | |||
| 5144 | **Parameters:** | ||
| 5145 | |||
| 5146 | | Parameter | Type | Description | | ||
| 5147 | | --- | --- | --- | | ||
| 5148 | | ... | any | The values to inspect. | | ||
| 5149 | |||
| 5150 | #### options | ||
| 5151 | |||
| 5152 | **Type:** Field. | ||
| 5153 | |||
| 5154 | **Description:** | ||
| 5155 | |||
| 5156 | The current compiler options. | ||
| 5157 | |||
| 5158 | **Signature:** | ||
| 5159 | ```lua | ||
| 5160 | options: Config.Options | ||
| 5161 | ``` | ||
| 5162 | |||
| 5163 | #### traceback | ||
| 5164 | |||
| 5165 | **Type:** Function. | ||
| 5166 | |||
| 5167 | **Description:** | ||
| 5168 | |||
| 5169 | The traceback function that rewrites the stack trace line numbers to the original line numbers in the YueScript code. | ||
| 5170 | |||
| 5171 | **Signature:** | ||
| 5172 | ```lua | ||
| 5173 | traceback: function(message: string): string | ||
| 5174 | ``` | ||
| 5175 | |||
| 5176 | **Parameters:** | ||
| 5177 | |||
| 5178 | | Parameter | Type | Description | | ||
| 5179 | | --- | --- | --- | | ||
| 5180 | | message | string | The traceback message. | | ||
| 5181 | |||
| 5182 | **Returns:** | ||
| 5183 | |||
| 5184 | | Return Type | Description | | ||
| 5185 | | --- | --- | | ||
| 5186 | | string | The rewritten traceback message. | | ||
| 5187 | |||
| 5188 | #### is_ast | ||
| 5189 | |||
| 5190 | **Type:** Function. | ||
| 5191 | |||
| 5192 | **Description:** | ||
| 5193 | |||
| 5194 | Checks whether the code matches the specified AST. | ||
| 5195 | |||
| 5196 | **Signature:** | ||
| 5197 | ```lua | ||
| 5198 | is_ast: function(astName: string, code: string): boolean | ||
| 5199 | ``` | ||
| 5200 | |||
| 5201 | **Parameters:** | ||
| 5202 | |||
| 5203 | | Parameter | Type | Description | | ||
| 5204 | | --- | --- | --- | | ||
| 5205 | | astName | string | The AST name. | | ||
| 5206 | | code | string | The code. | | ||
| 5207 | |||
| 5208 | **Returns:** | ||
| 5209 | |||
| 5210 | | Return Type | Description | | ||
| 5211 | | --- | --- | | ||
| 5212 | | boolean | Whether the code matches the AST. | | ||
| 5213 | |||
| 5214 | #### AST | ||
| 5215 | |||
| 5216 | **Type:** Field. | ||
| 5217 | |||
| 5218 | **Description:** | ||
| 5219 | |||
| 5220 | The AST type definition with name, row, column and sub nodes. | ||
| 5221 | |||
| 5222 | **Signature:** | ||
| 5223 | ```lua | ||
| 5224 | type AST = {string, integer, integer, any} | ||
| 5225 | ``` | ||
| 5226 | |||
| 5227 | #### to_ast | ||
| 5228 | |||
| 5229 | **Type:** Function. | ||
| 5230 | |||
| 5231 | **Description:** | ||
| 5232 | |||
| 5233 | Converts the code to the AST. | ||
| 5234 | |||
| 5235 | **Signature:** | ||
| 5236 | ```lua | ||
| 5237 | to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean): | ||
| 5238 | --[[AST]] AST | nil, | ||
| 5239 | --[[error]] nil | string | ||
| 5240 | ``` | ||
| 5241 | |||
| 5242 | **Parameters:** | ||
| 5243 | |||
| 5244 | | Parameter | Type | Description | | ||
| 5245 | | --- | --- | --- | | ||
| 5246 | | code | string | The code. | | ||
| 5247 | | flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. | | ||
| 5248 | | astName | string | [Optional] The AST name. Default is "File". | | ||
| 5249 | | reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is false. | | ||
| 5250 | |||
| 5251 | **Returns:** | ||
| 5252 | |||
| 5253 | | Return Type | Description | | ||
| 5254 | | --- | --- | | ||
| 5255 | | AST \| nil | The AST, or nil if the conversion failed. | | ||
| 5256 | | string \| nil | The error message, or nil if the conversion succeeded. | | ||
| 5257 | |||
| 5258 | #### format | ||
| 5259 | |||
| 5260 | **Type:** Function. | ||
| 5261 | |||
| 5262 | **Description:** | ||
| 5263 | |||
| 5264 | Formats the YueScript code. | ||
| 5265 | |||
| 5266 | **Signature:** | ||
| 5267 | ```lua | ||
| 5268 | format: function(code: string, tabSize?: number, reserveComment?: boolean): string | ||
| 5269 | ``` | ||
| 5270 | |||
| 5271 | **Parameters:** | ||
| 5272 | |||
| 5273 | | Parameter | Type | Description | | ||
| 5274 | | --- | --- | --- | | ||
| 5275 | | code | string | The code. | | ||
| 5276 | | tabSize | integer | [Optional] The tab size. Default is 4. | | ||
| 5277 | | reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is true. | | ||
| 5278 | |||
| 5279 | **Returns:** | ||
| 5280 | |||
| 5281 | | Return Type | Description | | ||
| 5282 | | --- | --- | | ||
| 5283 | | string | The formatted code. | | ||
| 5284 | |||
| 5285 | #### __call | ||
| 5286 | |||
| 5287 | **Type:** Metamethod. | ||
| 5288 | |||
| 5289 | **Description:** | ||
| 5290 | |||
| 5291 | Requires the YueScript module. | ||
| 5292 | Rewrites the error line number to the original line number in the YueScript code when loading fails. | ||
| 5293 | |||
| 5294 | **Signature:** | ||
| 5295 | ```lua | ||
| 5296 | metamethod __call: function(self: yue, module: string): any... | ||
| 5297 | ``` | ||
| 5298 | |||
| 5299 | **Parameters:** | ||
| 5300 | |||
| 5301 | | Parameter | Type | Description | | ||
| 5302 | | --- | --- | --- | | ||
| 5303 | | module | string | The module name. | | ||
| 5304 | |||
| 5305 | **Returns:** | ||
| 5306 | |||
| 5307 | | Return Type | Description | | ||
| 5308 | | --- | --- | | ||
| 5309 | | any | The module value. | | ||
| 5310 | |||
| 5311 | ### Config | ||
| 5312 | |||
| 5313 | **Description:** | ||
| 5314 | |||
| 5315 | The compiler compile options. | ||
| 5316 | |||
| 5317 | #### lint_global | ||
| 5318 | |||
| 5319 | **Type:** Field. | ||
| 5320 | |||
| 5321 | **Description:** | ||
| 5322 | |||
| 5323 | Whether the compiler should collect the global variables appearing in the code. | ||
| 5324 | |||
| 5325 | **Signature:** | ||
| 5326 | ```lua | ||
| 5327 | lint_global: boolean | ||
| 5328 | ``` | ||
| 5329 | |||
| 5330 | #### implicit_return_root | ||
| 5331 | |||
| 5332 | **Type:** Field. | ||
| 5333 | |||
| 5334 | **Description:** | ||
| 5335 | |||
| 5336 | Whether the compiler should do an implicit return for the root code block. | ||
| 5337 | |||
| 5338 | **Signature:** | ||
| 5339 | ```lua | ||
| 5340 | implicit_return_root: boolean | ||
| 5341 | ``` | ||
| 5342 | |||
| 5343 | #### reserve_line_number | ||
| 5344 | |||
| 5345 | **Type:** Field. | ||
| 5346 | |||
| 5347 | **Description:** | ||
| 5348 | |||
| 5349 | Whether the compiler should reserve the original line number in the compiled code. | ||
| 5350 | |||
| 5351 | **Signature:** | ||
| 5352 | ```lua | ||
| 5353 | reserve_line_number: boolean | ||
| 5354 | ``` | ||
| 5355 | |||
| 5356 | #### reserve_comment | ||
| 5357 | |||
| 5358 | **Type:** Field. | ||
| 5359 | |||
| 5360 | **Description:** | ||
| 5361 | |||
| 5362 | Whether the compiler should reserve the original comments in the compiled code. | ||
| 5363 | |||
| 5364 | **Signature:** | ||
| 5365 | ```lua | ||
| 5366 | reserve_comment: boolean | ||
| 5367 | ``` | ||
| 5368 | |||
| 5369 | #### space_over_tab | ||
| 5370 | |||
| 5371 | **Type:** Field. | ||
| 5372 | |||
| 5373 | **Description:** | ||
| 5374 | |||
| 5375 | Whether the compiler should use the space character instead of the tab character in the compiled code. | ||
| 5376 | |||
| 5377 | **Signature:** | ||
| 5378 | ```lua | ||
| 5379 | space_over_tab: boolean | ||
| 5380 | ``` | ||
| 5381 | |||
| 5382 | #### same_module | ||
| 5383 | |||
| 5384 | **Type:** Field. | ||
| 5385 | |||
| 5386 | **Description:** | ||
| 5387 | |||
| 5388 | Whether the compiler should treat the code to be compiled as the same currently being compiled module. For internal use only. | ||
| 5389 | |||
| 5390 | **Signature:** | ||
| 5391 | ```lua | ||
| 5392 | same_module: boolean | ||
| 5393 | ``` | ||
| 5394 | |||
| 5395 | #### line_offset | ||
| 5396 | |||
| 5397 | **Type:** Field. | ||
| 5398 | |||
| 5399 | **Description:** | ||
| 5400 | |||
| 5401 | Whether the compiler error message should include the line number offset. For internal use only. | ||
| 5402 | |||
| 5403 | **Signature:** | ||
| 5404 | ```lua | ||
| 5405 | line_offset: integer | ||
| 5406 | ``` | ||
| 5407 | |||
| 5408 | #### yue.Config.LuaTarget | ||
| 5409 | |||
| 5410 | **Type:** Enumeration. | ||
| 5411 | |||
| 5412 | **Description:** | ||
| 5413 | |||
| 5414 | The target Lua version enumeration. | ||
| 5415 | |||
| 5416 | **Signature:** | ||
| 5417 | ```lua | ||
| 5418 | enum LuaTarget | ||
| 5419 | "5.1" | ||
| 5420 | "5.2" | ||
| 5421 | "5.3" | ||
| 5422 | "5.4" | ||
| 5423 | "5.5" | ||
| 5424 | end | ||
| 5425 | ``` | ||
| 5426 | |||
| 5427 | #### options | ||
| 5428 | |||
| 5429 | **Type:** Field. | ||
| 5430 | |||
| 5431 | **Description:** | ||
| 5432 | |||
| 5433 | The extra options to be passed to the compilation function. | ||
| 5434 | |||
| 5435 | **Signature:** | ||
| 5436 | ```lua | ||
| 5437 | options: Options | ||
| 5438 | ``` | ||
| 5439 | |||
| 5440 | ### Options | ||
| 5441 | |||
| 5442 | **Description:** | ||
| 5443 | |||
| 5444 | The extra compiler options definition. | ||
| 5445 | |||
| 5446 | #### target | ||
| 5447 | |||
| 5448 | **Type:** Field. | ||
| 5449 | |||
| 5450 | **Description:** | ||
| 5451 | |||
| 5452 | The target Lua version for the compilation. | ||
| 5453 | |||
| 5454 | **Signature:** | ||
| 5455 | ```lua | ||
| 5456 | target: LuaTarget | ||
| 5457 | ``` | ||
| 5458 | |||
| 5459 | #### path | ||
| 5460 | |||
| 5461 | **Type:** Field. | ||
| 5462 | |||
| 5463 | **Description:** | ||
| 5464 | |||
| 5465 | The extra module search path. | ||
| 5466 | |||
| 5467 | **Signature:** | ||
| 5468 | ```lua | ||
| 5469 | path: string | ||
| 5470 | ``` | ||
| 5471 | |||
| 5472 | #### dump_locals | ||
| 5473 | |||
| 5474 | **Type:** Field. | ||
| 5475 | |||
| 5476 | **Description:** | ||
| 5477 | |||
| 5478 | Whether to dump the local variables in the traceback error message. Default is false. | ||
| 5479 | |||
| 5480 | **Signature:** | ||
| 5481 | ```lua | ||
| 5482 | dump_locals: boolean | ||
| 5483 | ``` | ||
| 5484 | |||
| 5485 | #### simplified | ||
| 5486 | |||
| 5487 | **Type:** Field. | ||
| 5488 | |||
| 5489 | **Description:** | ||
| 5490 | |||
| 5491 | Whether to simplify the error message. Default is true. | ||
| 5492 | |||
| 5493 | **Signature:** | ||
| 5494 | ```lua | ||
| 5495 | simplified: boolean | ||
| 5496 | ``` | ||
| 5497 | |||
| 5498 | ## Licence: MIT | ||
| 5499 | |||
| 5500 | Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\> | ||
| 5501 | |||
| 5502 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5503 | of this software and associated documentation files (the "Software"), to deal | ||
| 5504 | in the Software without restriction, including without limitation the rights | ||
| 5505 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 5506 | copies of the Software, and to permit persons to whom the Software is | ||
| 5507 | furnished to do so, subject to the following conditions: | ||
| 5508 | |||
| 5509 | The above copyright notice and this permission notice shall be included in all | ||
| 5510 | copies or substantial portions of the Software. | ||
| 5511 | |||
| 5512 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 5513 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 5514 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 5515 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 5516 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 5517 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 5518 | SOFTWARE. | ||
| 5519 | |||
| 5520 | <CompilerModal /> | ||
diff --git a/doc/docs/doc/installation.md b/doc/docs/doc/installation.md new file mode 100644 index 0000000..a93ddfd --- /dev/null +++ b/doc/docs/doc/installation.md | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # Installation | ||
| 2 | |||
| 3 | ## Lua Module | ||
| 4 | |||
| 5 | Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install it as a Lua module and executable with: | ||
| 6 | |||
| 7 | ```shell | ||
| 8 | luarocks install yuescript | ||
| 9 | ``` | ||
| 10 | |||
| 11 | Or you can build `yue.so` file with: | ||
| 12 | |||
| 13 | ```shell | ||
| 14 | make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
| 15 | ``` | ||
| 16 | |||
| 17 | Then get the binary file from path **bin/shared/yue.so**. | ||
| 18 | |||
| 19 | ## Build Binary Tool | ||
| 20 | |||
| 21 | Clone this repo, then build and install executable with: | ||
| 22 | |||
| 23 | ```shell | ||
| 24 | make install | ||
| 25 | ``` | ||
| 26 | |||
| 27 | Build YueScript tool without macro feature: | ||
| 28 | |||
| 29 | ```shell | ||
| 30 | make install NO_MACRO=true | ||
| 31 | ``` | ||
| 32 | |||
| 33 | Build YueScript tool without built-in Lua binary: | ||
| 34 | |||
| 35 | ```shell | ||
| 36 | make install NO_LUA=true | ||
| 37 | ``` | ||
| 38 | |||
| 39 | ## Download Precompiled Binary | ||
| 40 | |||
| 41 | You can download precompiled binary files, including binary executable files compatible with different Lua versions and library files. | ||
| 42 | |||
| 43 | Download precompiled binary files from [here](https://github.com/IppClub/YueScript/releases). | ||
diff --git a/doc/docs/doc/introduction.md b/doc/docs/doc/introduction.md new file mode 100644 index 0000000..a9a9389 --- /dev/null +++ b/doc/docs/doc/introduction.md | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | # Introduction | ||
| 2 | |||
| 3 | YueScript 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. | ||
| 4 | |||
| 5 | Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. | ||
| 6 | |||
| 7 | ## An Overview of YueScript | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | -- import syntax | ||
| 11 | import p, to_lua from "yue" | ||
| 12 | |||
| 13 | -- object literals | ||
| 14 | inventory = | ||
| 15 | equipment: | ||
| 16 | - "sword" | ||
| 17 | - "shield" | ||
| 18 | items: | ||
| 19 | - name: "potion" | ||
| 20 | count: 10 | ||
| 21 | - name: "bread" | ||
| 22 | count: 3 | ||
| 23 | |||
| 24 | -- list comprehension | ||
| 25 | map = (arr, action) -> | ||
| 26 | [action item for item in *arr] | ||
| 27 | |||
| 28 | filter = (arr, cond) -> | ||
| 29 | [item for item in *arr when cond item] | ||
| 30 | |||
| 31 | reduce = (arr, init, action): init -> | ||
| 32 | init = action init, item for item in *arr | ||
| 33 | |||
| 34 | -- pipe operator | ||
| 35 | [1, 2, 3] | ||
| 36 | |> map (x) -> x * 2 | ||
| 37 | |> filter (x) -> x > 4 | ||
| 38 | |> reduce 0, (a, b) -> a + b | ||
| 39 | |||
| 40 | |||
| 41 | -- metatable manipulation | ||
| 42 | apple = | ||
| 43 | size: 15 | ||
| 44 | <index>: | ||
| 45 | color: 0x00ffff | ||
| 46 | |||
| 47 | with apple | ||
| 48 | p .size, .color, .<index> if .<>? | ||
| 49 | |||
| 50 | -- js-like export syntax | ||
| 51 | export 🌛 = "月之脚本" | ||
| 52 | ``` | ||
| 53 | |||
| 54 | <YueDisplay> | ||
| 55 | |||
| 56 | ```yue | ||
| 57 | -- import syntax | ||
| 58 | import p, to_lua from "yue" | ||
| 59 | |||
| 60 | -- object literals | ||
| 61 | inventory = | ||
| 62 | equipment: | ||
| 63 | - "sword" | ||
| 64 | - "shield" | ||
| 65 | items: | ||
| 66 | - name: "potion" | ||
| 67 | count: 10 | ||
| 68 | - name: "bread" | ||
| 69 | count: 3 | ||
| 70 | |||
| 71 | -- list comprehension | ||
| 72 | map = (arr, action) -> | ||
| 73 | [action item for item in *arr] | ||
| 74 | |||
| 75 | filter = (arr, cond) -> | ||
| 76 | [item for item in *arr when cond item] | ||
| 77 | |||
| 78 | reduce = (arr, init, action): init -> | ||
| 79 | init = action init, item for item in *arr | ||
| 80 | |||
| 81 | -- pipe operator | ||
| 82 | [1, 2, 3] | ||
| 83 | |> map (x) -> x * 2 | ||
| 84 | |> filter (x) -> x > 4 | ||
| 85 | |> reduce 0, (a, b) -> a + b | ||
| 86 | |||
| 87 | |||
| 88 | -- metatable manipulation | ||
| 89 | apple = | ||
| 90 | size: 15 | ||
| 91 | <index>: | ||
| 92 | color: 0x00ffff | ||
| 93 | |||
| 94 | with apple | ||
| 95 | p .size, .color, .<index> if .<>? | ||
| 96 | |||
| 97 | -- js-like export syntax | ||
| 98 | export 🌛 = "月之脚本" | ||
| 99 | ``` | ||
| 100 | |||
| 101 | </YueDisplay> | ||
| 102 | |||
| 103 | ## About Dora SSR | ||
| 104 | |||
| 105 | YueScript 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. \ No newline at end of file | ||
diff --git a/doc/docs/doc/licence-mit.md b/doc/docs/doc/licence-mit.md new file mode 100644 index 0000000..253298f --- /dev/null +++ b/doc/docs/doc/licence-mit.md | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | # Licence: MIT | ||
| 2 | |||
| 3 | Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\> | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all | ||
| 13 | copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | SOFTWARE. | ||
| 22 | |||
| 23 | <CompilerModal /> | ||
diff --git a/doc/docs/doc/line-decorators.md b/doc/docs/doc/line-decorators.md new file mode 100644 index 0000000..292bc77 --- /dev/null +++ b/doc/docs/doc/line-decorators.md | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | # Line Decorators | ||
| 2 | |||
| 3 | For convenience, the for loop and if statement can be applied to single statements at the end of the line: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | print "hello world" if name == "Rob" | ||
| 7 | ``` | ||
| 8 | <YueDisplay> | ||
| 9 | |||
| 10 | ```yue | ||
| 11 | print "hello world" if name == "Rob" | ||
| 12 | ``` | ||
| 13 | |||
| 14 | </YueDisplay> | ||
| 15 | |||
| 16 | And with basic loops: | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | print "item: ", item for item in *items | ||
| 20 | ``` | ||
| 21 | <YueDisplay> | ||
| 22 | |||
| 23 | ```yue | ||
| 24 | print "item: ", item for item in *items | ||
| 25 | ``` | ||
| 26 | |||
| 27 | </YueDisplay> | ||
| 28 | |||
| 29 | And with while loops: | ||
| 30 | |||
| 31 | ```yuescript | ||
| 32 | game\update! while game\isRunning! | ||
| 33 | |||
| 34 | reader\parse_line! until reader\eof! | ||
| 35 | ``` | ||
| 36 | <YueDisplay> | ||
| 37 | |||
| 38 | ```yue | ||
| 39 | game\update! while game\isRunning! | ||
| 40 | |||
| 41 | reader\parse_line! until reader\eof! | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
diff --git a/doc/docs/doc/literals.md b/doc/docs/doc/literals.md new file mode 100644 index 0000000..e097c62 --- /dev/null +++ b/doc/docs/doc/literals.md | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | # Literals | ||
| 2 | |||
| 3 | All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. | ||
| 4 | |||
| 5 | Unlike Lua, Line breaks are allowed inside of single and double quote strings without an escape sequence: | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | some_string = "Here is a string | ||
| 9 | that has a line break in it." | ||
| 10 | |||
| 11 | -- You can mix expressions into string literals using #{} syntax. | ||
| 12 | -- String interpolation is only available in double quoted strings. | ||
| 13 | print "I am #{math.random! * 100}% sure." | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | some_string = "Here is a string | ||
| 19 | that has a line break in it." | ||
| 20 | |||
| 21 | -- You can mix expressions into string literals using #{} syntax. | ||
| 22 | -- String interpolation is only available in double quoted strings. | ||
| 23 | print "I am #{math.random! * 100}% sure." | ||
| 24 | ``` | ||
| 25 | |||
| 26 | </YueDisplay> | ||
| 27 | |||
| 28 | ## Number Literals | ||
| 29 | |||
| 30 | You can use underscores in a number literal to increase readability. | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | integer = 1_000_000 | ||
| 34 | hex = 0xEF_BB_BF | ||
| 35 | binary = 0B10011 | ||
| 36 | ``` | ||
| 37 | <YueDisplay> | ||
| 38 | |||
| 39 | ```yue | ||
| 40 | integer = 1_000_000 | ||
| 41 | hex = 0xEF_BB_BF | ||
| 42 | binary = 0B10011 | ||
| 43 | ``` | ||
| 44 | |||
| 45 | </YueDisplay> | ||
| 46 | |||
| 47 | ## YAML Multiline String | ||
| 48 | |||
| 49 | The `|` prefix introduces a YAML-style multiline string literal: | ||
| 50 | |||
| 51 | ```yuescript | ||
| 52 | str = | | ||
| 53 | key: value | ||
| 54 | list: | ||
| 55 | - item1 | ||
| 56 | - #{expr} | ||
| 57 | ``` | ||
| 58 | <YueDisplay> | ||
| 59 | |||
| 60 | ```yue | ||
| 61 | str = | | ||
| 62 | key: value | ||
| 63 | list: | ||
| 64 | - item1 | ||
| 65 | - #{expr} | ||
| 66 | ``` | ||
| 67 | |||
| 68 | </YueDisplay> | ||
| 69 | |||
| 70 | This 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)`. | ||
| 71 | |||
| 72 | YAML 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. | ||
| 73 | |||
| 74 | ```yuescript | ||
| 75 | fn = -> | ||
| 76 | str = | | ||
| 77 | foo: | ||
| 78 | bar: baz | ||
| 79 | return str | ||
| 80 | ``` | ||
| 81 | <YueDisplay> | ||
| 82 | |||
| 83 | ```yue | ||
| 84 | fn = -> | ||
| 85 | str = | | ||
| 86 | foo: | ||
| 87 | bar: baz | ||
| 88 | return str | ||
| 89 | ``` | ||
| 90 | |||
| 91 | </YueDisplay> | ||
| 92 | |||
| 93 | Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures. | ||
| 94 | |||
| 95 | All 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. | ||
| 96 | |||
| 97 | ```yuescript | ||
| 98 | str = | | ||
| 99 | path: "C:\Program Files\App" | ||
| 100 | note: 'He said: "#{Hello}!"' | ||
| 101 | ``` | ||
| 102 | <YueDisplay> | ||
| 103 | |||
| 104 | ```yue | ||
| 105 | str = | | ||
| 106 | path: "C:\Program Files\App" | ||
| 107 | note: 'He said: "#{Hello}!"' | ||
| 108 | ``` | ||
| 109 | |||
| 110 | </YueDisplay> | ||
diff --git a/doc/docs/doc/macro.md b/doc/docs/doc/macro.md new file mode 100644 index 0000000..917c20e --- /dev/null +++ b/doc/docs/doc/macro.md | |||
| @@ -0,0 +1,274 @@ | |||
| 1 | # Macro | ||
| 2 | |||
| 3 | ## Common Usage | ||
| 4 | |||
| 5 | Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation. | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | macro PI2 = -> math.pi * 2 | ||
| 9 | area = $PI2 * 5 | ||
| 10 | |||
| 11 | macro HELLO = -> "'hello world'" | ||
| 12 | print $HELLO | ||
| 13 | |||
| 14 | macro config = (debugging) -> | ||
| 15 | global debugMode = debugging == "true" | ||
| 16 | "" | ||
| 17 | |||
| 18 | macro asserts = (cond) -> | ||
| 19 | debugMode and "assert #{cond}" or "" | ||
| 20 | |||
| 21 | macro assert = (cond) -> | ||
| 22 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 23 | |||
| 24 | $config true | ||
| 25 | $asserts item ~= nil | ||
| 26 | |||
| 27 | $config false | ||
| 28 | value = $assert item | ||
| 29 | |||
| 30 | -- the passed expressions are treated as strings | ||
| 31 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 32 | if $and f1!, f2!, f3! | ||
| 33 | print "OK" | ||
| 34 | ``` | ||
| 35 | <YueDisplay> | ||
| 36 | |||
| 37 | ```yue | ||
| 38 | macro PI2 = -> math.pi * 2 | ||
| 39 | area = $PI2 * 5 | ||
| 40 | |||
| 41 | macro HELLO = -> "'hello world'" | ||
| 42 | print $HELLO | ||
| 43 | |||
| 44 | macro config = (debugging) -> | ||
| 45 | global debugMode = debugging == "true" | ||
| 46 | "" | ||
| 47 | |||
| 48 | macro asserts = (cond) -> | ||
| 49 | debugMode and "assert #{cond}" or "" | ||
| 50 | |||
| 51 | macro assert = (cond) -> | ||
| 52 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 53 | |||
| 54 | $config true | ||
| 55 | $asserts item ~= nil | ||
| 56 | |||
| 57 | $config false | ||
| 58 | value = $assert item | ||
| 59 | |||
| 60 | -- the passed expressions are treated as strings | ||
| 61 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 62 | if $and f1!, f2!, f3! | ||
| 63 | print "OK" | ||
| 64 | ``` | ||
| 65 | |||
| 66 | </YueDisplay> | ||
| 67 | |||
| 68 | ## Insert Raw Codes | ||
| 69 | |||
| 70 | A macro function can either return a YueScript string or a config table containing Lua codes. | ||
| 71 | ```yuescript | ||
| 72 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 73 | $yueFunc funcA | ||
| 74 | funcA = -> "fail to assign to the Yue macro defined variable" | ||
| 75 | |||
| 76 | macro luaFunc = (var) -> { | ||
| 77 | code: "local function #{var}() end" | ||
| 78 | type: "lua" | ||
| 79 | } | ||
| 80 | $luaFunc funcB | ||
| 81 | funcB = -> "fail to assign to the Lua macro defined variable" | ||
| 82 | |||
| 83 | macro lua = (code) -> { | ||
| 84 | :code | ||
| 85 | type: "lua" | ||
| 86 | } | ||
| 87 | |||
| 88 | -- the raw string leading and ending symbols are auto trimed | ||
| 89 | $lua[==[ | ||
| 90 | -- raw Lua codes insertion | ||
| 91 | if cond then | ||
| 92 | print("output") | ||
| 93 | end | ||
| 94 | ]==] | ||
| 95 | ``` | ||
| 96 | <YueDisplay> | ||
| 97 | |||
| 98 | ```yue | ||
| 99 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 100 | $yueFunc funcA | ||
| 101 | funcA = -> "fail to assign to the Yue macro defined variable" | ||
| 102 | |||
| 103 | macro luaFunc = (var) -> { | ||
| 104 | code: "local function #{var}() end" | ||
| 105 | type: "lua" | ||
| 106 | } | ||
| 107 | $luaFunc funcB | ||
| 108 | funcB = -> "fail to assign to the Lua macro defined variable" | ||
| 109 | |||
| 110 | macro lua = (code) -> { | ||
| 111 | :code | ||
| 112 | type: "lua" | ||
| 113 | } | ||
| 114 | |||
| 115 | -- the raw string leading and ending symbols are auto trimed | ||
| 116 | $lua[==[ | ||
| 117 | -- raw Lua codes insertion | ||
| 118 | if cond then | ||
| 119 | print("output") | ||
| 120 | end | ||
| 121 | ]==] | ||
| 122 | ``` | ||
| 123 | |||
| 124 | </YueDisplay> | ||
| 125 | |||
| 126 | ## Export Macro | ||
| 127 | |||
| 128 | Macro 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. | ||
| 129 | ```yuescript | ||
| 130 | -- file: utils.yue | ||
| 131 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 132 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 133 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 134 | #{action}" | ||
| 135 | |||
| 136 | -- file main.yue | ||
| 137 | import "utils" as { | ||
| 138 | $, -- symbol to import all macros | ||
| 139 | $foreach: $each -- rename macro $foreach to $each | ||
| 140 | } | ||
| 141 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 142 | ``` | ||
| 143 | <YueDisplay> | ||
| 144 | |||
| 145 | ```yue | ||
| 146 | -- file: utils.yue | ||
| 147 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 148 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 149 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 150 | #{action}" | ||
| 151 | -- file main.yue | ||
| 152 | -- import function is not available in browser, try it in a real environment | ||
| 153 | --[[ | ||
| 154 | import "utils" as { | ||
| 155 | $, -- symbol to import all macros | ||
| 156 | $foreach: $each -- rename macro $foreach to $each | ||
| 157 | } | ||
| 158 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 159 | ]] | ||
| 160 | ``` | ||
| 161 | |||
| 162 | </YueDisplay> | ||
| 163 | |||
| 164 | ## Builtin Macro | ||
| 165 | |||
| 166 | There are some builtin macros but you can override them by declaring macros with the same names. | ||
| 167 | ```yuescript | ||
| 168 | print $FILE -- get string of current module name | ||
| 169 | print $LINE -- get number 2 | ||
| 170 | ``` | ||
| 171 | <YueDisplay> | ||
| 172 | |||
| 173 | ```yue | ||
| 174 | print $FILE -- get string of current module name | ||
| 175 | print $LINE -- get number 2 | ||
| 176 | ``` | ||
| 177 | |||
| 178 | </YueDisplay> | ||
| 179 | |||
| 180 | ## Generating Macros with Macros | ||
| 181 | |||
| 182 | In 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. | ||
| 183 | |||
| 184 | ```yuescript | ||
| 185 | macro Enum = (...) -> | ||
| 186 | items = {...} | ||
| 187 | itemSet = {item, true for item in *items} | ||
| 188 | (item) -> | ||
| 189 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 190 | "\"#{item}\"" | ||
| 191 | |||
| 192 | macro BodyType = $Enum( | ||
| 193 | Static | ||
| 194 | Dynamic | ||
| 195 | Kinematic | ||
| 196 | ) | ||
| 197 | |||
| 198 | print "Valid enum type:", $BodyType Static | ||
| 199 | -- print "Compilation error with enum type:", $BodyType Unknown | ||
| 200 | ``` | ||
| 201 | |||
| 202 | <YueDisplay> | ||
| 203 | |||
| 204 | ```yue | ||
| 205 | macro Enum = (...) -> | ||
| 206 | items = {...} | ||
| 207 | itemSet = {item, true for item in *items} | ||
| 208 | (item) -> | ||
| 209 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 210 | "\"#{item}\"" | ||
| 211 | |||
| 212 | macro BodyType = $Enum( | ||
| 213 | Static | ||
| 214 | Dynamic | ||
| 215 | Kinematic | ||
| 216 | ) | ||
| 217 | |||
| 218 | print "Valid enum type:", $BodyType Static | ||
| 219 | -- print "Compilation error with enum type:", $BodyType Unknown | ||
| 220 | ``` | ||
| 221 | |||
| 222 | </YueDisplay> | ||
| 223 | |||
| 224 | ## Argument Validation | ||
| 225 | |||
| 226 | You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time. | ||
| 227 | |||
| 228 | ```yuescript | ||
| 229 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 230 | print( | ||
| 231 | #{num} | ||
| 232 | #{str} | ||
| 233 | ) | ||
| 234 | |||
| 235 | $printNumAndStr 123, "hello" | ||
| 236 | ``` | ||
| 237 | <YueDisplay> | ||
| 238 | |||
| 239 | ```yue | ||
| 240 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 241 | print( | ||
| 242 | #{num} | ||
| 243 | #{str} | ||
| 244 | ) | ||
| 245 | |||
| 246 | $printNumAndStr 123, "hello" | ||
| 247 | ``` | ||
| 248 | |||
| 249 | </YueDisplay> | ||
| 250 | |||
| 251 | If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place. | ||
| 252 | |||
| 253 | ```yuescript | ||
| 254 | macro printNumAndStr = (num, str) -> | ||
| 255 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 256 | error "expected String as second argument" unless $is_ast String, str | ||
| 257 | "print(#{num}, #{str})" | ||
| 258 | |||
| 259 | $printNumAndStr 123, "hello" | ||
| 260 | ``` | ||
| 261 | <YueDisplay> | ||
| 262 | |||
| 263 | ```yue | ||
| 264 | macro printNumAndStr = (num, str) -> | ||
| 265 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 266 | error "expected String as second argument" unless $is_ast String, str | ||
| 267 | "print(#{num}, #{str})" | ||
| 268 | |||
| 269 | $printNumAndStr 123, "hello" | ||
| 270 | ``` | ||
| 271 | |||
| 272 | </YueDisplay> | ||
| 273 | |||
| 274 | For 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). | ||
diff --git a/doc/docs/doc/module.md b/doc/docs/doc/module.md new file mode 100644 index 0000000..c955092 --- /dev/null +++ b/doc/docs/doc/module.md | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | # Module | ||
| 2 | |||
| 3 | ## Import | ||
| 4 | |||
| 5 | The 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. | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | -- used as table destructuring | ||
| 9 | do | ||
| 10 | import insert, concat from table | ||
| 11 | -- report error when assigning to insert, concat | ||
| 12 | import C, Ct, Cmt from require "lpeg" | ||
| 13 | -- shortcut for implicit requiring | ||
| 14 | import x, y, z from 'mymodule' | ||
| 15 | -- import with Python style | ||
| 16 | from 'module' import a, b, c | ||
| 17 | |||
| 18 | -- shortcut for requring a module | ||
| 19 | do | ||
| 20 | import 'module' | ||
| 21 | import 'module_x' | ||
| 22 | import "d-a-s-h-e-s" | ||
| 23 | import "module.part" | ||
| 24 | |||
| 25 | -- requring module with aliasing or table destructuring | ||
| 26 | do | ||
| 27 | import "player" as PlayerModule | ||
| 28 | import "lpeg" as :C, :Ct, :Cmt | ||
| 29 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 30 | ``` | ||
| 31 | <YueDisplay> | ||
| 32 | |||
| 33 | ```yue | ||
| 34 | -- used as table destructuring | ||
| 35 | do | ||
| 36 | import insert, concat from table | ||
| 37 | -- report error when assigning to insert, concat | ||
| 38 | import C, Ct, Cmt from require "lpeg" | ||
| 39 | -- shortcut for implicit requiring | ||
| 40 | import x, y, z from 'mymodule' | ||
| 41 | -- import with Python style | ||
| 42 | from 'module' import a, b, c | ||
| 43 | |||
| 44 | -- shortcut for requring a module | ||
| 45 | do | ||
| 46 | import 'module' | ||
| 47 | import 'module_x' | ||
| 48 | import "d-a-s-h-e-s" | ||
| 49 | import "module.part" | ||
| 50 | |||
| 51 | -- requring module with aliasing or table destructuring | ||
| 52 | do | ||
| 53 | import "player" as PlayerModule | ||
| 54 | import "lpeg" as :C, :Ct, :Cmt | ||
| 55 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 56 | ``` | ||
| 57 | |||
| 58 | </YueDisplay> | ||
| 59 | |||
| 60 | ## Import Global | ||
| 61 | |||
| 62 | You 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. | ||
| 63 | |||
| 64 | ```yuescript | ||
| 65 | do | ||
| 66 | import tostring | ||
| 67 | import table.concat | ||
| 68 | print concat ["a", tostring 1] | ||
| 69 | ``` | ||
| 70 | <YueDisplay> | ||
| 71 | |||
| 72 | ```yue | ||
| 73 | do | ||
| 74 | import tostring | ||
| 75 | import table.concat | ||
| 76 | print concat ["a", tostring 1] | ||
| 77 | ``` | ||
| 78 | |||
| 79 | </YueDisplay> | ||
| 80 | |||
| 81 | ### Automatic Global Variable Import | ||
| 82 | |||
| 83 | You 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. | ||
| 84 | |||
| 85 | Names that are explicitly declared as globals in the same scope will not be imported, so you can still assign to them. | ||
| 86 | |||
| 87 | ```yuescript | ||
| 88 | do | ||
| 89 | import global | ||
| 90 | print "hello" | ||
| 91 | math.random 3 | ||
| 92 | -- print = nil -- error: imported globals are const | ||
| 93 | |||
| 94 | do | ||
| 95 | -- explicit global variable will not be imported | ||
| 96 | import global | ||
| 97 | global FLAG | ||
| 98 | print FLAG | ||
| 99 | FLAG = 123 | ||
| 100 | ``` | ||
| 101 | <YueDisplay> | ||
| 102 | |||
| 103 | ```yue | ||
| 104 | do | ||
| 105 | import global | ||
| 106 | print "hello" | ||
| 107 | math.random 3 | ||
| 108 | -- print = nil -- error: imported globals are const | ||
| 109 | |||
| 110 | do | ||
| 111 | -- explicit global variable will not be imported | ||
| 112 | import global | ||
| 113 | global FLAG | ||
| 114 | print FLAG | ||
| 115 | FLAG = 123 | ||
| 116 | ``` | ||
| 117 | |||
| 118 | </YueDisplay> | ||
| 119 | |||
| 120 | ## Export | ||
| 121 | |||
| 122 | The export statement offers a concise way to define modules. | ||
| 123 | |||
| 124 | ### Named Export | ||
| 125 | |||
| 126 | Named export will define a local variable as well as adding a field in the exported table. | ||
| 127 | |||
| 128 | ```yuescript | ||
| 129 | export a, b, c = 1, 2, 3 | ||
| 130 | export cool = "cat" | ||
| 131 | |||
| 132 | export What = if this | ||
| 133 | "abc" | ||
| 134 | else | ||
| 135 | "def" | ||
| 136 | |||
| 137 | export y = -> | ||
| 138 | hallo = 3434 | ||
| 139 | |||
| 140 | export class Something | ||
| 141 | umm: "cool" | ||
| 142 | ``` | ||
| 143 | <YueDisplay> | ||
| 144 | |||
| 145 | ```yue | ||
| 146 | export a, b, c = 1, 2, 3 | ||
| 147 | export cool = "cat" | ||
| 148 | |||
| 149 | export What = if this | ||
| 150 | "abc" | ||
| 151 | else | ||
| 152 | "def" | ||
| 153 | |||
| 154 | export y = -> | ||
| 155 | hallo = 3434 | ||
| 156 | |||
| 157 | export class Something | ||
| 158 | umm: "cool" | ||
| 159 | ``` | ||
| 160 | |||
| 161 | </YueDisplay> | ||
| 162 | |||
| 163 | Doing named export with destructuring. | ||
| 164 | |||
| 165 | ```yuescript | ||
| 166 | export :loadstring, to_lua: tolua = yue | ||
| 167 | export {itemA: {:fieldA = 'default'}} = tb | ||
| 168 | ``` | ||
| 169 | <YueDisplay> | ||
| 170 | |||
| 171 | ```yue | ||
| 172 | export :loadstring, to_lua: tolua = yue | ||
| 173 | export {itemA: {:fieldA = 'default'}} = tb | ||
| 174 | ``` | ||
| 175 | |||
| 176 | </YueDisplay> | ||
| 177 | |||
| 178 | Export named items from module without creating local variables. | ||
| 179 | |||
| 180 | ```yuescript | ||
| 181 | export.itemA = tb | ||
| 182 | export.<index> = items | ||
| 183 | export["a-b-c"] = 123 | ||
| 184 | ``` | ||
| 185 | <YueDisplay> | ||
| 186 | |||
| 187 | ```yue | ||
| 188 | export.itemA = tb | ||
| 189 | export.<index> = items | ||
| 190 | export["a-b-c"] = 123 | ||
| 191 | ``` | ||
| 192 | |||
| 193 | </YueDisplay> | ||
| 194 | |||
| 195 | ### Unnamed Export | ||
| 196 | |||
| 197 | Unnamed export will add the target item into the array part of the exported table. | ||
| 198 | |||
| 199 | ```yuescript | ||
| 200 | d, e, f = 3, 2, 1 | ||
| 201 | export d, e, f | ||
| 202 | |||
| 203 | export if this | ||
| 204 | 123 | ||
| 205 | else | ||
| 206 | 456 | ||
| 207 | |||
| 208 | export with tmp | ||
| 209 | j = 2000 | ||
| 210 | ``` | ||
| 211 | <YueDisplay> | ||
| 212 | |||
| 213 | ```yue | ||
| 214 | d, e, f = 3, 2, 1 | ||
| 215 | export d, e, f | ||
| 216 | |||
| 217 | export if this | ||
| 218 | 123 | ||
| 219 | else | ||
| 220 | 456 | ||
| 221 | |||
| 222 | export with tmp | ||
| 223 | j = 2000 | ||
| 224 | ``` | ||
| 225 | |||
| 226 | </YueDisplay> | ||
| 227 | |||
| 228 | ### Default Export | ||
| 229 | |||
| 230 | Using the **default** keyword in export statement to replace the exported table with any thing. | ||
| 231 | |||
| 232 | ```yuescript | ||
| 233 | export default -> | ||
| 234 | print "hello" | ||
| 235 | 123 | ||
| 236 | ``` | ||
| 237 | <YueDisplay> | ||
| 238 | |||
| 239 | ```yue | ||
| 240 | export default -> | ||
| 241 | print "hello" | ||
| 242 | 123 | ||
| 243 | ``` | ||
| 244 | |||
| 245 | </YueDisplay> | ||
diff --git a/doc/docs/doc/object-oriented-programming.md b/doc/docs/doc/object-oriented-programming.md new file mode 100644 index 0000000..6a8559e --- /dev/null +++ b/doc/docs/doc/object-oriented-programming.md | |||
| @@ -0,0 +1,555 @@ | |||
| 1 | # Object Oriented Programming | ||
| 2 | |||
| 3 | In 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. | ||
| 4 | |||
| 5 | A simple class: | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | class Inventory | ||
| 9 | new: => | ||
| 10 | @items = {} | ||
| 11 | |||
| 12 | add_item: (name) => | ||
| 13 | if @items[name] | ||
| 14 | @items[name] += 1 | ||
| 15 | else | ||
| 16 | @items[name] = 1 | ||
| 17 | ``` | ||
| 18 | <YueDisplay> | ||
| 19 | |||
| 20 | ```yue | ||
| 21 | class Inventory | ||
| 22 | new: => | ||
| 23 | @items = {} | ||
| 24 | |||
| 25 | add_item: (name) => | ||
| 26 | if @items[name] | ||
| 27 | @items[name] += 1 | ||
| 28 | else | ||
| 29 | @items[name] = 1 | ||
| 30 | ``` | ||
| 31 | |||
| 32 | </YueDisplay> | ||
| 33 | |||
| 34 | A class is declared with a class statement followed by a table-like declaration where all of the methods and properties are listed. | ||
| 35 | |||
| 36 | The new property is special in that it will become the constructor. | ||
| 37 | |||
| 38 | Notice 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. | ||
| 39 | |||
| 40 | The @ prefix on a variable name is shorthand for self.. @items becomes self.items. | ||
| 41 | |||
| 42 | Creating an instance of the class is done by calling the name of the class as a function. | ||
| 43 | |||
| 44 | ```yuescript | ||
| 45 | inv = Inventory! | ||
| 46 | inv\add_item "t-shirt" | ||
| 47 | inv\add_item "pants" | ||
| 48 | ``` | ||
| 49 | <YueDisplay> | ||
| 50 | |||
| 51 | ```yue | ||
| 52 | inv = Inventory! | ||
| 53 | inv\add_item "t-shirt" | ||
| 54 | inv\add_item "pants" | ||
| 55 | ``` | ||
| 56 | |||
| 57 | </YueDisplay> | ||
| 58 | |||
| 59 | Because the instance of the class needs to be sent to the methods when they are called, the \ operator is used. | ||
| 60 | |||
| 61 | All properties of a class are shared among the instances. This is fine for functions, but for other types of objects, undesired results may occur. | ||
| 62 | |||
| 63 | Consider the example below, the clothes property is shared amongst all instances, so modifications to it in one instance will show up in another: | ||
| 64 | |||
| 65 | ```yuescript | ||
| 66 | class Person | ||
| 67 | clothes: [] | ||
| 68 | give_item: (name) => | ||
| 69 | table.insert @clothes, name | ||
| 70 | |||
| 71 | a = Person! | ||
| 72 | b = Person! | ||
| 73 | |||
| 74 | a\give_item "pants" | ||
| 75 | b\give_item "shirt" | ||
| 76 | |||
| 77 | -- will print both pants and shirt | ||
| 78 | print item for item in *a.clothes | ||
| 79 | ``` | ||
| 80 | <YueDisplay> | ||
| 81 | |||
| 82 | ```yue | ||
| 83 | class Person | ||
| 84 | clothes: [] | ||
| 85 | give_item: (name) => | ||
| 86 | table.insert @clothes, name | ||
| 87 | |||
| 88 | a = Person! | ||
| 89 | b = Person! | ||
| 90 | |||
| 91 | a\give_item "pants" | ||
| 92 | b\give_item "shirt" | ||
| 93 | |||
| 94 | -- will print both pants and shirt | ||
| 95 | print item for item in *a.clothes | ||
| 96 | ``` | ||
| 97 | |||
| 98 | </YueDisplay> | ||
| 99 | |||
| 100 | The proper way to avoid this problem is to create the mutable state of the object in the constructor: | ||
| 101 | |||
| 102 | ```yuescript | ||
| 103 | class Person | ||
| 104 | new: => | ||
| 105 | @clothes = [] | ||
| 106 | ``` | ||
| 107 | <YueDisplay> | ||
| 108 | |||
| 109 | ```yue | ||
| 110 | class Person | ||
| 111 | new: => | ||
| 112 | @clothes = [] | ||
| 113 | ``` | ||
| 114 | |||
| 115 | </YueDisplay> | ||
| 116 | |||
| 117 | ## Inheritance | ||
| 118 | |||
| 119 | The extends keyword can be used in a class declaration to inherit the properties and methods from another class. | ||
| 120 | |||
| 121 | ```yuescript | ||
| 122 | class BackPack extends Inventory | ||
| 123 | size: 10 | ||
| 124 | add_item: (name) => | ||
| 125 | if #@items > size then error "backpack is full" | ||
| 126 | super name | ||
| 127 | ``` | ||
| 128 | <YueDisplay> | ||
| 129 | |||
| 130 | ```yue | ||
| 131 | class BackPack extends Inventory | ||
| 132 | size: 10 | ||
| 133 | add_item: (name) => | ||
| 134 | if #@items > size then error "backpack is full" | ||
| 135 | super name | ||
| 136 | ``` | ||
| 137 | |||
| 138 | </YueDisplay> | ||
| 139 | |||
| 140 | Here we extend our Inventory class, and limit the amount of items it can carry. | ||
| 141 | |||
| 142 | In 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. | ||
| 143 | |||
| 144 | Whenever 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. | ||
| 145 | |||
| 146 | ```yuescript | ||
| 147 | class Shelf | ||
| 148 | @__inherited: (child) => | ||
| 149 | print @__name, "was inherited by", child.__name | ||
| 150 | |||
| 151 | -- will print: Shelf was inherited by Cupboard | ||
| 152 | class Cupboard extends Shelf | ||
| 153 | ``` | ||
| 154 | <YueDisplay> | ||
| 155 | |||
| 156 | ```yue | ||
| 157 | class Shelf | ||
| 158 | @__inherited: (child) => | ||
| 159 | print @__name, "was inherited by", child.__name | ||
| 160 | |||
| 161 | -- will print: Shelf was inherited by Cupboard | ||
| 162 | class Cupboard extends Shelf | ||
| 163 | ``` | ||
| 164 | |||
| 165 | </YueDisplay> | ||
| 166 | |||
| 167 | ## Super | ||
| 168 | |||
| 169 | **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. | ||
| 170 | |||
| 171 | When 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) | ||
| 172 | |||
| 173 | When super is used as a normal value, it is a reference to the parent class object. | ||
| 174 | |||
| 175 | It 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. | ||
| 176 | |||
| 177 | When 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. | ||
| 178 | |||
| 179 | A few examples of using super in different ways: | ||
| 180 | |||
| 181 | ```yuescript | ||
| 182 | class MyClass extends ParentClass | ||
| 183 | a_method: => | ||
| 184 | -- the following have the same effect: | ||
| 185 | super "hello", "world" | ||
| 186 | super\a_method "hello", "world" | ||
| 187 | super.a_method self, "hello", "world" | ||
| 188 | |||
| 189 | -- super as a value is equal to the parent class: | ||
| 190 | assert super == ParentClass | ||
| 191 | ``` | ||
| 192 | <YueDisplay> | ||
| 193 | |||
| 194 | ```yue | ||
| 195 | class MyClass extends ParentClass | ||
| 196 | a_method: => | ||
| 197 | -- the following have the same effect: | ||
| 198 | super "hello", "world" | ||
| 199 | super\a_method "hello", "world" | ||
| 200 | super.a_method self, "hello", "world" | ||
| 201 | |||
| 202 | -- super as a value is equal to the parent class: | ||
| 203 | assert super == ParentClass | ||
| 204 | ``` | ||
| 205 | |||
| 206 | </YueDisplay> | ||
| 207 | |||
| 208 | **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. | ||
| 209 | |||
| 210 | ## Types | ||
| 211 | |||
| 212 | Every 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. | ||
| 213 | |||
| 214 | ```yuescript | ||
| 215 | b = BackPack! | ||
| 216 | assert b.__class == BackPack | ||
| 217 | |||
| 218 | print BackPack.size -- prints 10 | ||
| 219 | ``` | ||
| 220 | <YueDisplay> | ||
| 221 | |||
| 222 | ```yue | ||
| 223 | b = BackPack! | ||
| 224 | assert b.__class == BackPack | ||
| 225 | |||
| 226 | print BackPack.size -- prints 10 | ||
| 227 | ``` | ||
| 228 | |||
| 229 | </YueDisplay> | ||
| 230 | |||
| 231 | ## Class Objects | ||
| 232 | |||
| 233 | The 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. | ||
| 234 | |||
| 235 | The 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. | ||
| 236 | |||
| 237 | A 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. | ||
| 238 | |||
| 239 | The 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. | ||
| 240 | |||
| 241 | It 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. | ||
| 242 | |||
| 243 | The class object has a couple special properties: | ||
| 244 | |||
| 245 | The name of the class as when it was declared is stored as a string in the __name field of the class object. | ||
| 246 | |||
| 247 | ```yuescript | ||
| 248 | print BackPack.__name -- prints Backpack | ||
| 249 | ``` | ||
| 250 | <YueDisplay> | ||
| 251 | |||
| 252 | ```yue | ||
| 253 | print BackPack.__name -- prints Backpack | ||
| 254 | ``` | ||
| 255 | |||
| 256 | </YueDisplay> | ||
| 257 | |||
| 258 | The 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. | ||
| 259 | |||
| 260 | If the class extends from anything, the parent class object is stored in __parent. | ||
| 261 | |||
| 262 | ## Class Variables | ||
| 263 | |||
| 264 | We 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. | ||
| 265 | |||
| 266 | ```yuescript | ||
| 267 | class Things | ||
| 268 | @some_func: => print "Hello from", @__name | ||
| 269 | |||
| 270 | Things\some_func! | ||
| 271 | |||
| 272 | -- class variables not visible in instances | ||
| 273 | assert Things().some_func == nil | ||
| 274 | ``` | ||
| 275 | <YueDisplay> | ||
| 276 | |||
| 277 | ```yue | ||
| 278 | class Things | ||
| 279 | @some_func: => print "Hello from", @__name | ||
| 280 | |||
| 281 | Things\some_func! | ||
| 282 | |||
| 283 | -- class variables not visible in instances | ||
| 284 | assert Things().some_func == nil | ||
| 285 | ``` | ||
| 286 | |||
| 287 | </YueDisplay> | ||
| 288 | |||
| 289 | In expressions, we can use @@ to access a value that is stored in the __class of self. Thus, @@hello is shorthand for self.__class.hello. | ||
| 290 | |||
| 291 | ```yuescript | ||
| 292 | class Counter | ||
| 293 | @count: 0 | ||
| 294 | |||
| 295 | new: => | ||
| 296 | @@count += 1 | ||
| 297 | |||
| 298 | Counter! | ||
| 299 | Counter! | ||
| 300 | |||
| 301 | print Counter.count -- prints 2 | ||
| 302 | ``` | ||
| 303 | <YueDisplay> | ||
| 304 | |||
| 305 | ```yue | ||
| 306 | class Counter | ||
| 307 | @count: 0 | ||
| 308 | |||
| 309 | new: => | ||
| 310 | @@count += 1 | ||
| 311 | |||
| 312 | Counter! | ||
| 313 | Counter! | ||
| 314 | |||
| 315 | print Counter.count -- prints 2 | ||
| 316 | ``` | ||
| 317 | |||
| 318 | </YueDisplay> | ||
| 319 | |||
| 320 | The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax. | ||
| 321 | |||
| 322 | ```yuescript | ||
| 323 | @@hello 1,2,3,4 | ||
| 324 | ``` | ||
| 325 | <YueDisplay> | ||
| 326 | |||
| 327 | ```yue | ||
| 328 | @@hello 1,2,3,4 | ||
| 329 | ``` | ||
| 330 | |||
| 331 | </YueDisplay> | ||
| 332 | |||
| 333 | ## Class Declaration Statements | ||
| 334 | |||
| 335 | In 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. | ||
| 336 | |||
| 337 | Here is an alternative way to create a class variable compared to what's described above: | ||
| 338 | |||
| 339 | ```yuescript | ||
| 340 | class Things | ||
| 341 | @class_var = "hello world" | ||
| 342 | ``` | ||
| 343 | <YueDisplay> | ||
| 344 | |||
| 345 | ```yue | ||
| 346 | class Things | ||
| 347 | @class_var = "hello world" | ||
| 348 | ``` | ||
| 349 | |||
| 350 | </YueDisplay> | ||
| 351 | |||
| 352 | These expressions are executed after all the properties have been added to the base. | ||
| 353 | |||
| 354 | All 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: | ||
| 355 | |||
| 356 | ```yuescript | ||
| 357 | class MoreThings | ||
| 358 | secret = 123 | ||
| 359 | log = (msg) -> print "LOG:", msg | ||
| 360 | |||
| 361 | some_method: => | ||
| 362 | log "hello world: " .. secret | ||
| 363 | ``` | ||
| 364 | <YueDisplay> | ||
| 365 | |||
| 366 | ```yue | ||
| 367 | class MoreThings | ||
| 368 | secret = 123 | ||
| 369 | log = (msg) -> print "LOG:", msg | ||
| 370 | |||
| 371 | some_method: => | ||
| 372 | log "hello world: " .. secret | ||
| 373 | ``` | ||
| 374 | |||
| 375 | </YueDisplay> | ||
| 376 | |||
| 377 | ## @ and @@ Values | ||
| 378 | |||
| 379 | When @ and @@ are prefixed in front of a name they represent, respectively, that name accessed in self and self.__class. | ||
| 380 | |||
| 381 | If they are used all by themselves, they are aliases for self and self.__class. | ||
| 382 | |||
| 383 | ```yuescript | ||
| 384 | assert @ == self | ||
| 385 | assert @@ == self.__class | ||
| 386 | ``` | ||
| 387 | <YueDisplay> | ||
| 388 | |||
| 389 | ```yue | ||
| 390 | assert @ == self | ||
| 391 | assert @@ == self.__class | ||
| 392 | ``` | ||
| 393 | |||
| 394 | </YueDisplay> | ||
| 395 | |||
| 396 | For example, a quick way to create a new instance of the same class from an instance method using @@: | ||
| 397 | |||
| 398 | ```yuescript | ||
| 399 | some_instance_method = (...) => @@ ... | ||
| 400 | ``` | ||
| 401 | <YueDisplay> | ||
| 402 | |||
| 403 | ```yue | ||
| 404 | some_instance_method = (...) => @@ ... | ||
| 405 | ``` | ||
| 406 | |||
| 407 | </YueDisplay> | ||
| 408 | |||
| 409 | ## Constructor Property Promotion | ||
| 410 | |||
| 411 | To reduce the boilerplate code for definition of simple value objects. You can write a simple class like: | ||
| 412 | |||
| 413 | ```yuescript | ||
| 414 | class Something | ||
| 415 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 416 | |||
| 417 | -- Which is short for | ||
| 418 | |||
| 419 | class Something | ||
| 420 | new: (foo, bar, biz, baz) => | ||
| 421 | @foo = foo | ||
| 422 | @bar = bar | ||
| 423 | @@biz = biz | ||
| 424 | @@baz = baz | ||
| 425 | ``` | ||
| 426 | <YueDisplay> | ||
| 427 | |||
| 428 | ```yue | ||
| 429 | class Something | ||
| 430 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 431 | |||
| 432 | -- Which is short for | ||
| 433 | |||
| 434 | class Something | ||
| 435 | new: (foo, bar, biz, baz) => | ||
| 436 | @foo = foo | ||
| 437 | @bar = bar | ||
| 438 | @@biz = biz | ||
| 439 | @@baz = baz | ||
| 440 | ``` | ||
| 441 | |||
| 442 | </YueDisplay> | ||
| 443 | |||
| 444 | You can also use this syntax for a common function to initialize a object's fields. | ||
| 445 | |||
| 446 | ```yuescript | ||
| 447 | new = (@fieldA, @fieldB) => @ | ||
| 448 | obj = new {}, 123, "abc" | ||
| 449 | print obj | ||
| 450 | ``` | ||
| 451 | <YueDisplay> | ||
| 452 | |||
| 453 | ```yue | ||
| 454 | new = (@fieldA, @fieldB) => @ | ||
| 455 | obj = new {}, 123, "abc" | ||
| 456 | print obj | ||
| 457 | ``` | ||
| 458 | |||
| 459 | </YueDisplay> | ||
| 460 | |||
| 461 | ## Class Expressions | ||
| 462 | |||
| 463 | The class syntax can also be used as an expression which can be assigned to a variable or explicitly returned. | ||
| 464 | |||
| 465 | ```yuescript | ||
| 466 | x = class Bucket | ||
| 467 | drops: 0 | ||
| 468 | add_drop: => @drops += 1 | ||
| 469 | ``` | ||
| 470 | <YueDisplay> | ||
| 471 | |||
| 472 | ```yue | ||
| 473 | x = class Bucket | ||
| 474 | drops: 0 | ||
| 475 | add_drop: => @drops += 1 | ||
| 476 | ``` | ||
| 477 | |||
| 478 | </YueDisplay> | ||
| 479 | |||
| 480 | ## Anonymous classes | ||
| 481 | |||
| 482 | The 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. | ||
| 483 | |||
| 484 | ```yuescript | ||
| 485 | BigBucket = class extends Bucket | ||
| 486 | add_drop: => @drops += 10 | ||
| 487 | |||
| 488 | assert Bucket.__name == "BigBucket" | ||
| 489 | ``` | ||
| 490 | <YueDisplay> | ||
| 491 | |||
| 492 | ```yue | ||
| 493 | BigBucket = class extends Bucket | ||
| 494 | add_drop: => @drops += 10 | ||
| 495 | |||
| 496 | assert Bucket.__name == "BigBucket" | ||
| 497 | ``` | ||
| 498 | |||
| 499 | </YueDisplay> | ||
| 500 | |||
| 501 | You can even leave off the body, meaning you can write a blank anonymous class like this: | ||
| 502 | |||
| 503 | ```yuescript | ||
| 504 | x = class | ||
| 505 | ``` | ||
| 506 | <YueDisplay> | ||
| 507 | |||
| 508 | ```yue | ||
| 509 | x = class | ||
| 510 | ``` | ||
| 511 | |||
| 512 | </YueDisplay> | ||
| 513 | |||
| 514 | ## Class Mixing | ||
| 515 | |||
| 516 | You 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. | ||
| 517 | |||
| 518 | ```yuescript | ||
| 519 | MyIndex = __index: var: 1 | ||
| 520 | |||
| 521 | class X using MyIndex | ||
| 522 | func: => | ||
| 523 | print 123 | ||
| 524 | |||
| 525 | x = X! | ||
| 526 | print x.var | ||
| 527 | |||
| 528 | class Y using X | ||
| 529 | |||
| 530 | y = Y! | ||
| 531 | y\func! | ||
| 532 | |||
| 533 | assert y.__class.__parent ~= X -- X is not parent of Y | ||
| 534 | ``` | ||
| 535 | <YueDisplay> | ||
| 536 | |||
| 537 | ```yue | ||
| 538 | MyIndex = __index: var: 1 | ||
| 539 | |||
| 540 | class X using MyIndex | ||
| 541 | func: => | ||
| 542 | print 123 | ||
| 543 | |||
| 544 | x = X! | ||
| 545 | print x.var | ||
| 546 | |||
| 547 | class Y using X | ||
| 548 | |||
| 549 | y = Y! | ||
| 550 | y\func! | ||
| 551 | |||
| 552 | assert y.__class.__parent ~= X -- X is not parent of Y | ||
| 553 | ``` | ||
| 554 | |||
| 555 | </YueDisplay> | ||
diff --git a/doc/docs/doc/operator.md b/doc/docs/doc/operator.md new file mode 100644 index 0000000..9a2e89b --- /dev/null +++ b/doc/docs/doc/operator.md | |||
| @@ -0,0 +1,460 @@ | |||
| 1 | # Operator | ||
| 2 | |||
| 3 | All 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. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | tb\func! if tb ~= nil | ||
| 7 | tb::func! if tb != nil | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | tb\func! if tb ~= nil | ||
| 13 | tb::func! if tb != nil | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | ## Chaining Comparisons | ||
| 19 | |||
| 20 | Comparisons can be arbitrarily chained: | ||
| 21 | |||
| 22 | ```yuescript | ||
| 23 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 24 | -- output: true | ||
| 25 | |||
| 26 | a = 5 | ||
| 27 | print 1 <= a <= 10 | ||
| 28 | -- output: true | ||
| 29 | ``` | ||
| 30 | <YueDisplay> | ||
| 31 | |||
| 32 | ```yue | ||
| 33 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 34 | -- output: true | ||
| 35 | |||
| 36 | a = 5 | ||
| 37 | print 1 <= a <= 10 | ||
| 38 | -- output: true | ||
| 39 | ``` | ||
| 40 | |||
| 41 | </YueDisplay> | ||
| 42 | |||
| 43 | Note the evaluation behavior of chained comparisons: | ||
| 44 | |||
| 45 | ```yuescript | ||
| 46 | v = (x) -> | ||
| 47 | print x | ||
| 48 | x | ||
| 49 | |||
| 50 | print v(1) < v(2) <= v(3) | ||
| 51 | --[[ | ||
| 52 | output: | ||
| 53 | 2 | ||
| 54 | 1 | ||
| 55 | 3 | ||
| 56 | true | ||
| 57 | ]] | ||
| 58 | |||
| 59 | print v(1) > v(2) <= v(3) | ||
| 60 | --[[ | ||
| 61 | output: | ||
| 62 | 2 | ||
| 63 | 1 | ||
| 64 | false | ||
| 65 | ]] | ||
| 66 | ``` | ||
| 67 | <YueDisplay> | ||
| 68 | |||
| 69 | ```yue | ||
| 70 | v = (x) -> | ||
| 71 | print x | ||
| 72 | x | ||
| 73 | |||
| 74 | print v(1) < v(2) <= v(3) | ||
| 75 | --[[ | ||
| 76 | output: | ||
| 77 | 2 | ||
| 78 | 1 | ||
| 79 | 3 | ||
| 80 | true | ||
| 81 | ]] | ||
| 82 | |||
| 83 | print v(1) > v(2) <= v(3) | ||
| 84 | --[[ | ||
| 85 | output: | ||
| 86 | 2 | ||
| 87 | 1 | ||
| 88 | false | ||
| 89 | ]] | ||
| 90 | ``` | ||
| 91 | |||
| 92 | </YueDisplay> | ||
| 93 | |||
| 94 | The 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. | ||
| 95 | |||
| 96 | ## Table Appending | ||
| 97 | |||
| 98 | The **[] =** operator is used to append values to tables. | ||
| 99 | |||
| 100 | ```yuescript | ||
| 101 | tab = [] | ||
| 102 | tab[] = "Value" | ||
| 103 | ``` | ||
| 104 | <YueDisplay> | ||
| 105 | |||
| 106 | ```yue | ||
| 107 | tab = [] | ||
| 108 | tab[] = "Value" | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
| 112 | |||
| 113 | You can also use the spread operator `...` to append all elements from one list to another: | ||
| 114 | |||
| 115 | ```yuescript | ||
| 116 | tbA = [1, 2, 3] | ||
| 117 | tbB = [4, 5, 6] | ||
| 118 | tbA[] = ...tbB | ||
| 119 | -- tbA is now [1, 2, 3, 4, 5, 6] | ||
| 120 | ``` | ||
| 121 | <YueDisplay> | ||
| 122 | |||
| 123 | ```yue | ||
| 124 | tbA = [1, 2, 3] | ||
| 125 | tbB = [4, 5, 6] | ||
| 126 | tbA[] = ...tbB | ||
| 127 | -- tbA is now [1, 2, 3, 4, 5, 6] | ||
| 128 | ``` | ||
| 129 | |||
| 130 | </YueDisplay> | ||
| 131 | |||
| 132 | ## Table Spreading | ||
| 133 | |||
| 134 | You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals. | ||
| 135 | |||
| 136 | ```yuescript | ||
| 137 | parts = | ||
| 138 | * "shoulders" | ||
| 139 | * "knees" | ||
| 140 | lyrics = | ||
| 141 | * "head" | ||
| 142 | * ...parts | ||
| 143 | * "and" | ||
| 144 | * "toes" | ||
| 145 | |||
| 146 | copy = {...other} | ||
| 147 | |||
| 148 | a = {1, 2, 3, x: 1} | ||
| 149 | b = {4, 5, y: 1} | ||
| 150 | merge = {...a, ...b} | ||
| 151 | ``` | ||
| 152 | <YueDisplay> | ||
| 153 | |||
| 154 | ```yue | ||
| 155 | parts = | ||
| 156 | * "shoulders" | ||
| 157 | * "knees" | ||
| 158 | lyrics = | ||
| 159 | * "head" | ||
| 160 | * ...parts | ||
| 161 | * "and" | ||
| 162 | * "toes" | ||
| 163 | |||
| 164 | copy = {...other} | ||
| 165 | |||
| 166 | a = {1, 2, 3, x: 1} | ||
| 167 | b = {4, 5, y: 1} | ||
| 168 | merge = {...a, ...b} | ||
| 169 | ``` | ||
| 170 | |||
| 171 | </YueDisplay> | ||
| 172 | |||
| 173 | ## Table Reversed Indexing | ||
| 174 | |||
| 175 | You can use the **#** operator to get the last elements of a table. | ||
| 176 | |||
| 177 | ```yuescript | ||
| 178 | last = data.items[#] | ||
| 179 | second_last = data.items[#-1] | ||
| 180 | data.items[#] = 1 | ||
| 181 | ``` | ||
| 182 | <YueDisplay> | ||
| 183 | |||
| 184 | ```yue | ||
| 185 | last = data.items[#] | ||
| 186 | second_last = data.items[#-1] | ||
| 187 | data.items[#] = 1 | ||
| 188 | ``` | ||
| 189 | |||
| 190 | </YueDisplay> | ||
| 191 | |||
| 192 | ## Metatable | ||
| 193 | |||
| 194 | The **<>** operator can be used as a shortcut for metatable manipulation. | ||
| 195 | |||
| 196 | ### Metatable Creation | ||
| 197 | |||
| 198 | Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. | ||
| 199 | |||
| 200 | ```yuescript | ||
| 201 | mt = {} | ||
| 202 | add = (right) => <>: mt, value: @value + right.value | ||
| 203 | mt.__add = add | ||
| 204 | |||
| 205 | a = <>: mt, value: 1 | ||
| 206 | -- set field with variable of the same name | ||
| 207 | b = :<add>, value: 2 | ||
| 208 | c = <add>: mt.__add, value: 3 | ||
| 209 | |||
| 210 | d = a + b + c | ||
| 211 | print d.value | ||
| 212 | |||
| 213 | close _ = <close>: -> print "out of scope" | ||
| 214 | ``` | ||
| 215 | <YueDisplay> | ||
| 216 | |||
| 217 | ```yue | ||
| 218 | mt = {} | ||
| 219 | add = (right) => <>: mt, value: @value + right.value | ||
| 220 | mt.__add = add | ||
| 221 | |||
| 222 | a = <>: mt, value: 1 | ||
| 223 | -- set field with variable of the same name | ||
| 224 | b = :<add>, value: 2 | ||
| 225 | c = <add>: mt.__add, value: 3 | ||
| 226 | |||
| 227 | d = a + b + c | ||
| 228 | print d.value | ||
| 229 | |||
| 230 | close _ = <close>: -> print "out of scope" | ||
| 231 | ``` | ||
| 232 | |||
| 233 | </YueDisplay> | ||
| 234 | |||
| 235 | ### Metatable Accessing | ||
| 236 | |||
| 237 | Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. | ||
| 238 | |||
| 239 | ```yuescript | ||
| 240 | -- create with metatable containing field "value" | ||
| 241 | tb = <"value">: 123 | ||
| 242 | tb.<index> = tb.<> | ||
| 243 | print tb.value | ||
| 244 | |||
| 245 | tb.<> = __index: {item: "hello"} | ||
| 246 | print tb.item | ||
| 247 | ``` | ||
| 248 | <YueDisplay> | ||
| 249 | |||
| 250 | ```yue | ||
| 251 | -- create with metatable containing field "value" | ||
| 252 | tb = <"value">: 123 | ||
| 253 | tb.<index> = tb.<> | ||
| 254 | print tb.value | ||
| 255 | tb.<> = __index: {item: "hello"} | ||
| 256 | print tb.item | ||
| 257 | ``` | ||
| 258 | |||
| 259 | </YueDisplay> | ||
| 260 | |||
| 261 | ### Metatable Destructure | ||
| 262 | |||
| 263 | Destruct metatable with metamethod key surrounded by **<>**. | ||
| 264 | |||
| 265 | ```yuescript | ||
| 266 | {item, :new, :<close>, <index>: getter} = tb | ||
| 267 | print item, new, close, getter | ||
| 268 | ``` | ||
| 269 | <YueDisplay> | ||
| 270 | |||
| 271 | ```yue | ||
| 272 | {item, :new, :<close>, <index>: getter} = tb | ||
| 273 | print item, new, close, getter | ||
| 274 | ``` | ||
| 275 | |||
| 276 | </YueDisplay> | ||
| 277 | |||
| 278 | ## Existence | ||
| 279 | |||
| 280 | The **?** operator can be used in a variety of contexts to check for existence. | ||
| 281 | |||
| 282 | ```yuescript | ||
| 283 | func?! | ||
| 284 | print abc?["hello world"]?.xyz | ||
| 285 | |||
| 286 | x = tab?.value | ||
| 287 | len = utf8?.len or string?.len or (o) -> #o | ||
| 288 | |||
| 289 | if print and x? | ||
| 290 | print x | ||
| 291 | |||
| 292 | with? io.open "test.txt", "w" | ||
| 293 | \write "hello" | ||
| 294 | \close! | ||
| 295 | ``` | ||
| 296 | <YueDisplay> | ||
| 297 | |||
| 298 | ```yue | ||
| 299 | func?! | ||
| 300 | print abc?["hello world"]?.xyz | ||
| 301 | |||
| 302 | x = tab?.value | ||
| 303 | len = utf8?.len or string?.len or (o) -> #o | ||
| 304 | |||
| 305 | if print and x? | ||
| 306 | print x | ||
| 307 | |||
| 308 | with? io.open "test.txt", "w" | ||
| 309 | \write "hello" | ||
| 310 | \close! | ||
| 311 | ``` | ||
| 312 | |||
| 313 | </YueDisplay> | ||
| 314 | |||
| 315 | ## Piping | ||
| 316 | |||
| 317 | Instead of a series of nested function calls, you can pipe values with operator **|>**. | ||
| 318 | |||
| 319 | ```yuescript | ||
| 320 | "hello" |> print | ||
| 321 | 1 |> print 2 -- insert pipe item as the first argument | ||
| 322 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
| 323 | |||
| 324 | -- pipe expression in multiline | ||
| 325 | readFile "example.txt" | ||
| 326 | |> extract language, {} | ||
| 327 | |> parse language | ||
| 328 | |> emit | ||
| 329 | |> render | ||
| 330 | |||
| 331 | ``` | ||
| 332 | <YueDisplay> | ||
| 333 | |||
| 334 | ```yue | ||
| 335 | "hello" |> print | ||
| 336 | 1 |> print 2 -- insert pipe item as the first argument | ||
| 337 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
| 338 | -- pipe expression in multiline | ||
| 339 | readFile "example.txt" | ||
| 340 | |> extract language, {} | ||
| 341 | |> parse language | ||
| 342 | |> emit | ||
| 343 | |> render | ||
| 344 | |||
| 345 | ``` | ||
| 346 | |||
| 347 | </YueDisplay> | ||
| 348 | |||
| 349 | ## Nil Coalescing | ||
| 350 | |||
| 351 | The 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. | ||
| 352 | ```yuescript | ||
| 353 | local a, b, c, d | ||
| 354 | a = b ?? c ?? d | ||
| 355 | func a ?? {} | ||
| 356 | |||
| 357 | a ??= false | ||
| 358 | ``` | ||
| 359 | <YueDisplay> | ||
| 360 | |||
| 361 | ```yue | ||
| 362 | local a, b, c, d | ||
| 363 | a = b ?? c ?? d | ||
| 364 | func a ?? {} | ||
| 365 | a ??= false | ||
| 366 | ``` | ||
| 367 | |||
| 368 | </YueDisplay> | ||
| 369 | |||
| 370 | ## Implicit Object | ||
| 371 | |||
| 372 | You 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. | ||
| 373 | |||
| 374 | ```yuescript | ||
| 375 | -- assignment with implicit object | ||
| 376 | list = | ||
| 377 | * 1 | ||
| 378 | * 2 | ||
| 379 | * 3 | ||
| 380 | |||
| 381 | -- function call with implicit object | ||
| 382 | func | ||
| 383 | * 1 | ||
| 384 | * 2 | ||
| 385 | * 3 | ||
| 386 | |||
| 387 | -- return with implicit object | ||
| 388 | f = -> | ||
| 389 | return | ||
| 390 | * 1 | ||
| 391 | * 2 | ||
| 392 | * 3 | ||
| 393 | |||
| 394 | -- table with implicit object | ||
| 395 | tb = | ||
| 396 | name: "abc" | ||
| 397 | |||
| 398 | values: | ||
| 399 | - "a" | ||
| 400 | - "b" | ||
| 401 | - "c" | ||
| 402 | |||
| 403 | objects: | ||
| 404 | - name: "a" | ||
| 405 | value: 1 | ||
| 406 | func: => @value + 1 | ||
| 407 | tb: | ||
| 408 | fieldA: 1 | ||
| 409 | |||
| 410 | - name: "b" | ||
| 411 | value: 2 | ||
| 412 | func: => @value + 2 | ||
| 413 | tb: { } | ||
| 414 | |||
| 415 | ``` | ||
| 416 | <YueDisplay> | ||
| 417 | |||
| 418 | ```yue | ||
| 419 | -- assignment with implicit object | ||
| 420 | list = | ||
| 421 | * 1 | ||
| 422 | * 2 | ||
| 423 | * 3 | ||
| 424 | |||
| 425 | -- function call with implicit object | ||
| 426 | func | ||
| 427 | * 1 | ||
| 428 | * 2 | ||
| 429 | * 3 | ||
| 430 | |||
| 431 | -- return with implicit object | ||
| 432 | f = -> | ||
| 433 | return | ||
| 434 | * 1 | ||
| 435 | * 2 | ||
| 436 | * 3 | ||
| 437 | |||
| 438 | -- table with implicit object | ||
| 439 | tb = | ||
| 440 | name: "abc" | ||
| 441 | |||
| 442 | values: | ||
| 443 | - "a" | ||
| 444 | - "b" | ||
| 445 | - "c" | ||
| 446 | |||
| 447 | objects: | ||
| 448 | - name: "a" | ||
| 449 | value: 1 | ||
| 450 | func: => @value + 1 | ||
| 451 | tb: | ||
| 452 | fieldA: 1 | ||
| 453 | |||
| 454 | - name: "b" | ||
| 455 | value: 2 | ||
| 456 | func: => @value + 2 | ||
| 457 | tb: { } | ||
| 458 | ``` | ||
| 459 | |||
| 460 | </YueDisplay> | ||
diff --git a/doc/docs/doc/switch.md b/doc/docs/doc/switch.md new file mode 100644 index 0000000..f503a80 --- /dev/null +++ b/doc/docs/doc/switch.md | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | # Switch | ||
| 2 | |||
| 3 | The 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. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | switch name := "Dan" | ||
| 7 | when "Robert" | ||
| 8 | print "You are Robert" | ||
| 9 | when "Dan", "Daniel" | ||
| 10 | print "Your name, it's Dan" | ||
| 11 | else | ||
| 12 | print "I don't know about you with name #{name}" | ||
| 13 | ``` | ||
| 14 | <YueDisplay> | ||
| 15 | |||
| 16 | ```yue | ||
| 17 | switch name := "Dan" | ||
| 18 | when "Robert" | ||
| 19 | print "You are Robert" | ||
| 20 | when "Dan", "Daniel" | ||
| 21 | print "Your name, it's Dan" | ||
| 22 | else | ||
| 23 | print "I don't know about you with name #{name}" | ||
| 24 | ``` | ||
| 25 | |||
| 26 | </YueDisplay> | ||
| 27 | |||
| 28 | A switch when clause can match against multiple values by listing them out comma separated. | ||
| 29 | |||
| 30 | Switches can be used as expressions as well, here we can assign the result of the switch to a variable: | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | b = 1 | ||
| 34 | next_number = switch b | ||
| 35 | when 1 | ||
| 36 | 2 | ||
| 37 | when 2 | ||
| 38 | 3 | ||
| 39 | else | ||
| 40 | error "can't count that high!" | ||
| 41 | ``` | ||
| 42 | <YueDisplay> | ||
| 43 | |||
| 44 | ```yue | ||
| 45 | b = 1 | ||
| 46 | next_number = switch b | ||
| 47 | when 1 | ||
| 48 | 2 | ||
| 49 | when 2 | ||
| 50 | 3 | ||
| 51 | else | ||
| 52 | error "can't count that high!" | ||
| 53 | ``` | ||
| 54 | |||
| 55 | </YueDisplay> | ||
| 56 | |||
| 57 | We 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. | ||
| 58 | |||
| 59 | ```yuescript | ||
| 60 | msg = switch math.random(1, 5) | ||
| 61 | when 1 then "you are lucky" | ||
| 62 | when 2 then "you are almost lucky" | ||
| 63 | else "not so lucky" | ||
| 64 | ``` | ||
| 65 | <YueDisplay> | ||
| 66 | |||
| 67 | ```yue | ||
| 68 | msg = switch math.random(1, 5) | ||
| 69 | when 1 then "you are lucky" | ||
| 70 | when 2 then "you are almost lucky" | ||
| 71 | else "not so lucky" | ||
| 72 | ``` | ||
| 73 | |||
| 74 | </YueDisplay> | ||
| 75 | |||
| 76 | If 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. | ||
| 77 | |||
| 78 | ```yuescript | ||
| 79 | switch math.random(1, 5) | ||
| 80 | when 1 | ||
| 81 | print "you are lucky" -- two indents | ||
| 82 | else | ||
| 83 | print "not so lucky" | ||
| 84 | |||
| 85 | switch math.random(1, 5) when 1 | ||
| 86 | print "you are lucky" -- one indent | ||
| 87 | else | ||
| 88 | print "not so lucky" | ||
| 89 | ``` | ||
| 90 | <YueDisplay> | ||
| 91 | |||
| 92 | ```yue | ||
| 93 | switch math.random(1, 5) | ||
| 94 | when 1 | ||
| 95 | print "you are lucky" -- two indents | ||
| 96 | else | ||
| 97 | print "not so lucky" | ||
| 98 | |||
| 99 | switch math.random(1, 5) when 1 | ||
| 100 | print "you are lucky" -- one indent | ||
| 101 | else | ||
| 102 | print "not so lucky" | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
| 106 | |||
| 107 | It 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. | ||
| 108 | |||
| 109 | ## Table Matching | ||
| 110 | |||
| 111 | You can do table matching in a switch when clause, if the table can be destructured by a specific structure and get non-nil values. | ||
| 112 | |||
| 113 | ```yuescript | ||
| 114 | items = | ||
| 115 | * x: 100 | ||
| 116 | y: 200 | ||
| 117 | * width: 300 | ||
| 118 | height: 400 | ||
| 119 | |||
| 120 | for item in *items | ||
| 121 | switch item | ||
| 122 | when :x, :y | ||
| 123 | print "Vec2 #{x}, #{y}" | ||
| 124 | when :width, :height | ||
| 125 | print "size #{width}, #{height}" | ||
| 126 | ``` | ||
| 127 | <YueDisplay> | ||
| 128 | |||
| 129 | ```yue | ||
| 130 | items = | ||
| 131 | * x: 100 | ||
| 132 | y: 200 | ||
| 133 | * width: 300 | ||
| 134 | height: 400 | ||
| 135 | |||
| 136 | for item in *items | ||
| 137 | switch item | ||
| 138 | when :x, :y | ||
| 139 | print "Vec2 #{x}, #{y}" | ||
| 140 | when :width, :height | ||
| 141 | print "size #{width}, #{height}" | ||
| 142 | ``` | ||
| 143 | |||
| 144 | </YueDisplay> | ||
| 145 | |||
| 146 | You can use default values to optionally destructure the table for some fields. | ||
| 147 | |||
| 148 | ```yuescript | ||
| 149 | item = {} | ||
| 150 | |||
| 151 | {pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos') | ||
| 152 | |||
| 153 | switch item | ||
| 154 | when {pos: {:x = 50, :y = 200}} | ||
| 155 | print "Vec2 #{x}, #{y}" -- table destructuring will still pass | ||
| 156 | ``` | ||
| 157 | <YueDisplay> | ||
| 158 | |||
| 159 | ```yue | ||
| 160 | item = {} | ||
| 161 | |||
| 162 | {pos: {:x = 50, :y = 200}} = item -- get error: attempt to index a nil value (field 'pos') | ||
| 163 | |||
| 164 | switch item | ||
| 165 | when {pos: {:x = 50, :y = 200}} | ||
| 166 | print "Vec2 #{x}, #{y}" -- table destructuring will still pass | ||
| 167 | ``` | ||
| 168 | |||
| 169 | </YueDisplay> | ||
| 170 | |||
| 171 | You can also match against array elements, table fields, and even nested structures with array or table literals. | ||
| 172 | |||
| 173 | Match against array elements. | ||
| 174 | |||
| 175 | ```yuescript | ||
| 176 | switch tb | ||
| 177 | when [1, 2, 3] | ||
| 178 | print "1, 2, 3" | ||
| 179 | when [1, b, 3] | ||
| 180 | print "1, #{b}, 3" | ||
| 181 | when [1, 2, b = 3] -- b has a default value | ||
| 182 | print "1, 2, #{b}" | ||
| 183 | ``` | ||
| 184 | <YueDisplay> | ||
| 185 | |||
| 186 | ```yue | ||
| 187 | switch tb | ||
| 188 | when [1, 2, 3] | ||
| 189 | print "1, 2, 3" | ||
| 190 | when [1, b, 3] | ||
| 191 | print "1, #{b}, 3" | ||
| 192 | when [1, 2, b = 3] -- b has a default value | ||
| 193 | print "1, 2, #{b}" | ||
| 194 | ``` | ||
| 195 | |||
| 196 | </YueDisplay> | ||
| 197 | |||
| 198 | Match against table fields with destructuring. | ||
| 199 | |||
| 200 | ```yuescript | ||
| 201 | switch tb | ||
| 202 | when success: true, :result | ||
| 203 | print "success", result | ||
| 204 | when success: false | ||
| 205 | print "failed", result | ||
| 206 | else | ||
| 207 | print "invalid" | ||
| 208 | ``` | ||
| 209 | <YueDisplay> | ||
| 210 | |||
| 211 | ```yue | ||
| 212 | switch tb | ||
| 213 | when success: true, :result | ||
| 214 | print "success", result | ||
| 215 | when success: false | ||
| 216 | print "failed", result | ||
| 217 | else | ||
| 218 | print "invalid" | ||
| 219 | ``` | ||
| 220 | |||
| 221 | </YueDisplay> | ||
| 222 | |||
| 223 | Match against nested table structures. | ||
| 224 | |||
| 225 | ```yuescript | ||
| 226 | switch tb | ||
| 227 | when data: {type: "success", :content} | ||
| 228 | print "success", content | ||
| 229 | when data: {type: "error", :content} | ||
| 230 | print "failed", content | ||
| 231 | else | ||
| 232 | print "invalid" | ||
| 233 | ``` | ||
| 234 | <YueDisplay> | ||
| 235 | |||
| 236 | ```yue | ||
| 237 | switch tb | ||
| 238 | when data: {type: "success", :content} | ||
| 239 | print "success", content | ||
| 240 | when data: {type: "error", :content} | ||
| 241 | print "failed", content | ||
| 242 | else | ||
| 243 | print "invalid" | ||
| 244 | ``` | ||
| 245 | |||
| 246 | </YueDisplay> | ||
| 247 | |||
| 248 | Match against array of tables. | ||
| 249 | |||
| 250 | ```yuescript | ||
| 251 | switch tb | ||
| 252 | when [ | ||
| 253 | {a: 1, b: 2} | ||
| 254 | {a: 3, b: 4} | ||
| 255 | {a: 5, b: 6} | ||
| 256 | fourth | ||
| 257 | ] | ||
| 258 | print "matched", fourth | ||
| 259 | ``` | ||
| 260 | <YueDisplay> | ||
| 261 | |||
| 262 | ```yue | ||
| 263 | switch tb | ||
| 264 | when [ | ||
| 265 | {a: 1, b: 2} | ||
| 266 | {a: 3, b: 4} | ||
| 267 | {a: 5, b: 6} | ||
| 268 | fourth | ||
| 269 | ] | ||
| 270 | print "matched", fourth | ||
| 271 | ``` | ||
| 272 | |||
| 273 | </YueDisplay> | ||
| 274 | |||
| 275 | Match against a list and capture a range of elements. | ||
| 276 | |||
| 277 | ```yuescript | ||
| 278 | segments = ["admin", "users", "logs", "view"] | ||
| 279 | switch segments | ||
| 280 | when [...groups, resource, action] | ||
| 281 | print "Group:", groups -- prints: {"admin", "users"} | ||
| 282 | print "Resource:", resource -- prints: "logs" | ||
| 283 | print "Action:", action -- prints: "view" | ||
| 284 | ``` | ||
| 285 | <YueDisplay> | ||
| 286 | |||
| 287 | ```yue | ||
| 288 | segments = ["admin", "users", "logs", "view"] | ||
| 289 | switch segments | ||
| 290 | when [...groups, resource, action] | ||
| 291 | print "Group:", groups -- prints: {"admin", "users"} | ||
| 292 | print "Resource:", resource -- prints: "logs" | ||
| 293 | print "Action:", action -- prints: "view" | ||
| 294 | ``` | ||
| 295 | |||
| 296 | </YueDisplay> | ||
diff --git a/doc/docs/doc/table-literals.md b/doc/docs/doc/table-literals.md new file mode 100644 index 0000000..c1adcab --- /dev/null +++ b/doc/docs/doc/table-literals.md | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | # Table Literals | ||
| 2 | |||
| 3 | Like in Lua, tables are delimited in curly braces. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | some_values = [1, 2, 3, 4] | ||
| 7 | ``` | ||
| 8 | <YueDisplay> | ||
| 9 | |||
| 10 | ```yue | ||
| 11 | some_values = [1, 2, 3, 4] | ||
| 12 | ``` | ||
| 13 | |||
| 14 | </YueDisplay> | ||
| 15 | |||
| 16 | Unlike Lua, assigning a value to a key in a table is done with **:** (instead of **=**). | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | some_values = { | ||
| 20 | name: "Bill", | ||
| 21 | age: 200, | ||
| 22 | ["favorite food"]: "rice" | ||
| 23 | } | ||
| 24 | ``` | ||
| 25 | <YueDisplay> | ||
| 26 | |||
| 27 | ```yue | ||
| 28 | some_values = { | ||
| 29 | name: "Bill", | ||
| 30 | age: 200, | ||
| 31 | ["favorite food"]: "rice" | ||
| 32 | } | ||
| 33 | ``` | ||
| 34 | |||
| 35 | </YueDisplay> | ||
| 36 | |||
| 37 | The curly braces can be left off if a single table of key value pairs is being assigned. | ||
| 38 | |||
| 39 | ```yuescript | ||
| 40 | profile = | ||
| 41 | height: "4 feet", | ||
| 42 | shoe_size: 13, | ||
| 43 | favorite_foods: ["ice cream", "donuts"] | ||
| 44 | ``` | ||
| 45 | <YueDisplay> | ||
| 46 | |||
| 47 | ```yue | ||
| 48 | profile = | ||
| 49 | height: "4 feet", | ||
| 50 | shoe_size: 13, | ||
| 51 | favorite_foods: ["ice cream", "donuts"] | ||
| 52 | ``` | ||
| 53 | |||
| 54 | </YueDisplay> | ||
| 55 | |||
| 56 | Newlines can be used to delimit values instead of a comma (or both): | ||
| 57 | |||
| 58 | ```yuescript | ||
| 59 | values = { | ||
| 60 | 1, 2, 3, 4 | ||
| 61 | 5, 6, 7, 8 | ||
| 62 | name: "superman" | ||
| 63 | occupation: "crime fighting" | ||
| 64 | } | ||
| 65 | ``` | ||
| 66 | <YueDisplay> | ||
| 67 | |||
| 68 | ```yue | ||
| 69 | values = { | ||
| 70 | 1, 2, 3, 4 | ||
| 71 | 5, 6, 7, 8 | ||
| 72 | name: "superman" | ||
| 73 | occupation: "crime fighting" | ||
| 74 | } | ||
| 75 | ``` | ||
| 76 | |||
| 77 | </YueDisplay> | ||
| 78 | |||
| 79 | When creating a single line table literal, the curly braces can also be left off: | ||
| 80 | |||
| 81 | ```yuescript | ||
| 82 | my_function dance: "Tango", partner: "none" | ||
| 83 | |||
| 84 | y = type: "dog", legs: 4, tails: 1 | ||
| 85 | ``` | ||
| 86 | <YueDisplay> | ||
| 87 | |||
| 88 | ```yue | ||
| 89 | my_function dance: "Tango", partner: "none" | ||
| 90 | |||
| 91 | y = type: "dog", legs: 4, tails: 1 | ||
| 92 | ``` | ||
| 93 | |||
| 94 | </YueDisplay> | ||
| 95 | |||
| 96 | The keys of a table literal can be language keywords without being escaped: | ||
| 97 | |||
| 98 | ```yuescript | ||
| 99 | tbl = { | ||
| 100 | do: "something" | ||
| 101 | end: "hunger" | ||
| 102 | } | ||
| 103 | ``` | ||
| 104 | <YueDisplay> | ||
| 105 | |||
| 106 | ```yue | ||
| 107 | tbl = { | ||
| 108 | do: "something" | ||
| 109 | end: "hunger" | ||
| 110 | } | ||
| 111 | ``` | ||
| 112 | |||
| 113 | </YueDisplay> | ||
| 114 | |||
| 115 | If 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: | ||
| 116 | |||
| 117 | ```yuescript | ||
| 118 | hair = "golden" | ||
| 119 | height = 200 | ||
| 120 | person = { :hair, :height, shoe_size: 40 } | ||
| 121 | |||
| 122 | print_table :hair, :height | ||
| 123 | ``` | ||
| 124 | <YueDisplay> | ||
| 125 | |||
| 126 | ```yue | ||
| 127 | hair = "golden" | ||
| 128 | height = 200 | ||
| 129 | person = { :hair, :height, shoe_size: 40 } | ||
| 130 | |||
| 131 | print_table :hair, :height | ||
| 132 | ``` | ||
| 133 | |||
| 134 | </YueDisplay> | ||
| 135 | |||
| 136 | If 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. | ||
| 137 | |||
| 138 | ```yuescript | ||
| 139 | t = { | ||
| 140 | [1 + 2]: "hello" | ||
| 141 | "hello world": true | ||
| 142 | } | ||
| 143 | ``` | ||
| 144 | <YueDisplay> | ||
| 145 | |||
| 146 | ```yue | ||
| 147 | t = { | ||
| 148 | [1 + 2]: "hello" | ||
| 149 | "hello world": true | ||
| 150 | } | ||
| 151 | ``` | ||
| 152 | |||
| 153 | </YueDisplay> | ||
| 154 | |||
| 155 | Lua 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. | ||
| 156 | |||
| 157 | ```yuescript | ||
| 158 | some_values = [1, 2, 3, 4] | ||
| 159 | list_with_one_element = [1, ] | ||
| 160 | ``` | ||
| 161 | <YueDisplay> | ||
| 162 | |||
| 163 | ```yue | ||
| 164 | some_values = [1, 2, 3, 4] | ||
| 165 | list_with_one_element = [1, ] | ||
| 166 | ``` | ||
| 167 | |||
| 168 | </YueDisplay> | ||
diff --git a/doc/docs/doc/the-using-clause-controlling-destructive-assignment.md b/doc/docs/doc/the-using-clause-controlling-destructive-assignment.md new file mode 100644 index 0000000..fb9b740 --- /dev/null +++ b/doc/docs/doc/the-using-clause-controlling-destructive-assignment.md | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | # The Using Clause; Controlling Destructive Assignment | ||
| 2 | |||
| 3 | While 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: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 100 | ||
| 7 | |||
| 8 | -- many lines of code... | ||
| 9 | |||
| 10 | my_func = -> | ||
| 11 | i = 10 | ||
| 12 | while i > 0 | ||
| 13 | print i | ||
| 14 | i -= 1 | ||
| 15 | |||
| 16 | my_func! | ||
| 17 | |||
| 18 | print i -- will print 0 | ||
| 19 | ``` | ||
| 20 | <YueDisplay> | ||
| 21 | |||
| 22 | ```yue | ||
| 23 | i = 100 | ||
| 24 | |||
| 25 | -- many lines of code... | ||
| 26 | |||
| 27 | my_func = -> | ||
| 28 | i = 10 | ||
| 29 | while i > 0 | ||
| 30 | print i | ||
| 31 | i -= 1 | ||
| 32 | |||
| 33 | my_func! | ||
| 34 | |||
| 35 | print i -- will print 0 | ||
| 36 | ``` | ||
| 37 | |||
| 38 | </YueDisplay> | ||
| 39 | |||
| 40 | In 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. | ||
| 41 | |||
| 42 | It 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. | ||
| 43 | |||
| 44 | The 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. | ||
| 45 | |||
| 46 | ```yuescript | ||
| 47 | i = 100 | ||
| 48 | |||
| 49 | my_func = (using nil) -> | ||
| 50 | i = "hello" -- a new local variable is created here | ||
| 51 | |||
| 52 | my_func! | ||
| 53 | print i -- prints 100, i is unaffected | ||
| 54 | ``` | ||
| 55 | <YueDisplay> | ||
| 56 | |||
| 57 | ```yue | ||
| 58 | i = 100 | ||
| 59 | |||
| 60 | my_func = (using nil) -> | ||
| 61 | i = "hello" -- a new local variable is created here | ||
| 62 | |||
| 63 | my_func! | ||
| 64 | print i -- prints 100, i is unaffected | ||
| 65 | ``` | ||
| 66 | |||
| 67 | </YueDisplay> | ||
| 68 | |||
| 69 | Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified: | ||
| 70 | |||
| 71 | ```yuescript | ||
| 72 | tmp = 1213 | ||
| 73 | i, k = 100, 50 | ||
| 74 | |||
| 75 | my_func = (add using k, i) -> | ||
| 76 | tmp = tmp + add -- a new local tmp is created | ||
| 77 | i += tmp | ||
| 78 | k += tmp | ||
| 79 | |||
| 80 | my_func(22) | ||
| 81 | print i, k -- these have been updated | ||
| 82 | ``` | ||
| 83 | <YueDisplay> | ||
| 84 | |||
| 85 | ```yue | ||
| 86 | tmp = 1213 | ||
| 87 | i, k = 100, 50 | ||
| 88 | |||
| 89 | my_func = (add using k, i) -> | ||
| 90 | tmp = tmp + add -- a new local tmp is created | ||
| 91 | i += tmp | ||
| 92 | k += tmp | ||
| 93 | |||
| 94 | my_func(22) | ||
| 95 | print i, k -- these have been updated | ||
| 96 | ``` | ||
| 97 | |||
| 98 | </YueDisplay> | ||
diff --git a/doc/docs/doc/the-yuescript-library.md b/doc/docs/doc/the-yuescript-library.md new file mode 100644 index 0000000..3761755 --- /dev/null +++ b/doc/docs/doc/the-yuescript-library.md | |||
| @@ -0,0 +1,821 @@ | |||
| 1 | # The YueScript Library | ||
| 2 | |||
| 3 | Access it by `local yue = require("yue")` in Lua. | ||
| 4 | |||
| 5 | ## yue | ||
| 6 | |||
| 7 | **Description:** | ||
| 8 | |||
| 9 | The YueScript language library. | ||
| 10 | |||
| 11 | ### version | ||
| 12 | |||
| 13 | **Type:** Field. | ||
| 14 | |||
| 15 | **Description:** | ||
| 16 | |||
| 17 | The YueScript version. | ||
| 18 | |||
| 19 | **Signature:** | ||
| 20 | ```lua | ||
| 21 | version: string | ||
| 22 | ``` | ||
| 23 | |||
| 24 | ### dirsep | ||
| 25 | |||
| 26 | **Type:** Field. | ||
| 27 | |||
| 28 | **Description:** | ||
| 29 | |||
| 30 | The file separator for the current platform. | ||
| 31 | |||
| 32 | **Signature:** | ||
| 33 | ```lua | ||
| 34 | dirsep: string | ||
| 35 | ``` | ||
| 36 | |||
| 37 | ### yue_compiled | ||
| 38 | |||
| 39 | **Type:** Field. | ||
| 40 | |||
| 41 | **Description:** | ||
| 42 | |||
| 43 | The compiled module code cache. | ||
| 44 | |||
| 45 | **Signature:** | ||
| 46 | ```lua | ||
| 47 | yue_compiled: {string: string} | ||
| 48 | ``` | ||
| 49 | |||
| 50 | ### to_lua | ||
| 51 | |||
| 52 | **Type:** Function. | ||
| 53 | |||
| 54 | **Description:** | ||
| 55 | |||
| 56 | The YueScript compiling function. It compiles the YueScript code to Lua code. | ||
| 57 | |||
| 58 | **Signature:** | ||
| 59 | ```lua | ||
| 60 | to_lua: function(code: string, config?: Config): | ||
| 61 | --[[codes]] string | nil, | ||
| 62 | --[[error]] string | nil, | ||
| 63 | --[[globals]] {{string, integer, integer}} | nil | ||
| 64 | ``` | ||
| 65 | |||
| 66 | **Parameters:** | ||
| 67 | |||
| 68 | | Parameter | Type | Description | | ||
| 69 | | --- | --- | --- | | ||
| 70 | | code | string | The YueScript code. | | ||
| 71 | | config | Config | [Optional] The compiler options. | | ||
| 72 | |||
| 73 | **Returns:** | ||
| 74 | |||
| 75 | | Return Type | Description | | ||
| 76 | | --- | --- | | ||
| 77 | | string \| nil | The compiled Lua code, or nil if the compilation failed. | | ||
| 78 | | string \| nil | The error message, or nil if the compilation succeeded. | | ||
| 79 | | {{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. | | ||
| 80 | |||
| 81 | ### file_exist | ||
| 82 | |||
| 83 | **Type:** Function. | ||
| 84 | |||
| 85 | **Description:** | ||
| 86 | |||
| 87 | The source file existence checking function. Can be overridden to customize the behavior. | ||
| 88 | |||
| 89 | **Signature:** | ||
| 90 | ```lua | ||
| 91 | file_exist: function(filename: string): boolean | ||
| 92 | ``` | ||
| 93 | |||
| 94 | **Parameters:** | ||
| 95 | |||
| 96 | | Parameter | Type | Description | | ||
| 97 | | --- | --- | --- | | ||
| 98 | | filename | string | The file name. | | ||
| 99 | |||
| 100 | **Returns:** | ||
| 101 | |||
| 102 | | Return Type | Description | | ||
| 103 | | --- | --- | | ||
| 104 | | boolean | Whether the file exists. | | ||
| 105 | |||
| 106 | ### read_file | ||
| 107 | |||
| 108 | **Type:** Function. | ||
| 109 | |||
| 110 | **Description:** | ||
| 111 | |||
| 112 | The source file reading function. Can be overridden to customize the behavior. | ||
| 113 | |||
| 114 | **Signature:** | ||
| 115 | ```lua | ||
| 116 | read_file: function(filename: string): string | ||
| 117 | ``` | ||
| 118 | |||
| 119 | **Parameters:** | ||
| 120 | |||
| 121 | | Parameter | Type | Description | | ||
| 122 | | --- | --- | --- | | ||
| 123 | | filename | string | The file name. | | ||
| 124 | |||
| 125 | **Returns:** | ||
| 126 | |||
| 127 | | Return Type | Description | | ||
| 128 | | --- | --- | | ||
| 129 | | string | The file content. | | ||
| 130 | |||
| 131 | ### insert_loader | ||
| 132 | |||
| 133 | **Type:** Function. | ||
| 134 | |||
| 135 | **Description:** | ||
| 136 | |||
| 137 | Insert the YueScript loader to the package loaders (searchers). | ||
| 138 | |||
| 139 | **Signature:** | ||
| 140 | ```lua | ||
| 141 | insert_loader: function(pos?: integer): boolean | ||
| 142 | ``` | ||
| 143 | |||
| 144 | **Parameters:** | ||
| 145 | |||
| 146 | | Parameter | Type | Description | | ||
| 147 | | --- | --- | --- | | ||
| 148 | | pos | integer | [Optional] The position to insert the loader. Default is 3. | | ||
| 149 | |||
| 150 | **Returns:** | ||
| 151 | |||
| 152 | | Return Type | Description | | ||
| 153 | | --- | --- | | ||
| 154 | | boolean | Whether the loader is inserted successfully. It will fail if the loader is already inserted. | | ||
| 155 | |||
| 156 | ### remove_loader | ||
| 157 | |||
| 158 | **Type:** Function. | ||
| 159 | |||
| 160 | **Description:** | ||
| 161 | |||
| 162 | Remove the YueScript loader from the package loaders (searchers). | ||
| 163 | |||
| 164 | **Signature:** | ||
| 165 | ```lua | ||
| 166 | remove_loader: function(): boolean | ||
| 167 | ``` | ||
| 168 | |||
| 169 | **Returns:** | ||
| 170 | |||
| 171 | | Return Type | Description | | ||
| 172 | | --- | --- | | ||
| 173 | | boolean | Whether the loader is removed successfully. It will fail if the loader is not inserted. | | ||
| 174 | |||
| 175 | ### loadstring | ||
| 176 | |||
| 177 | **Type:** Function. | ||
| 178 | |||
| 179 | **Description:** | ||
| 180 | |||
| 181 | Loads YueScript code from a string into a function. | ||
| 182 | |||
| 183 | **Signature:** | ||
| 184 | ```lua | ||
| 185 | loadstring: function(input: string, chunkname: string, env: table, config?: Config): | ||
| 186 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 187 | --[[error]] string | nil | ||
| 188 | ``` | ||
| 189 | |||
| 190 | **Parameters:** | ||
| 191 | |||
| 192 | | Parameter | Type | Description | | ||
| 193 | | --- | --- | --- | | ||
| 194 | | input | string | The YueScript code. | | ||
| 195 | | chunkname | string | The name of the code chunk. | | ||
| 196 | | env | table | The environment table. | | ||
| 197 | | config | Config | [Optional] The compiler options. | | ||
| 198 | |||
| 199 | **Returns:** | ||
| 200 | |||
| 201 | | Return Type | Description | | ||
| 202 | | --- | --- | | ||
| 203 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 204 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 205 | |||
| 206 | ### loadstring | ||
| 207 | |||
| 208 | **Type:** Function. | ||
| 209 | |||
| 210 | **Description:** | ||
| 211 | |||
| 212 | Loads YueScript code from a string into a function. | ||
| 213 | |||
| 214 | **Signature:** | ||
| 215 | ```lua | ||
| 216 | loadstring: function(input: string, chunkname: string, config?: Config): | ||
| 217 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 218 | --[[error]] string | nil | ||
| 219 | ``` | ||
| 220 | |||
| 221 | **Parameters:** | ||
| 222 | |||
| 223 | | Parameter | Type | Description | | ||
| 224 | | --- | --- | --- | | ||
| 225 | | input | string | The YueScript code. | | ||
| 226 | | chunkname | string | The name of the code chunk. | | ||
| 227 | | config | Config | [Optional] The compiler options. | | ||
| 228 | |||
| 229 | **Returns:** | ||
| 230 | |||
| 231 | | Return Type | Description | | ||
| 232 | | --- | --- | | ||
| 233 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 234 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 235 | |||
| 236 | ### loadstring | ||
| 237 | |||
| 238 | **Type:** Function. | ||
| 239 | |||
| 240 | **Description:** | ||
| 241 | |||
| 242 | Loads YueScript code from a string into a function. | ||
| 243 | |||
| 244 | **Signature:** | ||
| 245 | ```lua | ||
| 246 | loadstring: function(input: string, config?: Config): | ||
| 247 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 248 | --[[error]] string | nil | ||
| 249 | ``` | ||
| 250 | |||
| 251 | **Parameters:** | ||
| 252 | |||
| 253 | | Parameter | Type | Description | | ||
| 254 | | --- | --- | --- | | ||
| 255 | | input | string | The YueScript code. | | ||
| 256 | | config | Config | [Optional] The compiler options. | | ||
| 257 | |||
| 258 | **Returns:** | ||
| 259 | |||
| 260 | | Return Type | Description | | ||
| 261 | | --- | --- | | ||
| 262 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 263 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 264 | |||
| 265 | ### loadfile | ||
| 266 | |||
| 267 | **Type:** Function. | ||
| 268 | |||
| 269 | **Description:** | ||
| 270 | |||
| 271 | Loads YueScript code from a file into a function. | ||
| 272 | |||
| 273 | **Signature:** | ||
| 274 | ```lua | ||
| 275 | loadfile: function(filename: string, env: table, config?: Config): | ||
| 276 | nil | function(...: any): (any...), | ||
| 277 | string | nil | ||
| 278 | ``` | ||
| 279 | |||
| 280 | **Parameters:** | ||
| 281 | |||
| 282 | | Parameter | Type | Description | | ||
| 283 | | --- | --- | --- | | ||
| 284 | | filename | string | The file name. | | ||
| 285 | | env | table | The environment table. | | ||
| 286 | | config | Config | [Optional] The compiler options. | | ||
| 287 | |||
| 288 | **Returns:** | ||
| 289 | |||
| 290 | | Return Type | Description | | ||
| 291 | | --- | --- | | ||
| 292 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 293 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 294 | |||
| 295 | ### loadfile | ||
| 296 | |||
| 297 | **Type:** Function. | ||
| 298 | |||
| 299 | **Description:** | ||
| 300 | |||
| 301 | Loads YueScript code from a file into a function. | ||
| 302 | |||
| 303 | **Signature:** | ||
| 304 | ```lua | ||
| 305 | loadfile: function(filename: string, config?: Config): | ||
| 306 | nil | function(...: any): (any...), | ||
| 307 | string | nil | ||
| 308 | ``` | ||
| 309 | |||
| 310 | **Parameters:** | ||
| 311 | |||
| 312 | | Parameter | Type | Description | | ||
| 313 | | --- | --- | --- | | ||
| 314 | | filename | string | The file name. | | ||
| 315 | | config | Config | [Optional] The compiler options. | | ||
| 316 | |||
| 317 | **Returns:** | ||
| 318 | |||
| 319 | | Return Type | Description | | ||
| 320 | | --- | --- | | ||
| 321 | | function \| nil | The loaded function, or nil if the loading failed. | | ||
| 322 | | string \| nil | The error message, or nil if the loading succeeded. | | ||
| 323 | |||
| 324 | ### dofile | ||
| 325 | |||
| 326 | **Type:** Function. | ||
| 327 | |||
| 328 | **Description:** | ||
| 329 | |||
| 330 | Loads YueScript code from a file into a function and executes it. | ||
| 331 | |||
| 332 | **Signature:** | ||
| 333 | ```lua | ||
| 334 | dofile: function(filename: string, env: table, config?: Config): any... | ||
| 335 | ``` | ||
| 336 | |||
| 337 | **Parameters:** | ||
| 338 | |||
| 339 | | Parameter | Type | Description | | ||
| 340 | | --- | --- | --- | | ||
| 341 | | filename | string | The file name. | | ||
| 342 | | env | table | The environment table. | | ||
| 343 | | config | Config | [Optional] The compiler options. | | ||
| 344 | |||
| 345 | **Returns:** | ||
| 346 | |||
| 347 | | Return Type | Description | | ||
| 348 | | --- | --- | | ||
| 349 | | any... | The return values of the loaded function. | | ||
| 350 | |||
| 351 | ### dofile | ||
| 352 | |||
| 353 | **Type:** Function. | ||
| 354 | |||
| 355 | **Description:** | ||
| 356 | |||
| 357 | Loads YueScript code from a file into a function and executes it. | ||
| 358 | |||
| 359 | **Signature:** | ||
| 360 | ```lua | ||
| 361 | dofile: function(filename: string, config?: Config): any... | ||
| 362 | ``` | ||
| 363 | |||
| 364 | **Parameters:** | ||
| 365 | |||
| 366 | | Parameter | Type | Description | | ||
| 367 | | --- | --- | --- | | ||
| 368 | | filename | string | The file name. | | ||
| 369 | | config | Config | [Optional] The compiler options. | | ||
| 370 | |||
| 371 | **Returns:** | ||
| 372 | |||
| 373 | | Return Type | Description | | ||
| 374 | | --- | --- | | ||
| 375 | | any... | The return values of the loaded function. | | ||
| 376 | |||
| 377 | ### find_modulepath | ||
| 378 | |||
| 379 | **Type:** Function. | ||
| 380 | |||
| 381 | **Description:** | ||
| 382 | |||
| 383 | Resolves the YueScript module name to the file path. | ||
| 384 | |||
| 385 | **Signature:** | ||
| 386 | ```lua | ||
| 387 | find_modulepath: function(name: string): string | ||
| 388 | ``` | ||
| 389 | |||
| 390 | **Parameters:** | ||
| 391 | |||
| 392 | | Parameter | Type | Description | | ||
| 393 | | --- | --- | --- | | ||
| 394 | | name | string | The module name. | | ||
| 395 | |||
| 396 | **Returns:** | ||
| 397 | |||
| 398 | | Return Type | Description | | ||
| 399 | | --- | --- | | ||
| 400 | | string | The file path. | | ||
| 401 | |||
| 402 | ### pcall | ||
| 403 | |||
| 404 | **Type:** Function. | ||
| 405 | |||
| 406 | **Description:** | ||
| 407 | |||
| 408 | Calls a function in protected mode. | ||
| 409 | Catches any errors and returns a status code and results or error object. | ||
| 410 | Rewrites the error line number to the original line number in the YueScript code when errors occur. | ||
| 411 | |||
| 412 | **Signature:** | ||
| 413 | ```lua | ||
| 414 | pcall: function(f: function, ...: any): boolean, any... | ||
| 415 | ``` | ||
| 416 | |||
| 417 | **Parameters:** | ||
| 418 | |||
| 419 | | Parameter | Type | Description | | ||
| 420 | | --- | --- | --- | | ||
| 421 | | f | function | The function to call. | | ||
| 422 | | ... | any | Arguments to pass to the function. | | ||
| 423 | |||
| 424 | **Returns:** | ||
| 425 | |||
| 426 | | Return Type | Description | | ||
| 427 | | --- | --- | | ||
| 428 | | boolean, ... | Status code and function results or error object. | | ||
| 429 | |||
| 430 | ### require | ||
| 431 | |||
| 432 | **Type:** Function. | ||
| 433 | |||
| 434 | **Description:** | ||
| 435 | |||
| 436 | Loads a given module. Can be either a Lua module or a YueScript module. | ||
| 437 | Rewrites the error line number to the original line number in the YueScript code if the module is a YueScript module and loading fails. | ||
| 438 | |||
| 439 | **Signature:** | ||
| 440 | ```lua | ||
| 441 | require: function(name: string): any... | ||
| 442 | ``` | ||
| 443 | |||
| 444 | **Parameters:** | ||
| 445 | |||
| 446 | | Parameter | Type | Description | | ||
| 447 | | --- | --- | --- | | ||
| 448 | | modname | string | The name of the module to load. | | ||
| 449 | |||
| 450 | **Returns:** | ||
| 451 | |||
| 452 | | Return Type | Description | | ||
| 453 | | --- | --- | | ||
| 454 | | 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. | | ||
| 455 | |||
| 456 | ### p | ||
| 457 | |||
| 458 | **Type:** Function. | ||
| 459 | |||
| 460 | **Description:** | ||
| 461 | |||
| 462 | Inspects the structures of the passed values and prints string representations. | ||
| 463 | |||
| 464 | **Signature:** | ||
| 465 | ```lua | ||
| 466 | p: function(...: any) | ||
| 467 | ``` | ||
| 468 | |||
| 469 | **Parameters:** | ||
| 470 | |||
| 471 | | Parameter | Type | Description | | ||
| 472 | | --- | --- | --- | | ||
| 473 | | ... | any | The values to inspect. | | ||
| 474 | |||
| 475 | ### options | ||
| 476 | |||
| 477 | **Type:** Field. | ||
| 478 | |||
| 479 | **Description:** | ||
| 480 | |||
| 481 | The current compiler options. | ||
| 482 | |||
| 483 | **Signature:** | ||
| 484 | ```lua | ||
| 485 | options: Config.Options | ||
| 486 | ``` | ||
| 487 | |||
| 488 | ### traceback | ||
| 489 | |||
| 490 | **Type:** Function. | ||
| 491 | |||
| 492 | **Description:** | ||
| 493 | |||
| 494 | The traceback function that rewrites the stack trace line numbers to the original line numbers in the YueScript code. | ||
| 495 | |||
| 496 | **Signature:** | ||
| 497 | ```lua | ||
| 498 | traceback: function(message: string): string | ||
| 499 | ``` | ||
| 500 | |||
| 501 | **Parameters:** | ||
| 502 | |||
| 503 | | Parameter | Type | Description | | ||
| 504 | | --- | --- | --- | | ||
| 505 | | message | string | The traceback message. | | ||
| 506 | |||
| 507 | **Returns:** | ||
| 508 | |||
| 509 | | Return Type | Description | | ||
| 510 | | --- | --- | | ||
| 511 | | string | The rewritten traceback message. | | ||
| 512 | |||
| 513 | ### is_ast | ||
| 514 | |||
| 515 | **Type:** Function. | ||
| 516 | |||
| 517 | **Description:** | ||
| 518 | |||
| 519 | Checks whether the code matches the specified AST. | ||
| 520 | |||
| 521 | **Signature:** | ||
| 522 | ```lua | ||
| 523 | is_ast: function(astName: string, code: string): boolean | ||
| 524 | ``` | ||
| 525 | |||
| 526 | **Parameters:** | ||
| 527 | |||
| 528 | | Parameter | Type | Description | | ||
| 529 | | --- | --- | --- | | ||
| 530 | | astName | string | The AST name. | | ||
| 531 | | code | string | The code. | | ||
| 532 | |||
| 533 | **Returns:** | ||
| 534 | |||
| 535 | | Return Type | Description | | ||
| 536 | | --- | --- | | ||
| 537 | | boolean | Whether the code matches the AST. | | ||
| 538 | |||
| 539 | ### AST | ||
| 540 | |||
| 541 | **Type:** Field. | ||
| 542 | |||
| 543 | **Description:** | ||
| 544 | |||
| 545 | The AST type definition with name, row, column and sub nodes. | ||
| 546 | |||
| 547 | **Signature:** | ||
| 548 | ```lua | ||
| 549 | type AST = {string, integer, integer, any} | ||
| 550 | ``` | ||
| 551 | |||
| 552 | ### to_ast | ||
| 553 | |||
| 554 | **Type:** Function. | ||
| 555 | |||
| 556 | **Description:** | ||
| 557 | |||
| 558 | Converts the code to the AST. | ||
| 559 | |||
| 560 | **Signature:** | ||
| 561 | ```lua | ||
| 562 | to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean): | ||
| 563 | --[[AST]] AST | nil, | ||
| 564 | --[[error]] nil | string | ||
| 565 | ``` | ||
| 566 | |||
| 567 | **Parameters:** | ||
| 568 | |||
| 569 | | Parameter | Type | Description | | ||
| 570 | | --- | --- | --- | | ||
| 571 | | code | string | The code. | | ||
| 572 | | flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. | | ||
| 573 | | astName | string | [Optional] The AST name. Default is "File". | | ||
| 574 | | reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is false. | | ||
| 575 | |||
| 576 | **Returns:** | ||
| 577 | |||
| 578 | | Return Type | Description | | ||
| 579 | | --- | --- | | ||
| 580 | | AST \| nil | The AST, or nil if the conversion failed. | | ||
| 581 | | string \| nil | The error message, or nil if the conversion succeeded. | | ||
| 582 | |||
| 583 | ### format | ||
| 584 | |||
| 585 | **Type:** Function. | ||
| 586 | |||
| 587 | **Description:** | ||
| 588 | |||
| 589 | Formats the YueScript code. | ||
| 590 | |||
| 591 | **Signature:** | ||
| 592 | ```lua | ||
| 593 | format: function(code: string, tabSize?: number, reserveComment?: boolean): string | ||
| 594 | ``` | ||
| 595 | |||
| 596 | **Parameters:** | ||
| 597 | |||
| 598 | | Parameter | Type | Description | | ||
| 599 | | --- | --- | --- | | ||
| 600 | | code | string | The code. | | ||
| 601 | | tabSize | integer | [Optional] The tab size. Default is 4. | | ||
| 602 | | reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is true. | | ||
| 603 | |||
| 604 | **Returns:** | ||
| 605 | |||
| 606 | | Return Type | Description | | ||
| 607 | | --- | --- | | ||
| 608 | | string | The formatted code. | | ||
| 609 | |||
| 610 | ### __call | ||
| 611 | |||
| 612 | **Type:** Metamethod. | ||
| 613 | |||
| 614 | **Description:** | ||
| 615 | |||
| 616 | Requires the YueScript module. | ||
| 617 | Rewrites the error line number to the original line number in the YueScript code when loading fails. | ||
| 618 | |||
| 619 | **Signature:** | ||
| 620 | ```lua | ||
| 621 | metamethod __call: function(self: yue, module: string): any... | ||
| 622 | ``` | ||
| 623 | |||
| 624 | **Parameters:** | ||
| 625 | |||
| 626 | | Parameter | Type | Description | | ||
| 627 | | --- | --- | --- | | ||
| 628 | | module | string | The module name. | | ||
| 629 | |||
| 630 | **Returns:** | ||
| 631 | |||
| 632 | | Return Type | Description | | ||
| 633 | | --- | --- | | ||
| 634 | | any | The module value. | | ||
| 635 | |||
| 636 | ## Config | ||
| 637 | |||
| 638 | **Description:** | ||
| 639 | |||
| 640 | The compiler compile options. | ||
| 641 | |||
| 642 | ### lint_global | ||
| 643 | |||
| 644 | **Type:** Field. | ||
| 645 | |||
| 646 | **Description:** | ||
| 647 | |||
| 648 | Whether the compiler should collect the global variables appearing in the code. | ||
| 649 | |||
| 650 | **Signature:** | ||
| 651 | ```lua | ||
| 652 | lint_global: boolean | ||
| 653 | ``` | ||
| 654 | |||
| 655 | ### implicit_return_root | ||
| 656 | |||
| 657 | **Type:** Field. | ||
| 658 | |||
| 659 | **Description:** | ||
| 660 | |||
| 661 | Whether the compiler should do an implicit return for the root code block. | ||
| 662 | |||
| 663 | **Signature:** | ||
| 664 | ```lua | ||
| 665 | implicit_return_root: boolean | ||
| 666 | ``` | ||
| 667 | |||
| 668 | ### reserve_line_number | ||
| 669 | |||
| 670 | **Type:** Field. | ||
| 671 | |||
| 672 | **Description:** | ||
| 673 | |||
| 674 | Whether the compiler should reserve the original line number in the compiled code. | ||
| 675 | |||
| 676 | **Signature:** | ||
| 677 | ```lua | ||
| 678 | reserve_line_number: boolean | ||
| 679 | ``` | ||
| 680 | |||
| 681 | ### reserve_comment | ||
| 682 | |||
| 683 | **Type:** Field. | ||
| 684 | |||
| 685 | **Description:** | ||
| 686 | |||
| 687 | Whether the compiler should reserve the original comments in the compiled code. | ||
| 688 | |||
| 689 | **Signature:** | ||
| 690 | ```lua | ||
| 691 | reserve_comment: boolean | ||
| 692 | ``` | ||
| 693 | |||
| 694 | ### space_over_tab | ||
| 695 | |||
| 696 | **Type:** Field. | ||
| 697 | |||
| 698 | **Description:** | ||
| 699 | |||
| 700 | Whether the compiler should use the space character instead of the tab character in the compiled code. | ||
| 701 | |||
| 702 | **Signature:** | ||
| 703 | ```lua | ||
| 704 | space_over_tab: boolean | ||
| 705 | ``` | ||
| 706 | |||
| 707 | ### same_module | ||
| 708 | |||
| 709 | **Type:** Field. | ||
| 710 | |||
| 711 | **Description:** | ||
| 712 | |||
| 713 | Whether the compiler should treat the code to be compiled as the same currently being compiled module. For internal use only. | ||
| 714 | |||
| 715 | **Signature:** | ||
| 716 | ```lua | ||
| 717 | same_module: boolean | ||
| 718 | ``` | ||
| 719 | |||
| 720 | ### line_offset | ||
| 721 | |||
| 722 | **Type:** Field. | ||
| 723 | |||
| 724 | **Description:** | ||
| 725 | |||
| 726 | Whether the compiler error message should include the line number offset. For internal use only. | ||
| 727 | |||
| 728 | **Signature:** | ||
| 729 | ```lua | ||
| 730 | line_offset: integer | ||
| 731 | ``` | ||
| 732 | |||
| 733 | ### yue.Config.LuaTarget | ||
| 734 | |||
| 735 | **Type:** Enumeration. | ||
| 736 | |||
| 737 | **Description:** | ||
| 738 | |||
| 739 | The target Lua version enumeration. | ||
| 740 | |||
| 741 | **Signature:** | ||
| 742 | ```lua | ||
| 743 | enum LuaTarget | ||
| 744 | "5.1" | ||
| 745 | "5.2" | ||
| 746 | "5.3" | ||
| 747 | "5.4" | ||
| 748 | "5.5" | ||
| 749 | end | ||
| 750 | ``` | ||
| 751 | |||
| 752 | ### options | ||
| 753 | |||
| 754 | **Type:** Field. | ||
| 755 | |||
| 756 | **Description:** | ||
| 757 | |||
| 758 | The extra options to be passed to the compilation function. | ||
| 759 | |||
| 760 | **Signature:** | ||
| 761 | ```lua | ||
| 762 | options: Options | ||
| 763 | ``` | ||
| 764 | |||
| 765 | ## Options | ||
| 766 | |||
| 767 | **Description:** | ||
| 768 | |||
| 769 | The extra compiler options definition. | ||
| 770 | |||
| 771 | ### target | ||
| 772 | |||
| 773 | **Type:** Field. | ||
| 774 | |||
| 775 | **Description:** | ||
| 776 | |||
| 777 | The target Lua version for the compilation. | ||
| 778 | |||
| 779 | **Signature:** | ||
| 780 | ```lua | ||
| 781 | target: LuaTarget | ||
| 782 | ``` | ||
| 783 | |||
| 784 | ### path | ||
| 785 | |||
| 786 | **Type:** Field. | ||
| 787 | |||
| 788 | **Description:** | ||
| 789 | |||
| 790 | The extra module search path. | ||
| 791 | |||
| 792 | **Signature:** | ||
| 793 | ```lua | ||
| 794 | path: string | ||
| 795 | ``` | ||
| 796 | |||
| 797 | ### dump_locals | ||
| 798 | |||
| 799 | **Type:** Field. | ||
| 800 | |||
| 801 | **Description:** | ||
| 802 | |||
| 803 | Whether to dump the local variables in the traceback error message. Default is false. | ||
| 804 | |||
| 805 | **Signature:** | ||
| 806 | ```lua | ||
| 807 | dump_locals: boolean | ||
| 808 | ``` | ||
| 809 | |||
| 810 | ### simplified | ||
| 811 | |||
| 812 | **Type:** Field. | ||
| 813 | |||
| 814 | **Description:** | ||
| 815 | |||
| 816 | Whether to simplify the error message. Default is true. | ||
| 817 | |||
| 818 | **Signature:** | ||
| 819 | ```lua | ||
| 820 | simplified: boolean | ||
| 821 | ``` | ||
diff --git a/doc/docs/doc/try.md b/doc/docs/doc/try.md new file mode 100644 index 0000000..23c7877 --- /dev/null +++ b/doc/docs/doc/try.md | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | # Try | ||
| 2 | |||
| 3 | The syntax for Lua error handling in a common form. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | try | ||
| 7 | func 1, 2, 3 | ||
| 8 | catch err | ||
| 9 | print yue.traceback err | ||
| 10 | |||
| 11 | success, result = try | ||
| 12 | func 1, 2, 3 | ||
| 13 | catch err | ||
| 14 | yue.traceback err | ||
| 15 | |||
| 16 | try func 1, 2, 3 | ||
| 17 | catch err | ||
| 18 | print yue.traceback err | ||
| 19 | |||
| 20 | success, result = try func 1, 2, 3 | ||
| 21 | |||
| 22 | try | ||
| 23 | print "trying" | ||
| 24 | func 1, 2, 3 | ||
| 25 | |||
| 26 | -- working with if assignment pattern | ||
| 27 | if success, result := try func 1, 2, 3 | ||
| 28 | catch err | ||
| 29 | print yue.traceback err | ||
| 30 | print result | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | try | ||
| 36 | func 1, 2, 3 | ||
| 37 | catch err | ||
| 38 | print yue.traceback err | ||
| 39 | |||
| 40 | success, result = try | ||
| 41 | func 1, 2, 3 | ||
| 42 | catch err | ||
| 43 | yue.traceback err | ||
| 44 | |||
| 45 | try func 1, 2, 3 | ||
| 46 | catch err | ||
| 47 | print yue.traceback err | ||
| 48 | |||
| 49 | success, result = try func 1, 2, 3 | ||
| 50 | |||
| 51 | try | ||
| 52 | print "trying" | ||
| 53 | func 1, 2, 3 | ||
| 54 | |||
| 55 | -- working with if assignment pattern | ||
| 56 | if success, result := try func 1, 2, 3 | ||
| 57 | catch err | ||
| 58 | print yue.traceback err | ||
| 59 | print result | ||
| 60 | ``` | ||
| 61 | |||
| 62 | </YueDisplay> | ||
| 63 | |||
| 64 | ## Try? | ||
| 65 | |||
| 66 | `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. | ||
| 67 | |||
| 68 | ```yuescript | ||
| 69 | a, b, c = try? func! | ||
| 70 | |||
| 71 | -- with nil coalescing operator | ||
| 72 | a = (try? func!) ?? "default" | ||
| 73 | |||
| 74 | -- as function argument | ||
| 75 | f try? func! | ||
| 76 | |||
| 77 | -- with catch block | ||
| 78 | f try? | ||
| 79 | print 123 | ||
| 80 | func! | ||
| 81 | catch e | ||
| 82 | print e | ||
| 83 | e | ||
| 84 | ``` | ||
| 85 | <YueDisplay> | ||
| 86 | |||
| 87 | ```yue | ||
| 88 | a, b, c = try? func! | ||
| 89 | |||
| 90 | -- with nil coalescing operator | ||
| 91 | a = (try? func!) ?? "default" | ||
| 92 | |||
| 93 | -- as function argument | ||
| 94 | f try? func! | ||
| 95 | |||
| 96 | -- with catch block | ||
| 97 | f try? | ||
| 98 | print 123 | ||
| 99 | func! | ||
| 100 | catch e | ||
| 101 | print e | ||
| 102 | e | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
diff --git a/doc/docs/doc/usage.md b/doc/docs/doc/usage.md new file mode 100644 index 0000000..45161c6 --- /dev/null +++ b/doc/docs/doc/usage.md | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | # Usage | ||
| 2 | |||
| 3 | ## Lua Module | ||
| 4 | |||
| 5 | Use YueScript module in Lua: | ||
| 6 | |||
| 7 | * **Case 1** | ||
| 8 | |||
| 9 | Require "your_yuescript_entry.yue" in Lua. | ||
| 10 | ```Lua | ||
| 11 | require("yue")("your_yuescript_entry") | ||
| 12 | ``` | ||
| 13 | 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. | ||
| 14 | |||
| 15 | * **Case 2** | ||
| 16 | |||
| 17 | Require YueScript module and rewite message by hand. | ||
| 18 | |||
| 19 | ```lua | ||
| 20 | local yue = require("yue") | ||
| 21 | yue.insert_loader() | ||
| 22 | local success, result = xpcall(function() | ||
| 23 | return require("yuescript_module_name") | ||
| 24 | end, function(err) | ||
| 25 | return yue.traceback(err) | ||
| 26 | end) | ||
| 27 | ``` | ||
| 28 | |||
| 29 | * **Case 3** | ||
| 30 | |||
| 31 | Use the YueScript compiler function in Lua. | ||
| 32 | |||
| 33 | ```lua | ||
| 34 | local yue = require("yue") | ||
| 35 | local codes, err, globals = yue.to_lua([[ | ||
| 36 | f = -> | ||
| 37 | print "hello world" | ||
| 38 | f! | ||
| 39 | ]],{ | ||
| 40 | implicit_return_root = true, | ||
| 41 | reserve_line_number = true, | ||
| 42 | lint_global = true, | ||
| 43 | space_over_tab = false, | ||
| 44 | options = { | ||
| 45 | target = "5.4", | ||
| 46 | path = "/script" | ||
| 47 | } | ||
| 48 | }) | ||
| 49 | ``` | ||
| 50 | |||
| 51 | ## YueScript Tool | ||
| 52 | |||
| 53 | Use YueScript tool with: | ||
| 54 | |||
| 55 | ```shell | ||
| 56 | > yue -h | ||
| 57 | Usage: yue | ||
| 58 | [options] [<file/directory>] ... | ||
| 59 | yue -e <code_or_file> [args...] | ||
| 60 | yue -w [<directory>] [options] | ||
| 61 | yue - | ||
| 62 | |||
| 63 | Notes: | ||
| 64 | - '-' / '--' must be the first and only argument. | ||
| 65 | - '-o/--output' can not be used with multiple input files. | ||
| 66 | - '-w/--watch' can not be used with file input (directory only). | ||
| 67 | - with '-e/--execute', remaining tokens are treated as script args. | ||
| 68 | |||
| 69 | Options: | ||
| 70 | -h, --help Show this help message and exit. | ||
| 71 | -e <str>, --execute <str> Execute a file or raw codes | ||
| 72 | -m, --minify Generate minified codes | ||
| 73 | -r, --rewrite Rewrite output to match original line numbers | ||
| 74 | -t <output_to>, --output-to <output_to> | ||
| 75 | Specify where to place compiled files | ||
| 76 | -o <file>, --output <file> Write output to file | ||
| 77 | -p, --print Write output to standard out | ||
| 78 | -b, --benchmark Dump compile time (doesn't write output) | ||
| 79 | -g, --globals Dump global variables used in NAME LINE COLUMN | ||
| 80 | -s, --spaces Use spaces in generated codes instead of tabs | ||
| 81 | -l, --line-numbers Write line numbers from source codes | ||
| 82 | -j, --no-implicit-return Disable implicit return at end of file | ||
| 83 | -c, --reserve-comments Reserve comments before statement from source codes | ||
| 84 | -w [<dir>], --watch [<dir>] | ||
| 85 | Watch changes and compile every file under directory | ||
| 86 | -v, --version Print version | ||
| 87 | - Read from standard in, print to standard out | ||
| 88 | (Must be first and only argument) | ||
| 89 | -- Same as '-' (kept for backward compatibility) | ||
| 90 | |||
| 91 | --target <version> Specify the Lua version that codes will be generated to | ||
| 92 | (version can only be 5.1 to 5.5) | ||
| 93 | --path <path_str> Append an extra Lua search path string to package.path | ||
| 94 | --<key>=<value> Pass compiler option in key=value form (existing behavior) | ||
| 95 | |||
| 96 | Execute without options to enter REPL, type symbol '$' | ||
| 97 | in a single line to start/stop multi-line mode | ||
| 98 | ``` | ||
| 99 | Use cases: | ||
| 100 | |||
| 101 | Recursively compile every YueScript file with extension **.yue** under current path: **yue .** | ||
| 102 | |||
| 103 | Compile and save results to a target path: **yue -t /target/path/ .** | ||
| 104 | |||
| 105 | Compile and reserve debug info: **yue -l .** | ||
| 106 | |||
| 107 | Compile and generate minified codes: **yue -m .** | ||
| 108 | |||
| 109 | Execute raw codes: **yue -e 'print 123'** | ||
| 110 | |||
| 111 | Execute a YueScript file: **yue -e main.yue** | ||
diff --git a/doc/docs/doc/varargs-assignment.md b/doc/docs/doc/varargs-assignment.md new file mode 100644 index 0000000..1d66680 --- /dev/null +++ b/doc/docs/doc/varargs-assignment.md | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # Varargs Assignment | ||
| 2 | |||
| 3 | You can assign the results returned from a function to a varargs symbol `...`. And then access its content using the Lua way. | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | list = [1, 2, 3, 4, 5] | ||
| 7 | fn = (ok) -> ok, table.unpack list | ||
| 8 | ok, ... = fn true | ||
| 9 | count = select '#', ... | ||
| 10 | first = select 1, ... | ||
| 11 | print ok, count, first | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | list = [1, 2, 3, 4, 5] | ||
| 17 | fn = (ok) -> ok, table.unpack list | ||
| 18 | ok, ... = fn true | ||
| 19 | count = select '#', ... | ||
| 20 | first = select 1, ... | ||
| 21 | print ok, count, first | ||
| 22 | ``` | ||
| 23 | |||
| 24 | </YueDisplay> | ||
diff --git a/doc/docs/doc/while-loop.md b/doc/docs/doc/while-loop.md new file mode 100644 index 0000000..502935e --- /dev/null +++ b/doc/docs/doc/while-loop.md | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | # While Loop | ||
| 2 | |||
| 3 | The while loop also comes in four variations: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 10 | ||
| 7 | while i > 0 | ||
| 8 | print i | ||
| 9 | i -= 1 | ||
| 10 | |||
| 11 | while running == true do my_function! | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | i = 10 | ||
| 17 | while i > 0 | ||
| 18 | print i | ||
| 19 | i -= 1 | ||
| 20 | |||
| 21 | while running == true do my_function! | ||
| 22 | ``` | ||
| 23 | |||
| 24 | </YueDisplay> | ||
| 25 | |||
| 26 | ```yuescript | ||
| 27 | i = 10 | ||
| 28 | until i == 0 | ||
| 29 | print i | ||
| 30 | i -= 1 | ||
| 31 | |||
| 32 | until running == false do my_function! | ||
| 33 | ``` | ||
| 34 | <YueDisplay> | ||
| 35 | |||
| 36 | ```yue | ||
| 37 | i = 10 | ||
| 38 | until i == 0 | ||
| 39 | print i | ||
| 40 | i -= 1 | ||
| 41 | until running == false do my_function! | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
| 45 | |||
| 46 | Like 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. | ||
| 47 | |||
| 48 | ## Repeat Loop | ||
| 49 | |||
| 50 | The repeat loop comes from Lua: | ||
| 51 | |||
| 52 | ```yuescript | ||
| 53 | i = 10 | ||
| 54 | repeat | ||
| 55 | print i | ||
| 56 | i -= 1 | ||
| 57 | until i == 0 | ||
| 58 | ``` | ||
| 59 | <YueDisplay> | ||
| 60 | |||
| 61 | ```yue | ||
| 62 | i = 10 | ||
| 63 | repeat | ||
| 64 | print i | ||
| 65 | i -= 1 | ||
| 66 | until i == 0 | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
diff --git a/doc/docs/doc/whitespace.md b/doc/docs/doc/whitespace.md new file mode 100644 index 0000000..d742a2b --- /dev/null +++ b/doc/docs/doc/whitespace.md | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # Whitespace | ||
| 2 | |||
| 3 | YueScript 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. | ||
| 4 | |||
| 5 | ## Statement Separator | ||
| 6 | |||
| 7 | A 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: | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | a = 1; b = 2; print a + b | ||
| 11 | ``` | ||
| 12 | <YueDisplay> | ||
| 13 | |||
| 14 | ```yue | ||
| 15 | a = 1; b = 2; print a + b | ||
| 16 | ``` | ||
| 17 | |||
| 18 | </YueDisplay> | ||
| 19 | |||
| 20 | ## Multiline Chaining | ||
| 21 | |||
| 22 | You can write multi-line chaining function calls with a same indent. | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | Rx.Observable | ||
| 26 | .fromRange 1, 8 | ||
| 27 | \filter (x) -> x % 2 == 0 | ||
| 28 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 29 | \map (value) -> value .. '!' | ||
| 30 | \subscribe print | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | Rx.Observable | ||
| 36 | .fromRange 1, 8 | ||
| 37 | \filter (x) -> x % 2 == 0 | ||
| 38 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 39 | \map (value) -> value .. '!' | ||
| 40 | \subscribe print | ||
| 41 | ``` | ||
| 42 | |||
| 43 | </YueDisplay> | ||
diff --git a/doc/docs/doc/with-statement.md b/doc/docs/doc/with-statement.md new file mode 100644 index 0000000..7786803 --- /dev/null +++ b/doc/docs/doc/with-statement.md | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | # With Statement | ||
| 2 | |||
| 3 | |||
| 4 | A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it. | ||
| 5 | |||
| 6 | This 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. | ||
| 7 | |||
| 8 | The 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. | ||
| 9 | |||
| 10 | For example, we work with a newly created object: | ||
| 11 | |||
| 12 | ```yuescript | ||
| 13 | with Person! | ||
| 14 | .name = "Oswald" | ||
| 15 | \add_relative my_dad | ||
| 16 | \save! | ||
| 17 | print .name | ||
| 18 | ``` | ||
| 19 | <YueDisplay> | ||
| 20 | |||
| 21 | ```yue | ||
| 22 | with Person! | ||
| 23 | .name = "Oswald" | ||
| 24 | \add_relative my_dad | ||
| 25 | \save! | ||
| 26 | print .name | ||
| 27 | ``` | ||
| 28 | |||
| 29 | </YueDisplay> | ||
| 30 | |||
| 31 | The with statement can also be used as an expression which returns the value it has been giving access to. | ||
| 32 | |||
| 33 | ```yuescript | ||
| 34 | file = with File "favorite_foods.txt" | ||
| 35 | \set_encoding "utf8" | ||
| 36 | ``` | ||
| 37 | <YueDisplay> | ||
| 38 | |||
| 39 | ```yue | ||
| 40 | file = with File "favorite_foods.txt" | ||
| 41 | \set_encoding "utf8" | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
| 45 | |||
| 46 | Or… | ||
| 47 | |||
| 48 | ```yuescript | ||
| 49 | create_person = (name, relatives) -> | ||
| 50 | with Person! | ||
| 51 | .name = name | ||
| 52 | \add_relative relative for relative in *relatives | ||
| 53 | |||
| 54 | me = create_person "Leaf", [dad, mother, sister] | ||
| 55 | ``` | ||
| 56 | <YueDisplay> | ||
| 57 | |||
| 58 | ```yue | ||
| 59 | create_person = (name, relatives) -> | ||
| 60 | with Person! | ||
| 61 | .name = name | ||
| 62 | \add_relative relative for relative in *relatives | ||
| 63 | |||
| 64 | me = create_person "Leaf", [dad, mother, sister] | ||
| 65 | ``` | ||
| 66 | |||
| 67 | </YueDisplay> | ||
| 68 | |||
| 69 | In this usage, with can be seen as a special form of the K combinator. | ||
| 70 | |||
| 71 | The expression in the with statement can also be an assignment, if you want to give a name to the expression. | ||
| 72 | |||
| 73 | ```yuescript | ||
| 74 | with str := "Hello" | ||
| 75 | print "original:", str | ||
| 76 | print "upper:", \upper! | ||
| 77 | ``` | ||
| 78 | <YueDisplay> | ||
| 79 | |||
| 80 | ```yue | ||
| 81 | with str := "Hello" | ||
| 82 | print "original:", str | ||
| 83 | print "upper:", \upper! | ||
| 84 | ``` | ||
| 85 | |||
| 86 | </YueDisplay> | ||
| 87 | |||
| 88 | You can access special keys with `[]` in a `with` statement. | ||
| 89 | |||
| 90 | ```yuescript | ||
| 91 | with tb | ||
| 92 | [1] = 1 | ||
| 93 | print [2] | ||
| 94 | with [abc] | ||
| 95 | [3] = [2]\func! | ||
| 96 | ["key-name"] = value | ||
| 97 | [] = "abc" -- appending to "tb" | ||
| 98 | ``` | ||
| 99 | <YueDisplay> | ||
| 100 | |||
| 101 | ```yue | ||
| 102 | with tb | ||
| 103 | [1] = 1 | ||
| 104 | print [2] | ||
| 105 | with [abc] | ||
| 106 | [3] = [2]\func! | ||
| 107 | ["key-name"] = value | ||
| 108 | [] = "abc" -- appending to "tb" | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
| 112 | |||
| 113 | `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. | ||
| 114 | |||
| 115 | ```yuescript | ||
| 116 | with? obj | ||
| 117 | print obj.name | ||
| 118 | ``` | ||
| 119 | <YueDisplay> | ||
| 120 | |||
| 121 | ```yue | ||
| 122 | with? obj | ||
| 123 | print obj.name | ||
| 124 | ``` | ||
| 125 | |||
| 126 | </YueDisplay> | ||
diff --git a/doc/docs/index.md b/doc/docs/index.md index 0ce1284..03a33dd 100644 --- a/doc/docs/index.md +++ b/doc/docs/index.md | |||
| @@ -17,9 +17,8 @@ features: | |||
| 17 | details: Pipe, pattern matching, slicing, and destructuring without giving up Lua interop. | 17 | details: Pipe, pattern matching, slicing, and destructuring without giving up Lua interop. |
| 18 | - title: Rapid Iteration | 18 | - title: Rapid Iteration |
| 19 | details: Any feedback is welcome to help accelerate the language development and evolution! | 19 | details: Any feedback is welcome to help accelerate the language development and evolution! |
| 20 | footer: MIT Licensed | Copyright © 2017-2026 Li Jin | ||
| 21 | --- | 20 | --- |
| 22 | 21 | ||
| 23 | ## License & Copyright | 22 | ### License & Copyright |
| 24 | 23 | ||
| 25 | MIT License. Copyright © 2017-2026 Li Jin. All rights reserved. | 24 | MIT License. Copyright © 2017-2026 Li Jin. All rights reserved. |
diff --git a/doc/docs/zh/doc/assignment.md b/doc/docs/zh/doc/assignment.md new file mode 100644 index 0000000..49561fb --- /dev/null +++ b/doc/docs/zh/doc/assignment.md | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | # 赋值 | ||
| 2 | |||
| 3 |   月之脚本中定义的变量是动态类型的,并默认为局部变量。但你可以通过 **local** 和 **global** 声明来改变声明变量的作用范围。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | hello = "world" | ||
| 7 | a, b, c = 1, 2, 3 | ||
| 8 | hello = 123 -- 访问现有的变量 | ||
| 9 | ``` | ||
| 10 | <YueDisplay> | ||
| 11 | |||
| 12 | ```yue | ||
| 13 | hello = "world" | ||
| 14 | a, b, c = 1, 2, 3 | ||
| 15 | hello = 123 -- 访问现有的变量 | ||
| 16 | ``` | ||
| 17 | |||
| 18 | </YueDisplay> | ||
| 19 | |||
| 20 | ## 执行更新 | ||
| 21 | |||
| 22 |   你可以使用各式二进制运算符执行更新赋值。 | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | x = 1 | ||
| 26 | x += 1 | ||
| 27 | x -= 1 | ||
| 28 | x *= 10 | ||
| 29 | x /= 10 | ||
| 30 | x %= 10 | ||
| 31 | s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量 | ||
| 32 | arg or= "默认值" | ||
| 33 | ``` | ||
| 34 | <YueDisplay> | ||
| 35 | |||
| 36 | ```yue | ||
| 37 | x = 1 | ||
| 38 | x += 1 | ||
| 39 | x -= 1 | ||
| 40 | x *= 10 | ||
| 41 | x /= 10 | ||
| 42 | x %= 10 | ||
| 43 | s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量 | ||
| 44 | arg or= "默认值" | ||
| 45 | ``` | ||
| 46 | |||
| 47 | </YueDisplay> | ||
| 48 | |||
| 49 | ## 链式赋值 | ||
| 50 | |||
| 51 |   你可以进行链式赋值,将多个项目赋予相同的值。 | ||
| 52 | |||
| 53 | ```yuescript | ||
| 54 | a = b = c = d = e = 0 | ||
| 55 | x = y = z = f! | ||
| 56 | ``` | ||
| 57 | <YueDisplay> | ||
| 58 | |||
| 59 | ```yue | ||
| 60 | a = b = c = d = e = 0 | ||
| 61 | x = y = z = f! | ||
| 62 | ``` | ||
| 63 | |||
| 64 | </YueDisplay> | ||
| 65 | |||
| 66 | ## 显式声明局部变量 | ||
| 67 | |||
| 68 | ```yuescript | ||
| 69 | do | ||
| 70 | local a = 1 | ||
| 71 | local * | ||
| 72 | print "预先声明后续所有变量为局部变量" | ||
| 73 | x = -> 1 + y + z | ||
| 74 | y, z = 2, 3 | ||
| 75 | global instance = Item\new! | ||
| 76 | |||
| 77 | do | ||
| 78 | local X = 1 | ||
| 79 | local ^ | ||
| 80 | print "只预先声明后续大写的变量为局部变量" | ||
| 81 | a = 1 | ||
| 82 | B = 2 | ||
| 83 | ``` | ||
| 84 | <YueDisplay> | ||
| 85 | |||
| 86 | ```yue | ||
| 87 | do | ||
| 88 | local a = 1 | ||
| 89 | local * | ||
| 90 | print "预先声明后续所有变量为局部变量" | ||
| 91 | x = -> 1 + y + z | ||
| 92 | y, z = 2, 3 | ||
| 93 | global instance = Item\new! | ||
| 94 | |||
| 95 | do | ||
| 96 | local X = 1 | ||
| 97 | local ^ | ||
| 98 | print "只预先声明后续大写的变量为局部变量" | ||
| 99 | a = 1 | ||
| 100 | B = 2 | ||
| 101 | ``` | ||
| 102 | |||
| 103 | </YueDisplay> | ||
| 104 | |||
| 105 | ## 显式声明全局变量 | ||
| 106 | |||
| 107 | ```yuescript | ||
| 108 | do | ||
| 109 | global a = 1 | ||
| 110 | global * | ||
| 111 | print "预先声明所有变量为全局变量" | ||
| 112 | x = -> 1 + y + z | ||
| 113 | y, z = 2, 3 | ||
| 114 | |||
| 115 | do | ||
| 116 | global x = 1 | ||
| 117 | global ^ | ||
| 118 | print "只预先声明大写的变量为全局变量" | ||
| 119 | a = 1 | ||
| 120 | B = 2 | ||
| 121 | local Temp = "一个局部值" | ||
| 122 | ``` | ||
| 123 | <YueDisplay> | ||
| 124 | |||
| 125 | ```yue | ||
| 126 | do | ||
| 127 | global a = 1 | ||
| 128 | global * | ||
| 129 | print "预先声明所有变量为全局变量" | ||
| 130 | x = -> 1 + y + z | ||
| 131 | y, z = 2, 3 | ||
| 132 | |||
| 133 | do | ||
| 134 | global x = 1 | ||
| 135 | global ^ | ||
| 136 | print "只预先声明大写的变量为全局变量" | ||
| 137 | a = 1 | ||
| 138 | B = 2 | ||
| 139 | local Temp = "一个局部值" | ||
| 140 | ``` | ||
| 141 | |||
| 142 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/attributes.md b/doc/docs/zh/doc/attributes.md new file mode 100644 index 0000000..3dc3b0b --- /dev/null +++ b/doc/docs/zh/doc/attributes.md | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | # 属性 | ||
| 2 | |||
| 3 |   月之脚本现在提供了 Lua 5.4 新增的叫做属性的语法支持。在月之脚本编译到的 Lua 目标版本低于 5.4 时,你仍然可以同时使用`const` 和 `close` 的属性声明语法,并获得常量检查和作用域回调的功能。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | const a = 123 | ||
| 7 | close _ = <close>: -> print "超出范围。" | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | const a = 123 | ||
| 13 | close _ = <close>: -> print "超出范围。" | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 |   你可以对进行解构得到的变量标记为常量。 | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | const {:a, :b, c, d} = tb | ||
| 22 | -- a = 1 | ||
| 23 | ``` | ||
| 24 | <YueDisplay> | ||
| 25 | |||
| 26 | ```yue | ||
| 27 | const {:a, :b, c, d} = tb | ||
| 28 | -- a = 1 | ||
| 29 | ``` | ||
| 30 | |||
| 31 | </YueDisplay> | ||
| 32 | |||
| 33 |   你也可以声明全局变量为常量。 | ||
| 34 | |||
| 35 | ```yuescript | ||
| 36 | global const Constant = 123 | ||
| 37 | -- Constant = 1 | ||
| 38 | ``` | ||
| 39 | <YueDisplay> | ||
| 40 | |||
| 41 | ```yue | ||
| 42 | global const Constant = 123 | ||
| 43 | -- Constant = 1 | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/backcalls.md b/doc/docs/zh/doc/backcalls.md new file mode 100644 index 0000000..4c32fac --- /dev/null +++ b/doc/docs/zh/doc/backcalls.md | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | # 反向回调 | ||
| 2 | |||
| 3 |   反向回调用于减少函数回调的嵌套。它们使用指向左侧的箭头,并且默认会被定义为传入后续函数调用的最后一个参数。它的语法大部分与常规箭头函数相同,只是它指向另一方向,并且后续的函数体不需要进行缩进。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | x <- f | ||
| 7 | print "hello" .. x | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | x <- f | ||
| 13 | print "hello" .. x | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 |   月之脚本也提供了粗箭头反向回调函数。 | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | <= f | ||
| 22 | print @value | ||
| 23 | ``` | ||
| 24 | <YueDisplay> | ||
| 25 | |||
| 26 | ```yue | ||
| 27 | <= f | ||
| 28 | print @value | ||
| 29 | ``` | ||
| 30 | |||
| 31 | </YueDisplay> | ||
| 32 | |||
| 33 |   你可以通过一个占位符指定回调函数的传参位置。 | ||
| 34 | |||
| 35 | ```yuescript | ||
| 36 | (x) <- map _, [1, 2, 3] | ||
| 37 | x * 2 | ||
| 38 | ``` | ||
| 39 | <YueDisplay> | ||
| 40 | |||
| 41 | ```yue | ||
| 42 | (x) <- map _, [1, 2, 3] | ||
| 43 | x * 2 | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 |   如果你希望在反向回调处理后继续编写更多其它的代码,可以使用 do 语句将不属于反向回调的代码分隔开。对于非粗箭头函数的反向回调,回调返回值的括号也是可以省略的。 | ||
| 49 | |||
| 50 | ```yuescript | ||
| 51 | result, msg = do | ||
| 52 | data <- readAsync "文件名.txt" | ||
| 53 | print data | ||
| 54 | info <- processAsync data | ||
| 55 | check info | ||
| 56 | print result, msg | ||
| 57 | ``` | ||
| 58 | <YueDisplay> | ||
| 59 | |||
| 60 | ```yue | ||
| 61 | result, msg = do | ||
| 62 | data <- readAsync "文件名.txt" | ||
| 63 | print data | ||
| 64 | info <- processAsync data | ||
| 65 | check info | ||
| 66 | print result, msg | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/comment.md b/doc/docs/zh/doc/comment.md new file mode 100644 index 0000000..f6a7b4e --- /dev/null +++ b/doc/docs/zh/doc/comment.md | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | # 注释 | ||
| 2 | |||
| 3 | ```yuescript | ||
| 4 | -- 我是一个注释 | ||
| 5 | |||
| 6 | str = --[[ | ||
| 7 | 这是一个多行注释。 | ||
| 8 | 没问题。 | ||
| 9 | ]] strA \ -- 注释 1 | ||
| 10 | .. strB \ -- 注释 2 | ||
| 11 | .. strC | ||
| 12 | |||
| 13 | func --[[端口]] 3000, --[[ip]] "192.168.1.1" | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | -- 我是一个注释 | ||
| 19 | |||
| 20 | str = --[[ | ||
| 21 | 这是一个多行注释。 | ||
| 22 | 没问题。 | ||
| 23 | ]] strA \ -- 注释 1 | ||
| 24 | .. strB \ -- 注释 2 | ||
| 25 | .. strC | ||
| 26 | |||
| 27 | func --[[端口]] 3000, --[[ip]] "192.168.1.1" | ||
| 28 | ``` | ||
| 29 | |||
| 30 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/comprehensions.md b/doc/docs/zh/doc/comprehensions.md new file mode 100644 index 0000000..fd25b22 --- /dev/null +++ b/doc/docs/zh/doc/comprehensions.md | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | # 推导式 | ||
| 2 | |||
| 3 |   推导式为我们提供了一种便捷的语法,通过遍历现有对象并对其值应用表达式来构造出新的表格。月之脚本有两种推导式:列表推导式和表格推导式。它们最终都是产生 Lua 表格;列表推导式将值累积到类似数组的表格中,而表格推导式允许你在每次遍历时设置新表格的键和值。 | ||
| 4 | |||
| 5 | ## 列表推导式 | ||
| 6 | |||
| 7 |   以下操作创建了一个 items 表的副本,但所有包含的值都翻倍了。 | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | items = [1, 2, 3, 4] | ||
| 11 | doubled = [item * 2 for i, item in ipairs items] | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | items = [1, 2, 3, 4] | ||
| 17 | doubled = [item * 2 for i, item in ipairs items] | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 |   可以使用 `when` 子句筛选新表中包含的项目: | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 31 | ``` | ||
| 32 | |||
| 33 | </YueDisplay> | ||
| 34 | |||
| 35 |   因为我们常常需要迭代数值索引表的值,所以引入了 **\*** 操作符来做语法简化。doubled 示例可以重写为: | ||
| 36 | |||
| 37 | ```yuescript | ||
| 38 | doubled = [item * 2 for item in *items] | ||
| 39 | ``` | ||
| 40 | <YueDisplay> | ||
| 41 | |||
| 42 | ```yue | ||
| 43 | doubled = [item * 2 for item in *items] | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 |   在列表推导式中,你还可以使用展开操作符 `...` 来实现对列表嵌套层级进行扁平化的处理: | ||
| 49 | |||
| 50 | ```yuescript | ||
| 51 | data = | ||
| 52 | a: [1, 2, 3] | ||
| 53 | b: [4, 5, 6] | ||
| 54 | |||
| 55 | flat = [...v for k,v in pairs data] | ||
| 56 | -- flat 现在为 [1, 2, 3, 4, 5, 6] | ||
| 57 | ``` | ||
| 58 | <YueDisplay> | ||
| 59 | |||
| 60 | ```yue | ||
| 61 | data = | ||
| 62 | a: [1, 2, 3] | ||
| 63 | b: [4, 5, 6] | ||
| 64 | |||
| 65 | flat = [...v for k,v in pairs data] | ||
| 66 | -- flat 现在为 [1, 2, 3, 4, 5, 6] | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
| 70 | |||
| 71 |   for 和 when 子句可以根据需要进行链式操作。唯一的要求是推导式中至少要有一个 for 子句。 | ||
| 72 | |||
| 73 |   使用多个 for 子句与使用多重循环的效果相同: | ||
| 74 | |||
| 75 | ```yuescript | ||
| 76 | x_coords = [4, 5, 6, 7] | ||
| 77 | y_coords = [9, 2, 3] | ||
| 78 | |||
| 79 | points = [ [x, y] for x in *x_coords \ | ||
| 80 | for y in *y_coords] | ||
| 81 | ``` | ||
| 82 | <YueDisplay> | ||
| 83 | |||
| 84 | ```yue | ||
| 85 | x_coords = [4, 5, 6, 7] | ||
| 86 | y_coords = [9, 2, 3] | ||
| 87 | |||
| 88 | points = [ [x, y] for x in *x_coords \ | ||
| 89 | for y in *y_coords] | ||
| 90 | ``` | ||
| 91 | |||
| 92 | </YueDisplay> | ||
| 93 | |||
| 94 |   在推导式中也可以使用简单的数值 for 循环: | ||
| 95 | |||
| 96 | ```yuescript | ||
| 97 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 98 | ``` | ||
| 99 | <YueDisplay> | ||
| 100 | |||
| 101 | ```yue | ||
| 102 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
| 106 | |||
| 107 | ## 表格推导式 | ||
| 108 | |||
| 109 |   表格推导式和列表推导式的语法非常相似,只是要使用 **{** 和 **}** 并从每次迭代中取两个值。 | ||
| 110 | |||
| 111 |   以下示例生成了表格 thing 的副本: | ||
| 112 | |||
| 113 | ```yuescript | ||
| 114 | thing = { | ||
| 115 | color: "red" | ||
| 116 | name: "fast" | ||
| 117 | width: 123 | ||
| 118 | } | ||
| 119 | |||
| 120 | thing_copy = {k, v for k, v in pairs thing} | ||
| 121 | ``` | ||
| 122 | <YueDisplay> | ||
| 123 | |||
| 124 | ```yue | ||
| 125 | thing = { | ||
| 126 | color: "red" | ||
| 127 | name: "fast" | ||
| 128 | width: 123 | ||
| 129 | } | ||
| 130 | |||
| 131 | thing_copy = {k, v for k, v in pairs thing} | ||
| 132 | ``` | ||
| 133 | |||
| 134 | </YueDisplay> | ||
| 135 | |||
| 136 | ```yuescript | ||
| 137 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 138 | ``` | ||
| 139 | <YueDisplay> | ||
| 140 | |||
| 141 | ```yue | ||
| 142 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 143 | ``` | ||
| 144 | |||
| 145 | </YueDisplay> | ||
| 146 | |||
| 147 |   **\*** 操作符在表格推导式中能使用。在下面的例子里,我们为几个数字创建了一个平方根查找表。 | ||
| 148 | |||
| 149 | ```yuescript | ||
| 150 | numbers = [1, 2, 3, 4] | ||
| 151 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 152 | ``` | ||
| 153 | <YueDisplay> | ||
| 154 | |||
| 155 | ```yue | ||
| 156 | numbers = [1, 2, 3, 4] | ||
| 157 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 158 | ``` | ||
| 159 | |||
| 160 | </YueDisplay> | ||
| 161 | |||
| 162 |   表格推导式中的键值元组也可以来自单个表达式,在这种情况下,表达式在计算后应返回两个值。第一个用作键,第二个用作值: | ||
| 163 | |||
| 164 |   在下面的示例中,我们将一些数组转换为一个表,其中每个数组里的第一项是键,第二项是值。 | ||
| 165 | |||
| 166 | ```yuescript | ||
| 167 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 168 | tbl = {unpack tuple for tuple in *tuples} | ||
| 169 | ``` | ||
| 170 | <YueDisplay> | ||
| 171 | |||
| 172 | ```yue | ||
| 173 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 174 | tbl = {unpack tuple for tuple in *tuples} | ||
| 175 | ``` | ||
| 176 | |||
| 177 | </YueDisplay> | ||
| 178 | |||
| 179 | ## 切片 | ||
| 180 | |||
| 181 |   当使用 **\*** 操作符时,月之脚本还提供了一种特殊的语法来限制要遍历的列表范围。这个语法也相当于在 for 循环中设置迭代边界和步长。 | ||
| 182 | |||
| 183 |   下面的案例中,我们在切片中设置最小和最大边界,取索引在 1 到 5 之间(包括 1 和 5)的所有项目: | ||
| 184 | |||
| 185 | ```yuescript | ||
| 186 | slice = [item for item in *items[1, 5]] | ||
| 187 | ``` | ||
| 188 | <YueDisplay> | ||
| 189 | |||
| 190 | ```yue | ||
| 191 | slice = [item for item in *items[1, 5]] | ||
| 192 | ``` | ||
| 193 | |||
| 194 | </YueDisplay> | ||
| 195 | |||
| 196 |   切片的任意参数都可以省略,并会使用默认值。在如下示例中,如果省略了最大索引边界,它默认为表的长度。使下面的代码取除第一个元素之外的所有元素: | ||
| 197 | |||
| 198 | ```yuescript | ||
| 199 | slice = [item for item in *items[2,]] | ||
| 200 | ``` | ||
| 201 | <YueDisplay> | ||
| 202 | |||
| 203 | ```yue | ||
| 204 | slice = [item for item in *items[2,]] | ||
| 205 | ``` | ||
| 206 | |||
| 207 | </YueDisplay> | ||
| 208 | |||
| 209 |   如果省略了最小边界,便默认会设置为 1。这里我们只提供一个步长,并留下其他边界为空。这样会使得代码取出所有奇数索引的项目:(1, 3, 5, …) | ||
| 210 | |||
| 211 | ```yuescript | ||
| 212 | slice = [item for item in *items[,,2]] | ||
| 213 | ``` | ||
| 214 | <YueDisplay> | ||
| 215 | |||
| 216 | |||
| 217 | ```yue | ||
| 218 | slice = [item for item in *items[,,2]] | ||
| 219 | ``` | ||
| 220 | |||
| 221 | </YueDisplay> | ||
| 222 | |||
| 223 |   最小和最大边界都可以是负数,使用负数意味着边界是从表的末尾开始计算的。 | ||
| 224 | |||
| 225 | ```yuescript | ||
| 226 | -- 取最后4个元素 | ||
| 227 | slice = [item for item in *items[-4,-1]] | ||
| 228 | ``` | ||
| 229 | <YueDisplay> | ||
| 230 | |||
| 231 | ```yue | ||
| 232 | -- 取最后4个元素 | ||
| 233 | slice = [item for item in *items[-4,-1]] | ||
| 234 | ``` | ||
| 235 | |||
| 236 | </YueDisplay> | ||
| 237 | |||
| 238 |   切片的步长也可以是负数,这意味着元素会以相反的顺序被取出。 | ||
| 239 | |||
| 240 | ```yuescript | ||
| 241 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 242 | ``` | ||
| 243 | <YueDisplay> | ||
| 244 | |||
| 245 | ```yue | ||
| 246 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 247 | ``` | ||
| 248 | |||
| 249 | </YueDisplay> | ||
| 250 | |||
| 251 | ### 切片表达式 | ||
| 252 | |||
| 253 |   切片也可以作为表达式来使用。可以用于获取一个表包含的子列表。 | ||
| 254 | |||
| 255 | ```yuescript | ||
| 256 | -- 取第2和第4个元素作为新的列表 | ||
| 257 | sub_list = items[2, 4] | ||
| 258 | |||
| 259 | -- 取最后4个元素作为新的列表 | ||
| 260 | last_four_items = items[-4, -1] | ||
| 261 | ``` | ||
| 262 | <YueDisplay> | ||
| 263 | |||
| 264 | ```yue | ||
| 265 | -- 取第2和第4个元素作为新的列表 | ||
| 266 | sub_list = items[2, 4] | ||
| 267 | |||
| 268 | -- 取最后4个元素作为新的列表 | ||
| 269 | last_four_items = items[-4, -1] | ||
| 270 | ``` | ||
| 271 | |||
| 272 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/conditionals.md b/doc/docs/zh/doc/conditionals.md new file mode 100644 index 0000000..e4b217a --- /dev/null +++ b/doc/docs/zh/doc/conditionals.md | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | # 条件语句 | ||
| 2 | |||
| 3 | ```yuescript | ||
| 4 | have_coins = false | ||
| 5 | if have_coins | ||
| 6 | print "有硬币" | ||
| 7 | else | ||
| 8 | print "没有硬币" | ||
| 9 | ``` | ||
| 10 | <YueDisplay> | ||
| 11 | |||
| 12 | ```yue | ||
| 13 | have_coins = false | ||
| 14 | if have_coins | ||
| 15 | print "有硬币" | ||
| 16 | else | ||
| 17 | print "没有硬币" | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 |   对于简单的语句,也可以使用简短的语法: | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | have_coins = false | ||
| 26 | if have_coins then print "有硬币" else print "没有硬币" | ||
| 27 | ``` | ||
| 28 | <YueDisplay> | ||
| 29 | |||
| 30 | ```yue | ||
| 31 | have_coins = false | ||
| 32 | if have_coins then print "有硬币" else print "没有硬币" | ||
| 33 | ``` | ||
| 34 | |||
| 35 | </YueDisplay> | ||
| 36 | |||
| 37 |   因为 if 语句可以用作表达式,所以也可以这样写: | ||
| 38 | |||
| 39 | ```yuescript | ||
| 40 | have_coins = false | ||
| 41 | print if have_coins then "有硬币" else "没有硬币" | ||
| 42 | ``` | ||
| 43 | <YueDisplay> | ||
| 44 | |||
| 45 | ```yue | ||
| 46 | have_coins = false | ||
| 47 | print if have_coins then "有硬币" else "没有硬币" | ||
| 48 | ``` | ||
| 49 | |||
| 50 | </YueDisplay> | ||
| 51 | |||
| 52 |   条件语句也可以作为表达式用在返回语句和赋值语句中: | ||
| 53 | |||
| 54 | ```yuescript | ||
| 55 | is_tall = (name) -> | ||
| 56 | if name == "Rob" | ||
| 57 | true | ||
| 58 | else | ||
| 59 | false | ||
| 60 | |||
| 61 | message = if is_tall "Rob" | ||
| 62 | "我很高" | ||
| 63 | else | ||
| 64 | "我不是很高" | ||
| 65 | |||
| 66 | print message -- 打印: 我很高 | ||
| 67 | ``` | ||
| 68 | <YueDisplay> | ||
| 69 | |||
| 70 | ```yue | ||
| 71 | is_tall = (name) -> | ||
| 72 | if name == "Rob" | ||
| 73 | true | ||
| 74 | else | ||
| 75 | false | ||
| 76 | |||
| 77 | message = if is_tall "Rob" | ||
| 78 | "我很高" | ||
| 79 | else | ||
| 80 | "我不是很高" | ||
| 81 | |||
| 82 | print message -- 打印: 我很高 | ||
| 83 | ``` | ||
| 84 | |||
| 85 | </YueDisplay> | ||
| 86 | |||
| 87 |   if 的反义词是 unless(相当于 if not,正如“如果”对应“除非”): | ||
| 88 | |||
| 89 | ```yuescript | ||
| 90 | unless os.date("%A") == "Monday" | ||
| 91 | print "今天不是星期一!" | ||
| 92 | ``` | ||
| 93 | <YueDisplay> | ||
| 94 | |||
| 95 | |||
| 96 | ```yue | ||
| 97 | unless os.date("%A") == "Monday" | ||
| 98 | print "今天不是星期一!" | ||
| 99 | ``` | ||
| 100 | |||
| 101 | </YueDisplay> | ||
| 102 | |||
| 103 | ```yuescript | ||
| 104 | print "你真幸运!" unless math.random! > 0.1 | ||
| 105 | ``` | ||
| 106 | <YueDisplay> | ||
| 107 | |||
| 108 | ```yue | ||
| 109 | print "你真幸运!" unless math.random! > 0.1 | ||
| 110 | ``` | ||
| 111 | |||
| 112 | </YueDisplay> | ||
| 113 | |||
| 114 | ## 范围表达式 | ||
| 115 | |||
| 116 |   你可以使用范围表达式来编写进行范围检查的代码。 | ||
| 117 | |||
| 118 | ```yuescript | ||
| 119 | a = 5 | ||
| 120 | |||
| 121 | if a in [1, 3, 5, 7] | ||
| 122 | print "检查离散值的相等性" | ||
| 123 | |||
| 124 | if a in list | ||
| 125 | print "检查`a`是否在列表中" | ||
| 126 | ``` | ||
| 127 | <YueDisplay> | ||
| 128 | |||
| 129 | ```yue | ||
| 130 | a = 5 | ||
| 131 | |||
| 132 | if a in [1, 3, 5, 7] | ||
| 133 | print "检查离散值的相等性" | ||
| 134 | |||
| 135 | if a in list | ||
| 136 | print "检查`a`是否在列表中" | ||
| 137 | ``` | ||
| 138 | |||
| 139 | </YueDisplay> | ||
| 140 | |||
| 141 | ```yuescript | ||
| 142 | print "你很幸运!" unless math.random! > 0.1 | ||
| 143 | ``` | ||
| 144 | <YueDisplay> | ||
| 145 | |||
| 146 | ```yue | ||
| 147 | print "你很幸运!" unless math.random! > 0.1 | ||
| 148 | ``` | ||
| 149 | |||
| 150 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/continue.md b/doc/docs/zh/doc/continue.md new file mode 100644 index 0000000..9fab8a3 --- /dev/null +++ b/doc/docs/zh/doc/continue.md | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | # continue 语句 | ||
| 2 | |||
| 3 |   继续语句可以用来跳出当前的循环迭代。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 0 | ||
| 7 | while i < 10 | ||
| 8 | i += 1 | ||
| 9 | continue if i % 2 == 0 | ||
| 10 | print i | ||
| 11 | ``` | ||
| 12 | <YueDisplay> | ||
| 13 | |||
| 14 | ```yue | ||
| 15 | i = 0 | ||
| 16 | while i < 10 | ||
| 17 | i += 1 | ||
| 18 | continue if i % 2 == 0 | ||
| 19 | print i | ||
| 20 | ``` | ||
| 21 | |||
| 22 | </YueDisplay> | ||
| 23 | |||
| 24 |   继续语句也可以与各种循环表达式一起使用,以防止当前的循环迭代结果累积到结果列表中。以下示例将数组表过滤为仅包含偶数的数组: | ||
| 25 | |||
| 26 | ```yuescript | ||
| 27 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 28 | odds = for x in *my_numbers | ||
| 29 | continue if x % 2 == 1 | ||
| 30 | x | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 36 | odds = for x in *my_numbers | ||
| 37 | continue if x % 2 == 1 | ||
| 38 | x | ||
| 39 | ``` | ||
| 40 | |||
| 41 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/destructuring-assignment.md b/doc/docs/zh/doc/destructuring-assignment.md new file mode 100644 index 0000000..205a1ff --- /dev/null +++ b/doc/docs/zh/doc/destructuring-assignment.md | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | # 解构赋值 | ||
| 2 | |||
| 3 |   解构赋值是一种快速从 Lua 表中按名称或基于数组中的位置提取值的方法。 | ||
| 4 | |||
| 5 |   通常当你看到一个字面量的 Lua 表,比如 `{1,2,3}`,它位于赋值的右侧,因为它是一个值。解构赋值语句的写法就是交换了字面量 Lua 表的角色,并将其放在赋值语句的左侧。 | ||
| 6 | |||
| 7 |   最好是通过示例来解释。以下是如何从表格中解包前两个值的方法: | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | thing = [1, 2] | ||
| 11 | |||
| 12 | [a, b] = thing | ||
| 13 | print a, b | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | |||
| 18 | ```yue | ||
| 19 | thing = [1, 2] | ||
| 20 | |||
| 21 | [a, b] = thing | ||
| 22 | print a, b | ||
| 23 | ``` | ||
| 24 | |||
| 25 | </YueDisplay> | ||
| 26 | |||
| 27 |   在解构表格字面量中,键代表从右侧读取的键,值代表读取的值将被赋予的名称。 | ||
| 28 | |||
| 29 | ```yuescript | ||
| 30 | obj = { | ||
| 31 | hello: "world" | ||
| 32 | day: "tuesday" | ||
| 33 | length: 20 | ||
| 34 | } | ||
| 35 | |||
| 36 | {hello: hello, day: the_day} = obj | ||
| 37 | print hello, the_day | ||
| 38 | |||
| 39 | :day = obj -- 可以不带大括号进行简单的解构 | ||
| 40 | ``` | ||
| 41 | <YueDisplay> | ||
| 42 | |||
| 43 | ```yue | ||
| 44 | obj = { | ||
| 45 | hello: "world" | ||
| 46 | day: "tuesday" | ||
| 47 | length: 20 | ||
| 48 | } | ||
| 49 | |||
| 50 | {hello: hello, day: the_day} = obj | ||
| 51 | print hello, the_day | ||
| 52 | |||
| 53 | :day = obj -- 可以不带大括号进行简单的解构 | ||
| 54 | ``` | ||
| 55 | |||
| 56 | </YueDisplay> | ||
| 57 | |||
| 58 |   这也适用于嵌套的数据结构: | ||
| 59 | |||
| 60 | ```yuescript | ||
| 61 | obj2 = { | ||
| 62 | numbers: [1,2,3,4] | ||
| 63 | properties: { | ||
| 64 | color: "green" | ||
| 65 | height: 13.5 | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | {numbers: [first, second], properties: {color: color}} = obj2 | ||
| 70 | print first, second, color | ||
| 71 | ``` | ||
| 72 | <YueDisplay> | ||
| 73 | |||
| 74 | ```yue | ||
| 75 | obj2 = { | ||
| 76 | numbers: [1,2,3,4] | ||
| 77 | properties: { | ||
| 78 | color: "green" | ||
| 79 | height: 13.5 | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | {numbers: [first, second]} = obj2 | ||
| 84 | print first, second, color | ||
| 85 | ``` | ||
| 86 | |||
| 87 | </YueDisplay> | ||
| 88 | |||
| 89 |   如果解构语句很复杂,也可以任意将其分散在几行中。稍微复杂一些的示例: | ||
| 90 | |||
| 91 | ```yuescript | ||
| 92 | { | ||
| 93 | numbers: [first, second] | ||
| 94 | properties: { | ||
| 95 | color: color | ||
| 96 | } | ||
| 97 | } = obj2 | ||
| 98 | ``` | ||
| 99 | <YueDisplay> | ||
| 100 | |||
| 101 | ```yue | ||
| 102 | { | ||
| 103 | numbers: [first, second] | ||
| 104 | properties: { | ||
| 105 | color: color | ||
| 106 | } | ||
| 107 | } = obj2 | ||
| 108 | ``` | ||
| 109 | |||
| 110 | </YueDisplay> | ||
| 111 | |||
| 112 |   有时候我们会需要从 Lua 表中提取值并将它们赋给与键同名的局部变量。为了避免编写重复代码,我们可以使用 **:** 前缀操作符: | ||
| 113 | |||
| 114 | ```yuescript | ||
| 115 | {:concat, :insert} = table | ||
| 116 | ``` | ||
| 117 | <YueDisplay> | ||
| 118 | |||
| 119 | ```yue | ||
| 120 | {:concat, :insert} = table | ||
| 121 | ``` | ||
| 122 | |||
| 123 | </YueDisplay> | ||
| 124 | |||
| 125 |   这样的用法与导入语法有些相似。但我们可以通过混合语法重命名我们想要提取的字段: | ||
| 126 | |||
| 127 | ```yuescript | ||
| 128 | {:mix, :max, random: rand} = math | ||
| 129 | ``` | ||
| 130 | <YueDisplay> | ||
| 131 | |||
| 132 | ```yue | ||
| 133 | {:mix, :max, random: rand} = math | ||
| 134 | ``` | ||
| 135 | |||
| 136 | </YueDisplay> | ||
| 137 | |||
| 138 |   在进行解构时,你可以指定默认值,如: | ||
| 139 | |||
| 140 | ```yuescript | ||
| 141 | {:name = "nameless", :job = "jobless"} = person | ||
| 142 | ``` | ||
| 143 | <YueDisplay> | ||
| 144 | |||
| 145 | ```yue | ||
| 146 | {:name = "nameless", :job = "jobless"} = person | ||
| 147 | ``` | ||
| 148 | |||
| 149 | </YueDisplay> | ||
| 150 | |||
| 151 |   在进行列表解构时,你可以使用`_`作为占位符: | ||
| 152 | |||
| 153 | ```yuescript | ||
| 154 | [_, two, _, four] = items | ||
| 155 | ``` | ||
| 156 | <YueDisplay> | ||
| 157 | |||
| 158 | ```yue | ||
| 159 | [_, two, _, four] = items | ||
| 160 | ``` | ||
| 161 | |||
| 162 | </YueDisplay> | ||
| 163 | |||
| 164 | ## 范围解构 | ||
| 165 | |||
| 166 |   你可以使用展开运算符 `...` 在列表解构中来捕获一个范围的值到子列表中。这在当你想要从列表的开头和结尾提取特定元素,同时收集中间的元素时非常有用。 | ||
| 167 | |||
| 168 | ```yuescript | ||
| 169 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 170 | [first, ...bulk, last] = orders | ||
| 171 | print first -- 打印: first | ||
| 172 | print bulk -- 打印: {"second", "third", "fourth"} | ||
| 173 | print last -- 打印: last | ||
| 174 | ``` | ||
| 175 | <YueDisplay> | ||
| 176 | |||
| 177 | ```yue | ||
| 178 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 179 | [first, ...bulk, last] = orders | ||
| 180 | print first -- 打印: first | ||
| 181 | print bulk -- 打印: {"second", "third", "fourth"} | ||
| 182 | print last -- 打印: last | ||
| 183 | ``` | ||
| 184 | |||
| 185 | </YueDisplay> | ||
| 186 | |||
| 187 |   展开运算符可以用在不同的位置来捕获不同的范围,并且你可以使用 `_` 作为占位符来表示你想跳过对应范围的捕获: | ||
| 188 | |||
| 189 | ```yuescript | ||
| 190 | -- 捕获第一个元素之后的所有元素 | ||
| 191 | [first, ...rest] = orders | ||
| 192 | |||
| 193 | -- 捕获最后一个元素之前的所有元素 | ||
| 194 | [...start, last] = orders | ||
| 195 | |||
| 196 | -- 跳过中间的元素,只捕获第一个和最后一个元素 | ||
| 197 | [first, ..._, last] = orders | ||
| 198 | ``` | ||
| 199 | <YueDisplay> | ||
| 200 | |||
| 201 | ```yue | ||
| 202 | -- 捕获第一个元素之后的所有元素 | ||
| 203 | [first, ...rest] = orders | ||
| 204 | |||
| 205 | -- 捕获最后一个元素之前的所有元素 | ||
| 206 | [...start, last] = orders | ||
| 207 | |||
| 208 | -- 跳过中间的元素,只捕获第一个和最后一个元素 | ||
| 209 | [first, ..._, last] = orders | ||
| 210 | ``` | ||
| 211 | |||
| 212 | </YueDisplay> | ||
| 213 | |||
| 214 | ## 在其它地方的解构赋值 | ||
| 215 | |||
| 216 |   解构赋值也可以出现在其它隐式进行赋值的地方。一个例子是用在 for 循环中: | ||
| 217 | |||
| 218 | ```yuescript | ||
| 219 | tuples = [ | ||
| 220 | ["hello", "world"] | ||
| 221 | ["egg", "head"] | ||
| 222 | ] | ||
| 223 | |||
| 224 | for [left, right] in *tuples | ||
| 225 | print left, right | ||
| 226 | ``` | ||
| 227 | <YueDisplay> | ||
| 228 | |||
| 229 | ```yue | ||
| 230 | tuples = [ | ||
| 231 | ["hello", "world"] | ||
| 232 | ["egg", "head"] | ||
| 233 | ] | ||
| 234 | |||
| 235 | for [left, right] in *tuples | ||
| 236 | print left, right | ||
| 237 | ``` | ||
| 238 | |||
| 239 | </YueDisplay> | ||
| 240 | |||
| 241 |   我们知道数组表中的每个元素都是一个两项的元组,所以我们可以直接在 for 语句的名称子句中使用解构来解包它。 | ||
diff --git a/doc/docs/zh/doc/do.md b/doc/docs/zh/doc/do.md new file mode 100644 index 0000000..52dca26 --- /dev/null +++ b/doc/docs/zh/doc/do.md | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | # do 语句 | ||
| 2 | |||
| 3 |   当用作语句时,do 语句的作用就像在 Lua 中差不多。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | do | ||
| 7 | var = "hello" | ||
| 8 | print var | ||
| 9 | print var -- 这里是nil | ||
| 10 | ``` | ||
| 11 | <YueDisplay> | ||
| 12 | |||
| 13 | ```yue | ||
| 14 | do | ||
| 15 | var = "hello" | ||
| 16 | print var | ||
| 17 | print var -- 这里是nil | ||
| 18 | ``` | ||
| 19 | |||
| 20 | </YueDisplay> | ||
| 21 | |||
| 22 |   月之脚本的 **do** 也可以用作表达式。允许你将多行代码的处理合并为一个表达式,并将 do 语句代码块的最后一个语句作为表达式返回的结果。 | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | counter = do | ||
| 26 | i = 0 | ||
| 27 | -> | ||
| 28 | i += 1 | ||
| 29 | i | ||
| 30 | |||
| 31 | print counter! | ||
| 32 | print counter! | ||
| 33 | ``` | ||
| 34 | <YueDisplay> | ||
| 35 | |||
| 36 | ```yue | ||
| 37 | counter = do | ||
| 38 | i = 0 | ||
| 39 | -> | ||
| 40 | i += 1 | ||
| 41 | i | ||
| 42 | |||
| 43 | print counter! | ||
| 44 | print counter! | ||
| 45 | ``` | ||
| 46 | |||
| 47 | </YueDisplay> | ||
| 48 | |||
| 49 | ```yuescript | ||
| 50 | tbl = { | ||
| 51 | key: do | ||
| 52 | print "分配键值!" | ||
| 53 | 1234 | ||
| 54 | } | ||
| 55 | ``` | ||
| 56 | <YueDisplay> | ||
| 57 | |||
| 58 | ```yue | ||
| 59 | tbl = { | ||
| 60 | key: do | ||
| 61 | print "分配键值!" | ||
| 62 | 1234 | ||
| 63 | } | ||
| 64 | ``` | ||
| 65 | |||
| 66 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/for-loop.md b/doc/docs/zh/doc/for-loop.md new file mode 100644 index 0000000..212ff81 --- /dev/null +++ b/doc/docs/zh/doc/for-loop.md | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | # for 循环 | ||
| 2 | |||
| 3 |   Lua 中有两种 for 循环形式,数字型和通用型: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | for i = 10, 20 | ||
| 7 | print i | ||
| 8 | |||
| 9 | for k = 1, 15, 2 -- 提供了一个遍历的步长 | ||
| 10 | print k | ||
| 11 | |||
| 12 | for key, value in pairs object | ||
| 13 | print key, value | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | for i = 10, 20 | ||
| 19 | print i | ||
| 20 | |||
| 21 | for k = 1, 15, 2 -- 提供了一个遍历的步长 | ||
| 22 | print k | ||
| 23 | |||
| 24 | for key, value in pairs object | ||
| 25 | print key, value | ||
| 26 | ``` | ||
| 27 | |||
| 28 | </YueDisplay> | ||
| 29 | |||
| 30 |   可以使用切片和 **\*** 操作符,就像在列表推导中一样: | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | for item in *items[2, 4] | ||
| 34 | print item | ||
| 35 | ``` | ||
| 36 | <YueDisplay> | ||
| 37 | |||
| 38 | ```yue | ||
| 39 | for item in *items[2, 4] | ||
| 40 | print item | ||
| 41 | ``` | ||
| 42 | |||
| 43 | </YueDisplay> | ||
| 44 | |||
| 45 |   当代码语句只有一行时,循环语句也都可以写作更短的语法: | ||
| 46 | |||
| 47 | ```yuescript | ||
| 48 | for item in *items do print item | ||
| 49 | |||
| 50 | for j = 1, 10, 3 do print j | ||
| 51 | ``` | ||
| 52 | <YueDisplay> | ||
| 53 | |||
| 54 | ```yue | ||
| 55 | for item in *items do print item | ||
| 56 | |||
| 57 | for j = 1, 10, 3 do print j | ||
| 58 | ``` | ||
| 59 | |||
| 60 | </YueDisplay> | ||
| 61 | |||
| 62 |   for 循环也可以用作表达式。for 循环主体中的最后一条语句会被强制转换为一个返回值的表达式,并会将表达式计算结果的值追加到一个作为结果的数组表中。 | ||
| 63 | |||
| 64 |   将每个偶数加倍: | ||
| 65 | |||
| 66 | ```yuescript | ||
| 67 | doubled_evens = for i = 1, 20 | ||
| 68 | if i % 2 == 0 | ||
| 69 | i * 2 | ||
| 70 | else | ||
| 71 | i | ||
| 72 | ``` | ||
| 73 | <YueDisplay> | ||
| 74 | |||
| 75 | ```yue | ||
| 76 | doubled_evens = for i = 1, 20 | ||
| 77 | if i % 2 == 0 | ||
| 78 | i * 2 | ||
| 79 | else | ||
| 80 | i | ||
| 81 | ``` | ||
| 82 | |||
| 83 | </YueDisplay> | ||
| 84 | |||
| 85 |   此外,for 循环还支持带返回值的 break 语句,这样循环本身就可以作为一个表达式,在满足条件时提前退出并返回有意义的结果。 | ||
| 86 | |||
| 87 |   例如,查找第一个大于 10 的数字: | ||
| 88 | |||
| 89 | ```yuescript | ||
| 90 | first_large = for n in *numbers | ||
| 91 | break n if n > 10 | ||
| 92 | ``` | ||
| 93 | <YueDisplay> | ||
| 94 | |||
| 95 | ```yue | ||
| 96 | first_large = for n in *numbers | ||
| 97 | break n if n > 10 | ||
| 98 | ``` | ||
| 99 | |||
| 100 | </YueDisplay> | ||
| 101 | |||
| 102 |   你还可以结合 for 循环表达式与 continue 语句来过滤值。 | ||
| 103 | |||
| 104 |   注意出现在函数体末尾的 for 循环,不会被当作是一个表达式并将循环结果累积到一个列表中作为返回值(相反,函数将返回 nil)。如果要函数末尾的循环转换为列表表达式,可以显式地使用返回语句加 for 循环表达式。 | ||
| 105 | |||
| 106 | ```yuescript | ||
| 107 | func_a = -> for i = 1, 10 do print i | ||
| 108 | func_b = -> return for i = 1, 10 do i | ||
| 109 | |||
| 110 | print func_a! -- 打印 nil | ||
| 111 | print func_b! -- 打印 table 对象 | ||
| 112 | ``` | ||
| 113 | <YueDisplay> | ||
| 114 | |||
| 115 | ```yue | ||
| 116 | func_a = -> for i = 1, 10 do print i | ||
| 117 | func_b = -> return for i = 1, 10 do i | ||
| 118 | |||
| 119 | print func_a! -- 打印 nil | ||
| 120 | print func_b! -- 打印 table 对象 | ||
| 121 | ``` | ||
| 122 | |||
| 123 | </YueDisplay> | ||
| 124 | |||
| 125 |   这样做是为了避免在不需要返回循环结果的函数,创建无效的返回值表格。 | ||
diff --git a/doc/docs/zh/doc/function-literals.md b/doc/docs/zh/doc/function-literals.md new file mode 100644 index 0000000..efe920b --- /dev/null +++ b/doc/docs/zh/doc/function-literals.md | |||
| @@ -0,0 +1,494 @@ | |||
| 1 | # 函数字面量 | ||
| 2 | |||
| 3 |   所有函数都是使用月之脚本的函数表达式创建的。一个简单的函数可以用箭头表示为:**->**。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | my_function = -> | ||
| 7 | my_function() -- 调用空函数 | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | my_function = -> | ||
| 13 | my_function() -- 调用空函数 | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 |   函数体可以是紧跟在箭头后的一个语句,或者是在后面的行上使用同样缩进的一系列语句: | ||
| 19 | |||
| 20 | ```yuescript | ||
| 21 | func_a = -> print "你好,世界" | ||
| 22 | |||
| 23 | func_b = -> | ||
| 24 | value = 100 | ||
| 25 | print "这个值是:", value | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | func_a = -> print "你好,世界" | ||
| 31 | |||
| 32 | func_b = -> | ||
| 33 | value = 100 | ||
| 34 | print "这个值是:", value | ||
| 35 | ``` | ||
| 36 | |||
| 37 | </YueDisplay> | ||
| 38 | |||
| 39 |   如果一个函数没有参数,可以使用 **\!** 操作符调用它,而不是空括号。使用 **\!** 调用没有参数的函数是推荐的写法。 | ||
| 40 | |||
| 41 | ```yuescript | ||
| 42 | func_a! | ||
| 43 | func_b() | ||
| 44 | ``` | ||
| 45 | <YueDisplay> | ||
| 46 | |||
| 47 | ```yue | ||
| 48 | func_a! | ||
| 49 | func_b() | ||
| 50 | ``` | ||
| 51 | |||
| 52 | </YueDisplay> | ||
| 53 | |||
| 54 |   带有参数的函数可以通过在箭头前加上括号中的参数名列表来进行创建: | ||
| 55 | |||
| 56 | ```yuescript | ||
| 57 | sum = (x, y) -> print "数字的和", x + y | ||
| 58 | ``` | ||
| 59 | <YueDisplay> | ||
| 60 | |||
| 61 | ```yue | ||
| 62 | sum = (x, y) -> print "数字的和", x + y | ||
| 63 | ``` | ||
| 64 | |||
| 65 | </YueDisplay> | ||
| 66 | |||
| 67 |   函数可以通过在函数名后列出参数来调用。当对函数做嵌套的调用时,后面列出的参数会应用于左侧最近的函数。 | ||
| 68 | |||
| 69 | ```yuescript | ||
| 70 | sum 10, 20 | ||
| 71 | print sum 10, 20 | ||
| 72 | |||
| 73 | a b c "a", "b", "c" | ||
| 74 | ``` | ||
| 75 | <YueDisplay> | ||
| 76 | |||
| 77 | ```yue | ||
| 78 | sum 10, 20 | ||
| 79 | print sum 10, 20 | ||
| 80 | |||
| 81 | a b c "a", "b", "c" | ||
| 82 | ``` | ||
| 83 | |||
| 84 | </YueDisplay> | ||
| 85 | |||
| 86 |   为了避免在调用函数时产生歧义,也可以使用括号将参数括起来。比如在以下的例子中是必需的,这样才能确保参数被传入到正确的函数。 | ||
| 87 | |||
| 88 | ```yuescript | ||
| 89 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 90 | ``` | ||
| 91 | <YueDisplay> | ||
| 92 | |||
| 93 | ```yue | ||
| 94 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 95 | ``` | ||
| 96 | |||
| 97 | </YueDisplay> | ||
| 98 | |||
| 99 |   注意:函数名与开始括号之间不能有任何空格。 | ||
| 100 | |||
| 101 |   函数会将函数体中的最后一个语句强制转换为返回语句,这被称作隐式返回: | ||
| 102 | |||
| 103 | ```yuescript | ||
| 104 | sum = (x, y) -> x + y | ||
| 105 | print "数字的和是", sum 10, 20 | ||
| 106 | ``` | ||
| 107 | <YueDisplay> | ||
| 108 | |||
| 109 | ```yue | ||
| 110 | sum = (x, y) -> x + y | ||
| 111 | print "数字的和是", sum 10, 20 | ||
| 112 | ``` | ||
| 113 | |||
| 114 | </YueDisplay> | ||
| 115 | |||
| 116 |   如果你需要做显式返回,可以使用 return 关键字: | ||
| 117 | |||
| 118 | ```yuescript | ||
| 119 | sum = (x, y) -> return x + y | ||
| 120 | ``` | ||
| 121 | <YueDisplay> | ||
| 122 | |||
| 123 | ```yue | ||
| 124 | sum = (x, y) -> return x + y | ||
| 125 | ``` | ||
| 126 | |||
| 127 | </YueDisplay> | ||
| 128 | |||
| 129 |   就像在Lua中一样,函数可以返回多个值。最后一个语句必须是由逗号分隔的值列表: | ||
| 130 | |||
| 131 | ```yuescript | ||
| 132 | mystery = (x, y) -> x + y, x - y | ||
| 133 | a, b = mystery 10, 20 | ||
| 134 | ``` | ||
| 135 | <YueDisplay> | ||
| 136 | |||
| 137 | ```yue | ||
| 138 | mystery = (x, y) -> x + y, x - y | ||
| 139 | a, b = mystery 10, 20 | ||
| 140 | ``` | ||
| 141 | |||
| 142 | </YueDisplay> | ||
| 143 | |||
| 144 | ## 粗箭头 | ||
| 145 | |||
| 146 |   因为在 Lua 中调用方法时,经常习惯将对象作为第一个参数传入,所以月之脚本提供了一种特殊的语法来创建自动包含 self 参数的函数。 | ||
| 147 | |||
| 148 | ```yuescript | ||
| 149 | func = (num) => @value + num | ||
| 150 | ``` | ||
| 151 | <YueDisplay> | ||
| 152 | |||
| 153 | ```yue | ||
| 154 | func = (num) => @value + num | ||
| 155 | ``` | ||
| 156 | |||
| 157 | </YueDisplay> | ||
| 158 | |||
| 159 | ## 参数默认值 | ||
| 160 | |||
| 161 |   可以为函数的参数提供默认值。如果参数的值为 nil,则确定该参数为空。任何具有默认值的 nil 参数在函数体运行之前都会被替换。 | ||
| 162 | |||
| 163 | ```yuescript | ||
| 164 | my_function = (name = "某物", height = 100) -> | ||
| 165 | print "你好,我是", name | ||
| 166 | print "我的高度是", height | ||
| 167 | ``` | ||
| 168 | <YueDisplay> | ||
| 169 | |||
| 170 | ```yue | ||
| 171 | my_function = (name = "某物", height = 100) -> | ||
| 172 | print "你好,我是", name | ||
| 173 | print "我的高度是", height | ||
| 174 | ``` | ||
| 175 | |||
| 176 | </YueDisplay> | ||
| 177 | |||
| 178 |   函数参数的默认值表达式在函数体中会按参数声明的顺序进行计算。因此,在默认值的表达式中可以访问先前声明的参数。 | ||
| 179 | |||
| 180 | ```yuescript | ||
| 181 | some_args = (x = 100, y = x + 1000) -> | ||
| 182 | print x + y | ||
| 183 | ``` | ||
| 184 | <YueDisplay> | ||
| 185 | |||
| 186 | ```yue | ||
| 187 | some_args = (x = 100, y = x + 1000) -> | ||
| 188 | print x + y | ||
| 189 | ``` | ||
| 190 | |||
| 191 | </YueDisplay> | ||
| 192 | |||
| 193 | ## 注意事项 | ||
| 194 | |||
| 195 |   由于月之脚本支持无需括号的表达式式函数调用,因此为了避免因空白字符造成的解析歧义,需要进行一些限制。 | ||
| 196 | |||
| 197 |   减号(-)在表达式中既可以作为一元取反操作符,也可以作为二元减法操作符。请注意下面这些示例的编译方式: | ||
| 198 | |||
| 199 | ```yuescript | ||
| 200 | a = x - 10 | ||
| 201 | b = x-10 | ||
| 202 | c = x -y | ||
| 203 | d = x- z | ||
| 204 | ``` | ||
| 205 | <YueDisplay> | ||
| 206 | |||
| 207 | ```yue | ||
| 208 | a = x - 10 | ||
| 209 | b = x-10 | ||
| 210 | c = x -y | ||
| 211 | d = x- z | ||
| 212 | ``` | ||
| 213 | |||
| 214 | </YueDisplay> | ||
| 215 | |||
| 216 |   当函数调用的第一个参数是字符串字面量时,可以通过空白控制其优先级。在 Lua 中,常见的写法是调用仅有一个字符串或表字面量参数的函数时省略括号。 | ||
| 217 | |||
| 218 |   当变量名和字符串字面量之间没有空格时,函数的调用优先级高于后续表达式,因此此时无法再传入其他参数。 | ||
| 219 | |||
| 220 |   当变量名和字符串字面量之间有空格时,字符串字面量会作为后续表达式(如果存在)的参数,这样可以传递参数列表。 | ||
| 221 | |||
| 222 | ```yuescript | ||
| 223 | x = func"hello" + 100 | ||
| 224 | y = func "hello" + 100 | ||
| 225 | ``` | ||
| 226 | <YueDisplay> | ||
| 227 | |||
| 228 | ```yue | ||
| 229 | x = func"hello" + 100 | ||
| 230 | y = func "hello" + 100 | ||
| 231 | ``` | ||
| 232 | |||
| 233 | </YueDisplay> | ||
| 234 | |||
| 235 | ## 多行参数 | ||
| 236 | |||
| 237 |   当调用接收大量参数的函数时,将参数列表分成多行是很方便的。由于月之脚本语言对空白字符的敏感性,做参数列表的分割时务必要小心。 | ||
| 238 | |||
| 239 |   如果要将参数列表写到下一行,那么当前行必须以逗号结束。并且下一行的缩进必须比当前的缩进多。一旦做了参数的缩进,所有其他参数列表的行必须保持相同的缩进级别,以成为参数列表的一部分。 | ||
| 240 | |||
| 241 | ```yuescript | ||
| 242 | my_func 5, 4, 3, | ||
| 243 | 8, 9, 10 | ||
| 244 | |||
| 245 | cool_func 1, 2, | ||
| 246 | 3, 4, | ||
| 247 | 5, 6, | ||
| 248 | 7, 8 | ||
| 249 | ``` | ||
| 250 | <YueDisplay> | ||
| 251 | |||
| 252 | ```yue | ||
| 253 | my_func 5, 4, 3, | ||
| 254 | 8, 9, 10 | ||
| 255 | |||
| 256 | cool_func 1, 2, | ||
| 257 | 3, 4, | ||
| 258 | 5, 6, | ||
| 259 | 7, 8 | ||
| 260 | ``` | ||
| 261 | |||
| 262 | </YueDisplay> | ||
| 263 | |||
| 264 |   这种调用方式可以做嵌套。并通过缩进级别来确定参数属于哪一个函数。 | ||
| 265 | |||
| 266 | ```yuescript | ||
| 267 | my_func 5, 6, 7, | ||
| 268 | 6, another_func 6, 7, 8, | ||
| 269 | 9, 1, 2, | ||
| 270 | 5, 4 | ||
| 271 | ``` | ||
| 272 | <YueDisplay> | ||
| 273 | |||
| 274 | ```yue | ||
| 275 | my_func 5, 6, 7, | ||
| 276 | 6, another_func 6, 7, 8, | ||
| 277 | 9, 1, 2, | ||
| 278 | 5, 4 | ||
| 279 | ``` | ||
| 280 | |||
| 281 | </YueDisplay> | ||
| 282 | |||
| 283 |   因为 Lua 表也使用逗号作为分隔符,这种缩进语法有助于让值成为参数列表的一部分,而不是 Lua 表的一部分。 | ||
| 284 | |||
| 285 | ```yuescript | ||
| 286 | x = [ | ||
| 287 | 1, 2, 3, 4, a_func 4, 5, | ||
| 288 | 5, 6, | ||
| 289 | 8, 9, 10 | ||
| 290 | ] | ||
| 291 | ``` | ||
| 292 | <YueDisplay> | ||
| 293 | |||
| 294 | ```yue | ||
| 295 | x = [ | ||
| 296 | 1, 2, 3, 4, a_func 4, 5, | ||
| 297 | 5, 6, | ||
| 298 | 8, 9, 10 | ||
| 299 | ] | ||
| 300 | ``` | ||
| 301 | |||
| 302 | </YueDisplay> | ||
| 303 | |||
| 304 |   有个不常见的写法可以注意一下,如果我们将在后面使用较低的缩进,我们可以为函数参数提供更深的缩进来区分列表的归属。 | ||
| 305 | |||
| 306 | ```yuescript | ||
| 307 | y = [ my_func 1, 2, 3, | ||
| 308 | 4, 5, | ||
| 309 | 5, 6, 7 | ||
| 310 | ] | ||
| 311 | ``` | ||
| 312 | <YueDisplay> | ||
| 313 | |||
| 314 | ```yue | ||
| 315 | y = [ my_func 1, 2, 3, | ||
| 316 | 4, 5, | ||
| 317 | 5, 6, 7 | ||
| 318 | ] | ||
| 319 | ``` | ||
| 320 | |||
| 321 | </YueDisplay> | ||
| 322 | |||
| 323 |   对于其它有代码块跟随的语句,比如条件语句,也可以通过小心安排缩进来做类似的事。比如我们可以通过调整缩进级别来控制一些值归属于哪个语句: | ||
| 324 | |||
| 325 | ```yuescript | ||
| 326 | if func 1, 2, 3, | ||
| 327 | "你好", | ||
| 328 | "世界" | ||
| 329 | print "你好" | ||
| 330 | print "我在if内部" | ||
| 331 | |||
| 332 | if func 1, 2, 3, | ||
| 333 | "你好", | ||
| 334 | "世界" | ||
| 335 | print "hello" | ||
| 336 | print "我在if内部" | ||
| 337 | ``` | ||
| 338 | <YueDisplay> | ||
| 339 | |||
| 340 | ```yue | ||
| 341 | if func 1, 2, 3, | ||
| 342 | "你好", | ||
| 343 | "世界" | ||
| 344 | print "你好" | ||
| 345 | print "我在if内部" | ||
| 346 | |||
| 347 | if func 1, 2, 3, | ||
| 348 | "你好", | ||
| 349 | "世界" | ||
| 350 | print "你好" | ||
| 351 | print "我在if内部" | ||
| 352 | ``` | ||
| 353 | |||
| 354 | </YueDisplay> | ||
| 355 | |||
| 356 | ## 参数解构 | ||
| 357 | |||
| 358 |   月之脚本支持在函数形参位置对传入对象进行解构。适用两类解构表子面量: | ||
| 359 | |||
| 360 | - 使用 {} 包裹的字面量/对象形参,支持提供获得空字段时的默认值(例如 {:a, :b}、{a: a1 = 123})。 | ||
| 361 | |||
| 362 | - 无 {} 包裹、以键值/简写键序列开头,直至遇到其它表达式终止(例如 :a, b: b1, :c),表示从同一个对象中解构多个字段。 | ||
| 363 | |||
| 364 | ```yuescript | ||
| 365 | f1 = (:a, :b, :c) -> | ||
| 366 | print a, b, c | ||
| 367 | |||
| 368 | f1 a: 1, b: "2", c: {} | ||
| 369 | |||
| 370 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 371 | print a1, b, c | ||
| 372 | |||
| 373 | arg1 = {a: 0} | ||
| 374 | f2 arg1, arg2 | ||
| 375 | ``` | ||
| 376 | <YueDisplay> | ||
| 377 | |||
| 378 | ```yue | ||
| 379 | f1 = (:a, :b, :c) -> | ||
| 380 | print a, b, c | ||
| 381 | |||
| 382 | f1 a: 1, b: "2", c: {} | ||
| 383 | |||
| 384 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 385 | print a1, b, c | ||
| 386 | |||
| 387 | arg1 = {a: 0} | ||
| 388 | f2 arg1, arg2 | ||
| 389 | ``` | ||
| 390 | |||
| 391 | </YueDisplay> | ||
| 392 | |||
| 393 | ## 前置返回表达式 | ||
| 394 | |||
| 395 |   在深度嵌套的函数体中,为了提升返回值的可读性及编写便利性,我们新增了 “前置返回表达式” 语法。其形式如下: | ||
| 396 | |||
| 397 | ```yuescript | ||
| 398 | findFirstEven = (list): nil -> | ||
| 399 | for item in *list | ||
| 400 | if type(item) == "table" | ||
| 401 | for sub in *item | ||
| 402 | if sub % 2 == 0 | ||
| 403 | return sub | ||
| 404 | ``` | ||
| 405 | <YueDisplay> | ||
| 406 | |||
| 407 | ```yue | ||
| 408 | findFirstEven = (list): nil -> | ||
| 409 | for item in *list | ||
| 410 | if type(item) == "table" | ||
| 411 | for sub in *item | ||
| 412 | if sub % 2 == 0 | ||
| 413 | return sub | ||
| 414 | ``` | ||
| 415 | |||
| 416 | </YueDisplay> | ||
| 417 | |||
| 418 |   这个写法等价于: | ||
| 419 | |||
| 420 | ```yuescript | ||
| 421 | findFirstEven = (list) -> | ||
| 422 | for item in *list | ||
| 423 | if type(item) == "table" | ||
| 424 | for sub in *item | ||
| 425 | if sub % 2 == 0 | ||
| 426 | return sub | ||
| 427 | nil | ||
| 428 | ``` | ||
| 429 | <YueDisplay> | ||
| 430 | |||
| 431 | ```yue | ||
| 432 | findFirstEven = (list) -> | ||
| 433 | for item in *list | ||
| 434 | if type(item) == "table" | ||
| 435 | for sub in *item | ||
| 436 | if sub % 2 == 0 | ||
| 437 | return sub | ||
| 438 | nil | ||
| 439 | ``` | ||
| 440 | |||
| 441 | </YueDisplay> | ||
| 442 | |||
| 443 |   唯一的区别在于:你可以将函数的返回值表达式提前写在 `->` 或 `=>` 前,用以指示该函数应隐式返回该表达式的值。这样即使在多层循环或条件判断的场景下,也无需编写尾行悬挂的返回表达式,逻辑结构会更加直观清晰。 | ||
| 444 | |||
| 445 | ## 命名变长参数 | ||
| 446 | |||
| 447 |   你可以使用 `(...t) ->` 语法来将变长参数自动存储到一个命名表中。这个表会包含所有传入的参数(包括 `nil` 值),并且会在表的 `n` 字段中存储实际传入的参数个数(包括 `nil` 值在内的个数)。 | ||
| 448 | |||
| 449 | ```yuescript | ||
| 450 | f = (...t) -> | ||
| 451 | print "参数个数:", t.n | ||
| 452 | print "表长度:", #t | ||
| 453 | for i = 1, t.n | ||
| 454 | print t[i] | ||
| 455 | |||
| 456 | f 1, 2, 3 | ||
| 457 | f "a", "b", "c", "d" | ||
| 458 | f! | ||
| 459 | |||
| 460 | -- 处理包含 nil 的情况 | ||
| 461 | process = (...args) -> | ||
| 462 | sum = 0 | ||
| 463 | for i = 1, args.n | ||
| 464 | if args[i] != nil and type(args[i]) == "number" | ||
| 465 | sum += args[i] | ||
| 466 | sum | ||
| 467 | |||
| 468 | process 1, nil, 3, nil, 5 | ||
| 469 | ``` | ||
| 470 | <YueDisplay> | ||
| 471 | |||
| 472 | ```yue | ||
| 473 | f = (...t) -> | ||
| 474 | print "参数个数:", t.n | ||
| 475 | print "表长度:", #t | ||
| 476 | for i = 1, t.n | ||
| 477 | print t[i] | ||
| 478 | |||
| 479 | f 1, 2, 3 | ||
| 480 | f "a", "b", "c", "d" | ||
| 481 | f! | ||
| 482 | |||
| 483 | -- 处理包含 nil 的情况 | ||
| 484 | process = (...args) -> | ||
| 485 | sum = 0 | ||
| 486 | for i = 1, args.n | ||
| 487 | if args[i] != nil and type(args[i]) == "number" | ||
| 488 | sum += args[i] | ||
| 489 | sum | ||
| 490 | |||
| 491 | process 1, nil, 3, nil, 5 | ||
| 492 | ``` | ||
| 493 | |||
| 494 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/function-stubs.md b/doc/docs/zh/doc/function-stubs.md new file mode 100644 index 0000000..af08feb --- /dev/null +++ b/doc/docs/zh/doc/function-stubs.md | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | # 函数存根 | ||
| 2 | |||
| 3 |   在编程中,将对象的方法作为函数类型的值进行传递是一种常见做法,尤其是在将实例方法作为回调函数传递给其他函数的情形中。当目标函数需要将该对象作为其第一个参数时,我们需要找到一种方式将对象和函数绑定在一起,以便能够正确地调用该函数。 | ||
| 4 | |||
| 5 |   函数存根(stub)语法提供了一种便捷的方法来创建一个新的闭包函数,这个函数将对象和原函数绑定在一起。这样,当调用这个新创建的函数时,它会在正确的对象上下文中执行原有的函数。 | ||
| 6 | |||
| 7 |   这种语法类似于使用 \ 操作符调用实例方法的方式,区别在于,这里不需要在 \ 操作符后面附加参数列表。 | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | my_object = { | ||
| 11 | value: 1000 | ||
| 12 | write: => print "值为:", @value | ||
| 13 | } | ||
| 14 | |||
| 15 | run_callback = (func) -> | ||
| 16 | print "运行回调..." | ||
| 17 | func! | ||
| 18 | |||
| 19 | -- 这样写不起作用: | ||
| 20 | -- 函数没有引用my_object | ||
| 21 | run_callback my_object.write | ||
| 22 | |||
| 23 | -- 函数存根语法 | ||
| 24 | -- 让我们把对象捆绑到一个新函数中 | ||
| 25 | run_callback my_object\write | ||
| 26 | ``` | ||
| 27 | <YueDisplay> | ||
| 28 | |||
| 29 | ```yue | ||
| 30 | my_object = { | ||
| 31 | value: 1000 | ||
| 32 | write: => print "值为:", @value | ||
| 33 | } | ||
| 34 | |||
| 35 | run_callback = (func) -> | ||
| 36 | print "运行回调..." | ||
| 37 | func! | ||
| 38 | |||
| 39 | -- 这样写不起作用: | ||
| 40 | -- 函数没有引用my_object | ||
| 41 | run_callback my_object.write | ||
| 42 | |||
| 43 | -- 函数存根语法 | ||
| 44 | -- 让我们把对象捆绑到一个新函数中 | ||
| 45 | run_callback my_object\write | ||
| 46 | ``` | ||
| 47 | |||
| 48 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/if-assignment.md b/doc/docs/zh/doc/if-assignment.md new file mode 100644 index 0000000..e4077e1 --- /dev/null +++ b/doc/docs/zh/doc/if-assignment.md | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | # If 赋值 | ||
| 2 | |||
| 3 |   `if` 和 `elseif` 代码块可以在条件表达式的位置进行赋值。在代码执行到要计算条件时,会首先进行赋值计算,并使用赋与的值作为分支判断的条件。赋值的变量仅在条件分支的代码块内有效,这意味着如果值不是真值,那么它就不会被用到。注意,你必须使用“海象运算符” `:=` 而不是 `=` 来做赋值。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | if user := database.find_user "moon" | ||
| 7 | print user.name | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | if user := database.find_user "moon" | ||
| 13 | print user.name | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | if hello := os.getenv "hello" | ||
| 20 | print "你有 hello", hello | ||
| 21 | elseif world := os.getenv "world" | ||
| 22 | print "你有 world", world | ||
| 23 | else | ||
| 24 | print "什么都没有 :(" | ||
| 25 | ``` | ||
| 26 | <YueDisplay> | ||
| 27 | |||
| 28 | ```yue | ||
| 29 | if hello := os.getenv "hello" | ||
| 30 | print "你有 hello", hello | ||
| 31 | elseif world := os.getenv "world" | ||
| 32 | print "你有 world", world | ||
| 33 | else | ||
| 34 | print "什么都没有 :(" | ||
| 35 | ``` | ||
| 36 | |||
| 37 | </YueDisplay> | ||
| 38 | |||
| 39 |   使用多个返回值的 If 赋值。只有第一个值会被检查,其他值都有同样的作用域。 | ||
| 40 | |||
| 41 | ```yuescript | ||
| 42 | if success, result := pcall -> "无报错地获取结果" | ||
| 43 | print result -- 变量 result 是有作用域的 | ||
| 44 | print "好的" | ||
| 45 | ``` | ||
| 46 | <YueDisplay> | ||
| 47 | |||
| 48 | ```yue | ||
| 49 | if success, result := pcall -> "无报错地获取结果" | ||
| 50 | print result -- 变量 result 是有作用域的 | ||
| 51 | print "好的" | ||
| 52 | ``` | ||
| 53 | |||
| 54 | </YueDisplay> | ||
| 55 | |||
| 56 | ## While 赋值 | ||
| 57 | |||
| 58 |   你可以在 while 循环中同样使用赋值来获取循环条件的值。 | ||
| 59 | |||
| 60 | ```yuescript | ||
| 61 | while byte := stream\read_one! | ||
| 62 | -- 对 byte 做一些操作 | ||
| 63 | print byte | ||
| 64 | ``` | ||
| 65 | <YueDisplay> | ||
| 66 | |||
| 67 | ```yue | ||
| 68 | while byte := stream\read_one! | ||
| 69 | -- 对 byte 做一些操作 | ||
| 70 | print byte | ||
| 71 | ``` | ||
| 72 | |||
| 73 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/index.md b/doc/docs/zh/doc/index.md index 5250325..7611fc6 100755 --- a/doc/docs/zh/doc/index.md +++ b/doc/docs/zh/doc/index.md | |||
| @@ -1,5453 +1,11 @@ | |||
| 1 | --- | 1 | --- |
| 2 | sidebar: auto | ||
| 3 | title: 参考手册 | 2 | title: 参考手册 |
| 4 | --- | 3 | --- |
| 5 | 4 | ||
| 6 | # 月之脚本 | 5 | # 月之脚本文档 |
| 7 | 6 | ||
| 8 | <img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em;"/> | 7 | <img src="/image/yuescript.svg" width="250px" height="250px" alt="logo" style="padding-top: 3em;padding-bottom: 2em;"/> |
| 9 | 8 | ||
| 10 | ## 介绍 | 9 | 欢迎来到 <b>月之脚本(YueScript)</b> 官方文档!<br/> |
| 11 | 10 | 这里收录了语言特性、用法、参考示例和资源。<br/> | |
| 12 | 月之脚本(YueScript)是一种动态语言,可以编译为 Lua。它是 [MoonScript](https://github.com/leafo/moonscript) 的方言。用月之脚本编写的代码既有表现力又非常简洁。它适合编写一些更易于维护的代码,并在嵌入 Lua 的环境中运行,如游戏或网站服务器。 | 11 | 请选择左侧的章节索引或目录,开启你的月之脚本之旅 ☽ |
| 13 | |||
| 14 | Yue(月)是中文中“月亮”的名称。 | ||
| 15 | |||
| 16 | ### 月之脚本概览 | ||
| 17 | ```yuescript | ||
| 18 | -- 导入语法 | ||
| 19 | import p, to_lua from "yue" | ||
| 20 | |||
| 21 | -- 隐式对象 | ||
| 22 | inventory = | ||
| 23 | equipment: | ||
| 24 | - "sword" | ||
| 25 | - "shield" | ||
| 26 | items: | ||
| 27 | - name: "potion" | ||
| 28 | count: 10 | ||
| 29 | - name: "bread" | ||
| 30 | count: 3 | ||
| 31 | |||
| 32 | -- 列表推导 | ||
| 33 | map = (arr, action) -> | ||
| 34 | [action item for item in *arr] | ||
| 35 | |||
| 36 | filter = (arr, cond) -> | ||
| 37 | [item for item in *arr when cond item] | ||
| 38 | |||
| 39 | reduce = (arr, init, action): init -> | ||
| 40 | init = action init, item for item in *arr | ||
| 41 | |||
| 42 | -- 管道操作符 | ||
| 43 | [1, 2, 3] | ||
| 44 | |> map (x) -> x * 2 | ||
| 45 | |> filter (x) -> x > 4 | ||
| 46 | |> reduce 0, (a, b) -> a + b | ||
| 47 | |||
| 48 | |||
| 49 | -- 元表操作 | ||
| 50 | apple = | ||
| 51 | size: 15 | ||
| 52 | <index>: | ||
| 53 | color: 0x00ffff | ||
| 54 | |||
| 55 | with apple | ||
| 56 | p .size, .color, .<index> if .<>? | ||
| 57 | |||
| 58 | -- 类似js的导出语法 | ||
| 59 | export 🌛 = "月之脚本" | ||
| 60 | ``` | ||
| 61 | <YueDisplay> | ||
| 62 | |||
| 63 | ```yue | ||
| 64 | -- 导入语法 | ||
| 65 | import p, to_lua from "yue" | ||
| 66 | |||
| 67 | -- 隐式对象 | ||
| 68 | inventory = | ||
| 69 | equipment: | ||
| 70 | - "sword" | ||
| 71 | - "shield" | ||
| 72 | items: | ||
| 73 | - name: "potion" | ||
| 74 | count: 10 | ||
| 75 | - name: "bread" | ||
| 76 | count: 3 | ||
| 77 | |||
| 78 | -- 列表推导 | ||
| 79 | map = (arr, action) -> | ||
| 80 | [action item for item in *arr] | ||
| 81 | |||
| 82 | filter = (arr, cond) -> | ||
| 83 | [item for item in *arr when cond item] | ||
| 84 | |||
| 85 | reduce = (arr, init, action): init -> | ||
| 86 | init = action init, item for item in *arr | ||
| 87 | |||
| 88 | -- 管道操作符 | ||
| 89 | [1, 2, 3] | ||
| 90 | |> map (x) -> x * 2 | ||
| 91 | |> filter (x) -> x > 4 | ||
| 92 | |> reduce 0, (a, b) -> a + b | ||
| 93 | |||
| 94 | |||
| 95 | -- 元表操作 | ||
| 96 | apple = | ||
| 97 | size: 15 | ||
| 98 | <index>: | ||
| 99 | color: 0x00ffff | ||
| 100 | |||
| 101 | with apple | ||
| 102 | p .size, .color, .<index> if .<>? | ||
| 103 | |||
| 104 | -- 类似js的导出语法 | ||
| 105 | export 🌛 = "月之脚本" | ||
| 106 | ``` | ||
| 107 | |||
| 108 | </YueDisplay> | ||
| 109 | |||
| 110 | ## 安装 | ||
| 111 | |||
| 112 | * **Lua 模块** | ||
| 113 | |||
| 114 |  安装 [luarocks](https://luarocks.org),一个 Lua 模块的包管理器。然后作为 Lua 模块和可执行文件安装它: | ||
| 115 | |||
| 116 | ``` | ||
| 117 | > luarocks install yuescript | ||
| 118 | ``` | ||
| 119 | |||
| 120 |  或者你可以自己构建 `yue.so` 文件: | ||
| 121 | |||
| 122 | ``` | ||
| 123 | > make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
| 124 | ``` | ||
| 125 | |||
| 126 |  然后从路径 **bin/shared/yue.so** 获取二进制文件。 | ||
| 127 | |||
| 128 | * **构建二进制工具** | ||
| 129 | |||
| 130 |  克隆项目仓库,然后构建并安装可执行文件: | ||
| 131 | ``` | ||
| 132 | > make install | ||
| 133 | ``` | ||
| 134 | |||
| 135 |  构建不带宏功能的月之脚本编译工具: | ||
| 136 | ``` | ||
| 137 | > make install NO_MACRO=true | ||
| 138 | ``` | ||
| 139 | |||
| 140 |  构建不带内置Lua二进制文件的月之脚本编译工具: | ||
| 141 | ``` | ||
| 142 | > make install NO_LUA=true | ||
| 143 | ``` | ||
| 144 | |||
| 145 | * **下载预编译的二进制程序** | ||
| 146 | |||
| 147 |  你可以下载预编译的二进制程序,包括兼容不同 Lua 版本的二进制可执行文件和库文件。 | ||
| 148 | |||
| 149 |  在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程序。 | ||
| 150 | |||
| 151 | ## 使用方法 | ||
| 152 | |||
| 153 | ### Lua 模块 | ||
| 154 | |||
| 155 | 在 Lua 中使用月之脚本模块: | ||
| 156 | |||
| 157 | * **用法 1** | ||
| 158 | 在 Lua 中引入 "你的脚本入口文件.yue"。 | ||
| 159 | ```Lua | ||
| 160 | require("yue")("你的脚本入口文件") | ||
| 161 | ``` | ||
| 162 | 当你在同一路径下把 "你的脚本入口文件.yue" 编译成了 "你的脚本入口文件.lua" 时,仍然可以使用这个代码加载 .lua 代码文件。在其余的月之脚本文件中,只需正常使用 **require** 或 **import** 进行脚本引用即可。错误消息中的代码行号也会被正确处理。 | ||
| 163 | |||
| 164 | * **用法 2** | ||
| 165 | 手动引入月之脚本模块并重写错误消息来帮助调试。 | ||
| 166 | ```lua | ||
| 167 | local yue = require("yue") | ||
| 168 | yue.insert_loaders() | ||
| 169 | local success, result = xpcall(function() | ||
| 170 | return require("yuescript_module_name") | ||
| 171 | end, function(err) | ||
| 172 | return yue.traceback(err) | ||
| 173 | end) | ||
| 174 | ``` | ||
| 175 | |||
| 176 | * **用法 3** | ||
| 177 | 在 Lua 中使用月之脚本编译器功能。 | ||
| 178 | ```lua | ||
| 179 | local yue = require("yue") | ||
| 180 | local codes, err, globals = yue.to_lua([[ | ||
| 181 | f = -> | ||
| 182 | print "hello world" | ||
| 183 | f! | ||
| 184 | ]],{ | ||
| 185 | implicit_return_root = true, | ||
| 186 | reserve_line_number = true, | ||
| 187 | lint_global = true, | ||
| 188 | space_over_tab = false, | ||
| 189 | options = { | ||
| 190 | target = "5.4", | ||
| 191 | path = "/script" | ||
| 192 | } | ||
| 193 | }) | ||
| 194 | ``` | ||
| 195 | |||
| 196 | ### 月之脚本编译工具 | ||
| 197 | |||
| 198 | 使用月之脚本编译工具: | ||
| 199 | ```sh | ||
| 200 | 命令行用法: yue | ||
| 201 | [选项] [<文件/目录>] ... | ||
| 202 | yue -e <代码或文件> [参数...] | ||
| 203 | yue -w [<目录>] [选项] | ||
| 204 | yue - | ||
| 205 | |||
| 206 | 说明: | ||
| 207 | - '-' 或 '--' 必须作为唯一且第一个参数,用于读取标准输入。 | ||
| 208 | - '-o/--output' 不能与多个输入文件一起使用。 | ||
| 209 | - '-w/--watch' 仅能用于目录,不能用于单个文件。 | ||
| 210 | - 使用 '-e/--execute' 时,后续的参数将作为脚本参数传递。 | ||
| 211 | |||
| 212 | 选项: | ||
| 213 | -h, --help 显示帮助信息并退出 | ||
| 214 | -e <字符串>, --execute <字符串> 执行文件或原始代码 | ||
| 215 | -m, --minify 生成压缩(最小化)代码 | ||
| 216 | -r, --rewrite 重写输出以匹配原始代码行号 | ||
| 217 | -t <目标路径>, --output-to <目标路径> | ||
| 218 | 指定编译后文件的输出路径 | ||
| 219 | -o <文件>, --output <文件> 将输出写入文件 | ||
| 220 | -p, --print 输出到标准输出 | ||
| 221 | -b, --benchmark 输出编译耗时(不写入文件) | ||
| 222 | -g, --globals 显示用到的全局变量及其所在的名称、行号、列号 | ||
| 223 | -s, --spaces 用空格代替制表符(tab)输出代码 | ||
| 224 | -l, --line-numbers 输出源代码的行号 | ||
| 225 | -j, --no-implicit-return 禁用文件末尾的隐式返回 | ||
| 226 | -c, --reserve-comments 保留源代码中的注释 | ||
| 227 | -w [<目录>], --watch [<目录>] | ||
| 228 | 监视目录变化并自动编译 | ||
| 229 | -v, --version 显示版本信息 | ||
| 230 | - 从标准输入读取,输出到标准输出(仅能作为唯一参数) | ||
| 231 | -- 等同于 '-',为兼容旧版本保留 | ||
| 232 | |||
| 233 | --target <版本> 指定生成代码的 Lua 版本 (只能为 5.1 ~ 5.5) | ||
| 234 | --path <路径字符串> 附加一个 Lua 搜索路径到 package.path | ||
| 235 | --<键>=<值> 以 key=value 形式传递编译器选项(保持已有用法) | ||
| 236 | |||
| 237 | 不带选项直接运行可进入交互模式(REPL),在交互模式里输入单独的符号 '$' | ||
| 238 | 可用于开始或结束多行模式。 | ||
| 239 | ``` | ||
| 240 |   使用案例: | ||
| 241 |   递归编译当前路径下扩展名为 **.yue** 的每个月之脚本文件: **yue .** | ||
| 242 |   编译并将结果保存到目标路径: **yue -t /target/path/ .** | ||
| 243 |   编译并保留调试信息: **yue -l .** | ||
| 244 |   编译并生成压缩代码: **yue -m .** | ||
| 245 |   直接执行代码: **yue -e 'print 123'** | ||
| 246 |   执行一个月之脚本文件: **yue -e main.yue** | ||
| 247 | |||
| 248 | ## 宏 | ||
| 249 | |||
| 250 | ### 常见用法 | ||
| 251 | |||
| 252 | 宏函数用于在编译时执行一段代码来生成新的代码,并将生成的代码插入到最终编译结果中。 | ||
| 253 | |||
| 254 | ```yuescript | ||
| 255 | macro PI2 = -> math.pi * 2 | ||
| 256 | area = $PI2 * 5 | ||
| 257 | |||
| 258 | macro HELLO = -> "'你好 世界'" | ||
| 259 | print $HELLO | ||
| 260 | |||
| 261 | macro config = (debugging) -> | ||
| 262 | global debugMode = debugging == "true" | ||
| 263 | "" | ||
| 264 | |||
| 265 | macro asserts = (cond) -> | ||
| 266 | debugMode and "assert #{cond}" or "" | ||
| 267 | |||
| 268 | macro assert = (cond) -> | ||
| 269 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 270 | |||
| 271 | $config true | ||
| 272 | $asserts item ~= nil | ||
| 273 | |||
| 274 | $config false | ||
| 275 | value = $assert item | ||
| 276 | |||
| 277 | -- 宏函数参数传递的表达式会被转换为字符串 | ||
| 278 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 279 | if $and f1!, f2!, f3! | ||
| 280 | print "OK" | ||
| 281 | ``` | ||
| 282 | <YueDisplay> | ||
| 283 | |||
| 284 | ```yue | ||
| 285 | macro PI2 = -> math.pi * 2 | ||
| 286 | area = $PI2 * 5 | ||
| 287 | |||
| 288 | macro HELLO = -> "'你好 世界'" | ||
| 289 | print $HELLO | ||
| 290 | |||
| 291 | macro config = (debugging) -> | ||
| 292 | global debugMode = debugging == "true" | ||
| 293 | "" | ||
| 294 | |||
| 295 | macro asserts = (cond) -> | ||
| 296 | debugMode and "assert #{cond}" or "" | ||
| 297 | |||
| 298 | macro assert = (cond) -> | ||
| 299 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 300 | |||
| 301 | $config true | ||
| 302 | $asserts item ~= nil | ||
| 303 | |||
| 304 | $config false | ||
| 305 | value = $assert item | ||
| 306 | |||
| 307 | -- 宏函数参数传递的表达式会被转换为字符串 | ||
| 308 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 309 | if $and f1!, f2!, f3! | ||
| 310 | print "OK" | ||
| 311 | ``` | ||
| 312 | |||
| 313 | </YueDisplay> | ||
| 314 | |||
| 315 | ### 直接插入代码 | ||
| 316 | |||
| 317 | 宏函数可以返回一个包含月之脚本代码的字符串,或是一个包含 Lua 代码字符串的配置表。 | ||
| 318 | ```yuescript | ||
| 319 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 320 | $yueFunc funcA | ||
| 321 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | ||
| 322 | |||
| 323 | macro luaFunc = (var) -> { | ||
| 324 | code: "local function #{var}() end" | ||
| 325 | type: "lua" | ||
| 326 | } | ||
| 327 | $luaFunc funcB | ||
| 328 | funcB = -> "无法访问宏生成 Lua 代码里定义的变量" | ||
| 329 | |||
| 330 | macro lua = (code) -> { | ||
| 331 | :code | ||
| 332 | type: "lua" | ||
| 333 | } | ||
| 334 | |||
| 335 | -- raw字符串的开始和结束符号会自动被去除了再传入宏函数 | ||
| 336 | $lua[==[ | ||
| 337 | -- 插入原始Lua代码 | ||
| 338 | if cond then | ||
| 339 | print("输出") | ||
| 340 | end | ||
| 341 | ]==] | ||
| 342 | ``` | ||
| 343 | <YueDisplay> | ||
| 344 | |||
| 345 | ```yue | ||
| 346 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 347 | $yueFunc funcA | ||
| 348 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | ||
| 349 | |||
| 350 | macro luaFunc = (var) -> { | ||
| 351 | code: "local function #{var}() end" | ||
| 352 | type: "lua" | ||
| 353 | } | ||
| 354 | $luaFunc funcB | ||
| 355 | funcB = -> "无法访问宏生成 Lua 代码里定义的变量" | ||
| 356 | |||
| 357 | macro lua = (code) -> { | ||
| 358 | :code | ||
| 359 | type: "lua" | ||
| 360 | } | ||
| 361 | |||
| 362 | -- raw字符串的开始和结束符号会自动被去除了再传入宏函数 | ||
| 363 | $lua[==[ | ||
| 364 | -- 插入原始Lua代码 | ||
| 365 | if cond then | ||
| 366 | print("输出") | ||
| 367 | end | ||
| 368 | ]==] | ||
| 369 | ``` | ||
| 370 | |||
| 371 | </YueDisplay> | ||
| 372 | |||
| 373 | ### 导出宏 | ||
| 374 | |||
| 375 | 宏函数可以从一个模块中导出,并在另一个模块中导入。你必须将导出的宏函数放在一个单独的文件中使用,而且只有宏定义、宏导入和宏展开可以放入这个宏导出模块中。 | ||
| 376 | ```yuescript | ||
| 377 | -- 文件: utils.yue | ||
| 378 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 379 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 380 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 381 | #{action}" | ||
| 382 | |||
| 383 | -- 文件 main.yue | ||
| 384 | import "utils" as { | ||
| 385 | $, -- 表示导入所有宏的符号 | ||
| 386 | $foreach: $each -- 重命名宏 $foreach 为 $each | ||
| 387 | } | ||
| 388 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 389 | ``` | ||
| 390 | <YueDisplay> | ||
| 391 | |||
| 392 | ```yue | ||
| 393 | -- 文件: utils.yue | ||
| 394 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 395 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 396 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 397 | #{action}" | ||
| 398 | -- 文件 main.yue | ||
| 399 | -- 在浏览器中不支持import函数,请在真实环境中尝试 | ||
| 400 | --[[ | ||
| 401 | import "utils" as { | ||
| 402 | $, -- 表示导入所有宏的符号 | ||
| 403 | $foreach: $each -- 重命名宏 $foreach 为 $each | ||
| 404 | } | ||
| 405 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 406 | ]] | ||
| 407 | ``` | ||
| 408 | |||
| 409 | </YueDisplay> | ||
| 410 | |||
| 411 | ### 内置宏 | ||
| 412 | |||
| 413 | 月之脚本中有一些内置可以直接使用的宏,但你可以通过声明相同名称的宏来覆盖它们。 | ||
| 414 | ```yuescript | ||
| 415 | print $FILE -- 获取当前模块名称的字符串 | ||
| 416 | print $LINE -- 获取当前代码行数:2 | ||
| 417 | ``` | ||
| 418 | <YueDisplay> | ||
| 419 | |||
| 420 | ```yue | ||
| 421 | print $FILE -- 获取当前模块名称的字符串 | ||
| 422 | print $LINE -- 获取当前代码行数:2 | ||
| 423 | ``` | ||
| 424 | |||
| 425 | </YueDisplay> | ||
| 426 | |||
| 427 | ### 用宏生成宏 | ||
| 428 | |||
| 429 | 在月之脚本中,宏函数允许你在编译时生成代码。通过嵌套的宏函数,你可以创建更复杂的生成模式。这个特性允许你定义一个宏函数,用它来生成另一个宏函数,从而实现更加动态的代码生成。 | ||
| 430 | |||
| 431 | ```yuescript | ||
| 432 | macro Enum = (...) -> | ||
| 433 | items = {...} | ||
| 434 | itemSet = {item, true for item in *items} | ||
| 435 | (item) -> | ||
| 436 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 437 | "\"#{item}\"" | ||
| 438 | |||
| 439 | macro BodyType = $Enum( | ||
| 440 | Static | ||
| 441 | Dynamic | ||
| 442 | Kinematic | ||
| 443 | ) | ||
| 444 | |||
| 445 | print "有效的枚举类型:", $BodyType Static | ||
| 446 | -- print "编译报错的枚举类型:", $BodyType Unknown | ||
| 447 | ``` | ||
| 448 | <YueDisplay> | ||
| 449 | |||
| 450 | ```yue | ||
| 451 | macro Enum = (...) -> | ||
| 452 | items = {...} | ||
| 453 | itemSet = {item, true for item in *items} | ||
| 454 | (item) -> | ||
| 455 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 456 | "\"#{item}\"" | ||
| 457 | |||
| 458 | macro BodyType = $Enum( | ||
| 459 | Static | ||
| 460 | Dynamic | ||
| 461 | Kinematic | ||
| 462 | ) | ||
| 463 | |||
| 464 | print "有效的枚举类型:", $BodyType Static | ||
| 465 | -- print "编译报错的枚举类型:", $BodyType Unknown | ||
| 466 | ``` | ||
| 467 | |||
| 468 | </YueDisplay> | ||
| 469 | |||
| 470 | ### 宏参数检查 | ||
| 471 | |||
| 472 | 可以直接在参数列表中声明期望的 AST 节点类型,并在编译时检查传入的宏参数是否符合预期。 | ||
| 473 | |||
| 474 | ```yuescript | ||
| 475 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 476 | print( | ||
| 477 | #{num} | ||
| 478 | #{str} | ||
| 479 | ) | ||
| 480 | |||
| 481 | $printNumAndStr 123, "hello" | ||
| 482 | ``` | ||
| 483 | <YueDisplay> | ||
| 484 | |||
| 485 | ```yue | ||
| 486 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 487 | print( | ||
| 488 | #{num} | ||
| 489 | #{str} | ||
| 490 | ) | ||
| 491 | |||
| 492 | $printNumAndStr 123, "hello" | ||
| 493 | ``` | ||
| 494 | |||
| 495 | </YueDisplay> | ||
| 496 | |||
| 497 | 如果需要做更加灵活的参数检查操作,可以使用内置的 `$is_ast` 宏函数在合适的位置进行手动检查。 | ||
| 498 | |||
| 499 | ```yuescript | ||
| 500 | macro printNumAndStr = (num, str) -> | ||
| 501 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 502 | error "expected String as second argument" unless $is_ast String, str | ||
| 503 | "print(#{num}, #{str})" | ||
| 504 | |||
| 505 | $printNumAndStr 123, "hello" | ||
| 506 | ``` | ||
| 507 | <YueDisplay> | ||
| 508 | |||
| 509 | ```yue | ||
| 510 | macro printNumAndStr = (num, str) -> | ||
| 511 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 512 | error "expected String as second argument" unless $is_ast String, str | ||
| 513 | "print(#{num}, #{str})" | ||
| 514 | |||
| 515 | $printNumAndStr 123, "hello" | ||
| 516 | ``` | ||
| 517 | |||
| 518 | </YueDisplay> | ||
| 519 | |||
| 520 | 更多关于可用 AST 节点的详细信息,请参考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) 中大写的规则定义。 | ||
| 521 | |||
| 522 | ## 操作符 | ||
| 523 | |||
| 524 | Lua 的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\** 或 **::** 均可用于编写链式函数调用,如写作 `tb\func!` 或 `tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。 | ||
| 525 | |||
| 526 | ```yuescript | ||
| 527 | tb\func! if tb ~= nil | ||
| 528 | tb::func! if tb != nil | ||
| 529 | ``` | ||
| 530 | <YueDisplay> | ||
| 531 | |||
| 532 | ```yue | ||
| 533 | tb\func! if tb ~= nil | ||
| 534 | tb::func! if tb != nil | ||
| 535 | ``` | ||
| 536 | |||
| 537 | </YueDisplay> | ||
| 538 | |||
| 539 | ### 链式比较 | ||
| 540 | |||
| 541 | 你可以在月之脚本中进行比较表达式的链式书写: | ||
| 542 | |||
| 543 | ```yuescript | ||
| 544 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 545 | -- 输出:true | ||
| 546 | |||
| 547 | a = 5 | ||
| 548 | print 1 <= a <= 10 | ||
| 549 | -- 输出:true | ||
| 550 | ``` | ||
| 551 | <YueDisplay> | ||
| 552 | |||
| 553 | ```yue | ||
| 554 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 555 | -- 输出:true | ||
| 556 | |||
| 557 | a = 5 | ||
| 558 | print 1 <= a <= 10 | ||
| 559 | -- 输出:true | ||
| 560 | ``` | ||
| 561 | |||
| 562 | </YueDisplay> | ||
| 563 | |||
| 564 | 可以注意一下链式比较表达式的求值行为: | ||
| 565 | |||
| 566 | ```yuescript | ||
| 567 | v = (x) -> | ||
| 568 | print x | ||
| 569 | x | ||
| 570 | |||
| 571 | print v(1) < v(2) <= v(3) | ||
| 572 | --[[ | ||
| 573 | 输出: | ||
| 574 | 2 | ||
| 575 | 1 | ||
| 576 | 3 | ||
| 577 | true | ||
| 578 | ]] | ||
| 579 | |||
| 580 | print v(1) > v(2) <= v(3) | ||
| 581 | --[[ | ||
| 582 | 输出: | ||
| 583 | 2 | ||
| 584 | 1 | ||
| 585 | false | ||
| 586 | ]] | ||
| 587 | ``` | ||
| 588 | <YueDisplay> | ||
| 589 | |||
| 590 | ```yue | ||
| 591 | v = (x) -> | ||
| 592 | print x | ||
| 593 | x | ||
| 594 | |||
| 595 | print v(1) < v(2) <= v(3) | ||
| 596 | --[[ | ||
| 597 | 输出: | ||
| 598 | 2 | ||
| 599 | 1 | ||
| 600 | 3 | ||
| 601 | true | ||
| 602 | ]] | ||
| 603 | |||
| 604 | print v(1) > v(2) <= v(3) | ||
| 605 | --[[ | ||
| 606 | 输出: | ||
| 607 | 2 | ||
| 608 | 1 | ||
| 609 | false | ||
| 610 | ]] | ||
| 611 | ``` | ||
| 612 | |||
| 613 | </YueDisplay> | ||
| 614 | |||
| 615 | 在上面的例子里,中间的表达式 `v(2)` 仅被计算一次,如果把表达式写成 `v(1) < v(2) and v(2) <= v(3)` 的方式,中间的 `v(2)` 才会被计算两次。在链式比较中,求值的顺序往往是未定义的。所以强烈建议不要在链式比较中使用具有副作用(比如做打印操作)的表达式。如果需要使用有副作用的函数,应明确使用短路 `and` 运算符来做连接。 | ||
| 616 | |||
| 617 | ### 表追加 | ||
| 618 | |||
| 619 | **[] =** 操作符用于向 Lua 表的最后插入值。 | ||
| 620 | |||
| 621 | ```yuescript | ||
| 622 | tab = [] | ||
| 623 | tab[] = "Value" | ||
| 624 | ``` | ||
| 625 | <YueDisplay> | ||
| 626 | |||
| 627 | ```yue | ||
| 628 | tab = [] | ||
| 629 | tab[] = "Value" | ||
| 630 | ``` | ||
| 631 | |||
| 632 | </YueDisplay> | ||
| 633 | |||
| 634 | 你还可以使用展开操作符 `...` 来将一个列表中的所有元素追加到另一个列表中: | ||
| 635 | |||
| 636 | ```yuescript | ||
| 637 | tbA = [1, 2, 3] | ||
| 638 | tbB = [4, 5, 6] | ||
| 639 | tbA[] = ...tbB | ||
| 640 | -- tbA 现在为 [1, 2, 3, 4, 5, 6] | ||
| 641 | ``` | ||
| 642 | <YueDisplay> | ||
| 643 | |||
| 644 | ```yue | ||
| 645 | tbA = [1, 2, 3] | ||
| 646 | tbB = [4, 5, 6] | ||
| 647 | tbA[] = ...tbB | ||
| 648 | -- tbA 现在为 [1, 2, 3, 4, 5, 6] | ||
| 649 | ``` | ||
| 650 | |||
| 651 | </YueDisplay> | ||
| 652 | |||
| 653 | ### 表扩展 | ||
| 654 | |||
| 655 | 你可以使用前置 `...` 操作符在 Lua 表中插入数组表或哈希表。 | ||
| 656 | |||
| 657 | ```yuescript | ||
| 658 | parts = | ||
| 659 | * "shoulders" | ||
| 660 | * "knees" | ||
| 661 | lyrics = | ||
| 662 | * "head" | ||
| 663 | * ...parts | ||
| 664 | * "and" | ||
| 665 | * "toes" | ||
| 666 | |||
| 667 | copy = {...other} | ||
| 668 | |||
| 669 | a = {1, 2, 3, x: 1} | ||
| 670 | b = {4, 5, y: 1} | ||
| 671 | merge = {...a, ...b} | ||
| 672 | ``` | ||
| 673 | <YueDisplay> | ||
| 674 | |||
| 675 | ```yue | ||
| 676 | parts = | ||
| 677 | * "shoulders" | ||
| 678 | * "knees" | ||
| 679 | lyrics = | ||
| 680 | * "head" | ||
| 681 | * ...parts | ||
| 682 | * "and" | ||
| 683 | * "toes" | ||
| 684 | |||
| 685 | copy = {...other} | ||
| 686 | |||
| 687 | a = {1, 2, 3, x: 1} | ||
| 688 | b = {4, 5, y: 1} | ||
| 689 | merge = {...a, ...b} | ||
| 690 | ``` | ||
| 691 | |||
| 692 | </YueDisplay> | ||
| 693 | |||
| 694 | ### 表反向索引 | ||
| 695 | |||
| 696 | 你可以使用 **#** 操作符来反向索引表中的元素。 | ||
| 697 | |||
| 698 | ```yuescript | ||
| 699 | last = data.items[#] | ||
| 700 | second_last = data.items[#-1] | ||
| 701 | data.items[#] = 1 | ||
| 702 | ``` | ||
| 703 | <YueDisplay> | ||
| 704 | |||
| 705 | ```yue | ||
| 706 | last = data.items[#] | ||
| 707 | second_last = data.items[#-1] | ||
| 708 | data.items[#] = 1 | ||
| 709 | ``` | ||
| 710 | |||
| 711 | </YueDisplay> | ||
| 712 | |||
| 713 | ### 元表 | ||
| 714 | |||
| 715 | **<>** 操作符可提供元表操作的快捷方式。 | ||
| 716 | |||
| 717 | * **元表创建** | ||
| 718 | 使用空括号 **<>** 或被 **<>** 包围的元方法键创建普通的 Lua 表。 | ||
| 719 | |||
| 720 | ```yuescript | ||
| 721 | mt = {} | ||
| 722 | add = (right) => <>: mt, value: @value + right.value | ||
| 723 | mt.__add = add | ||
| 724 | |||
| 725 | a = <>: mt, value: 1 | ||
| 726 | -- 使用与临时变量名相同的字段名,将临时变量赋值给元表 | ||
| 727 | b = :<add>, value: 2 | ||
| 728 | c = <add>: mt.__add, value: 3 | ||
| 729 | |||
| 730 | d = a + b + c | ||
| 731 | print d.value | ||
| 732 | |||
| 733 | close _ = <close>: -> print "超出范围" | ||
| 734 | ``` | ||
| 735 | <YueDisplay> | ||
| 736 | |||
| 737 | ```yue | ||
| 738 | mt = {} | ||
| 739 | add = (right) => <>: mt, value: @value + right.value | ||
| 740 | mt.__add = add | ||
| 741 | |||
| 742 | a = <>: mt, value: 1 | ||
| 743 | -- 使用与临时变量名相同的字段名,将临时变量赋值给元表 | ||
| 744 | b = :<add>, value: 2 | ||
| 745 | c = <add>: mt.__add, value: 3 | ||
| 746 | |||
| 747 | d = a + b + c | ||
| 748 | print d.value | ||
| 749 | |||
| 750 | close _ = <close>: -> print "超出范围" | ||
| 751 | ``` | ||
| 752 | |||
| 753 | </YueDisplay> | ||
| 754 | |||
| 755 | * **元表访问** | ||
| 756 | 使用 **<>** 或被 **<>** 包围的元方法名或在 **<>** 中编写某些表达式来访问元表。 | ||
| 757 | |||
| 758 | ```yuescript | ||
| 759 | -- 使用包含字段 "value" 的元表创建 | ||
| 760 | tb = <"value">: 123 | ||
| 761 | tb.<index> = tb.<> | ||
| 762 | print tb.value | ||
| 763 | |||
| 764 | tb.<> = __index: {item: "hello"} | ||
| 765 | print tb.item | ||
| 766 | ``` | ||
| 767 | <YueDisplay> | ||
| 768 | |||
| 769 | |||
| 770 | ```yue | ||
| 771 | -- 使用包含字段 "value" 的元表创建 | ||
| 772 | tb = <"value">: 123 | ||
| 773 | tb.<index> = tb.<> | ||
| 774 | print tb.value | ||
| 775 | tb.<> = __index: {item: "hello"} | ||
| 776 | print tb.item | ||
| 777 | ``` | ||
| 778 | |||
| 779 | </YueDisplay> | ||
| 780 | |||
| 781 | * **元表解构** | ||
| 782 | 使用被 **<>** 包围的元方法键解构元表。 | ||
| 783 | |||
| 784 | ```yuescript | ||
| 785 | {item, :new, :<close>, <index>: getter} = tb | ||
| 786 | print item, new, close, getter | ||
| 787 | ``` | ||
| 788 | <YueDisplay> | ||
| 789 | |||
| 790 | ```yue | ||
| 791 | {item, :new, :<close>, <index>: getter} = tb | ||
| 792 | print item, new, close, getter | ||
| 793 | ``` | ||
| 794 | |||
| 795 | </YueDisplay> | ||
| 796 | |||
| 797 | ### 存在性 | ||
| 798 | |||
| 799 | **?** 运算符可以在多种上下文中用来检查存在性。 | ||
| 800 | |||
| 801 | ```yuescript | ||
| 802 | func?! | ||
| 803 | print abc?["你好 世界"]?.xyz | ||
| 804 | |||
| 805 | x = tab?.value | ||
| 806 | len = utf8?.len or string?.len or (o) -> #o | ||
| 807 | |||
| 808 | if print and x? | ||
| 809 | print x | ||
| 810 | |||
| 811 | with? io.open "test.txt", "w" | ||
| 812 | \write "你好" | ||
| 813 | \close! | ||
| 814 | ``` | ||
| 815 | <YueDisplay> | ||
| 816 | |||
| 817 | ```yue | ||
| 818 | func?! | ||
| 819 | print abc?["你好 世界"]?.xyz | ||
| 820 | |||
| 821 | x = tab?.value | ||
| 822 | len = utf8?.len or string?.len or (o) -> #o | ||
| 823 | |||
| 824 | if print and x? | ||
| 825 | print x | ||
| 826 | |||
| 827 | with? io.open "test.txt", "w" | ||
| 828 | \write "你好" | ||
| 829 | \close! | ||
| 830 | ``` | ||
| 831 | |||
| 832 | </YueDisplay> | ||
| 833 | |||
| 834 | ### 管道 | ||
| 835 | |||
| 836 | 与其使用一系列嵌套的函数调用,你还可以考虑使用运算符 **|>** 来传递值。 | ||
| 837 | |||
| 838 | ```yuescript | ||
| 839 | "你好" |> print | ||
| 840 | 1 |> print 2 -- 将管道项作为第一个参数插入 | ||
| 841 | 2 |> print 1, _, 3 -- 带有占位符的管道 | ||
| 842 | |||
| 843 | -- 多行的管道表达式 | ||
| 844 | readFile "example.txt" | ||
| 845 | |> extract language, {} | ||
| 846 | |> parse language | ||
| 847 | |> emit | ||
| 848 | |> render | ||
| 849 | |||
| 850 | ``` | ||
| 851 | <YueDisplay> | ||
| 852 | |||
| 853 | ```yue | ||
| 854 | "你好" |> print | ||
| 855 | 1 |> print 2 -- 将管道项作为第一个参数插入 | ||
| 856 | 2 |> print 1, _, 3 -- 带有占位符的管道 | ||
| 857 | -- 多行的管道表达式 | ||
| 858 | readFile "example.txt" | ||
| 859 | |> extract language, {} | ||
| 860 | |> parse language | ||
| 861 | |> emit | ||
| 862 | |> render | ||
| 863 | |||
| 864 | ``` | ||
| 865 | |||
| 866 | </YueDisplay> | ||
| 867 | |||
| 868 | ### 空值合并 | ||
| 869 | |||
| 870 | 如果其左操作数不是 **nil**,则nil合并运算符 **??** 返回其左操作数的值;否则,它将计算右操作数并返回其结果。如果左操作数计算结果为非 nil 的值,**??** 运算符将不再计算其右操作数。 | ||
| 871 | ```yuescript | ||
| 872 | local a, b, c, d | ||
| 873 | a = b ?? c ?? d | ||
| 874 | func a ?? {} | ||
| 875 | |||
| 876 | a ??= false | ||
| 877 | ``` | ||
| 878 | <YueDisplay> | ||
| 879 | |||
| 880 | ```yue | ||
| 881 | local a, b, c, d | ||
| 882 | a = b ?? c ?? d | ||
| 883 | func a ?? {} | ||
| 884 | a ??= false | ||
| 885 | ``` | ||
| 886 | |||
| 887 | </YueDisplay> | ||
| 888 | |||
| 889 | ### 隐式对象 | ||
| 890 | |||
| 891 | 你可以在表格块内使用符号 **\*** 或是 **-** 开始编写一系列隐式结构。如果你正在创建隐式对象,对象的字段必须具有相同的缩进。 | ||
| 892 | |||
| 893 | ```yuescript | ||
| 894 | -- 赋值时使用隐式对象 | ||
| 895 | list = | ||
| 896 | * 1 | ||
| 897 | * 2 | ||
| 898 | * 3 | ||
| 899 | |||
| 900 | -- 函数调用时使用隐式对象 | ||
| 901 | func | ||
| 902 | * 1 | ||
| 903 | * 2 | ||
| 904 | * 3 | ||
| 905 | |||
| 906 | -- 返回时使用隐式对象 | ||
| 907 | f = -> | ||
| 908 | return | ||
| 909 | * 1 | ||
| 910 | * 2 | ||
| 911 | * 3 | ||
| 912 | |||
| 913 | -- 表格时使用隐式对象 | ||
| 914 | tb = | ||
| 915 | name: "abc" | ||
| 916 | |||
| 917 | values: | ||
| 918 | - "a" | ||
| 919 | - "b" | ||
| 920 | - "c" | ||
| 921 | |||
| 922 | objects: | ||
| 923 | - name: "a" | ||
| 924 | value: 1 | ||
| 925 | func: => @value + 1 | ||
| 926 | tb: | ||
| 927 | fieldA: 1 | ||
| 928 | |||
| 929 | - name: "b" | ||
| 930 | value: 2 | ||
| 931 | func: => @value + 2 | ||
| 932 | tb: { } | ||
| 933 | ``` | ||
| 934 | <YueDisplay> | ||
| 935 | |||
| 936 | ```yue | ||
| 937 | -- 赋值时使用隐式对象 | ||
| 938 | list = | ||
| 939 | * 1 | ||
| 940 | * 2 | ||
| 941 | * 3 | ||
| 942 | |||
| 943 | -- 函数调用时使用隐式对象 | ||
| 944 | func | ||
| 945 | * 1 | ||
| 946 | * 2 | ||
| 947 | * 3 | ||
| 948 | |||
| 949 | -- 返回时使用隐式对象 | ||
| 950 | f = -> | ||
| 951 | return | ||
| 952 | * 1 | ||
| 953 | * 2 | ||
| 954 | * 3 | ||
| 955 | |||
| 956 | -- 表格时使用隐式对象 | ||
| 957 | tb = | ||
| 958 | name: "abc" | ||
| 959 | |||
| 960 | values: | ||
| 961 | - "a" | ||
| 962 | - "b" | ||
| 963 | - "c" | ||
| 964 | |||
| 965 | objects: | ||
| 966 | - name: "a" | ||
| 967 | value: 1 | ||
| 968 | func: => @value + 1 | ||
| 969 | tb: | ||
| 970 | fieldA: 1 | ||
| 971 | |||
| 972 | - name: "b" | ||
| 973 | value: 2 | ||
| 974 | func: => @value + 2 | ||
| 975 | tb: { } | ||
| 976 | ``` | ||
| 977 | |||
| 978 | </YueDisplay> | ||
| 979 | |||
| 980 | ## 模块 | ||
| 981 | |||
| 982 | ### 导入 | ||
| 983 | |||
| 984 | 导入语句是一个语法糖,用于需要引入一个模块或者从已导入的模块中提取子项目。从模块导入的变量默认为不可修改的常量。 | ||
| 985 | |||
| 986 | ```yuescript | ||
| 987 | -- 用作表解构 | ||
| 988 | do | ||
| 989 | import insert, concat from table | ||
| 990 | -- 当给 insert, concat 变量赋值时,编译器会报告错误 | ||
| 991 | import C, Ct, Cmt from require "lpeg" | ||
| 992 | -- 快捷写法引入模块的子项 | ||
| 993 | import x, y, z from 'mymodule' | ||
| 994 | -- 使用Python风格的导入 | ||
| 995 | from 'module' import a, b, c | ||
| 996 | |||
| 997 | -- 快捷地导入一个模块 | ||
| 998 | do | ||
| 999 | import 'module' | ||
| 1000 | import 'module_x' | ||
| 1001 | import "d-a-s-h-e-s" | ||
| 1002 | import "module.part" | ||
| 1003 | |||
| 1004 | -- 导入模块后起一个别名使用,或是进行导入模块表的解构 | ||
| 1005 | do | ||
| 1006 | import "player" as PlayerModule | ||
| 1007 | import "lpeg" as :C, :Ct, :Cmt | ||
| 1008 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 1009 | ``` | ||
| 1010 | <YueDisplay> | ||
| 1011 | |||
| 1012 | ```yue | ||
| 1013 | -- 用作表解构 | ||
| 1014 | do | ||
| 1015 | import insert, concat from table | ||
| 1016 | -- 当给 insert, concat 变量赋值时,编译器会报告错误 | ||
| 1017 | import C, Ct, Cmt from require "lpeg" | ||
| 1018 | -- 快捷写法引入模块的子项 | ||
| 1019 | import x, y, z from 'mymodule' | ||
| 1020 | -- 使用Python风格的导入 | ||
| 1021 | from 'module' import a, b, c | ||
| 1022 | |||
| 1023 | -- 快捷地导入一个模块 | ||
| 1024 | do | ||
| 1025 | import 'module' | ||
| 1026 | import 'module_x' | ||
| 1027 | import "d-a-s-h-e-s" | ||
| 1028 | import "module.part" | ||
| 1029 | |||
| 1030 | -- 导入模块后起一个别名使用,或是进行导入模块表的解构 | ||
| 1031 | do | ||
| 1032 | import "player" as PlayerModule | ||
| 1033 | import "lpeg" as :C, :Ct, :Cmt | ||
| 1034 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 1035 | ``` | ||
| 1036 | |||
| 1037 | </YueDisplay> | ||
| 1038 | |||
| 1039 | ### 导入全局变量 | ||
| 1040 | |||
| 1041 | 你可以使用 `import` 将指定的全局变量导入到本地变量中。当导入一系列对全局变量的链式访问时,最后一个访问的字段将被赋值给本地变量。 | ||
| 1042 | |||
| 1043 | ```yuescript | ||
| 1044 | do | ||
| 1045 | import tostring | ||
| 1046 | import table.concat | ||
| 1047 | print concat ["a", tostring 1] | ||
| 1048 | ``` | ||
| 1049 | <YueDisplay> | ||
| 1050 | |||
| 1051 | ```yue | ||
| 1052 | do | ||
| 1053 | import tostring | ||
| 1054 | import table.concat | ||
| 1055 | print concat ["a", tostring 1] | ||
| 1056 | ``` | ||
| 1057 | |||
| 1058 | </YueDisplay> | ||
| 1059 | |||
| 1060 | #### 自动导入 | ||
| 1061 | |||
| 1062 | 在一个代码块的顶部写 `import global`,会将当前作用域中尚未显式声明或赋值过的变量名,自动导入为本地常量,并在该语句的位置绑定到同名的全局变量。 | ||
| 1063 | |||
| 1064 | 但是在同一作用域中被显式声明为全局的变量不会被自动导入,因此可以继续进行赋值操作。 | ||
| 1065 | |||
| 1066 | ```yuescript | ||
| 1067 | do | ||
| 1068 | import global | ||
| 1069 | print "hello" | ||
| 1070 | math.random 3 | ||
| 1071 | -- print = nil -- 报错:自动导入的全局变量为常量 | ||
| 1072 | |||
| 1073 | do | ||
| 1074 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 1075 | import global | ||
| 1076 | global FLAG | ||
| 1077 | print FLAG | ||
| 1078 | FLAG = 123 | ||
| 1079 | ``` | ||
| 1080 | <YueDisplay> | ||
| 1081 | |||
| 1082 | ```yue | ||
| 1083 | do | ||
| 1084 | import global | ||
| 1085 | print "hello" | ||
| 1086 | math.random 3 | ||
| 1087 | -- print = nil -- 报错:自动导入的全局变量是常量 | ||
| 1088 | |||
| 1089 | do | ||
| 1090 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 1091 | import global | ||
| 1092 | global FLAG | ||
| 1093 | print FLAG | ||
| 1094 | FLAG = 123 | ||
| 1095 | ``` | ||
| 1096 | |||
| 1097 | </YueDisplay> | ||
| 1098 | |||
| 1099 | ### 导出 | ||
| 1100 | |||
| 1101 | 导出语句提供了一种简洁的方式来定义当前的模块。 | ||
| 1102 | |||
| 1103 | * **命名导出** | ||
| 1104 | 带命名的导出将定义一个局部变量,并在导出的表中添加一个同名的字段。 | ||
| 1105 | |||
| 1106 | ```yuescript | ||
| 1107 | export a, b, c = 1, 2, 3 | ||
| 1108 | export cool = "cat" | ||
| 1109 | |||
| 1110 | export What = if this | ||
| 1111 | "abc" | ||
| 1112 | else | ||
| 1113 | "def" | ||
| 1114 | |||
| 1115 | export y = -> | ||
| 1116 | hallo = 3434 | ||
| 1117 | |||
| 1118 | export class Something | ||
| 1119 | umm: "cool" | ||
| 1120 | ``` | ||
| 1121 | <YueDisplay> | ||
| 1122 | |||
| 1123 | ```yue | ||
| 1124 | export a, b, c = 1, 2, 3 | ||
| 1125 | export cool = "cat" | ||
| 1126 | |||
| 1127 | export What = if this | ||
| 1128 | "abc" | ||
| 1129 | else | ||
| 1130 | "def" | ||
| 1131 | |||
| 1132 | export y = -> | ||
| 1133 | hallo = 3434 | ||
| 1134 | |||
| 1135 | export class Something | ||
| 1136 | umm: "cool" | ||
| 1137 | ``` | ||
| 1138 | |||
| 1139 | </YueDisplay> | ||
| 1140 | |||
| 1141 | 使用解构进行命名导出。 | ||
| 1142 | |||
| 1143 | ```yuescript | ||
| 1144 | export :loadstring, to_lua: tolua = yue | ||
| 1145 | export {itemA: {:fieldA = '默认值'}} = tb | ||
| 1146 | ``` | ||
| 1147 | <YueDisplay> | ||
| 1148 | |||
| 1149 | ```yue | ||
| 1150 | export :loadstring, to_lua: tolua = yue | ||
| 1151 | export {itemA: {:fieldA = '默认值'}} = tb | ||
| 1152 | ``` | ||
| 1153 | |||
| 1154 | </YueDisplay> | ||
| 1155 | |||
| 1156 | 从模块导出命名项目时,可以不用创建局部变量。 | ||
| 1157 | |||
| 1158 | ```yuescript | ||
| 1159 | export.itemA = tb | ||
| 1160 | export.<index> = items | ||
| 1161 | export["a-b-c"] = 123 | ||
| 1162 | ``` | ||
| 1163 | <YueDisplay> | ||
| 1164 | |||
| 1165 | ```yue | ||
| 1166 | export.itemA = tb | ||
| 1167 | export.<index> = items | ||
| 1168 | export["a-b-c"] = 123 | ||
| 1169 | ``` | ||
| 1170 | |||
| 1171 | </YueDisplay> | ||
| 1172 | |||
| 1173 | * **未命名导出** | ||
| 1174 | 未命名导出会将要导出的目标项目添加到导出表的数组部分。 | ||
| 1175 | |||
| 1176 | ```yuescript | ||
| 1177 | d, e, f = 3, 2, 1 | ||
| 1178 | export d, e, f | ||
| 1179 | |||
| 1180 | export if this | ||
| 1181 | 123 | ||
| 1182 | else | ||
| 1183 | 456 | ||
| 1184 | |||
| 1185 | export with tmp | ||
| 1186 | j = 2000 | ||
| 1187 | ``` | ||
| 1188 | <YueDisplay> | ||
| 1189 | |||
| 1190 | ```yue | ||
| 1191 | d, e, f = 3, 2, 1 | ||
| 1192 | export d, e, f | ||
| 1193 | |||
| 1194 | export if this | ||
| 1195 | 123 | ||
| 1196 | else | ||
| 1197 | 456 | ||
| 1198 | |||
| 1199 | export with tmp | ||
| 1200 | j = 2000 | ||
| 1201 | ``` | ||
| 1202 | |||
| 1203 | </YueDisplay> | ||
| 1204 | |||
| 1205 | * **默认导出** | ||
| 1206 | 在导出语句中使用 **default** 关键字,来替换导出的表为一个目标的对象。 | ||
| 1207 | |||
| 1208 | ```yuescript | ||
| 1209 | export default -> | ||
| 1210 | print "你好" | ||
| 1211 | 123 | ||
| 1212 | ``` | ||
| 1213 | <YueDisplay> | ||
| 1214 | |||
| 1215 | ```yue | ||
| 1216 | export default -> | ||
| 1217 | print "你好" | ||
| 1218 | 123 | ||
| 1219 | ``` | ||
| 1220 | |||
| 1221 | </YueDisplay> | ||
| 1222 | |||
| 1223 | ## 赋值 | ||
| 1224 | |||
| 1225 | 月之脚本中定义的变量是动态类型的,并默认为局部变量。但你可以通过 **local** 和 **global** 声明来改变声明变量的作用范围。 | ||
| 1226 | |||
| 1227 | ```yuescript | ||
| 1228 | hello = "world" | ||
| 1229 | a, b, c = 1, 2, 3 | ||
| 1230 | hello = 123 -- 访问现有的变量 | ||
| 1231 | ``` | ||
| 1232 | <YueDisplay> | ||
| 1233 | |||
| 1234 | ```yue | ||
| 1235 | hello = "world" | ||
| 1236 | a, b, c = 1, 2, 3 | ||
| 1237 | hello = 123 -- 访问现有的变量 | ||
| 1238 | ``` | ||
| 1239 | |||
| 1240 | </YueDisplay> | ||
| 1241 | |||
| 1242 | ### 执行更新 | ||
| 1243 | |||
| 1244 | 你可以使用各式二进制运算符执行更新赋值。 | ||
| 1245 | ```yuescript | ||
| 1246 | x = 1 | ||
| 1247 | x += 1 | ||
| 1248 | x -= 1 | ||
| 1249 | x *= 10 | ||
| 1250 | x /= 10 | ||
| 1251 | x %= 10 | ||
| 1252 | s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量 | ||
| 1253 | arg or= "默认值" | ||
| 1254 | ``` | ||
| 1255 | <YueDisplay> | ||
| 1256 | |||
| 1257 | ```yue | ||
| 1258 | x = 1 | ||
| 1259 | x += 1 | ||
| 1260 | x -= 1 | ||
| 1261 | x *= 10 | ||
| 1262 | x /= 10 | ||
| 1263 | x %= 10 | ||
| 1264 | s ..= "world" -- 如果执行更新的局部变量不存在,将新建一个局部变量 | ||
| 1265 | arg or= "默认值" | ||
| 1266 | ``` | ||
| 1267 | |||
| 1268 | </YueDisplay> | ||
| 1269 | |||
| 1270 | ### 链式赋值 | ||
| 1271 | |||
| 1272 | 你可以进行链式赋值,将多个项目赋予相同的值。 | ||
| 1273 | ```yuescript | ||
| 1274 | a = b = c = d = e = 0 | ||
| 1275 | x = y = z = f! | ||
| 1276 | ``` | ||
| 1277 | <YueDisplay> | ||
| 1278 | |||
| 1279 | ```yue | ||
| 1280 | a = b = c = d = e = 0 | ||
| 1281 | x = y = z = f! | ||
| 1282 | ``` | ||
| 1283 | |||
| 1284 | </YueDisplay> | ||
| 1285 | |||
| 1286 | ### 显式声明局部变量 | ||
| 1287 | ```yuescript | ||
| 1288 | do | ||
| 1289 | local a = 1 | ||
| 1290 | local * | ||
| 1291 | print "预先声明后续所有变量为局部变量" | ||
| 1292 | x = -> 1 + y + z | ||
| 1293 | y, z = 2, 3 | ||
| 1294 | global instance = Item\new! | ||
| 1295 | |||
| 1296 | do | ||
| 1297 | local X = 1 | ||
| 1298 | local ^ | ||
| 1299 | print "只预先声明后续大写的变量为局部变量" | ||
| 1300 | a = 1 | ||
| 1301 | B = 2 | ||
| 1302 | ``` | ||
| 1303 | <YueDisplay> | ||
| 1304 | |||
| 1305 | ```yue | ||
| 1306 | do | ||
| 1307 | local a = 1 | ||
| 1308 | local * | ||
| 1309 | print "预先声明后续所有变量为局部变量" | ||
| 1310 | x = -> 1 + y + z | ||
| 1311 | y, z = 2, 3 | ||
| 1312 | global instance = Item\new! | ||
| 1313 | |||
| 1314 | do | ||
| 1315 | local X = 1 | ||
| 1316 | local ^ | ||
| 1317 | print "只预先声明后续大写的变量为局部变量" | ||
| 1318 | a = 1 | ||
| 1319 | B = 2 | ||
| 1320 | ``` | ||
| 1321 | |||
| 1322 | </YueDisplay> | ||
| 1323 | |||
| 1324 | ### 显式声明全局变量 | ||
| 1325 | ```yuescript | ||
| 1326 | do | ||
| 1327 | global a = 1 | ||
| 1328 | global * | ||
| 1329 | print "预先声明所有变量为全局变量" | ||
| 1330 | x = -> 1 + y + z | ||
| 1331 | y, z = 2, 3 | ||
| 1332 | |||
| 1333 | do | ||
| 1334 | global x = 1 | ||
| 1335 | global ^ | ||
| 1336 | print "只预先声明大写的变量为全局变量" | ||
| 1337 | a = 1 | ||
| 1338 | B = 2 | ||
| 1339 | local Temp = "一个局部值" | ||
| 1340 | ``` | ||
| 1341 | <YueDisplay> | ||
| 1342 | |||
| 1343 | ```yue | ||
| 1344 | do | ||
| 1345 | global a = 1 | ||
| 1346 | global * | ||
| 1347 | print "预先声明所有变量为全局变量" | ||
| 1348 | x = -> 1 + y + z | ||
| 1349 | y, z = 2, 3 | ||
| 1350 | |||
| 1351 | do | ||
| 1352 | global x = 1 | ||
| 1353 | global ^ | ||
| 1354 | print "只预先声明大写的变量为全局变量" | ||
| 1355 | a = 1 | ||
| 1356 | B = 2 | ||
| 1357 | local Temp = "一个局部值" | ||
| 1358 | ``` | ||
| 1359 | |||
| 1360 | </YueDisplay> | ||
| 1361 | |||
| 1362 | ## 解构赋值 | ||
| 1363 | |||
| 1364 | 解构赋值是一种快速从 Lua 表中按名称或基于数组中的位置提取值的方法。 | ||
| 1365 | |||
| 1366 | 通常当你看到一个字面量的 Lua 表,比如 `{1,2,3}`,它位于赋值的右侧,因为它是一个值。解构赋值语句的写法就是交换了字面量 Lua 表的角色,并将其放在赋值语句的左侧。 | ||
| 1367 | |||
| 1368 | 最好是通过示例来解释。以下是如何从表格中解包前两个值的方法: | ||
| 1369 | |||
| 1370 | ```yuescript | ||
| 1371 | thing = [1, 2] | ||
| 1372 | |||
| 1373 | [a, b] = thing | ||
| 1374 | print a, b | ||
| 1375 | ``` | ||
| 1376 | <YueDisplay> | ||
| 1377 | |||
| 1378 | |||
| 1379 | ```yue | ||
| 1380 | thing = [1, 2] | ||
| 1381 | |||
| 1382 | [a, b] = thing | ||
| 1383 | print a, b | ||
| 1384 | ``` | ||
| 1385 | |||
| 1386 | </YueDisplay> | ||
| 1387 | |||
| 1388 | 在解构表格字面量中,键代表从右侧读取的键,值代表读取的值将被赋予的名称。 | ||
| 1389 | |||
| 1390 | ```yuescript | ||
| 1391 | obj = { | ||
| 1392 | hello: "world" | ||
| 1393 | day: "tuesday" | ||
| 1394 | length: 20 | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | {hello: hello, day: the_day} = obj | ||
| 1398 | print hello, the_day | ||
| 1399 | |||
| 1400 | :day = obj -- 可以不带大括号进行简单的解构 | ||
| 1401 | ``` | ||
| 1402 | <YueDisplay> | ||
| 1403 | |||
| 1404 | ```yue | ||
| 1405 | obj = { | ||
| 1406 | hello: "world" | ||
| 1407 | day: "tuesday" | ||
| 1408 | length: 20 | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | {hello: hello, day: the_day} = obj | ||
| 1412 | print hello, the_day | ||
| 1413 | |||
| 1414 | :day = obj -- 可以不带大括号进行简单的解构 | ||
| 1415 | ``` | ||
| 1416 | |||
| 1417 | </YueDisplay> | ||
| 1418 | |||
| 1419 | 这也适用于嵌套的数据结构: | ||
| 1420 | |||
| 1421 | ```yuescript | ||
| 1422 | obj2 = { | ||
| 1423 | numbers: [1,2,3,4] | ||
| 1424 | properties: { | ||
| 1425 | color: "green" | ||
| 1426 | height: 13.5 | ||
| 1427 | } | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | {numbers: [first, second], properties: {color: color}} = obj2 | ||
| 1431 | print first, second, color | ||
| 1432 | ``` | ||
| 1433 | <YueDisplay> | ||
| 1434 | |||
| 1435 | ```yue | ||
| 1436 | obj2 = { | ||
| 1437 | numbers: [1,2,3,4] | ||
| 1438 | properties: { | ||
| 1439 | color: "green" | ||
| 1440 | height: 13.5 | ||
| 1441 | } | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | {numbers: [first, second]} = obj2 | ||
| 1445 | print first, second, color | ||
| 1446 | ``` | ||
| 1447 | |||
| 1448 | </YueDisplay> | ||
| 1449 | |||
| 1450 | 如果解构语句很复杂,也可以任意将其分散在几行中。稍微复杂一些的示例: | ||
| 1451 | |||
| 1452 | ```yuescript | ||
| 1453 | { | ||
| 1454 | numbers: [first, second] | ||
| 1455 | properties: { | ||
| 1456 | color: color | ||
| 1457 | } | ||
| 1458 | } = obj2 | ||
| 1459 | ``` | ||
| 1460 | <YueDisplay> | ||
| 1461 | |||
| 1462 | ```yue | ||
| 1463 | { | ||
| 1464 | numbers: [first, second] | ||
| 1465 | properties: { | ||
| 1466 | color: color | ||
| 1467 | } | ||
| 1468 | } = obj2 | ||
| 1469 | ``` | ||
| 1470 | |||
| 1471 | </YueDisplay> | ||
| 1472 | |||
| 1473 | 有时候我们会需要从 Lua 表中提取值并将它们赋给与键同名的局部变量。为了避免编写重复代码,我们可以使用 **:** 前缀操作符: | ||
| 1474 | |||
| 1475 | ```yuescript | ||
| 1476 | {:concat, :insert} = table | ||
| 1477 | ``` | ||
| 1478 | <YueDisplay> | ||
| 1479 | |||
| 1480 | ```yue | ||
| 1481 | {:concat, :insert} = table | ||
| 1482 | ``` | ||
| 1483 | |||
| 1484 | </YueDisplay> | ||
| 1485 | |||
| 1486 | 这样的用法与导入语法有些相似。但我们可以通过混合语法重命名我们想要提取的字段: | ||
| 1487 | |||
| 1488 | ```yuescript | ||
| 1489 | {:mix, :max, random: rand} = math | ||
| 1490 | ``` | ||
| 1491 | <YueDisplay> | ||
| 1492 | |||
| 1493 | ```yue | ||
| 1494 | {:mix, :max, random: rand} = math | ||
| 1495 | ``` | ||
| 1496 | |||
| 1497 | </YueDisplay> | ||
| 1498 | |||
| 1499 | 在进行解构时,你可以指定默认值,如: | ||
| 1500 | |||
| 1501 | ```yuescript | ||
| 1502 | {:name = "nameless", :job = "jobless"} = person | ||
| 1503 | ``` | ||
| 1504 | <YueDisplay> | ||
| 1505 | |||
| 1506 | ```yue | ||
| 1507 | {:name = "nameless", :job = "jobless"} = person | ||
| 1508 | ``` | ||
| 1509 | |||
| 1510 | </YueDisplay> | ||
| 1511 | |||
| 1512 | 在进行列表解构时,你可以使用`_`作为占位符: | ||
| 1513 | |||
| 1514 | ```yuescript | ||
| 1515 | [_, two, _, four] = items | ||
| 1516 | ``` | ||
| 1517 | <YueDisplay> | ||
| 1518 | |||
| 1519 | ```yue | ||
| 1520 | [_, two, _, four] = items | ||
| 1521 | ``` | ||
| 1522 | |||
| 1523 | </YueDisplay> | ||
| 1524 | |||
| 1525 | ### 范围解构 | ||
| 1526 | |||
| 1527 | 你可以使用展开运算符 `...` 在列表解构中来捕获一个范围的值到子列表中。这在当你想要从列表的开头和结尾提取特定元素,同时收集中间的元素时非常有用。 | ||
| 1528 | |||
| 1529 | ```yuescript | ||
| 1530 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 1531 | [first, ...bulk, last] = orders | ||
| 1532 | print first -- 打印: first | ||
| 1533 | print bulk -- 打印: {"second", "third", "fourth"} | ||
| 1534 | print last -- 打印: last | ||
| 1535 | ``` | ||
| 1536 | <YueDisplay> | ||
| 1537 | |||
| 1538 | ```yue | ||
| 1539 | orders = ["first", "second", "third", "fourth", "last"] | ||
| 1540 | [first, ...bulk, last] = orders | ||
| 1541 | print first -- 打印: first | ||
| 1542 | print bulk -- 打印: {"second", "third", "fourth"} | ||
| 1543 | print last -- 打印: last | ||
| 1544 | ``` | ||
| 1545 | |||
| 1546 | </YueDisplay> | ||
| 1547 | |||
| 1548 | 展开运算符可以用在不同的位置来捕获不同的范围,并且你可以使用 `_` 作为占位符来表示你想跳过对应范围的捕获: | ||
| 1549 | |||
| 1550 | ```yuescript | ||
| 1551 | -- 捕获第一个元素之后的所有元素 | ||
| 1552 | [first, ...rest] = orders | ||
| 1553 | |||
| 1554 | -- 捕获最后一个元素之前的所有元素 | ||
| 1555 | [...start, last] = orders | ||
| 1556 | |||
| 1557 | -- 跳过中间的元素,只捕获第一个和最后一个元素 | ||
| 1558 | [first, ..._, last] = orders | ||
| 1559 | ``` | ||
| 1560 | <YueDisplay> | ||
| 1561 | |||
| 1562 | ```yue | ||
| 1563 | -- 捕获第一个元素之后的所有元素 | ||
| 1564 | [first, ...rest] = orders | ||
| 1565 | |||
| 1566 | -- 捕获最后一个元素之前的所有元素 | ||
| 1567 | [...start, last] = orders | ||
| 1568 | |||
| 1569 | -- 跳过中间的元素,只捕获第一个和最后一个元素 | ||
| 1570 | [first, ..._, last] = orders | ||
| 1571 | ``` | ||
| 1572 | |||
| 1573 | </YueDisplay> | ||
| 1574 | |||
| 1575 | ### 在其它地方的解构赋值 | ||
| 1576 | |||
| 1577 | 解构赋值也可以出现在其它隐式进行赋值的地方。一个例子是用在 for 循环中: | ||
| 1578 | |||
| 1579 | ```yuescript | ||
| 1580 | tuples = [ | ||
| 1581 | ["hello", "world"] | ||
| 1582 | ["egg", "head"] | ||
| 1583 | ] | ||
| 1584 | |||
| 1585 | for [left, right] in *tuples | ||
| 1586 | print left, right | ||
| 1587 | ``` | ||
| 1588 | <YueDisplay> | ||
| 1589 | |||
| 1590 | ```yue | ||
| 1591 | tuples = [ | ||
| 1592 | ["hello", "world"] | ||
| 1593 | ["egg", "head"] | ||
| 1594 | ] | ||
| 1595 | |||
| 1596 | for [left, right] in *tuples | ||
| 1597 | print left, right | ||
| 1598 | ``` | ||
| 1599 | |||
| 1600 | </YueDisplay> | ||
| 1601 | |||
| 1602 | 我们知道数组表中的每个元素都是一个两项的元组,所以我们可以直接在 for 语句的名称子句中使用解构来解包它。 | ||
| 1603 | |||
| 1604 | ## If 赋值 | ||
| 1605 | |||
| 1606 | `if` 和 `elseif` 代码块可以在条件表达式的位置进行赋值。在代码执行到要计算条件时,会首先进行赋值计算,并使用赋与的值作为分支判断的条件。赋值的变量仅在条件分支的代码块内有效,这意味着如果值不是真值,那么它就不会被用到。注意,你必须使用“海象运算符” `:=` 而不是 `=` 来做赋值。 | ||
| 1607 | |||
| 1608 | ```yuescript | ||
| 1609 | if user := database.find_user "moon" | ||
| 1610 | print user.name | ||
| 1611 | ``` | ||
| 1612 | <YueDisplay> | ||
| 1613 | |||
| 1614 | ```yue | ||
| 1615 | if user := database.find_user "moon" | ||
| 1616 | print user.name | ||
| 1617 | ``` | ||
| 1618 | |||
| 1619 | </YueDisplay> | ||
| 1620 | |||
| 1621 | ```yuescript | ||
| 1622 | if hello := os.getenv "hello" | ||
| 1623 | print "你有 hello", hello | ||
| 1624 | elseif world := os.getenv "world" | ||
| 1625 | print "你有 world", world | ||
| 1626 | else | ||
| 1627 | print "什么都没有 :(" | ||
| 1628 | ``` | ||
| 1629 | <YueDisplay> | ||
| 1630 | |||
| 1631 | ```yue | ||
| 1632 | if hello := os.getenv "hello" | ||
| 1633 | print "你有 hello", hello | ||
| 1634 | elseif world := os.getenv "world" | ||
| 1635 | print "你有 world", world | ||
| 1636 | else | ||
| 1637 | print "什么都没有 :(" | ||
| 1638 | ``` | ||
| 1639 | |||
| 1640 | </YueDisplay> | ||
| 1641 | |||
| 1642 | 使用多个返回值的 If 赋值。只有第一个值会被检查,其他值都有同样的作用域。 | ||
| 1643 | ```yuescript | ||
| 1644 | if success, result := pcall -> "无报错地获取结果" | ||
| 1645 | print result -- 变量 result 是有作用域的 | ||
| 1646 | print "好的" | ||
| 1647 | ``` | ||
| 1648 | <YueDisplay> | ||
| 1649 | |||
| 1650 | ```yue | ||
| 1651 | if success, result := pcall -> "无报错地获取结果" | ||
| 1652 | print result -- 变量 result 是有作用域的 | ||
| 1653 | print "好的" | ||
| 1654 | ``` | ||
| 1655 | |||
| 1656 | </YueDisplay> | ||
| 1657 | |||
| 1658 | ### While 赋值 | ||
| 1659 | |||
| 1660 | 你可以在 while 循环中同样使用赋值来获取循环条件的值。 | ||
| 1661 | ```yuescript | ||
| 1662 | while byte := stream\read_one! | ||
| 1663 | -- 对 byte 做一些操作 | ||
| 1664 | print byte | ||
| 1665 | ``` | ||
| 1666 | <YueDisplay> | ||
| 1667 | |||
| 1668 | ```yue | ||
| 1669 | while byte := stream\read_one! | ||
| 1670 | -- 对 byte 做一些操作 | ||
| 1671 | print byte | ||
| 1672 | ``` | ||
| 1673 | |||
| 1674 | </YueDisplay> | ||
| 1675 | |||
| 1676 | ## 可变参数赋值 | ||
| 1677 | |||
| 1678 | 你可以将函数返回的结果赋值给一个可变参数符号 `...`。然后使用 Lua 的方式访问其内容。 | ||
| 1679 | ```yuescript | ||
| 1680 | list = [1, 2, 3, 4, 5] | ||
| 1681 | fn = (ok) -> ok, table.unpack list | ||
| 1682 | ok, ... = fn true | ||
| 1683 | count = select '#', ... | ||
| 1684 | first = select 1, ... | ||
| 1685 | print ok, count, first | ||
| 1686 | ``` | ||
| 1687 | <YueDisplay> | ||
| 1688 | |||
| 1689 | ```yue | ||
| 1690 | list = [1, 2, 3, 4, 5] | ||
| 1691 | fn = (ok) -> ok, table.unpack list | ||
| 1692 | ok, ... = fn true | ||
| 1693 | count = select '#', ... | ||
| 1694 | first = select 1, ... | ||
| 1695 | print ok, count, first | ||
| 1696 | ``` | ||
| 1697 | |||
| 1698 | </YueDisplay> | ||
| 1699 | |||
| 1700 | ## 空白 | ||
| 1701 | |||
| 1702 | 月之脚本是一个对空白敏感的语言。你必须在相同的缩进中使用空格 **' '** 或制表符 **'\t'** 来编写一些代码块,如函数体、值列表和一些控制块。包含不同空白的表达式可能意味着不同的事情。制表符被视为4个空格,但最好不要混合使用空格和制表符。 | ||
| 1703 | |||
| 1704 | ### 语句分隔符 | ||
| 1705 | |||
| 1706 | 一条语句通常以换行结束。你也可以使用分号 `;` 显式结束一条语句,从而在同一行中编写多条语句: | ||
| 1707 | |||
| 1708 | ```yuescript | ||
| 1709 | a = 1; b = 2; print a + b | ||
| 1710 | ``` | ||
| 1711 | <YueDisplay> | ||
| 1712 | |||
| 1713 | ```yue | ||
| 1714 | a = 1; b = 2; print a + b | ||
| 1715 | ``` | ||
| 1716 | |||
| 1717 | </YueDisplay> | ||
| 1718 | |||
| 1719 | ### 多行链式调用 | ||
| 1720 | |||
| 1721 | 你可以使用相同的缩进来编写多行链式函数调用。 | ||
| 1722 | ```yuescript | ||
| 1723 | Rx.Observable | ||
| 1724 | .fromRange 1, 8 | ||
| 1725 | \filter (x) -> x % 2 == 0 | ||
| 1726 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 1727 | \map (value) -> value .. '!' | ||
| 1728 | \subscribe print | ||
| 1729 | ``` | ||
| 1730 | <YueDisplay> | ||
| 1731 | |||
| 1732 | ```yue | ||
| 1733 | Rx.Observable | ||
| 1734 | .fromRange 1, 8 | ||
| 1735 | \filter (x) -> x % 2 == 0 | ||
| 1736 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 1737 | \map (value) -> value .. '!' | ||
| 1738 | \subscribe print | ||
| 1739 | ``` | ||
| 1740 | |||
| 1741 | </YueDisplay> | ||
| 1742 | |||
| 1743 | ## 注释 | ||
| 1744 | |||
| 1745 | ```yuescript | ||
| 1746 | -- 我是一个注释 | ||
| 1747 | |||
| 1748 | str = --[[ | ||
| 1749 | 这是一个多行注释。 | ||
| 1750 | 没问题。 | ||
| 1751 | ]] strA \ -- 注释 1 | ||
| 1752 | .. strB \ -- 注释 2 | ||
| 1753 | .. strC | ||
| 1754 | |||
| 1755 | func --[[端口]] 3000, --[[ip]] "192.168.1.1" | ||
| 1756 | ``` | ||
| 1757 | <YueDisplay> | ||
| 1758 | |||
| 1759 | ```yue | ||
| 1760 | -- 我是一个注释 | ||
| 1761 | |||
| 1762 | str = --[[ | ||
| 1763 | 这是一个多行注释。 | ||
| 1764 | 没问题。 | ||
| 1765 | ]] strA \ -- 注释 1 | ||
| 1766 | .. strB \ -- 注释 2 | ||
| 1767 | .. strC | ||
| 1768 | |||
| 1769 | func --[[端口]] 3000, --[[ip]] "192.168.1.1" | ||
| 1770 | ``` | ||
| 1771 | |||
| 1772 | </YueDisplay> | ||
| 1773 | |||
| 1774 | ## 错误处理 | ||
| 1775 | |||
| 1776 | 用于统一进行 Lua 错误处理的便捷语法。 | ||
| 1777 | |||
| 1778 | ```yuescript | ||
| 1779 | try | ||
| 1780 | func 1, 2, 3 | ||
| 1781 | catch err | ||
| 1782 | print yue.traceback err | ||
| 1783 | |||
| 1784 | success, result = try | ||
| 1785 | func 1, 2, 3 | ||
| 1786 | catch err | ||
| 1787 | yue.traceback err | ||
| 1788 | |||
| 1789 | try func 1, 2, 3 | ||
| 1790 | catch err | ||
| 1791 | print yue.traceback err | ||
| 1792 | |||
| 1793 | success, result = try func 1, 2, 3 | ||
| 1794 | |||
| 1795 | try | ||
| 1796 | print "尝试中" | ||
| 1797 | func 1, 2, 3 | ||
| 1798 | |||
| 1799 | -- 使用if赋值模式 | ||
| 1800 | if success, result := try func 1, 2, 3 | ||
| 1801 | catch err | ||
| 1802 | print yue.traceback err | ||
| 1803 | print result | ||
| 1804 | ``` | ||
| 1805 | <YueDisplay> | ||
| 1806 | |||
| 1807 | ```yue | ||
| 1808 | try | ||
| 1809 | func 1, 2, 3 | ||
| 1810 | catch err | ||
| 1811 | print yue.traceback err | ||
| 1812 | |||
| 1813 | success, result = try | ||
| 1814 | func 1, 2, 3 | ||
| 1815 | catch err | ||
| 1816 | yue.traceback err | ||
| 1817 | |||
| 1818 | try func 1, 2, 3 | ||
| 1819 | catch err | ||
| 1820 | print yue.traceback err | ||
| 1821 | |||
| 1822 | success, result = try func 1, 2, 3 | ||
| 1823 | |||
| 1824 | try | ||
| 1825 | print "尝试中" | ||
| 1826 | func 1, 2, 3 | ||
| 1827 | |||
| 1828 | -- 使用if赋值模式 | ||
| 1829 | if success, result := try func 1, 2, 3 | ||
| 1830 | catch err | ||
| 1831 | print yue.traceback err | ||
| 1832 | print result | ||
| 1833 | ``` | ||
| 1834 | |||
| 1835 | </YueDisplay> | ||
| 1836 | |||
| 1837 | ### 错误处理简化 | ||
| 1838 | |||
| 1839 | `try?` 是 `try` 的功能简化语法,它不再返回 `try` 语句的布尔状态,并在成功时直接返回 `try` 代码块的结果,失败时返回 `nil` 值而非错误对象。 | ||
| 1840 | |||
| 1841 | ```yuescript | ||
| 1842 | a, b, c = try? func! | ||
| 1843 | |||
| 1844 | -- 与空值合并运算符一起使用 | ||
| 1845 | a = (try? func!) ?? "default" | ||
| 1846 | |||
| 1847 | -- 作为函数参数 | ||
| 1848 | f try? func! | ||
| 1849 | |||
| 1850 | -- 带 catch 块的 try! | ||
| 1851 | f try? | ||
| 1852 | print 123 | ||
| 1853 | func! | ||
| 1854 | catch e | ||
| 1855 | print e | ||
| 1856 | e | ||
| 1857 | ``` | ||
| 1858 | <YueDisplay> | ||
| 1859 | |||
| 1860 | ```yue | ||
| 1861 | a, b, c = try? func! | ||
| 1862 | |||
| 1863 | -- 与空值合并运算符一起使用 | ||
| 1864 | a = (try? func!) ?? "default" | ||
| 1865 | |||
| 1866 | -- 作为函数参数 | ||
| 1867 | f try? func! | ||
| 1868 | |||
| 1869 | -- 带 catch 块的 try! | ||
| 1870 | f try? | ||
| 1871 | print 123 | ||
| 1872 | func! | ||
| 1873 | catch e | ||
| 1874 | print e | ||
| 1875 | e | ||
| 1876 | ``` | ||
| 1877 | |||
| 1878 | </YueDisplay> | ||
| 1879 | |||
| 1880 | ## 属性 | ||
| 1881 | |||
| 1882 | 月之脚本现在提供了 Lua 5.4 新增的叫做属性的语法支持。在月之脚本编译到的 Lua 目标版本低于 5.4 时,你仍然可以同时使用`const` 和 `close` 的属性声明语法,并获得常量检查和作用域回调的功能。 | ||
| 1883 | |||
| 1884 | ```yuescript | ||
| 1885 | const a = 123 | ||
| 1886 | close _ = <close>: -> print "超出范围。" | ||
| 1887 | ``` | ||
| 1888 | <YueDisplay> | ||
| 1889 | |||
| 1890 | ```yue | ||
| 1891 | const a = 123 | ||
| 1892 | close _ = <close>: -> print "超出范围。" | ||
| 1893 | ``` | ||
| 1894 | |||
| 1895 | </YueDisplay> | ||
| 1896 | |||
| 1897 | 你可以对进行解构得到的变量标记为常量。 | ||
| 1898 | |||
| 1899 | ```yuescript | ||
| 1900 | const {:a, :b, c, d} = tb | ||
| 1901 | -- a = 1 | ||
| 1902 | ``` | ||
| 1903 | <YueDisplay> | ||
| 1904 | |||
| 1905 | ```yue | ||
| 1906 | const {:a, :b, c, d} = tb | ||
| 1907 | -- a = 1 | ||
| 1908 | ``` | ||
| 1909 | |||
| 1910 | </YueDisplay> | ||
| 1911 | |||
| 1912 | 你也可以声明全局变量为常量。 | ||
| 1913 | |||
| 1914 | ```yuescript | ||
| 1915 | global const Constant = 123 | ||
| 1916 | -- Constant = 1 | ||
| 1917 | ``` | ||
| 1918 | <YueDisplay> | ||
| 1919 | |||
| 1920 | ```yue | ||
| 1921 | global const Constant = 123 | ||
| 1922 | -- Constant = 1 | ||
| 1923 | ``` | ||
| 1924 | |||
| 1925 | </YueDisplay> | ||
| 1926 | |||
| 1927 | ## 字面量 | ||
| 1928 | |||
| 1929 | Lua 中的所有基本字面量都可以在月之脚本中使用。包括数字、字符串、布尔值和 **nil**。 | ||
| 1930 | |||
| 1931 | 但与 Lua 不同的是,单引号和双引号字符串内部允许有换行: | ||
| 1932 | |||
| 1933 | ```yuescript | ||
| 1934 | some_string = "这是一个字符串 | ||
| 1935 | 并包括一个换行。" | ||
| 1936 | |||
| 1937 | -- 使用#{}语法可以将表达式插入到字符串字面量中。 | ||
| 1938 | -- 字符串插值只在双引号字符串中可用。 | ||
| 1939 | print "我有#{math.random! * 100}%的把握。" | ||
| 1940 | ``` | ||
| 1941 | <YueDisplay> | ||
| 1942 | |||
| 1943 | ```yue | ||
| 1944 | some_string = "这是一个字符串 | ||
| 1945 | 并包括一个换行。" | ||
| 1946 | |||
| 1947 | -- 使用#{}语法可以将表达式插入到字符串字面量中。 | ||
| 1948 | -- 字符串插值只在双引号字符串中可用。 | ||
| 1949 | print "我有#{math.random! * 100}%的把握。" | ||
| 1950 | ``` | ||
| 1951 | |||
| 1952 | </YueDisplay> | ||
| 1953 | |||
| 1954 | ### 数字字面量 | ||
| 1955 | |||
| 1956 | 你可以在数字字面量中使用下划线来增加可读性。 | ||
| 1957 | |||
| 1958 | ```yuescript | ||
| 1959 | integer = 1_000_000 | ||
| 1960 | hex = 0xEF_BB_BF | ||
| 1961 | binary = 0B10011 | ||
| 1962 | ``` | ||
| 1963 | <YueDisplay> | ||
| 1964 | |||
| 1965 | |||
| 1966 | ```yue | ||
| 1967 | integer = 1_000_000 | ||
| 1968 | hex = 0xEF_BB_BF | ||
| 1969 | binary = 0B10011 | ||
| 1970 | ``` | ||
| 1971 | |||
| 1972 | </YueDisplay> | ||
| 1973 | |||
| 1974 | ### YAML 风格字符串 | ||
| 1975 | |||
| 1976 | 使用 `|` 前缀标记一个多行 YAML 风格字符串: | ||
| 1977 | |||
| 1978 | ```yuescript | ||
| 1979 | str = | | ||
| 1980 | key: value | ||
| 1981 | list: | ||
| 1982 | - item1 | ||
| 1983 | - #{expr} | ||
| 1984 | ``` | ||
| 1985 | <YueDisplay> | ||
| 1986 | |||
| 1987 | ```yue | ||
| 1988 | str = | | ||
| 1989 | key: value | ||
| 1990 | list: | ||
| 1991 | - item1 | ||
| 1992 | - #{expr} | ||
| 1993 | ``` | ||
| 1994 | |||
| 1995 | </YueDisplay> | ||
| 1996 | |||
| 1997 | 其效果类似于原生 Lua 的多行拼接,所有文本(含换行)将被保留下来,并支持 `#{...}` 语法,通过 `tostring(expr)` 插入表达式结果。 | ||
| 1998 | |||
| 1999 | YAML 风格的多行字符串会自动检测首行后最小的公共缩进,并从所有行中删除该前缀空白字符。这让你可以在代码中对齐文本,但输出字符串不会带多余缩进。 | ||
| 2000 | |||
| 2001 | ```yuescript | ||
| 2002 | fn = -> | ||
| 2003 | str = | | ||
| 2004 | foo: | ||
| 2005 | bar: baz | ||
| 2006 | return str | ||
| 2007 | ``` | ||
| 2008 | <YueDisplay> | ||
| 2009 | |||
| 2010 | ```yue | ||
| 2011 | fn = -> | ||
| 2012 | str = | | ||
| 2013 | foo: | ||
| 2014 | bar: baz | ||
| 2015 | return str | ||
| 2016 | ``` | ||
| 2017 | |||
| 2018 | </YueDisplay> | ||
| 2019 | |||
| 2020 | 输出字符串中的 foo: 对齐到行首,不会带有函数缩进空格。保留内部缩进的相对结构,适合书写结构化嵌套样式的内容。 | ||
| 2021 | |||
| 2022 | 支持自动处理字符中的引号、反斜杠等特殊符号,无需手动转义: | ||
| 2023 | |||
| 2024 | ```yuescript | ||
| 2025 | str = | | ||
| 2026 | path: "C:\Program Files\App" | ||
| 2027 | note: 'He said: "#{Hello}!"' | ||
| 2028 | ``` | ||
| 2029 | <YueDisplay> | ||
| 2030 | |||
| 2031 | ```yue | ||
| 2032 | str = | | ||
| 2033 | path: "C:\Program Files\App" | ||
| 2034 | note: 'He said: "#{Hello}!"' | ||
| 2035 | ``` | ||
| 2036 | |||
| 2037 | </YueDisplay> | ||
| 2038 | |||
| 2039 | ## 函数字面量 | ||
| 2040 | |||
| 2041 | 所有函数都是使用月之脚本的函数表达式创建的。一个简单的函数可以用箭头表示为:**->**。 | ||
| 2042 | |||
| 2043 | ```yuescript | ||
| 2044 | my_function = -> | ||
| 2045 | my_function() -- 调用空函数 | ||
| 2046 | ``` | ||
| 2047 | <YueDisplay> | ||
| 2048 | |||
| 2049 | ```yue | ||
| 2050 | my_function = -> | ||
| 2051 | my_function() -- 调用空函数 | ||
| 2052 | ``` | ||
| 2053 | |||
| 2054 | </YueDisplay> | ||
| 2055 | |||
| 2056 | 函数体可以是紧跟在箭头后的一个语句,或者是在后面的行上使用同样缩进的一系列语句: | ||
| 2057 | |||
| 2058 | ```yuescript | ||
| 2059 | func_a = -> print "你好,世界" | ||
| 2060 | |||
| 2061 | func_b = -> | ||
| 2062 | value = 100 | ||
| 2063 | print "这个值是:", value | ||
| 2064 | ``` | ||
| 2065 | <YueDisplay> | ||
| 2066 | |||
| 2067 | ```yue | ||
| 2068 | func_a = -> print "你好,世界" | ||
| 2069 | |||
| 2070 | func_b = -> | ||
| 2071 | value = 100 | ||
| 2072 | print "这个值是:", value | ||
| 2073 | ``` | ||
| 2074 | |||
| 2075 | </YueDisplay> | ||
| 2076 | |||
| 2077 | 如果一个函数没有参数,可以使用 **\!** 操作符调用它,而不是空括号。使用 **\!** 调用没有参数的函数是推荐的写法。 | ||
| 2078 | |||
| 2079 | ```yuescript | ||
| 2080 | func_a! | ||
| 2081 | func_b() | ||
| 2082 | ``` | ||
| 2083 | <YueDisplay> | ||
| 2084 | |||
| 2085 | ```yue | ||
| 2086 | func_a! | ||
| 2087 | func_b() | ||
| 2088 | ``` | ||
| 2089 | |||
| 2090 | </YueDisplay> | ||
| 2091 | |||
| 2092 | 带有参数的函数可以通过在箭头前加上括号中的参数名列表来进行创建: | ||
| 2093 | |||
| 2094 | ```yuescript | ||
| 2095 | sum = (x, y) -> print "数字的和", x + y | ||
| 2096 | ``` | ||
| 2097 | <YueDisplay> | ||
| 2098 | |||
| 2099 | ```yue | ||
| 2100 | sum = (x, y) -> print "数字的和", x + y | ||
| 2101 | ``` | ||
| 2102 | |||
| 2103 | </YueDisplay> | ||
| 2104 | |||
| 2105 | 函数可以通过在函数名后列出参数来调用。当对函数做嵌套的调用时,后面列出的参数会应用于左侧最近的函数。 | ||
| 2106 | |||
| 2107 | ```yuescript | ||
| 2108 | sum 10, 20 | ||
| 2109 | print sum 10, 20 | ||
| 2110 | |||
| 2111 | a b c "a", "b", "c" | ||
| 2112 | ``` | ||
| 2113 | <YueDisplay> | ||
| 2114 | |||
| 2115 | ```yue | ||
| 2116 | sum 10, 20 | ||
| 2117 | print sum 10, 20 | ||
| 2118 | |||
| 2119 | a b c "a", "b", "c" | ||
| 2120 | ``` | ||
| 2121 | |||
| 2122 | </YueDisplay> | ||
| 2123 | |||
| 2124 | 为了避免在调用函数时产生歧义,也可以使用括号将参数括起来。比如在以下的例子中是必需的,这样才能确保参数被传入到正确的函数。 | ||
| 2125 | |||
| 2126 | ```yuescript | ||
| 2127 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 2128 | ``` | ||
| 2129 | <YueDisplay> | ||
| 2130 | |||
| 2131 | ```yue | ||
| 2132 | print "x:", sum(10, 20), "y:", sum(30, 40) | ||
| 2133 | ``` | ||
| 2134 | |||
| 2135 | </YueDisplay> | ||
| 2136 | |||
| 2137 | 注意:函数名与开始括号之间不能有任何空格。 | ||
| 2138 | |||
| 2139 | 函数会将函数体中的最后一个语句强制转换为返回语句,这被称作隐式返回: | ||
| 2140 | |||
| 2141 | ```yuescript | ||
| 2142 | sum = (x, y) -> x + y | ||
| 2143 | print "数字的和是", sum 10, 20 | ||
| 2144 | ``` | ||
| 2145 | <YueDisplay> | ||
| 2146 | |||
| 2147 | ```yue | ||
| 2148 | sum = (x, y) -> x + y | ||
| 2149 | print "数字的和是", sum 10, 20 | ||
| 2150 | ``` | ||
| 2151 | |||
| 2152 | </YueDisplay> | ||
| 2153 | |||
| 2154 | 如果你需要做显式返回,可以使用 return 关键字: | ||
| 2155 | |||
| 2156 | ```yuescript | ||
| 2157 | sum = (x, y) -> return x + y | ||
| 2158 | ``` | ||
| 2159 | <YueDisplay> | ||
| 2160 | |||
| 2161 | ```yue | ||
| 2162 | sum = (x, y) -> return x + y | ||
| 2163 | ``` | ||
| 2164 | |||
| 2165 | </YueDisplay> | ||
| 2166 | |||
| 2167 | 就像在Lua中一样,函数可以返回多个值。最后一个语句必须是由逗号分隔的值列表: | ||
| 2168 | |||
| 2169 | ```yuescript | ||
| 2170 | mystery = (x, y) -> x + y, x - y | ||
| 2171 | a, b = mystery 10, 20 | ||
| 2172 | ``` | ||
| 2173 | <YueDisplay> | ||
| 2174 | |||
| 2175 | ```yue | ||
| 2176 | mystery = (x, y) -> x + y, x - y | ||
| 2177 | a, b = mystery 10, 20 | ||
| 2178 | ``` | ||
| 2179 | |||
| 2180 | </YueDisplay> | ||
| 2181 | |||
| 2182 | ### 粗箭头 | ||
| 2183 | |||
| 2184 | 因为在 Lua 中调用方法时,经常习惯将对象作为第一个参数传入,所以月之脚本提供了一种特殊的语法来创建自动包含 self 参数的函数。 | ||
| 2185 | |||
| 2186 | ```yuescript | ||
| 2187 | func = (num) => @value + num | ||
| 2188 | ``` | ||
| 2189 | <YueDisplay> | ||
| 2190 | |||
| 2191 | ```yue | ||
| 2192 | func = (num) => @value + num | ||
| 2193 | ``` | ||
| 2194 | |||
| 2195 | </YueDisplay> | ||
| 2196 | |||
| 2197 | ### 参数默认值 | ||
| 2198 | |||
| 2199 | 可以为函数的参数提供默认值。如果参数的值为 nil,则确定该参数为空。任何具有默认值的 nil 参数在函数体运行之前都会被替换。 | ||
| 2200 | |||
| 2201 | ```yuescript | ||
| 2202 | my_function = (name = "某物", height = 100) -> | ||
| 2203 | print "你好,我是", name | ||
| 2204 | print "我的高度是", height | ||
| 2205 | ``` | ||
| 2206 | <YueDisplay> | ||
| 2207 | |||
| 2208 | ```yue | ||
| 2209 | my_function = (name = "某物", height = 100) -> | ||
| 2210 | print "你好,我是", name | ||
| 2211 | print "我的高度是", height | ||
| 2212 | ``` | ||
| 2213 | |||
| 2214 | </YueDisplay> | ||
| 2215 | |||
| 2216 | 函数参数的默认值表达式在函数体中会按参数声明的顺序进行计算。因此,在默认值的表达式中可以访问先前声明的参数。 | ||
| 2217 | |||
| 2218 | ```yuescript | ||
| 2219 | some_args = (x = 100, y = x + 1000) -> | ||
| 2220 | print x + y | ||
| 2221 | ``` | ||
| 2222 | <YueDisplay> | ||
| 2223 | |||
| 2224 | ```yue | ||
| 2225 | some_args = (x = 100, y = x + 1000) -> | ||
| 2226 | print x + y | ||
| 2227 | ``` | ||
| 2228 | |||
| 2229 | </YueDisplay> | ||
| 2230 | |||
| 2231 | ### 多行参数 | ||
| 2232 | |||
| 2233 | 当调用接收大量参数的函数时,将参数列表分成多行是很方便的。由于月之脚本语言对空白字符的敏感性,做参数列表的分割时务必要小心。 | ||
| 2234 | |||
| 2235 | 如果要将参数列表写到下一行,那么当前行必须以逗号结束。并且下一行的缩进必须比当前的缩进多。一旦做了参数的缩进,所有其他参数列表的行必须保持相同的缩进级别,以成为参数列表的一部分。 | ||
| 2236 | |||
| 2237 | ```yuescript | ||
| 2238 | my_func 5, 4, 3, | ||
| 2239 | 8, 9, 10 | ||
| 2240 | |||
| 2241 | cool_func 1, 2, | ||
| 2242 | 3, 4, | ||
| 2243 | 5, 6, | ||
| 2244 | 7, 8 | ||
| 2245 | ``` | ||
| 2246 | <YueDisplay> | ||
| 2247 | |||
| 2248 | ```yue | ||
| 2249 | my_func 5, 4, 3, | ||
| 2250 | 8, 9, 10 | ||
| 2251 | |||
| 2252 | cool_func 1, 2, | ||
| 2253 | 3, 4, | ||
| 2254 | 5, 6, | ||
| 2255 | 7, 8 | ||
| 2256 | ``` | ||
| 2257 | |||
| 2258 | </YueDisplay> | ||
| 2259 | |||
| 2260 | 这种调用方式可以做嵌套。并通过缩进级别来确定参数属于哪一个函数。 | ||
| 2261 | |||
| 2262 | ```yuescript | ||
| 2263 | my_func 5, 6, 7, | ||
| 2264 | 6, another_func 6, 7, 8, | ||
| 2265 | 9, 1, 2, | ||
| 2266 | 5, 4 | ||
| 2267 | ``` | ||
| 2268 | <YueDisplay> | ||
| 2269 | |||
| 2270 | ```yue | ||
| 2271 | my_func 5, 6, 7, | ||
| 2272 | 6, another_func 6, 7, 8, | ||
| 2273 | 9, 1, 2, | ||
| 2274 | 5, 4 | ||
| 2275 | ``` | ||
| 2276 | |||
| 2277 | </YueDisplay> | ||
| 2278 | |||
| 2279 | 因为 Lua 表也使用逗号作为分隔符,这种缩进语法有助于让值成为参数列表的一部分,而不是 Lua 表的一部分。 | ||
| 2280 | |||
| 2281 | ```yuescript | ||
| 2282 | x = [ | ||
| 2283 | 1, 2, 3, 4, a_func 4, 5, | ||
| 2284 | 5, 6, | ||
| 2285 | 8, 9, 10 | ||
| 2286 | ] | ||
| 2287 | ``` | ||
| 2288 | <YueDisplay> | ||
| 2289 | |||
| 2290 | ```yue | ||
| 2291 | x = [ | ||
| 2292 | 1, 2, 3, 4, a_func 4, 5, | ||
| 2293 | 5, 6, | ||
| 2294 | 8, 9, 10 | ||
| 2295 | ] | ||
| 2296 | ``` | ||
| 2297 | |||
| 2298 | </YueDisplay> | ||
| 2299 | |||
| 2300 | 有个不常见的写法可以注意一下,如果我们将在后面使用较低的缩进,我们可以为函数参数提供更深的缩进来区分列表的归属。 | ||
| 2301 | |||
| 2302 | ```yuescript | ||
| 2303 | y = [ my_func 1, 2, 3, | ||
| 2304 | 4, 5, | ||
| 2305 | 5, 6, 7 | ||
| 2306 | ] | ||
| 2307 | ``` | ||
| 2308 | <YueDisplay> | ||
| 2309 | |||
| 2310 | ```yue | ||
| 2311 | y = [ my_func 1, 2, 3, | ||
| 2312 | 4, 5, | ||
| 2313 | 5, 6, 7 | ||
| 2314 | ] | ||
| 2315 | ``` | ||
| 2316 | |||
| 2317 | </YueDisplay> | ||
| 2318 | |||
| 2319 | 对于其它有代码块跟随的语句,比如条件语句,也可以通过小心安排缩进来做类似的事。比如我们可以通过调整缩进级别来控制一些值归属于哪个语句: | ||
| 2320 | |||
| 2321 | ```yuescript | ||
| 2322 | if func 1, 2, 3, | ||
| 2323 | "你好", | ||
| 2324 | "世界" | ||
| 2325 | print "你好" | ||
| 2326 | print "我在if内部" | ||
| 2327 | |||
| 2328 | if func 1, 2, 3, | ||
| 2329 | "你好", | ||
| 2330 | "世界" | ||
| 2331 | print "hello" | ||
| 2332 | print "我在if内部" | ||
| 2333 | ``` | ||
| 2334 | <YueDisplay> | ||
| 2335 | |||
| 2336 | ```yue | ||
| 2337 | if func 1, 2, 3, | ||
| 2338 | "你好", | ||
| 2339 | "世界" | ||
| 2340 | print "你好" | ||
| 2341 | print "我在if内部" | ||
| 2342 | |||
| 2343 | if func 1, 2, 3, | ||
| 2344 | "你好", | ||
| 2345 | "世界" | ||
| 2346 | print "你好" | ||
| 2347 | print "我在if内部" | ||
| 2348 | ``` | ||
| 2349 | |||
| 2350 | </YueDisplay> | ||
| 2351 | |||
| 2352 | ### 参数解构 | ||
| 2353 | |||
| 2354 | 月之脚本支持在函数形参位置对传入对象进行解构。适用两类解构表子面量: | ||
| 2355 | |||
| 2356 | - 使用 {} 包裹的字面量/对象形参,支持提供获得空字段时的默认值(例如 {:a, :b}、{a: a1 = 123})。 | ||
| 2357 | |||
| 2358 | - 无 {} 包裹、以键值/简写键序列开头,直至遇到其它表达式终止(例如 :a, b: b1, :c),表示从同一个对象中解构多个字段。 | ||
| 2359 | |||
| 2360 | ```yuescript | ||
| 2361 | f1 = (:a, :b, :c) -> | ||
| 2362 | print a, b, c | ||
| 2363 | |||
| 2364 | f1 a: 1, b: "2", c: {} | ||
| 2365 | |||
| 2366 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 2367 | print a1, b, c | ||
| 2368 | |||
| 2369 | arg1 = {a: 0} | ||
| 2370 | f2 arg1, arg2 | ||
| 2371 | ``` | ||
| 2372 | <YueDisplay> | ||
| 2373 | |||
| 2374 | ```yue | ||
| 2375 | f1 = (:a, :b, :c) -> | ||
| 2376 | print a, b, c | ||
| 2377 | |||
| 2378 | f1 a: 1, b: "2", c: {} | ||
| 2379 | |||
| 2380 | f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) -> | ||
| 2381 | print a1, b, c | ||
| 2382 | |||
| 2383 | arg1 = {a: 0} | ||
| 2384 | f2 arg1, arg2 | ||
| 2385 | ``` | ||
| 2386 | |||
| 2387 | </YueDisplay> | ||
| 2388 | |||
| 2389 | ### 前置返回表达式 | ||
| 2390 | |||
| 2391 | 在深度嵌套的函数体中,为了提升返回值的可读性及编写便利性,我们新增了 “前置返回表达式” 语法。其形式如下: | ||
| 2392 | |||
| 2393 | ```yuescript | ||
| 2394 | findFirstEven = (list): nil -> | ||
| 2395 | for item in *list | ||
| 2396 | if type(item) == "table" | ||
| 2397 | for sub in *item | ||
| 2398 | if sub % 2 == 0 | ||
| 2399 | return sub | ||
| 2400 | ``` | ||
| 2401 | <YueDisplay> | ||
| 2402 | |||
| 2403 | ```yue | ||
| 2404 | findFirstEven = (list): nil -> | ||
| 2405 | for item in *list | ||
| 2406 | if type(item) == "table" | ||
| 2407 | for sub in *item | ||
| 2408 | if sub % 2 == 0 | ||
| 2409 | return sub | ||
| 2410 | ``` | ||
| 2411 | |||
| 2412 | </YueDisplay> | ||
| 2413 | |||
| 2414 | 这个写法等价于: | ||
| 2415 | |||
| 2416 | ```yuescript | ||
| 2417 | findFirstEven = (list) -> | ||
| 2418 | for item in *list | ||
| 2419 | if type(item) == "table" | ||
| 2420 | for sub in *item | ||
| 2421 | if sub % 2 == 0 | ||
| 2422 | return sub | ||
| 2423 | nil | ||
| 2424 | ``` | ||
| 2425 | <YueDisplay> | ||
| 2426 | |||
| 2427 | ```yue | ||
| 2428 | findFirstEven = (list) -> | ||
| 2429 | for item in *list | ||
| 2430 | if type(item) == "table" | ||
| 2431 | for sub in *item | ||
| 2432 | if sub % 2 == 0 | ||
| 2433 | return sub | ||
| 2434 | nil | ||
| 2435 | ``` | ||
| 2436 | |||
| 2437 | </YueDisplay> | ||
| 2438 | |||
| 2439 | 唯一的区别在于:你可以将函数的返回值表达式提前写在 `->` 或 `=>` 前,用以指示该函数应隐式返回该表达式的值。这样即使在多层循环或条件判断的场景下,也无需编写尾行悬挂的返回表达式,逻辑结构会更加直观清晰。 | ||
| 2440 | |||
| 2441 | ### 命名变长参数 | ||
| 2442 | |||
| 2443 | 你可以使用 `(...t) ->` 语法来将变长参数自动存储到一个命名表中。这个表会包含所有传入的参数(包括 `nil` 值),并且会在表的 `n` 字段中存储实际传入的参数个数(包括 `nil` 值在内的个数)。 | ||
| 2444 | |||
| 2445 | ```yuescript | ||
| 2446 | f = (...t) -> | ||
| 2447 | print "参数个数:", t.n | ||
| 2448 | print "表长度:", #t | ||
| 2449 | for i = 1, t.n | ||
| 2450 | print t[i] | ||
| 2451 | |||
| 2452 | f 1, 2, 3 | ||
| 2453 | f "a", "b", "c", "d" | ||
| 2454 | f! | ||
| 2455 | |||
| 2456 | -- 处理包含 nil 的情况 | ||
| 2457 | process = (...args) -> | ||
| 2458 | sum = 0 | ||
| 2459 | for i = 1, args.n | ||
| 2460 | if args[i] != nil and type(args[i]) == "number" | ||
| 2461 | sum += args[i] | ||
| 2462 | sum | ||
| 2463 | |||
| 2464 | process 1, nil, 3, nil, 5 | ||
| 2465 | ``` | ||
| 2466 | <YueDisplay> | ||
| 2467 | |||
| 2468 | ```yue | ||
| 2469 | f = (...t) -> | ||
| 2470 | print "参数个数:", t.n | ||
| 2471 | print "表长度:", #t | ||
| 2472 | for i = 1, t.n | ||
| 2473 | print t[i] | ||
| 2474 | |||
| 2475 | f 1, 2, 3 | ||
| 2476 | f "a", "b", "c", "d" | ||
| 2477 | f! | ||
| 2478 | |||
| 2479 | -- 处理包含 nil 的情况 | ||
| 2480 | process = (...args) -> | ||
| 2481 | sum = 0 | ||
| 2482 | for i = 1, args.n | ||
| 2483 | if args[i] != nil and type(args[i]) == "number" | ||
| 2484 | sum += args[i] | ||
| 2485 | sum | ||
| 2486 | |||
| 2487 | process 1, nil, 3, nil, 5 | ||
| 2488 | ``` | ||
| 2489 | |||
| 2490 | </YueDisplay> | ||
| 2491 | |||
| 2492 | ## 反向回调 | ||
| 2493 | |||
| 2494 | 反向回调用于减少函数回调的嵌套。它们使用指向左侧的箭头,并且默认会被定义为传入后续函数调用的最后一个参数。它的语法大部分与常规箭头函数相同,只是它指向另一方向,并且后续的函数体不需要进行缩进。 | ||
| 2495 | |||
| 2496 | ```yuescript | ||
| 2497 | <- f | ||
| 2498 | print "hello" | ||
| 2499 | ``` | ||
| 2500 | <YueDisplay> | ||
| 2501 | |||
| 2502 | ```yue | ||
| 2503 | <- f | ||
| 2504 | print "hello" | ||
| 2505 | ``` | ||
| 2506 | |||
| 2507 | </YueDisplay> | ||
| 2508 | |||
| 2509 | 月之脚本也提供了粗箭头反向回调函数。 | ||
| 2510 | |||
| 2511 | ```yuescript | ||
| 2512 | <= f | ||
| 2513 | print @value | ||
| 2514 | ``` | ||
| 2515 | <YueDisplay> | ||
| 2516 | |||
| 2517 | ```yue | ||
| 2518 | <= f | ||
| 2519 | print @value | ||
| 2520 | ``` | ||
| 2521 | |||
| 2522 | </YueDisplay> | ||
| 2523 | |||
| 2524 | 你可以通过一个占位符指定回调函数的传参位置。 | ||
| 2525 | |||
| 2526 | ```yuescript | ||
| 2527 | (x) <- map _, [1, 2, 3] | ||
| 2528 | x * 2 | ||
| 2529 | ``` | ||
| 2530 | <YueDisplay> | ||
| 2531 | |||
| 2532 | ```yue | ||
| 2533 | (x) <- map _, [1, 2, 3] | ||
| 2534 | x * 2 | ||
| 2535 | ``` | ||
| 2536 | |||
| 2537 | </YueDisplay> | ||
| 2538 | |||
| 2539 | 如果你希望在反向回调处理后继续编写更多其它的代码,可以使用 do 语句将不属于反向回调的代码分隔开。对于非粗箭头函数的反向回调,回调返回值的括号也是可以省略的。 | ||
| 2540 | |||
| 2541 | ```yuescript | ||
| 2542 | result, msg = do | ||
| 2543 | data <- readAsync "文件名.txt" | ||
| 2544 | print data | ||
| 2545 | info <- processAsync data | ||
| 2546 | check info | ||
| 2547 | print result, msg | ||
| 2548 | ``` | ||
| 2549 | <YueDisplay> | ||
| 2550 | |||
| 2551 | ```yue | ||
| 2552 | result, msg = do | ||
| 2553 | data <- readAsync "文件名.txt" | ||
| 2554 | print data | ||
| 2555 | info <- processAsync data | ||
| 2556 | check info | ||
| 2557 | print result, msg | ||
| 2558 | ``` | ||
| 2559 | |||
| 2560 | </YueDisplay> | ||
| 2561 | |||
| 2562 | ## 表格字面量 | ||
| 2563 | |||
| 2564 | 和 Lua 一样,表格可以通过花括号进行定义。 | ||
| 2565 | |||
| 2566 | ```yuescript | ||
| 2567 | some_values = [1, 2, 3, 4] | ||
| 2568 | ``` | ||
| 2569 | <YueDisplay> | ||
| 2570 | |||
| 2571 | ```yue | ||
| 2572 | some_values = [1, 2, 3, 4] | ||
| 2573 | ``` | ||
| 2574 | |||
| 2575 | </YueDisplay> | ||
| 2576 | |||
| 2577 | 但与Lua不同的是,给表格中的键赋值是用 **:**(而不是 **=**)。 | ||
| 2578 | |||
| 2579 | ```yuescript | ||
| 2580 | some_values = { | ||
| 2581 | name: "Bill", | ||
| 2582 | age: 200, | ||
| 2583 | ["favorite food"]: "rice" | ||
| 2584 | } | ||
| 2585 | ``` | ||
| 2586 | <YueDisplay> | ||
| 2587 | |||
| 2588 | ```yue | ||
| 2589 | some_values = { | ||
| 2590 | name: "Bill", | ||
| 2591 | age: 200, | ||
| 2592 | ["favorite food"]: "rice" | ||
| 2593 | } | ||
| 2594 | ``` | ||
| 2595 | |||
| 2596 | </YueDisplay> | ||
| 2597 | |||
| 2598 | 如果只分配一个键值对的表格,可以省略花括号。 | ||
| 2599 | |||
| 2600 | ```yuescript | ||
| 2601 | profile = | ||
| 2602 | height: "4英尺", | ||
| 2603 | shoe_size: 13, | ||
| 2604 | favorite_foods: ["冰淇淋", "甜甜圈"] | ||
| 2605 | ``` | ||
| 2606 | <YueDisplay> | ||
| 2607 | |||
| 2608 | ```yue | ||
| 2609 | profile = | ||
| 2610 | height: "4英尺", | ||
| 2611 | shoe_size: 13, | ||
| 2612 | favorite_foods: ["冰淇淋", "甜甜圈"] | ||
| 2613 | ``` | ||
| 2614 | |||
| 2615 | </YueDisplay> | ||
| 2616 | |||
| 2617 | 可以使用换行符而不使用逗号(或两者都用)来分隔表格中的值: | ||
| 2618 | |||
| 2619 | ```yuescript | ||
| 2620 | values = { | ||
| 2621 | 1, 2, 3, 4 | ||
| 2622 | 5, 6, 7, 8 | ||
| 2623 | name: "超人" | ||
| 2624 | occupation: "打击犯罪" | ||
| 2625 | } | ||
| 2626 | ``` | ||
| 2627 | <YueDisplay> | ||
| 2628 | |||
| 2629 | ```yue | ||
| 2630 | values = { | ||
| 2631 | 1, 2, 3, 4 | ||
| 2632 | 5, 6, 7, 8 | ||
| 2633 | name: "超人" | ||
| 2634 | occupation: "打击犯罪" | ||
| 2635 | } | ||
| 2636 | ``` | ||
| 2637 | |||
| 2638 | </YueDisplay> | ||
| 2639 | |||
| 2640 | 创建单行表格字面量时,也可以省略花括号: | ||
| 2641 | |||
| 2642 | ```yuescript | ||
| 2643 | my_function dance: "探戈", partner: "无" | ||
| 2644 | |||
| 2645 | y = type: "狗", legs: 4, tails: 1 | ||
| 2646 | ``` | ||
| 2647 | <YueDisplay> | ||
| 2648 | |||
| 2649 | ```yue | ||
| 2650 | my_function dance: "探戈", partner: "无" | ||
| 2651 | |||
| 2652 | y = type: "狗", legs: 4, tails: 1 | ||
| 2653 | ``` | ||
| 2654 | |||
| 2655 | </YueDisplay> | ||
| 2656 | |||
| 2657 | 表格字面量的键可以使用 Lua 语言的关键字,而无需转义: | ||
| 2658 | |||
| 2659 | ```yuescript | ||
| 2660 | tbl = { | ||
| 2661 | do: "某事" | ||
| 2662 | end: "饥饿" | ||
| 2663 | } | ||
| 2664 | ``` | ||
| 2665 | <YueDisplay> | ||
| 2666 | |||
| 2667 | ```yue | ||
| 2668 | tbl = { | ||
| 2669 | do: "某事" | ||
| 2670 | end: "饥饿" | ||
| 2671 | } | ||
| 2672 | ``` | ||
| 2673 | |||
| 2674 | </YueDisplay> | ||
| 2675 | |||
| 2676 | 如果你要构造一个由变量组成的表,并希望键与变量名相同,那么可以使用 **:** 前缀操作符: | ||
| 2677 | |||
| 2678 | ```yuescript | ||
| 2679 | hair = "金色" | ||
| 2680 | height = 200 | ||
| 2681 | person = { :hair, :height, shoe_size: 40 } | ||
| 2682 | |||
| 2683 | print_table :hair, :height | ||
| 2684 | ``` | ||
| 2685 | <YueDisplay> | ||
| 2686 | |||
| 2687 | ```yue | ||
| 2688 | hair = "金色" | ||
| 2689 | height = 200 | ||
| 2690 | person = { :hair, :height, shoe_size: 40 } | ||
| 2691 | |||
| 2692 | print_table :hair, :height | ||
| 2693 | ``` | ||
| 2694 | |||
| 2695 | </YueDisplay> | ||
| 2696 | |||
| 2697 | 如果你希望表中字段的键是某个表达式的结果,那么可以用 **[ ]** 包裹它,就像在 Lua 中一样。如果键中有任何特殊字符,也可以直接使用字符串字面量作为键,省略方括号。 | ||
| 2698 | |||
| 2699 | ```yuescript | ||
| 2700 | t = { | ||
| 2701 | [1 + 2]: "你好" | ||
| 2702 | "你好 世界": true | ||
| 2703 | } | ||
| 2704 | ``` | ||
| 2705 | <YueDisplay> | ||
| 2706 | |||
| 2707 | ```yue | ||
| 2708 | t = { | ||
| 2709 | [1 + 2]: "你好" | ||
| 2710 | "你好 世界": true | ||
| 2711 | } | ||
| 2712 | ``` | ||
| 2713 | |||
| 2714 | </YueDisplay> | ||
| 2715 | |||
| 2716 | Lua 的表同时具有数组部分和哈希部分,但有时候你会希望在书写 Lua 表时,对 Lua 表做数组和哈希不同用法的语义区分。然后你可以用 **[ ]** 而不是 **{ }** 来编写表示数组的 Lua 表,并且不允许在数组 Lua 表中写入任何键值对。 | ||
| 2717 | |||
| 2718 | ```yuescript | ||
| 2719 | some_values = [ 1, 2, 3, 4 ] | ||
| 2720 | list_with_one_element = [ 1, ] | ||
| 2721 | ``` | ||
| 2722 | <YueDisplay> | ||
| 2723 | |||
| 2724 | ```yue | ||
| 2725 | some_values = [ 1, 2, 3, 4 ] | ||
| 2726 | list_with_one_element = [ 1, ] | ||
| 2727 | ``` | ||
| 2728 | |||
| 2729 | </YueDisplay> | ||
| 2730 | |||
| 2731 | ## 推导式 | ||
| 2732 | |||
| 2733 | 推导式为我们提供了一种便捷的语法,通过遍历现有对象并对其值应用表达式来构造出新的表格。月之脚本有两种推导式:列表推导式和表格推导式。它们最终都是产生 Lua 表格;列表推导式将值累积到类似数组的表格中,而表格推导式允许你在每次遍历时设置新表格的键和值。 | ||
| 2734 | |||
| 2735 | ### 列表推导式 | ||
| 2736 | |||
| 2737 | 以下操作创建了一个 items 表的副本,但所有包含的值都翻倍了。 | ||
| 2738 | |||
| 2739 | ```yuescript | ||
| 2740 | items = [1, 2, 3, 4] | ||
| 2741 | doubled = [item * 2 for i, item in ipairs items] | ||
| 2742 | ``` | ||
| 2743 | <YueDisplay> | ||
| 2744 | |||
| 2745 | ```yue | ||
| 2746 | items = [1, 2, 3, 4] | ||
| 2747 | doubled = [item * 2 for i, item in ipairs items] | ||
| 2748 | ``` | ||
| 2749 | |||
| 2750 | </YueDisplay> | ||
| 2751 | |||
| 2752 | 可以使用 `when` 子句筛选新表中包含的项目: | ||
| 2753 | |||
| 2754 | ```yuescript | ||
| 2755 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 2756 | ``` | ||
| 2757 | <YueDisplay> | ||
| 2758 | |||
| 2759 | ```yue | ||
| 2760 | slice = [item for i, item in ipairs items when i > 1 and i < 3] | ||
| 2761 | ``` | ||
| 2762 | |||
| 2763 | </YueDisplay> | ||
| 2764 | |||
| 2765 | 因为我们常常需要迭代数值索引表的值,所以引入了 **\*** 操作符来做语法简化。doubled 示例可以重写为: | ||
| 2766 | |||
| 2767 | ```yuescript | ||
| 2768 | doubled = [item * 2 for item in *items] | ||
| 2769 | ``` | ||
| 2770 | <YueDisplay> | ||
| 2771 | |||
| 2772 | ```yue | ||
| 2773 | doubled = [item * 2 for item in *items] | ||
| 2774 | ``` | ||
| 2775 | |||
| 2776 | </YueDisplay> | ||
| 2777 | |||
| 2778 | 在列表推导式中,你还可以使用展开操作符 `...` 来实现对列表嵌套层级进行扁平化的处理: | ||
| 2779 | |||
| 2780 | ```yuescript | ||
| 2781 | data = | ||
| 2782 | a: [1, 2, 3] | ||
| 2783 | b: [4, 5, 6] | ||
| 2784 | |||
| 2785 | flat = [...v for k,v in pairs data] | ||
| 2786 | -- flat 现在为 [1, 2, 3, 4, 5, 6] | ||
| 2787 | ``` | ||
| 2788 | <YueDisplay> | ||
| 2789 | |||
| 2790 | ```yue | ||
| 2791 | data = | ||
| 2792 | a: [1, 2, 3] | ||
| 2793 | b: [4, 5, 6] | ||
| 2794 | |||
| 2795 | flat = [...v for k,v in pairs data] | ||
| 2796 | -- flat 现在为 [1, 2, 3, 4, 5, 6] | ||
| 2797 | ``` | ||
| 2798 | |||
| 2799 | </YueDisplay> | ||
| 2800 | |||
| 2801 | for 和 when 子句可以根据需要进行链式操作。唯一的要求是推导式中至少要有一个 for 子句。 | ||
| 2802 | |||
| 2803 | 使用多个 for 子句与使用多重循环的效果相同: | ||
| 2804 | |||
| 2805 | ```yuescript | ||
| 2806 | x_coords = [4, 5, 6, 7] | ||
| 2807 | y_coords = [9, 2, 3] | ||
| 2808 | |||
| 2809 | points = [ [x, y] for x in *x_coords \ | ||
| 2810 | for y in *y_coords] | ||
| 2811 | ``` | ||
| 2812 | <YueDisplay> | ||
| 2813 | |||
| 2814 | ```yue | ||
| 2815 | x_coords = [4, 5, 6, 7] | ||
| 2816 | y_coords = [9, 2, 3] | ||
| 2817 | |||
| 2818 | points = [ [x, y] for x in *x_coords \ | ||
| 2819 | for y in *y_coords] | ||
| 2820 | ``` | ||
| 2821 | |||
| 2822 | </YueDisplay> | ||
| 2823 | |||
| 2824 | 在推导式中也可以使用简单的数值 for 循环: | ||
| 2825 | |||
| 2826 | ```yuescript | ||
| 2827 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 2828 | ``` | ||
| 2829 | <YueDisplay> | ||
| 2830 | |||
| 2831 | ```yue | ||
| 2832 | evens = [i for i = 1, 100 when i % 2 == 0] | ||
| 2833 | ``` | ||
| 2834 | |||
| 2835 | </YueDisplay> | ||
| 2836 | |||
| 2837 | ### 表格推导式 | ||
| 2838 | |||
| 2839 | 表格推导式和列表推导式的语法非常相似,只是要使用 **{** 和 **}** 并从每次迭代中取两个值。 | ||
| 2840 | |||
| 2841 | 以下示例生成了表格 thing 的副本: | ||
| 2842 | |||
| 2843 | ```yuescript | ||
| 2844 | thing = { | ||
| 2845 | color: "red" | ||
| 2846 | name: "fast" | ||
| 2847 | width: 123 | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | thing_copy = {k, v for k, v in pairs thing} | ||
| 2851 | ``` | ||
| 2852 | <YueDisplay> | ||
| 2853 | |||
| 2854 | ```yue | ||
| 2855 | thing = { | ||
| 2856 | color: "red" | ||
| 2857 | name: "fast" | ||
| 2858 | width: 123 | ||
| 2859 | } | ||
| 2860 | |||
| 2861 | thing_copy = {k, v for k, v in pairs thing} | ||
| 2862 | ``` | ||
| 2863 | |||
| 2864 | </YueDisplay> | ||
| 2865 | |||
| 2866 | ```yuescript | ||
| 2867 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 2868 | ``` | ||
| 2869 | <YueDisplay> | ||
| 2870 | |||
| 2871 | ```yue | ||
| 2872 | no_color = {k, v for k, v in pairs thing when k != "color"} | ||
| 2873 | ``` | ||
| 2874 | |||
| 2875 | </YueDisplay> | ||
| 2876 | |||
| 2877 | **\*** 操作符在表格推导式中能使用。在下面的例子里,我们为几个数字创建了一个平方根查找表。 | ||
| 2878 | |||
| 2879 | ```yuescript | ||
| 2880 | numbers = [1, 2, 3, 4] | ||
| 2881 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 2882 | ``` | ||
| 2883 | <YueDisplay> | ||
| 2884 | |||
| 2885 | ```yue | ||
| 2886 | numbers = [1, 2, 3, 4] | ||
| 2887 | sqrts = {i, math.sqrt i for i in *numbers} | ||
| 2888 | ``` | ||
| 2889 | |||
| 2890 | </YueDisplay> | ||
| 2891 | |||
| 2892 | 表格推导式中的键值元组也可以来自单个表达式,在这种情况下,表达式在计算后应返回两个值。第一个用作键,第二个用作值: | ||
| 2893 | |||
| 2894 | 在下面的示例中,我们将一些数组转换为一个表,其中每个数组里的第一项是键,第二项是值。 | ||
| 2895 | |||
| 2896 | ```yuescript | ||
| 2897 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 2898 | tbl = {unpack tuple for tuple in *tuples} | ||
| 2899 | ``` | ||
| 2900 | <YueDisplay> | ||
| 2901 | |||
| 2902 | ```yue | ||
| 2903 | tuples = [ ["hello", "world"], ["foo", "bar"]] | ||
| 2904 | tbl = {unpack tuple for tuple in *tuples} | ||
| 2905 | ``` | ||
| 2906 | |||
| 2907 | </YueDisplay> | ||
| 2908 | |||
| 2909 | ### 切片 | ||
| 2910 | |||
| 2911 | 当使用 **\*** 操作符时,月之脚本还提供了一种特殊的语法来限制要遍历的列表范围。这个语法也相当于在 for 循环中设置迭代边界和步长。 | ||
| 2912 | |||
| 2913 | 下面的案例中,我们在切片中设置最小和最大边界,取索引在 1 到 5 之间(包括 1 和 5)的所有项目: | ||
| 2914 | |||
| 2915 | ```yuescript | ||
| 2916 | slice = [item for item in *items[1, 5]] | ||
| 2917 | ``` | ||
| 2918 | <YueDisplay> | ||
| 2919 | |||
| 2920 | ```yue | ||
| 2921 | slice = [item for item in *items[1, 5]] | ||
| 2922 | ``` | ||
| 2923 | |||
| 2924 | </YueDisplay> | ||
| 2925 | |||
| 2926 | 切片的任意参数都可以省略,并会使用默认值。在如下示例中,如果省略了最大索引边界,它默认为表的长度。使下面的代码取除第一个元素之外的所有元素: | ||
| 2927 | |||
| 2928 | ```yuescript | ||
| 2929 | slice = [item for item in *items[2,]] | ||
| 2930 | ``` | ||
| 2931 | <YueDisplay> | ||
| 2932 | |||
| 2933 | ```yue | ||
| 2934 | slice = [item for item in *items[2,]] | ||
| 2935 | ``` | ||
| 2936 | |||
| 2937 | </YueDisplay> | ||
| 2938 | |||
| 2939 | 如果省略了最小边界,便默认会设置为 1。这里我们只提供一个步长,并留下其他边界为空。这样会使得代码取出所有奇数索引的项目:(1, 3, 5, …) | ||
| 2940 | |||
| 2941 | ```yuescript | ||
| 2942 | slice = [item for item in *items[,,2]] | ||
| 2943 | ``` | ||
| 2944 | <YueDisplay> | ||
| 2945 | |||
| 2946 | |||
| 2947 | ```yue | ||
| 2948 | slice = [item for item in *items[,,2]] | ||
| 2949 | ``` | ||
| 2950 | |||
| 2951 | </YueDisplay> | ||
| 2952 | |||
| 2953 | 最小和最大边界都可以是负数,使用负数意味着边界是从表的末尾开始计算的。 | ||
| 2954 | |||
| 2955 | ```yuescript | ||
| 2956 | -- 取最后4个元素 | ||
| 2957 | slice = [item for item in *items[-4,-1]] | ||
| 2958 | ``` | ||
| 2959 | <YueDisplay> | ||
| 2960 | |||
| 2961 | ```yue | ||
| 2962 | -- 取最后4个元素 | ||
| 2963 | slice = [item for item in *items[-4,-1]] | ||
| 2964 | ``` | ||
| 2965 | |||
| 2966 | </YueDisplay> | ||
| 2967 | |||
| 2968 | 切片的步长也可以是负数,这意味着元素会以相反的顺序被取出。 | ||
| 2969 | |||
| 2970 | ```yuescript | ||
| 2971 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 2972 | ``` | ||
| 2973 | <YueDisplay> | ||
| 2974 | |||
| 2975 | ```yue | ||
| 2976 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
| 2977 | ``` | ||
| 2978 | |||
| 2979 | </YueDisplay> | ||
| 2980 | |||
| 2981 | #### 切片表达式 | ||
| 2982 | |||
| 2983 | 切片也可以作为表达式来使用。可以用于获取一个表包含的子列表。 | ||
| 2984 | |||
| 2985 | ```yuescript | ||
| 2986 | -- 取第2和第4个元素作为新的列表 | ||
| 2987 | sub_list = items[2, 4] | ||
| 2988 | ``` | ||
| 2989 | <YueDisplay> | ||
| 2990 | |||
| 2991 | ```yue | ||
| 2992 | -- 取第2和第4个元素作为新的列表 | ||
| 2993 | sub_list = items[2, 4] | ||
| 2994 | ``` | ||
| 2995 | |||
| 2996 | </YueDisplay> | ||
| 2997 | |||
| 2998 | ## for 循环 | ||
| 2999 | |||
| 3000 | Lua 中有两种 for 循环形式,数字型和通用型: | ||
| 3001 | |||
| 3002 | ```yuescript | ||
| 3003 | for i = 10, 20 | ||
| 3004 | print i | ||
| 3005 | |||
| 3006 | for k = 1, 15, 2 -- 提供了一个遍历的步长 | ||
| 3007 | print k | ||
| 3008 | |||
| 3009 | for key, value in pairs object | ||
| 3010 | print key, value | ||
| 3011 | ``` | ||
| 3012 | <YueDisplay> | ||
| 3013 | |||
| 3014 | ```yue | ||
| 3015 | for i = 10, 20 | ||
| 3016 | print i | ||
| 3017 | |||
| 3018 | for k = 1, 15, 2 -- 提供了一个遍历的步长 | ||
| 3019 | print k | ||
| 3020 | |||
| 3021 | for key, value in pairs object | ||
| 3022 | print key, value | ||
| 3023 | ``` | ||
| 3024 | |||
| 3025 | </YueDisplay> | ||
| 3026 | |||
| 3027 | 可以使用切片和 **\*** 操作符,就像在列表推导中一样: | ||
| 3028 | |||
| 3029 | ```yuescript | ||
| 3030 | for item in *items[2, 4] | ||
| 3031 | print item | ||
| 3032 | ``` | ||
| 3033 | <YueDisplay> | ||
| 3034 | |||
| 3035 | ```yue | ||
| 3036 | for item in *items[2, 4] | ||
| 3037 | print item | ||
| 3038 | ``` | ||
| 3039 | |||
| 3040 | </YueDisplay> | ||
| 3041 | |||
| 3042 | 当代码语句只有一行时,循环语句也都可以写作更短的语法: | ||
| 3043 | |||
| 3044 | ```yuescript | ||
| 3045 | for item in *items do print item | ||
| 3046 | |||
| 3047 | for j = 1, 10, 3 do print j | ||
| 3048 | ``` | ||
| 3049 | <YueDisplay> | ||
| 3050 | |||
| 3051 | ```yue | ||
| 3052 | for item in *items do print item | ||
| 3053 | |||
| 3054 | for j = 1, 10, 3 do print j | ||
| 3055 | ``` | ||
| 3056 | |||
| 3057 | </YueDisplay> | ||
| 3058 | |||
| 3059 | for 循环也可以用作表达式。for 循环主体中的最后一条语句会被强制转换为一个返回值的表达式,并会将表达式计算结果的值追加到一个作为结果的数组表中。 | ||
| 3060 | |||
| 3061 | 将每个偶数加倍: | ||
| 3062 | |||
| 3063 | ```yuescript | ||
| 3064 | doubled_evens = for i = 1, 20 | ||
| 3065 | if i % 2 == 0 | ||
| 3066 | i * 2 | ||
| 3067 | else | ||
| 3068 | i | ||
| 3069 | ``` | ||
| 3070 | <YueDisplay> | ||
| 3071 | |||
| 3072 | ```yue | ||
| 3073 | doubled_evens = for i = 1, 20 | ||
| 3074 | if i % 2 == 0 | ||
| 3075 | i * 2 | ||
| 3076 | else | ||
| 3077 | i | ||
| 3078 | ``` | ||
| 3079 | |||
| 3080 | </YueDisplay> | ||
| 3081 | |||
| 3082 | 此外,for 循环还支持带返回值的 break 语句,这样循环本身就可以作为一个表达式,在满足条件时提前退出并返回有意义的结果。 | ||
| 3083 | |||
| 3084 | 例如,查找第一个大于 10 的数字: | ||
| 3085 | |||
| 3086 | ```yuescript | ||
| 3087 | first_large = for n in *numbers | ||
| 3088 | break n if n > 10 | ||
| 3089 | ``` | ||
| 3090 | <YueDisplay> | ||
| 3091 | |||
| 3092 | ```yue | ||
| 3093 | first_large = for n in *numbers | ||
| 3094 | break n if n > 10 | ||
| 3095 | ``` | ||
| 3096 | |||
| 3097 | </YueDisplay> | ||
| 3098 | |||
| 3099 | 你还可以结合 for 循环表达式与 continue 语句来过滤值。 | ||
| 3100 | |||
| 3101 | 注意出现在函数体末尾的 for 循环,不会被当作是一个表达式并将循环结果累积到一个列表中作为返回值(相反,函数将返回 nil)。如果要函数末尾的循环转换为列表表达式,可以显式地使用返回语句加 for 循环表达式。 | ||
| 3102 | |||
| 3103 | ```yuescript | ||
| 3104 | func_a = -> for i = 1, 10 do print i | ||
| 3105 | func_b = -> return for i = 1, 10 do i | ||
| 3106 | |||
| 3107 | print func_a! -- 打印 nil | ||
| 3108 | print func_b! -- 打印 table 对象 | ||
| 3109 | ``` | ||
| 3110 | <YueDisplay> | ||
| 3111 | |||
| 3112 | ```yue | ||
| 3113 | func_a = -> for i = 1, 10 do print i | ||
| 3114 | func_b = -> return for i = 1, 10 do i | ||
| 3115 | |||
| 3116 | print func_a! -- 打印 nil | ||
| 3117 | print func_b! -- 打印 table 对象 | ||
| 3118 | ``` | ||
| 3119 | |||
| 3120 | </YueDisplay> | ||
| 3121 | |||
| 3122 | 这样做是为了避免在不需要返回循环结果的函数,创建无效的返回值表格。 | ||
| 3123 | |||
| 3124 | ## repeat 循环 | ||
| 3125 | |||
| 3126 | repeat 循环是从 Lua 语言中搬过来的相似语法: | ||
| 3127 | |||
| 3128 | ```yuescript | ||
| 3129 | i = 10 | ||
| 3130 | repeat | ||
| 3131 | print i | ||
| 3132 | i -= 1 | ||
| 3133 | until i == 0 | ||
| 3134 | ``` | ||
| 3135 | <YueDisplay> | ||
| 3136 | |||
| 3137 | ```yue | ||
| 3138 | i = 10 | ||
| 3139 | repeat | ||
| 3140 | print i | ||
| 3141 | i -= 1 | ||
| 3142 | until i == 0 | ||
| 3143 | ``` | ||
| 3144 | |||
| 3145 | </YueDisplay> | ||
| 3146 | |||
| 3147 | ## while 循环 | ||
| 3148 | |||
| 3149 | 在月之脚本中的 while 循环有四种写法: | ||
| 3150 | |||
| 3151 | ```yuescript | ||
| 3152 | i = 10 | ||
| 3153 | while i > 0 | ||
| 3154 | print i | ||
| 3155 | i -= 1 | ||
| 3156 | |||
| 3157 | while running == true do my_function! | ||
| 3158 | ``` | ||
| 3159 | <YueDisplay> | ||
| 3160 | |||
| 3161 | ```yue | ||
| 3162 | i = 10 | ||
| 3163 | while i > 0 | ||
| 3164 | print i | ||
| 3165 | i -= 1 | ||
| 3166 | |||
| 3167 | while running == true do my_function! | ||
| 3168 | ``` | ||
| 3169 | |||
| 3170 | </YueDisplay> | ||
| 3171 | |||
| 3172 | ```yuescript | ||
| 3173 | i = 10 | ||
| 3174 | until i == 0 | ||
| 3175 | print i | ||
| 3176 | i -= 1 | ||
| 3177 | |||
| 3178 | until running == false do my_function! | ||
| 3179 | ``` | ||
| 3180 | <YueDisplay> | ||
| 3181 | |||
| 3182 | ```yue | ||
| 3183 | i = 10 | ||
| 3184 | until i == 0 | ||
| 3185 | print i | ||
| 3186 | i -= 1 | ||
| 3187 | until running == false do my_function! | ||
| 3188 | ``` | ||
| 3189 | |||
| 3190 | </YueDisplay> | ||
| 3191 | |||
| 3192 | 像 for 循环的语法一样,while 循环也可以作为一个表达式使用。为了使函数返回 while 循环的累积列表值,必须明确使用返回语句返回 while 循环表达式。 | ||
| 3193 | |||
| 3194 | ## 继续 | ||
| 3195 | |||
| 3196 | 继续语句可以用来跳出当前的循环迭代。 | ||
| 3197 | |||
| 3198 | ```yuescript | ||
| 3199 | i = 0 | ||
| 3200 | while i < 10 | ||
| 3201 | i += 1 | ||
| 3202 | continue if i % 2 == 0 | ||
| 3203 | print i | ||
| 3204 | ``` | ||
| 3205 | <YueDisplay> | ||
| 3206 | |||
| 3207 | ```yue | ||
| 3208 | i = 0 | ||
| 3209 | while i < 10 | ||
| 3210 | i += 1 | ||
| 3211 | continue if i % 2 == 0 | ||
| 3212 | print i | ||
| 3213 | ``` | ||
| 3214 | |||
| 3215 | </YueDisplay> | ||
| 3216 | |||
| 3217 | 继续语句也可以与各种循环表达式一起使用,以防止当前的循环迭代结果累积到结果列表中。以下示例将数组表过滤为仅包含偶数的数组: | ||
| 3218 | |||
| 3219 | ```yuescript | ||
| 3220 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 3221 | odds = for x in *my_numbers | ||
| 3222 | continue if x % 2 == 1 | ||
| 3223 | x | ||
| 3224 | ``` | ||
| 3225 | <YueDisplay> | ||
| 3226 | |||
| 3227 | ```yue | ||
| 3228 | my_numbers = [1, 2, 3, 4, 5, 6] | ||
| 3229 | odds = for x in *my_numbers | ||
| 3230 | continue if x % 2 == 1 | ||
| 3231 | x | ||
| 3232 | ``` | ||
| 3233 | |||
| 3234 | </YueDisplay> | ||
| 3235 | |||
| 3236 | ## 条件语句 | ||
| 3237 | |||
| 3238 | ```yuescript | ||
| 3239 | have_coins = false | ||
| 3240 | if have_coins | ||
| 3241 | print "有硬币" | ||
| 3242 | else | ||
| 3243 | print "没有硬币" | ||
| 3244 | ``` | ||
| 3245 | <YueDisplay> | ||
| 3246 | |||
| 3247 | ```yue | ||
| 3248 | have_coins = false | ||
| 3249 | if have_coins | ||
| 3250 | print "有硬币" | ||
| 3251 | else | ||
| 3252 | print "没有硬币" | ||
| 3253 | ``` | ||
| 3254 | |||
| 3255 | </YueDisplay> | ||
| 3256 | |||
| 3257 | 对于简单的语句,也可以使用简短的语法: | ||
| 3258 | |||
| 3259 | ```yuescript | ||
| 3260 | have_coins = false | ||
| 3261 | if have_coins then print "有硬币" else print "没有硬币" | ||
| 3262 | ``` | ||
| 3263 | <YueDisplay> | ||
| 3264 | |||
| 3265 | ```yue | ||
| 3266 | have_coins = false | ||
| 3267 | if have_coins then print "有硬币" else print "没有硬币" | ||
| 3268 | ``` | ||
| 3269 | |||
| 3270 | </YueDisplay> | ||
| 3271 | |||
| 3272 | 因为if语句可以用作表达式,所以也可以这样写: | ||
| 3273 | |||
| 3274 | ```yuescript | ||
| 3275 | have_coins = false | ||
| 3276 | print if have_coins then "有硬币" else "没有硬币" | ||
| 3277 | ``` | ||
| 3278 | <YueDisplay> | ||
| 3279 | |||
| 3280 | ```yue | ||
| 3281 | have_coins = false | ||
| 3282 | print if have_coins then "有硬币" else "没有硬币" | ||
| 3283 | ``` | ||
| 3284 | |||
| 3285 | </YueDisplay> | ||
| 3286 | |||
| 3287 | 条件语句也可以作为表达式用在返回语句和赋值语句中: | ||
| 3288 | |||
| 3289 | ```yuescript | ||
| 3290 | is_tall = (name) -> | ||
| 3291 | if name == "Rob" | ||
| 3292 | true | ||
| 3293 | else | ||
| 3294 | false | ||
| 3295 | |||
| 3296 | message = if is_tall "Rob" | ||
| 3297 | "我很高" | ||
| 3298 | else | ||
| 3299 | "我不是很高" | ||
| 3300 | |||
| 3301 | print message -- 打印: 我很高 | ||
| 3302 | ``` | ||
| 3303 | <YueDisplay> | ||
| 3304 | |||
| 3305 | ```yue | ||
| 3306 | is_tall = (name) -> | ||
| 3307 | if name == "Rob" | ||
| 3308 | true | ||
| 3309 | else | ||
| 3310 | false | ||
| 3311 | |||
| 3312 | message = if is_tall "Rob" | ||
| 3313 | "我很高" | ||
| 3314 | else | ||
| 3315 | "我不是很高" | ||
| 3316 | |||
| 3317 | print message -- 打印: 我很高 | ||
| 3318 | ``` | ||
| 3319 | |||
| 3320 | </YueDisplay> | ||
| 3321 | |||
| 3322 | if 的反义词是 unless(相当于 if not,正如“如果”对应“除非”): | ||
| 3323 | |||
| 3324 | ```yuescript | ||
| 3325 | unless os.date("%A") == "Monday" | ||
| 3326 | print "今天不是星期一!" | ||
| 3327 | ``` | ||
| 3328 | <YueDisplay> | ||
| 3329 | |||
| 3330 | |||
| 3331 | ```yue | ||
| 3332 | unless os.date("%A") == "Monday" | ||
| 3333 | print "今天不是星期一!" | ||
| 3334 | ``` | ||
| 3335 | |||
| 3336 | </YueDisplay> | ||
| 3337 | |||
| 3338 | ```yuescript | ||
| 3339 | print "你真幸运!" unless math.random! > 0.1 | ||
| 3340 | ``` | ||
| 3341 | <YueDisplay> | ||
| 3342 | |||
| 3343 | ```yue | ||
| 3344 | print "你真幸运!" unless math.random! > 0.1 | ||
| 3345 | ``` | ||
| 3346 | |||
| 3347 | </YueDisplay> | ||
| 3348 | |||
| 3349 | ### 范围表达式 | ||
| 3350 | |||
| 3351 | 你可以使用范围表达式来编写进行范围检查的代码。 | ||
| 3352 | |||
| 3353 | ```yuescript | ||
| 3354 | a = 5 | ||
| 3355 | |||
| 3356 | if a in [1, 3, 5, 7] | ||
| 3357 | print "检查离散值的相等性" | ||
| 3358 | |||
| 3359 | if a in list | ||
| 3360 | print "检查`a`是否在列表中" | ||
| 3361 | ``` | ||
| 3362 | <YueDisplay> | ||
| 3363 | |||
| 3364 | ```yue | ||
| 3365 | a = 5 | ||
| 3366 | |||
| 3367 | if a in [1, 3, 5, 7] | ||
| 3368 | print "检查离散值的相等性" | ||
| 3369 | |||
| 3370 | if a in list | ||
| 3371 | print "检查`a`是否在列表中" | ||
| 3372 | ``` | ||
| 3373 | |||
| 3374 | </YueDisplay> | ||
| 3375 | |||
| 3376 | ```yuescript | ||
| 3377 | print "你很幸运!" unless math.random! > 0.1 | ||
| 3378 | ``` | ||
| 3379 | <YueDisplay> | ||
| 3380 | |||
| 3381 | ```yue | ||
| 3382 | print "你很幸运!" unless math.random! > 0.1 | ||
| 3383 | ``` | ||
| 3384 | |||
| 3385 | </YueDisplay> | ||
| 3386 | |||
| 3387 | ## 代码行修饰符 | ||
| 3388 | |||
| 3389 | 为了方便编写代码,循环语句和 if 语句可以应用于单行代码语句的末尾: | ||
| 3390 | |||
| 3391 | ```yuescript | ||
| 3392 | print "你好,世界" if name == "Rob" | ||
| 3393 | ``` | ||
| 3394 | <YueDisplay> | ||
| 3395 | |||
| 3396 | ```yue | ||
| 3397 | print "你好,世界" if name == "Rob" | ||
| 3398 | ``` | ||
| 3399 | |||
| 3400 | </YueDisplay> | ||
| 3401 | |||
| 3402 | 修饰 for 循环的示例: | ||
| 3403 | |||
| 3404 | ```yuescript | ||
| 3405 | print "项目: ", item for item in *items | ||
| 3406 | ``` | ||
| 3407 | <YueDisplay> | ||
| 3408 | |||
| 3409 | ```yue | ||
| 3410 | print "项目: ", item for item in *items | ||
| 3411 | ``` | ||
| 3412 | |||
| 3413 | </YueDisplay> | ||
| 3414 | |||
| 3415 | 修饰 while 循环的示例: | ||
| 3416 | |||
| 3417 | ```yuescript | ||
| 3418 | game\update! while game\isRunning! | ||
| 3419 | |||
| 3420 | reader\parse_line! until reader\eof! | ||
| 3421 | ``` | ||
| 3422 | <YueDisplay> | ||
| 3423 | |||
| 3424 | ```yue | ||
| 3425 | game\update! while game\isRunning! | ||
| 3426 | |||
| 3427 | reader\parse_line! until reader\eof! | ||
| 3428 | ``` | ||
| 3429 | |||
| 3430 | </YueDisplay> | ||
| 3431 | |||
| 3432 | ## switch 语句 | ||
| 3433 | |||
| 3434 | switch 语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和 if 语句一样,switch 语句在最后可以接一个 else 代码块来处理没有匹配的情况。在生成的 Lua 代码中,进行比较是使用 == 操作符完成的。switch 语句中也可以使用赋值表达式来储存临时变量值。 | ||
| 3435 | |||
| 3436 | ```yuescript | ||
| 3437 | switch name := "Dan" | ||
| 3438 | when "Robert" | ||
| 3439 | print "你是Robert" | ||
| 3440 | when "Dan", "Daniel" | ||
| 3441 | print "你的名字是Dan" | ||
| 3442 | else | ||
| 3443 | print "我不认识你,你的名字是#{name}" | ||
| 3444 | ``` | ||
| 3445 | <YueDisplay> | ||
| 3446 | |||
| 3447 | ```yue | ||
| 3448 | switch name := "Dan" | ||
| 3449 | when "Robert" | ||
| 3450 | print "你是Robert" | ||
| 3451 | when "Dan", "Daniel" | ||
| 3452 | print "你的名字是Dan" | ||
| 3453 | else | ||
| 3454 | print "我不认识你,你的名字是#{name}" | ||
| 3455 | ``` | ||
| 3456 | |||
| 3457 | </YueDisplay> | ||
| 3458 | |||
| 3459 | switch 语句的 when 子句中可以通过使用逗号分隔的列表来匹配多个值。 | ||
| 3460 | |||
| 3461 | switch 语句也可以作为表达式使用,下面我们可以将 switch 语句返回的结果分配给一个变量: | ||
| 3462 | |||
| 3463 | ```yuescript | ||
| 3464 | b = 1 | ||
| 3465 | next_number = switch b | ||
| 3466 | when 1 | ||
| 3467 | 2 | ||
| 3468 | when 2 | ||
| 3469 | 3 | ||
| 3470 | else | ||
| 3471 | error "数字数得太大了!" | ||
| 3472 | ``` | ||
| 3473 | <YueDisplay> | ||
| 3474 | |||
| 3475 | ```yue | ||
| 3476 | b = 1 | ||
| 3477 | next_number = switch b | ||
| 3478 | when 1 | ||
| 3479 | 2 | ||
| 3480 | when 2 | ||
| 3481 | 3 | ||
| 3482 | else | ||
| 3483 | error "数字数得太大了!" | ||
| 3484 | ``` | ||
| 3485 | |||
| 3486 | </YueDisplay> | ||
| 3487 | |||
| 3488 | 我们可以使用 then 关键字在 when 子句的同一行上编写处理代码。else 代码块的后续代码中要写在同一行上不需要额外的关键字。 | ||
| 3489 | |||
| 3490 | ```yuescript | ||
| 3491 | msg = switch math.random(1, 5) | ||
| 3492 | when 1 then "你很幸运" | ||
| 3493 | when 2 then "你差点很幸运" | ||
| 3494 | else "不太幸运" | ||
| 3495 | ``` | ||
| 3496 | <YueDisplay> | ||
| 3497 | |||
| 3498 | ```yue | ||
| 3499 | msg = switch math.random(1, 5) | ||
| 3500 | when 1 then "你很幸运" | ||
| 3501 | when 2 then "你差点很幸运" | ||
| 3502 | else "不太幸运" | ||
| 3503 | ``` | ||
| 3504 | |||
| 3505 | </YueDisplay> | ||
| 3506 | |||
| 3507 | 如果在编写 switch 语句时希望少写一个缩进,那么你可以把第一个 when 子句放在 switch 开始语句的第一行,然后后续的子语句就都可以都少写一个缩进。 | ||
| 3508 | |||
| 3509 | ```yuescript | ||
| 3510 | switch math.random(1, 5) | ||
| 3511 | when 1 | ||
| 3512 | print "你很幸运" -- 两个缩进级别 | ||
| 3513 | else | ||
| 3514 | print "不太幸运" | ||
| 3515 | |||
| 3516 | switch math.random(1, 5) when 1 | ||
| 3517 | print "你很幸运" -- 一个缩进级别 | ||
| 3518 | else | ||
| 3519 | print "不太幸运" | ||
| 3520 | ``` | ||
| 3521 | <YueDisplay> | ||
| 3522 | |||
| 3523 | ```yue | ||
| 3524 | switch math.random(1, 5) | ||
| 3525 | when 1 | ||
| 3526 | print "你很幸运" -- 两个缩进级别 | ||
| 3527 | else | ||
| 3528 | print "不太幸运" | ||
| 3529 | |||
| 3530 | switch math.random(1, 5) when 1 | ||
| 3531 | print "你很幸运" -- 一个缩进级别 | ||
| 3532 | else | ||
| 3533 | print "不太幸运" | ||
| 3534 | ``` | ||
| 3535 | |||
| 3536 | </YueDisplay> | ||
| 3537 | |||
| 3538 | 值得注意的是,在生成 Lua 代码时,我们要做检查的目标变量会放在 == 表达式的右侧。当你希望给 when 子句的比较对象定义一个 \_\_eq 元方法来重载判断逻辑时,可能会有用。 | ||
| 3539 | |||
| 3540 | ### 表格匹配 | ||
| 3541 | |||
| 3542 | 在 switch 的 when 子句中,如果期待检查目标是一个表格,且可以通过特定的结构进行解构并获得非 nil 值,那么你可以尝试使用表格匹配的语法。 | ||
| 3543 | |||
| 3544 | ```yuescript | ||
| 3545 | items = | ||
| 3546 | * x: 100 | ||
| 3547 | y: 200 | ||
| 3548 | * width: 300 | ||
| 3549 | height: 400 | ||
| 3550 | |||
| 3551 | for item in *items | ||
| 3552 | switch item | ||
| 3553 | when :x, :y | ||
| 3554 | print "Vec2 #{x}, #{y}" | ||
| 3555 | when :width, :height | ||
| 3556 | print "尺寸 #{width}, #{height}" | ||
| 3557 | ``` | ||
| 3558 | <YueDisplay> | ||
| 3559 | |||
| 3560 | ```yue | ||
| 3561 | items = | ||
| 3562 | * x: 100 | ||
| 3563 | y: 200 | ||
| 3564 | * width: 300 | ||
| 3565 | height: 400 | ||
| 3566 | |||
| 3567 | for item in *items | ||
| 3568 | switch item | ||
| 3569 | when :x, :y | ||
| 3570 | print "Vec2 #{x}, #{y}" | ||
| 3571 | when :width, :height | ||
| 3572 | print "尺寸 #{width}, #{height}" | ||
| 3573 | ``` | ||
| 3574 | |||
| 3575 | </YueDisplay> | ||
| 3576 | |||
| 3577 | 你可以使用默认值来选择性地解构表格的某些字段。 | ||
| 3578 | |||
| 3579 | ```yuescript | ||
| 3580 | item = {} | ||
| 3581 | |||
| 3582 | {pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos') | ||
| 3583 | |||
| 3584 | switch item | ||
| 3585 | when {pos: {:x = 50, :y = 200}} | ||
| 3586 | print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过 | ||
| 3587 | ``` | ||
| 3588 | <YueDisplay> | ||
| 3589 | |||
| 3590 | ```yue | ||
| 3591 | item = {} | ||
| 3592 | |||
| 3593 | {pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos') | ||
| 3594 | |||
| 3595 | switch item | ||
| 3596 | when {pos: {:x = 50, :y = 200}} | ||
| 3597 | print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过 | ||
| 3598 | ``` | ||
| 3599 | |||
| 3600 | </YueDisplay> | ||
| 3601 | |||
| 3602 | 你也可以匹配数组元素、表格字段,甚至使用数组或表格字面量来匹配嵌套的结构。 | ||
| 3603 | |||
| 3604 | 匹配数组元素。 | ||
| 3605 | |||
| 3606 | ```yuescript | ||
| 3607 | switch tb | ||
| 3608 | when [1, 2, 3] | ||
| 3609 | print "1, 2, 3" | ||
| 3610 | when [1, b, 3] | ||
| 3611 | print "1, #{b}, 3" | ||
| 3612 | when [1, 2, b = 3] -- 变量b有默认值 | ||
| 3613 | print "1, 2, #{b}" | ||
| 3614 | ``` | ||
| 3615 | <YueDisplay> | ||
| 3616 | |||
| 3617 | ```yue | ||
| 3618 | switch tb | ||
| 3619 | when [1, 2, 3] | ||
| 3620 | print "1, 2, 3" | ||
| 3621 | when [1, b, 3] | ||
| 3622 | print "1, #{b}, 3" | ||
| 3623 | when [1, 2, b = 3] -- 变量b有默认值 | ||
| 3624 | print "1, 2, #{b}" | ||
| 3625 | ``` | ||
| 3626 | |||
| 3627 | </YueDisplay> | ||
| 3628 | |||
| 3629 | 匹配表格字段。 | ||
| 3630 | |||
| 3631 | ```yuescript | ||
| 3632 | switch tb | ||
| 3633 | when success: true, :result | ||
| 3634 | print "成功", result | ||
| 3635 | when success: false | ||
| 3636 | print "失败", result | ||
| 3637 | else | ||
| 3638 | print "无效值" | ||
| 3639 | ``` | ||
| 3640 | <YueDisplay> | ||
| 3641 | |||
| 3642 | ```yue | ||
| 3643 | switch tb | ||
| 3644 | when success: true, :result | ||
| 3645 | print "成功", result | ||
| 3646 | when success: false | ||
| 3647 | print "失败", result | ||
| 3648 | else | ||
| 3649 | print "无效值" | ||
| 3650 | ``` | ||
| 3651 | |||
| 3652 | </YueDisplay> | ||
| 3653 | |||
| 3654 | 匹配嵌套的表格结构。 | ||
| 3655 | |||
| 3656 | ```yuescript | ||
| 3657 | switch tb | ||
| 3658 | when data: {type: "success", :content} | ||
| 3659 | print "成功", content | ||
| 3660 | when data: {type: "error", :content} | ||
| 3661 | print "失败", content | ||
| 3662 | else | ||
| 3663 | print "无效值" | ||
| 3664 | ``` | ||
| 3665 | <YueDisplay> | ||
| 3666 | |||
| 3667 | ```yue | ||
| 3668 | switch tb | ||
| 3669 | when data: {type: "success", :content} | ||
| 3670 | print "成功", content | ||
| 3671 | when data: {type: "error", :content} | ||
| 3672 | print "失败", content | ||
| 3673 | else | ||
| 3674 | print "无效值" | ||
| 3675 | ``` | ||
| 3676 | |||
| 3677 | </YueDisplay> | ||
| 3678 | |||
| 3679 | 匹配表格数组。 | ||
| 3680 | |||
| 3681 | ```yuescript | ||
| 3682 | switch tb | ||
| 3683 | when [ | ||
| 3684 | {a: 1, b: 2} | ||
| 3685 | {a: 3, b: 4} | ||
| 3686 | {a: 5, b: 6} | ||
| 3687 | fourth | ||
| 3688 | ] | ||
| 3689 | print "匹配成功", fourth | ||
| 3690 | ``` | ||
| 3691 | <YueDisplay> | ||
| 3692 | |||
| 3693 | ```yue | ||
| 3694 | switch tb | ||
| 3695 | when [ | ||
| 3696 | {a: 1, b: 2} | ||
| 3697 | {a: 3, b: 4} | ||
| 3698 | {a: 5, b: 6} | ||
| 3699 | fourth | ||
| 3700 | ] | ||
| 3701 | print "匹配成功", fourth | ||
| 3702 | ``` | ||
| 3703 | |||
| 3704 | </YueDisplay> | ||
| 3705 | |||
| 3706 | 匹配一个列表并捕获特定范围内的元素。 | ||
| 3707 | |||
| 3708 | ```yuescript | ||
| 3709 | segments = ["admin", "users", "logs", "view"] | ||
| 3710 | switch segments | ||
| 3711 | when [...groups, resource, action] | ||
| 3712 | print "Group:", groups -- 打印: {"admin", "users"} | ||
| 3713 | print "Resource:", resource -- 打印: "logs" | ||
| 3714 | print "Action:", action -- 打印: "view" | ||
| 3715 | ``` | ||
| 3716 | <YueDisplay> | ||
| 3717 | |||
| 3718 | ```yue | ||
| 3719 | segments = ["admin", "users", "logs", "view"] | ||
| 3720 | switch segments | ||
| 3721 | when [...groups, resource, action] | ||
| 3722 | print "Group:", groups -- 打印: {"admin", "users"} | ||
| 3723 | print "Resource:", resource -- 打印: "logs" | ||
| 3724 | print "Action:", action -- 打印: "view" | ||
| 3725 | ``` | ||
| 3726 | |||
| 3727 | </YueDisplay> | ||
| 3728 | |||
| 3729 | ## 面向对象编程 | ||
| 3730 | |||
| 3731 | 在以下的示例中,月之脚本生成的 Lua 代码可能看起来会很复杂。所以最好主要关注月之脚本代码层面的意义,然后如果你想知道关于面向对象功能的实现细节,再查看 Lua 代码。 | ||
| 3732 | |||
| 3733 | 一个简单的类: | ||
| 3734 | |||
| 3735 | ```yuescript | ||
| 3736 | class Inventory | ||
| 3737 | new: => | ||
| 3738 | @items = {} | ||
| 3739 | |||
| 3740 | add_item: (name) => | ||
| 3741 | if @items[name] | ||
| 3742 | @items[name] += 1 | ||
| 3743 | else | ||
| 3744 | @items[name] = 1 | ||
| 3745 | ``` | ||
| 3746 | <YueDisplay> | ||
| 3747 | |||
| 3748 | ```yue | ||
| 3749 | class Inventory | ||
| 3750 | new: => | ||
| 3751 | @items = {} | ||
| 3752 | |||
| 3753 | add_item: (name) => | ||
| 3754 | if @items[name] | ||
| 3755 | @items[name] += 1 | ||
| 3756 | else | ||
| 3757 | @items[name] = 1 | ||
| 3758 | ``` | ||
| 3759 | |||
| 3760 | </YueDisplay> | ||
| 3761 | |||
| 3762 | 在月之脚本中采用面向对象的编程方式时,通常会使用类声明语句结合 Lua 表格字面量来做类定义。这个类的定义包含了它的所有方法和属性。在这种结构中,键名为 “new” 的成员扮演了一个重要的角色,是作为构造函数来使用。 | ||
| 3763 | |||
| 3764 | 值得注意的是,类中的方法都采用了粗箭头函数语法。当在类的实例上调用方法时,该实例会自动作为第一个参数被传入,因此粗箭头函数用于生成一个名为 “self” 的参数。 | ||
| 3765 | |||
| 3766 | 此外,“@” 前缀在变量名上起到了简化作用,代表 “self”。例如,`@items` 就等同于 `self.items`。 | ||
| 3767 | |||
| 3768 | 为了创建类的一个新实例,可以将类名当作一个函数来调用,这样就可以生成并返回一个新的实例。 | ||
| 3769 | |||
| 3770 | ```yuescript | ||
| 3771 | inv = Inventory! | ||
| 3772 | inv\add_item "t-shirt" | ||
| 3773 | inv\add_item "pants" | ||
| 3774 | ``` | ||
| 3775 | <YueDisplay> | ||
| 3776 | |||
| 3777 | |||
| 3778 | ```yue | ||
| 3779 | inv = Inventory! | ||
| 3780 | inv\add_item "t-shirt" | ||
| 3781 | inv\add_item "pants" | ||
| 3782 | ``` | ||
| 3783 | |||
| 3784 | </YueDisplay> | ||
| 3785 | |||
| 3786 | 在月之脚本的类中,由于需要将类的实例作为参数传入到调用的方法中,因此使用了 **\\** 操作符做类的成员函数调用。 | ||
| 3787 | |||
| 3788 | 需要特别注意的是,类的所有属性在其实例之间是共享的。这对于函数类型的成员属性通常不会造成问题,但对于其他类型的属性,可能会导致意外的结果。 | ||
| 3789 | |||
| 3790 | 例如,在下面的示例中,clothes 属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影响到其他所有实例。 | ||
| 3791 | |||
| 3792 | ```yuescript | ||
| 3793 | class Person | ||
| 3794 | clothes: [] | ||
| 3795 | give_item: (name) => | ||
| 3796 | table.insert @clothes, name | ||
| 3797 | |||
| 3798 | a = Person! | ||
| 3799 | b = Person! | ||
| 3800 | |||
| 3801 | a\give_item "pants" | ||
| 3802 | b\give_item "shirt" | ||
| 3803 | |||
| 3804 | -- 会同时打印出裤子和衬衫 | ||
| 3805 | print item for item in *a.clothes | ||
| 3806 | ``` | ||
| 3807 | <YueDisplay> | ||
| 3808 | |||
| 3809 | ```yue | ||
| 3810 | class Person | ||
| 3811 | clothes: [] | ||
| 3812 | give_item: (name) => | ||
| 3813 | table.insert @clothes, name | ||
| 3814 | |||
| 3815 | a = Person! | ||
| 3816 | b = Person! | ||
| 3817 | |||
| 3818 | a\give_item "pants" | ||
| 3819 | b\give_item "shirt" | ||
| 3820 | |||
| 3821 | -- 会同时打印出裤子和衬衫 | ||
| 3822 | print item for item in *a.clothes | ||
| 3823 | ``` | ||
| 3824 | |||
| 3825 | </YueDisplay> | ||
| 3826 | |||
| 3827 | 避免这个问题的正确方法是在构造函数中创建对象的可变状态: | ||
| 3828 | |||
| 3829 | ```yuescript | ||
| 3830 | class Person | ||
| 3831 | new: => | ||
| 3832 | @clothes = [] | ||
| 3833 | ``` | ||
| 3834 | <YueDisplay> | ||
| 3835 | |||
| 3836 | ```yue | ||
| 3837 | class Person | ||
| 3838 | new: => | ||
| 3839 | @clothes = [] | ||
| 3840 | ``` | ||
| 3841 | |||
| 3842 | </YueDisplay> | ||
| 3843 | |||
| 3844 | ### 继承 | ||
| 3845 | |||
| 3846 | `extends` 关键字可以在类声明中使用,以继承另一个类的属性和方法。 | ||
| 3847 | |||
| 3848 | ```yuescript | ||
| 3849 | class BackPack extends Inventory | ||
| 3850 | size: 10 | ||
| 3851 | add_item: (name) => | ||
| 3852 | if #@items > size then error "背包已满" | ||
| 3853 | super name | ||
| 3854 | ``` | ||
| 3855 | <YueDisplay> | ||
| 3856 | |||
| 3857 | ```yue | ||
| 3858 | class BackPack extends Inventory | ||
| 3859 | size: 10 | ||
| 3860 | add_item: (name) => | ||
| 3861 | if #@items > size then error "背包已满" | ||
| 3862 | super name | ||
| 3863 | ``` | ||
| 3864 | |||
| 3865 | </YueDisplay> | ||
| 3866 | |||
| 3867 | |||
| 3868 | 在这一部分,我们对月之脚本中的 `Inventory` 类进行了扩展,加入了对可以携带物品数量的限制。 | ||
| 3869 | |||
| 3870 | 在这个特定的例子中,子类并没有定义自己的构造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在子类中定义了构造函数,我们可以利用 `super` 方法来调用并执行父类的构造函数。 | ||
| 3871 | |||
| 3872 | 此外,当一个类继承自另一个类时,它会尝试调用父类上的 `__inherited` 方法(如果这个方法存在的话),以此来向父类发送通知。这个 `__inherited` 函数接受两个参数:被继承的父类和继承的子类。 | ||
| 3873 | |||
| 3874 | ```yuescript | ||
| 3875 | class Shelf | ||
| 3876 | @__inherited: (child) => | ||
| 3877 | print @__name, "被", child.__name, "继承" | ||
| 3878 | |||
| 3879 | -- 将打印: Shelf 被 Cupboard 继承 | ||
| 3880 | class Cupboard extends Shelf | ||
| 3881 | ``` | ||
| 3882 | <YueDisplay> | ||
| 3883 | |||
| 3884 | ```yue | ||
| 3885 | class Shelf | ||
| 3886 | @__inherited: (child) => | ||
| 3887 | print @__name, "被", child.__name, "继承" | ||
| 3888 | |||
| 3889 | -- 将打印: Shelf 被 Cupboard 继承 | ||
| 3890 | class Cupboard extends Shelf | ||
| 3891 | ``` | ||
| 3892 | |||
| 3893 | </YueDisplay> | ||
| 3894 | |||
| 3895 | ### super 关键字 | ||
| 3896 | |||
| 3897 | `super` 是一个特别的关键字,它有两种不同的使用方式:既可以当作一个对象来看待,也可以像调用函数那样使用。它仅在类的内部使用时具有特殊的功能。 | ||
| 3898 | |||
| 3899 | 当 `super` 被作为一个函数调用时,它将调用父类中与之同名的函数。此时,当前的 `self` 会自动作为第一个参数传递,正如上面提到的继承示例所展示的那样。 | ||
| 3900 | |||
| 3901 | 在将 `super` 当作普通值使用时,它实际上是对父类对象的引用。通过这种方式,我们可以访问父类中可能被子类覆盖的值,就像访问任何普通对象一样。 | ||
| 3902 | |||
| 3903 | 此外,当使用 `\` 操作符与 `super` 一起使用时,`self`将被插入为第一个参数,而不是使用 `super` 本身的值。而在使用`.`操作符来检索函数时,则会返回父类中的原始函数。 | ||
| 3904 | |||
| 3905 | 下面是一些使用 `super` 的不同方法的示例: | ||
| 3906 | |||
| 3907 | ```yuescript | ||
| 3908 | class MyClass extends ParentClass | ||
| 3909 | a_method: => | ||
| 3910 | -- 以下效果相同: | ||
| 3911 | super "你好", "世界" | ||
| 3912 | super\a_method "你好", "世界" | ||
| 3913 | super.a_method self, "你好", "世界" | ||
| 3914 | |||
| 3915 | -- super 作为值等于父类: | ||
| 3916 | assert super == ParentClass | ||
| 3917 | ``` | ||
| 3918 | <YueDisplay> | ||
| 3919 | |||
| 3920 | ```yue | ||
| 3921 | class MyClass extends ParentClass | ||
| 3922 | a_method: => | ||
| 3923 | -- 以下效果相同: | ||
| 3924 | super "你好", "世界" | ||
| 3925 | super\a_method "你好", "世界" | ||
| 3926 | super.a_method self, "你好", "世界" | ||
| 3927 | |||
| 3928 | -- super 作为值等于父类: | ||
| 3929 | assert super == ParentClass | ||
| 3930 | ``` | ||
| 3931 | |||
| 3932 | </YueDisplay> | ||
| 3933 | |||
| 3934 | **super** 也可以用在函数存根的左侧。唯一的主要区别是,生成的函数不是绑定到 super 的值,而是绑定到 self。 | ||
| 3935 | |||
| 3936 | ### 类型 | ||
| 3937 | |||
| 3938 | 每个类的实例都带有它的类型。这存储在特殊的 \_\_class 属性中。此属性会保存类对象。类对象是我们用来构建新实例的对象。我们还可以索引类对象以检索类方法和属性。 | ||
| 3939 | |||
| 3940 | ```yuescript | ||
| 3941 | b = BackPack! | ||
| 3942 | assert b.__class == BackPack | ||
| 3943 | |||
| 3944 | print BackPack.size -- 打印 10 | ||
| 3945 | ``` | ||
| 3946 | <YueDisplay> | ||
| 3947 | |||
| 3948 | ```yue | ||
| 3949 | b = BackPack! | ||
| 3950 | assert b.__class == BackPack | ||
| 3951 | |||
| 3952 | print BackPack.size -- 打印 10 | ||
| 3953 | ``` | ||
| 3954 | |||
| 3955 | </YueDisplay> | ||
| 3956 | |||
| 3957 | ### 类对象 | ||
| 3958 | |||
| 3959 | |||
| 3960 | 在月之脚本中,当我们编写类的定义语句时,实际上是在创建一个类对象。这个类对象被保存在一个与该类同名的变量中。 | ||
| 3961 | |||
| 3962 | 类对象具有函数的特性,可以被调用来创建新的实例。这正是我们在之前示例中所展示的创建类实例的方式。 | ||
| 3963 | |||
| 3964 | 一个类由两个表构成:类表本身和一个基表。基表作为所有实例的元表。在类声明中列出的所有属性都存放在基表中。 | ||
| 3965 | |||
| 3966 | 如果在类对象的元表中找不到某个属性,系统会从基表中检索该属性。这就意味着我们可以直接从类本身访问到其方法和属性。 | ||
| 3967 | |||
| 3968 | 需要特别注意的是,对类对象的赋值并不会影响到基表,因此这不是向实例添加新方法的正确方式。相反,需要直接修改基表。关于这点,可以参考下面的 “__base” 字段。 | ||
| 3969 | |||
| 3970 | 此外,类对象包含几个特殊的属性:当类被声明时,类的名称会作为一个字符串存储在类对象的 “__name” 字段中。 | ||
| 3971 | |||
| 3972 | ```yuescript | ||
| 3973 | print BackPack.__name -- 打印 Backpack | ||
| 3974 | ``` | ||
| 3975 | <YueDisplay> | ||
| 3976 | |||
| 3977 | ```yue | ||
| 3978 | print BackPack.__name -- 打印 Backpack | ||
| 3979 | ``` | ||
| 3980 | |||
| 3981 | </YueDisplay> | ||
| 3982 | |||
| 3983 | 基础对象被保存在一个名为 `__base` 的特殊表中。我们可以编辑这个表,以便为那些已经创建出来的实例和还未创建的实例增加新的功能。 | ||
| 3984 | |||
| 3985 | 另外,如果一个类是从另一个类派生而来的,那么其父类对象则会被存储在名为 `__parent` 的地方。这种机制允许在类之间实现继承和功能扩展。 | ||
| 3986 | |||
| 3987 | ### 类变量 | ||
| 3988 | |||
| 3989 | 我们可以直接在类对象中创建变量,而不是在类的基对象中,通过在类声明中的属性名前使用 @。 | ||
| 3990 | |||
| 3991 | ```yuescript | ||
| 3992 | class Things | ||
| 3993 | @some_func: => print "Hello from", @__name | ||
| 3994 | |||
| 3995 | Things\some_func! | ||
| 3996 | |||
| 3997 | -- 类变量在实例中不可见 | ||
| 3998 | assert Things().some_func == nil | ||
| 3999 | ``` | ||
| 4000 | <YueDisplay> | ||
| 4001 | |||
| 4002 | ```yue | ||
| 4003 | class Things | ||
| 4004 | @some_func: => print "Hello from", @__name | ||
| 4005 | |||
| 4006 | Things\some_func! | ||
| 4007 | |||
| 4008 | -- 类变量在实例中不可见 | ||
| 4009 | assert Things().some_func == nil | ||
| 4010 | ``` | ||
| 4011 | |||
| 4012 | </YueDisplay> | ||
| 4013 | |||
| 4014 | 在表达式中,我们可以使用 @@ 来访问存储在 `self.__class` 中的值。因此,`@@hello` 是 `self.__class.hello` 的简写。 | ||
| 4015 | |||
| 4016 | ```yuescript | ||
| 4017 | class Counter | ||
| 4018 | @count: 0 | ||
| 4019 | |||
| 4020 | new: => | ||
| 4021 | @@count += 1 | ||
| 4022 | |||
| 4023 | Counter! | ||
| 4024 | Counter! | ||
| 4025 | |||
| 4026 | print Counter.count -- 输出 2 | ||
| 4027 | ``` | ||
| 4028 | <YueDisplay> | ||
| 4029 | |||
| 4030 | ```yue | ||
| 4031 | class Counter | ||
| 4032 | @count: 0 | ||
| 4033 | |||
| 4034 | new: => | ||
| 4035 | @@count += 1 | ||
| 4036 | |||
| 4037 | Counter! | ||
| 4038 | Counter! | ||
| 4039 | |||
| 4040 | print Counter.count -- 输出 2 | ||
| 4041 | ``` | ||
| 4042 | |||
| 4043 | </YueDisplay> | ||
| 4044 | |||
| 4045 | @@ 的调用语义与 @ 类似。调用 @@ 时,会使用 Lua 的冒号语法将类作为第一个参数传入。 | ||
| 4046 | |||
| 4047 | ```yuescript | ||
| 4048 | @@hello 1,2,3,4 | ||
| 4049 | ``` | ||
| 4050 | <YueDisplay> | ||
| 4051 | |||
| 4052 | ```yue | ||
| 4053 | @@hello 1,2,3,4 | ||
| 4054 | ``` | ||
| 4055 | |||
| 4056 | </YueDisplay> | ||
| 4057 | |||
| 4058 | ### 类声明语句 | ||
| 4059 | |||
| 4060 | 在类声明的主体中,除了键/值对外,我们还可以编写普通的表达式。在这种类声明体中的普通代码的上下文中,self 等于类对象,而不是实例对象。 | ||
| 4061 | |||
| 4062 | 以下是创建类变量的另一种方法: | ||
| 4063 | |||
| 4064 | ```yuescript | ||
| 4065 | class Things | ||
| 4066 | @class_var = "hello world" | ||
| 4067 | ``` | ||
| 4068 | <YueDisplay> | ||
| 4069 | |||
| 4070 | ```yue | ||
| 4071 | class Things | ||
| 4072 | @class_var = "hello world" | ||
| 4073 | ``` | ||
| 4074 | |||
| 4075 | </YueDisplay> | ||
| 4076 | |||
| 4077 | 这些表达式会在所有属性被添加到类的基对象后执行。 | ||
| 4078 | |||
| 4079 | 在类的主体中声明的所有变量都会限制作用域只在类声明的范围。这对于放置只有类方法可以访问的私有值或辅助函数很方便: | ||
| 4080 | |||
| 4081 | ```yuescript | ||
| 4082 | class MoreThings | ||
| 4083 | secret = 123 | ||
| 4084 | log = (msg) -> print "LOG:", msg | ||
| 4085 | |||
| 4086 | some_method: => | ||
| 4087 | log "hello world: " .. secret | ||
| 4088 | ``` | ||
| 4089 | <YueDisplay> | ||
| 4090 | |||
| 4091 | ```yue | ||
| 4092 | class MoreThings | ||
| 4093 | secret = 123 | ||
| 4094 | log = (msg) -> print "LOG:", msg | ||
| 4095 | |||
| 4096 | some_method: => | ||
| 4097 | log "hello world: " .. secret | ||
| 4098 | ``` | ||
| 4099 | |||
| 4100 | </YueDisplay> | ||
| 4101 | |||
| 4102 | ### @ 和 @@ 值 | ||
| 4103 | |||
| 4104 | 当 @ 和 @@ 前缀在一个名字前时,它们分别代表在 self 和 self.\_\_class 中访问的那个名字。 | ||
| 4105 | |||
| 4106 | 如果它们单独使用,它们是 self 和 self.\_\_class 的别名。 | ||
| 4107 | |||
| 4108 | ```yuescript | ||
| 4109 | assert @ == self | ||
| 4110 | assert @@ == self.__class | ||
| 4111 | ``` | ||
| 4112 | <YueDisplay> | ||
| 4113 | |||
| 4114 | ```yue | ||
| 4115 | assert @ == self | ||
| 4116 | assert @@ == self.__class | ||
| 4117 | ``` | ||
| 4118 | |||
| 4119 | </YueDisplay> | ||
| 4120 | |||
| 4121 | 例如,使用 @@ 从实例方法快速创建同一类的新实例的方法: | ||
| 4122 | |||
| 4123 | ```yuescript | ||
| 4124 | some_instance_method = (...) => @@ ... | ||
| 4125 | ``` | ||
| 4126 | <YueDisplay> | ||
| 4127 | |||
| 4128 | ```yue | ||
| 4129 | some_instance_method = (...) => @@ ... | ||
| 4130 | ``` | ||
| 4131 | |||
| 4132 | </YueDisplay> | ||
| 4133 | |||
| 4134 | ### 构造属性提升 | ||
| 4135 | |||
| 4136 | 为了减少编写简单值对象定义的代码。你可以这样简单写一个类: | ||
| 4137 | |||
| 4138 | ```yuescript | ||
| 4139 | class Something | ||
| 4140 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 4141 | |||
| 4142 | -- 这是以下声明的简写形式 | ||
| 4143 | |||
| 4144 | class Something | ||
| 4145 | new: (foo, bar, biz, baz) => | ||
| 4146 | @foo = foo | ||
| 4147 | @bar = bar | ||
| 4148 | @@biz = biz | ||
| 4149 | @@baz = baz | ||
| 4150 | ``` | ||
| 4151 | <YueDisplay> | ||
| 4152 | |||
| 4153 | ```yue | ||
| 4154 | class Something | ||
| 4155 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 4156 | |||
| 4157 | -- 这是以下声明的简写形式 | ||
| 4158 | |||
| 4159 | class Something | ||
| 4160 | new: (foo, bar, biz, baz) => | ||
| 4161 | @foo = foo | ||
| 4162 | @bar = bar | ||
| 4163 | @@biz = biz | ||
| 4164 | @@baz = baz | ||
| 4165 | ``` | ||
| 4166 | |||
| 4167 | </YueDisplay> | ||
| 4168 | |||
| 4169 | 你也可以使用这种语法为一个函数初始化传入对象的字段。 | ||
| 4170 | |||
| 4171 | ```yuescript | ||
| 4172 | new = (@fieldA, @fieldB) => @ | ||
| 4173 | obj = new {}, 123, "abc" | ||
| 4174 | print obj | ||
| 4175 | ``` | ||
| 4176 | <YueDisplay> | ||
| 4177 | |||
| 4178 | ```yue | ||
| 4179 | new = (@fieldA, @fieldB) => @ | ||
| 4180 | obj = new {}, 123, "abc" | ||
| 4181 | print obj | ||
| 4182 | ``` | ||
| 4183 | |||
| 4184 | </YueDisplay> | ||
| 4185 | |||
| 4186 | ### 类表达式 | ||
| 4187 | |||
| 4188 | 类声明的语法也可以作为一个表达式使用,可以赋值给一个变量或者被返回语句返回。 | ||
| 4189 | |||
| 4190 | ```yuescript | ||
| 4191 | x = class Bucket | ||
| 4192 | drops: 0 | ||
| 4193 | add_drop: => @drops += 1 | ||
| 4194 | ``` | ||
| 4195 | <YueDisplay> | ||
| 4196 | |||
| 4197 | ```yue | ||
| 4198 | x = class Bucket | ||
| 4199 | drops: 0 | ||
| 4200 | add_drop: => @drops += 1 | ||
| 4201 | ``` | ||
| 4202 | |||
| 4203 | </YueDisplay> | ||
| 4204 | |||
| 4205 | ### 匿名类 | ||
| 4206 | |||
| 4207 | 声明类时可以省略名称。如果类的表达式不在赋值语句中,\_\_name 属性将为 nil。如果出现在赋值语句中,赋值操作左侧的名称将代替 nil。 | ||
| 4208 | |||
| 4209 | ```yuescript | ||
| 4210 | BigBucket = class extends Bucket | ||
| 4211 | add_drop: => @drops += 10 | ||
| 4212 | |||
| 4213 | assert Bucket.__name == "BigBucket" | ||
| 4214 | ``` | ||
| 4215 | <YueDisplay> | ||
| 4216 | |||
| 4217 | ```yue | ||
| 4218 | BigBucket = class extends Bucket | ||
| 4219 | add_drop: => @drops += 10 | ||
| 4220 | |||
| 4221 | assert Bucket.__name == "BigBucket" | ||
| 4222 | ``` | ||
| 4223 | |||
| 4224 | </YueDisplay> | ||
| 4225 | |||
| 4226 | 你甚至可以省略掉主体,这意味着你可以这样写一个空白的匿名类: | ||
| 4227 | |||
| 4228 | ```yuescript | ||
| 4229 | x = class | ||
| 4230 | ``` | ||
| 4231 | <YueDisplay> | ||
| 4232 | |||
| 4233 | ```yue | ||
| 4234 | x = class | ||
| 4235 | ``` | ||
| 4236 | |||
| 4237 | </YueDisplay> | ||
| 4238 | |||
| 4239 | ### 类混合 | ||
| 4240 | |||
| 4241 | 你可以通过使用 `using` 关键字来实现类混合。这意味着你可以从一个普通 Lua 表格或已定义的类对象中,复制函数到你创建的新类中。当你使用普通 Lua 表格进行类混合时,你有机会用自己的实现来重写类的索引方法(例如元方法 `__index`)。然而,当你从一个类对象做混合时,需要注意的是该类对象的元方法将不会被复制到新类。 | ||
| 4242 | |||
| 4243 | ```yuescript | ||
| 4244 | MyIndex = __index: var: 1 | ||
| 4245 | |||
| 4246 | class X using MyIndex | ||
| 4247 | func: => | ||
| 4248 | print 123 | ||
| 4249 | |||
| 4250 | x = X! | ||
| 4251 | print x.var | ||
| 4252 | |||
| 4253 | class Y using X | ||
| 4254 | |||
| 4255 | y = Y! | ||
| 4256 | y\func! | ||
| 4257 | |||
| 4258 | assert y.__class.__parent ~= X -- X 不是 Y 的父类 | ||
| 4259 | ``` | ||
| 4260 | <YueDisplay> | ||
| 4261 | |||
| 4262 | ```yue | ||
| 4263 | MyIndex = __index: var: 1 | ||
| 4264 | |||
| 4265 | class X using MyIndex | ||
| 4266 | func: => | ||
| 4267 | print 123 | ||
| 4268 | |||
| 4269 | x = X! | ||
| 4270 | print x.var | ||
| 4271 | |||
| 4272 | class Y using X | ||
| 4273 | |||
| 4274 | y = Y! | ||
| 4275 | y\func! | ||
| 4276 | |||
| 4277 | assert y.__class.__parent ~= X -- X 不是 Y 的父类 | ||
| 4278 | ``` | ||
| 4279 | |||
| 4280 | </YueDisplay> | ||
| 4281 | |||
| 4282 | ## with 语句 | ||
| 4283 | |||
| 4284 | 在编写 Lua 代码时,我们在创建对象后的常见操作是立即调用这个对象一系列操作函数并设置一系列属性。 | ||
| 4285 | |||
| 4286 | 这导致在代码中多次重复引用对象的名称,增加了不必要的文本噪音。一个常见的解决方案是在创建对象时,在构造函数传入一个表,该表包含要覆盖设置的键和值的集合。这样做的缺点是该对象的构造函数必须支持这种初始化形式。 | ||
| 4287 | |||
| 4288 | with 块有助于简化编写这样的代码。在 with 块内,我们可以使用以 . 或 \ 开头的特殊语句,这些语句代表我们正在使用的对象的操作。 | ||
| 4289 | |||
| 4290 | 例如,我们可以这样处理一个新创建的对象: | ||
| 4291 | |||
| 4292 | ```yuescript | ||
| 4293 | with Person! | ||
| 4294 | .name = "Oswald" | ||
| 4295 | \add_relative my_dad | ||
| 4296 | \save! | ||
| 4297 | print .name | ||
| 4298 | ``` | ||
| 4299 | <YueDisplay> | ||
| 4300 | |||
| 4301 | ```yue | ||
| 4302 | with Person! | ||
| 4303 | .name = "Oswald" | ||
| 4304 | \add_relative my_dad | ||
| 4305 | \save! | ||
| 4306 | print .name | ||
| 4307 | ``` | ||
| 4308 | |||
| 4309 | </YueDisplay> | ||
| 4310 | |||
| 4311 | with 语句也可以用作一个表达式,并返回它的代码块正在处理的对象。 | ||
| 4312 | |||
| 4313 | ```yuescript | ||
| 4314 | file = with File "favorite_foods.txt" | ||
| 4315 | \set_encoding "utf8" | ||
| 4316 | ``` | ||
| 4317 | <YueDisplay> | ||
| 4318 | |||
| 4319 | ```yue | ||
| 4320 | file = with File "favorite_foods.txt" | ||
| 4321 | \set_encoding "utf8" | ||
| 4322 | ``` | ||
| 4323 | |||
| 4324 | </YueDisplay> | ||
| 4325 | |||
| 4326 | 或者… | ||
| 4327 | |||
| 4328 | ```yuescript | ||
| 4329 | create_person = (name, relatives) -> | ||
| 4330 | with Person! | ||
| 4331 | .name = name | ||
| 4332 | \add_relative relative for relative in *relatives | ||
| 4333 | |||
| 4334 | me = create_person "Leaf", [dad, mother, sister] | ||
| 4335 | ``` | ||
| 4336 | <YueDisplay> | ||
| 4337 | |||
| 4338 | ```yue | ||
| 4339 | create_person = (name, relatives) -> | ||
| 4340 | with Person! | ||
| 4341 | .name = name | ||
| 4342 | \add_relative relative for relative in *relatives | ||
| 4343 | |||
| 4344 | me = create_person "Leaf", [dad, mother, sister] | ||
| 4345 | ``` | ||
| 4346 | |||
| 4347 | </YueDisplay> | ||
| 4348 | |||
| 4349 | 在此用法中,with 可以被视为K组合子(k-combinator)的一种特殊形式。 | ||
| 4350 | |||
| 4351 | 如果你想给表达式另外起一个名称的话,with 语句中的表达式也可以是一个赋值语句。 | ||
| 4352 | |||
| 4353 | ```yuescript | ||
| 4354 | with str := "你好" | ||
| 4355 | print "原始:", str | ||
| 4356 | print "大写:", \upper! | ||
| 4357 | ``` | ||
| 4358 | <YueDisplay> | ||
| 4359 | |||
| 4360 | ```yue | ||
| 4361 | with str := "你好" | ||
| 4362 | print "原始:", str | ||
| 4363 | print "大写:", \upper! | ||
| 4364 | ``` | ||
| 4365 | |||
| 4366 | </YueDisplay> | ||
| 4367 | |||
| 4368 | 你可以在 `with` 语句中使用 `[]` 访问特殊键。 | ||
| 4369 | |||
| 4370 | ```yuescript | ||
| 4371 | with tb | ||
| 4372 | [1] = 1 | ||
| 4373 | print [2] | ||
| 4374 | with [abc] | ||
| 4375 | [3] = [2]\func! | ||
| 4376 | ["key-name"] = value | ||
| 4377 | [] = "abc" -- 追加到 "tb" | ||
| 4378 | ``` | ||
| 4379 | <YueDisplay> | ||
| 4380 | |||
| 4381 | ```yue | ||
| 4382 | with tb | ||
| 4383 | [1] = 1 | ||
| 4384 | print [2] | ||
| 4385 | with [abc] | ||
| 4386 | [3] = [2]\func! | ||
| 4387 | ["key-name"] = value | ||
| 4388 | [] = "abc" -- 追加到 "tb" | ||
| 4389 | ``` | ||
| 4390 | |||
| 4391 | </YueDisplay> | ||
| 4392 | |||
| 4393 | `with?` 是 `with` 语法的一个增强版本,引入了存在性检查,用于在不显式判空的情况下安全访问可能为 nil 的对象。 | ||
| 4394 | |||
| 4395 | ```yuescript | ||
| 4396 | with? obj | ||
| 4397 | print obj.name | ||
| 4398 | ``` | ||
| 4399 | <YueDisplay> | ||
| 4400 | |||
| 4401 | ```yue | ||
| 4402 | with? obj | ||
| 4403 | print obj.name | ||
| 4404 | ``` | ||
| 4405 | |||
| 4406 | </YueDisplay> | ||
| 4407 | |||
| 4408 | ## do 语句 | ||
| 4409 | |||
| 4410 | 当用作语句时,do 语句的作用就像在 Lua 中差不多。 | ||
| 4411 | |||
| 4412 | ```yuescript | ||
| 4413 | do | ||
| 4414 | var = "hello" | ||
| 4415 | print var | ||
| 4416 | print var -- 这里是nil | ||
| 4417 | ``` | ||
| 4418 | <YueDisplay> | ||
| 4419 | |||
| 4420 | ```yue | ||
| 4421 | do | ||
| 4422 | var = "hello" | ||
| 4423 | print var | ||
| 4424 | print var -- 这里是nil | ||
| 4425 | ``` | ||
| 4426 | |||
| 4427 | </YueDisplay> | ||
| 4428 | |||
| 4429 | 月之脚本的 **do** 也可以用作表达式。允许你将多行代码的处理合并为一个表达式,并将 do 语句代码块的最后一个语句作为表达式返回的结果。 | ||
| 4430 | |||
| 4431 | ```yuescript | ||
| 4432 | counter = do | ||
| 4433 | i = 0 | ||
| 4434 | -> | ||
| 4435 | i += 1 | ||
| 4436 | i | ||
| 4437 | |||
| 4438 | print counter! | ||
| 4439 | print counter! | ||
| 4440 | ``` | ||
| 4441 | <YueDisplay> | ||
| 4442 | |||
| 4443 | ```yue | ||
| 4444 | counter = do | ||
| 4445 | i = 0 | ||
| 4446 | -> | ||
| 4447 | i += 1 | ||
| 4448 | i | ||
| 4449 | |||
| 4450 | print counter! | ||
| 4451 | print counter! | ||
| 4452 | ``` | ||
| 4453 | |||
| 4454 | </YueDisplay> | ||
| 4455 | |||
| 4456 | ```yuescript | ||
| 4457 | tbl = { | ||
| 4458 | key: do | ||
| 4459 | print "分配键值!" | ||
| 4460 | 1234 | ||
| 4461 | } | ||
| 4462 | ``` | ||
| 4463 | <YueDisplay> | ||
| 4464 | |||
| 4465 | ```yue | ||
| 4466 | tbl = { | ||
| 4467 | key: do | ||
| 4468 | print "分配键值!" | ||
| 4469 | 1234 | ||
| 4470 | } | ||
| 4471 | ``` | ||
| 4472 | |||
| 4473 | </YueDisplay> | ||
| 4474 | |||
| 4475 | ## 函数存根 | ||
| 4476 | |||
| 4477 | 在编程中,将对象的方法作为函数类型的值进行传递是一种常见做法,尤其是在将实例方法作为回调函数传递给其他函数的情形中。当目标函数需要将该对象作为其第一个参数时,我们需要找到一种方式将对象和函数绑定在一起,以便能够正确地调用该函数。 | ||
| 4478 | |||
| 4479 | 函数存根(stub)语法提供了一种便捷的方法来创建一个新的闭包函数,这个函数将对象和原函数绑定在一起。这样,当调用这个新创建的函数时,它会在正确的对象上下文中执行原有的函数。 | ||
| 4480 | |||
| 4481 | 这种语法类似于使用 \ 操作符调用实例方法的方式,区别在于,这里不需要在 \ 操作符后面附加参数列表。 | ||
| 4482 | |||
| 4483 | ```yuescript | ||
| 4484 | my_object = { | ||
| 4485 | value: 1000 | ||
| 4486 | write: => print "值为:", @value | ||
| 4487 | } | ||
| 4488 | |||
| 4489 | run_callback = (func) -> | ||
| 4490 | print "运行回调..." | ||
| 4491 | func! | ||
| 4492 | |||
| 4493 | -- 这样写不起作用: | ||
| 4494 | -- 函数没有引用my_object | ||
| 4495 | run_callback my_object.write | ||
| 4496 | |||
| 4497 | -- 函数存根语法 | ||
| 4498 | -- 让我们把对象捆绑到一个新函数中 | ||
| 4499 | run_callback my_object\write | ||
| 4500 | ``` | ||
| 4501 | <YueDisplay> | ||
| 4502 | |||
| 4503 | ```yue | ||
| 4504 | my_object = { | ||
| 4505 | value: 1000 | ||
| 4506 | write: => print "值为:", @value | ||
| 4507 | } | ||
| 4508 | |||
| 4509 | run_callback = (func) -> | ||
| 4510 | print "运行回调..." | ||
| 4511 | func! | ||
| 4512 | |||
| 4513 | -- 这样写不起作用: | ||
| 4514 | -- 函数没有引用my_object | ||
| 4515 | run_callback my_object.write | ||
| 4516 | |||
| 4517 | -- 函数存根语法 | ||
| 4518 | -- 让我们把对象捆绑到一个新函数中 | ||
| 4519 | run_callback my_object\write | ||
| 4520 | ``` | ||
| 4521 | |||
| 4522 | </YueDisplay> | ||
| 4523 | |||
| 4524 | ## 使用 using 语句:防止破坏性赋值 | ||
| 4525 | |||
| 4526 | Lua 的变量作用域是降低代码复杂度的重要工具。然而,随着代码量的增加,维护这些变量可能变得更加困难。比如,看看下面的代码片段: | ||
| 4527 | |||
| 4528 | ```yuescript | ||
| 4529 | i = 100 | ||
| 4530 | |||
| 4531 | -- 许多代码行... | ||
| 4532 | |||
| 4533 | my_func = -> | ||
| 4534 | i = 10 | ||
| 4535 | while i > 0 | ||
| 4536 | print i | ||
| 4537 | i -= 1 | ||
| 4538 | |||
| 4539 | my_func! | ||
| 4540 | |||
| 4541 | print i -- 将打印 0 | ||
| 4542 | ``` | ||
| 4543 | <YueDisplay> | ||
| 4544 | |||
| 4545 | ```yue | ||
| 4546 | i = 100 | ||
| 4547 | |||
| 4548 | -- 许多代码行... | ||
| 4549 | |||
| 4550 | my_func = -> | ||
| 4551 | i = 10 | ||
| 4552 | while i > 0 | ||
| 4553 | print i | ||
| 4554 | i -= 1 | ||
| 4555 | |||
| 4556 | my_func! | ||
| 4557 | |||
| 4558 | print i -- 将打印 0 | ||
| 4559 | ``` | ||
| 4560 | |||
| 4561 | </YueDisplay> | ||
| 4562 | |||
| 4563 | 在 `my_func` 中,我们不小心覆盖了变量 `i` 的值。虽然在这个例子中这个问题很明显,但在一个庞大的或者是由多人共同维护的代码库中,很难追踪每个变量的声明情况。 | ||
| 4564 | |||
| 4565 | 如果我们可以明确指出哪些变量是我们想在当前作用域内修改的,并且防止我们不小心更改了其他作用域中同名的变量,那将大有裨益。 | ||
| 4566 | |||
| 4567 | `using` 语句就是为此而生。`using nil` 确保函数内部的赋值不会意外地影响到外部作用域的变量。我们只需将 `using` 子句放在函数的参数列表之后;若函数没有参数,则直接放在括号内即可。 | ||
| 4568 | |||
| 4569 | ```yuescript | ||
| 4570 | i = 100 | ||
| 4571 | |||
| 4572 | my_func = (using nil) -> | ||
| 4573 | i = "hello" -- 这里创建了一个新的局部变量 | ||
| 4574 | |||
| 4575 | my_func! | ||
| 4576 | print i -- 打印 100,i 没有受到影响 | ||
| 4577 | ``` | ||
| 4578 | <YueDisplay> | ||
| 4579 | |||
| 4580 | ```yue | ||
| 4581 | i = 100 | ||
| 4582 | |||
| 4583 | my_func = (using nil) -> | ||
| 4584 | i = "hello" -- 这里创建了一个新的局部变量 | ||
| 4585 | |||
| 4586 | my_func! | ||
| 4587 | print i -- 打印 100,i 没有受到影响 | ||
| 4588 | ``` | ||
| 4589 | |||
| 4590 | </YueDisplay> | ||
| 4591 | |||
| 4592 | using子句中可以填写多个用逗号分隔名称。指定可以访问和修改的外部变量的名称: | ||
| 4593 | |||
| 4594 | ```yuescript | ||
| 4595 | tmp = 1213 | ||
| 4596 | i, k = 100, 50 | ||
| 4597 | |||
| 4598 | my_func = (add using k, i) -> | ||
| 4599 | tmp = tmp + add -- 创建了一个新的局部tmp | ||
| 4600 | i += tmp | ||
| 4601 | k += tmp | ||
| 4602 | |||
| 4603 | my_func(22) | ||
| 4604 | print i, k -- 这些已经被更新 | ||
| 4605 | ``` | ||
| 4606 | <YueDisplay> | ||
| 4607 | |||
| 4608 | ```yue | ||
| 4609 | tmp = 1213 | ||
| 4610 | i, k = 100, 50 | ||
| 4611 | |||
| 4612 | my_func = (add using k, i) -> | ||
| 4613 | tmp = tmp + add -- 创建了一个新的局部tmp | ||
| 4614 | i += tmp | ||
| 4615 | k += tmp | ||
| 4616 | |||
| 4617 | my_func(22) | ||
| 4618 | print i, k -- 这些已经被更新 | ||
| 4619 | ``` | ||
| 4620 | |||
| 4621 | </YueDisplay> | ||
| 4622 | |||
| 4623 | ## 月之脚本语言库 | ||
| 4624 | |||
| 4625 | 使用 `require("yue")` 来访问。 | ||
| 4626 | |||
| 4627 | ### yue | ||
| 4628 | |||
| 4629 | **描述:** | ||
| 4630 | |||
| 4631 | 月之脚本语言库。 | ||
| 4632 | |||
| 4633 | #### version | ||
| 4634 | |||
| 4635 | **类型:** 成员变量。 | ||
| 4636 | |||
| 4637 | **描述:** | ||
| 4638 | |||
| 4639 | 月之脚本版本。 | ||
| 4640 | |||
| 4641 | **签名:** | ||
| 4642 | ```lua | ||
| 4643 | version: string | ||
| 4644 | ``` | ||
| 4645 | |||
| 4646 | #### dirsep | ||
| 4647 | |||
| 4648 | **类型:** 成员变量。 | ||
| 4649 | |||
| 4650 | **描述:** | ||
| 4651 | |||
| 4652 | 当前平台的文件分隔符。 | ||
| 4653 | |||
| 4654 | **签名:** | ||
| 4655 | ```lua | ||
| 4656 | dirsep: string | ||
| 4657 | ``` | ||
| 4658 | |||
| 4659 | #### yue_compiled | ||
| 4660 | |||
| 4661 | **类型:** 成员变量。 | ||
| 4662 | |||
| 4663 | **描述:** | ||
| 4664 | |||
| 4665 | 编译模块代码缓存。 | ||
| 4666 | |||
| 4667 | **签名:** | ||
| 4668 | ```lua | ||
| 4669 | yue_compiled: {string: string} | ||
| 4670 | ``` | ||
| 4671 | |||
| 4672 | #### to_lua | ||
| 4673 | |||
| 4674 | **类型:** 函数。 | ||
| 4675 | |||
| 4676 | **描述:** | ||
| 4677 | |||
| 4678 | 月之脚本的编译函数。它将 YueScript 代码编译为 Lua 代码。 | ||
| 4679 | |||
| 4680 | **签名:** | ||
| 4681 | ```lua | ||
| 4682 | to_lua: function(code: string, config?: Config): | ||
| 4683 | --[[codes]] string | nil, | ||
| 4684 | --[[error]] string | nil, | ||
| 4685 | --[[globals]] {{string, integer, integer}} | nil | ||
| 4686 | ``` | ||
| 4687 | |||
| 4688 | **参数:** | ||
| 4689 | |||
| 4690 | | 参数名 | 类型 | 描述 | | ||
| 4691 | | --- | --- | --- | | ||
| 4692 | | code | string | YueScript 代码。 | | ||
| 4693 | | config | Config | [可选] 编译器选项。 | | ||
| 4694 | |||
| 4695 | **返回值:** | ||
| 4696 | |||
| 4697 | | 返回类型 | 描述 | | ||
| 4698 | | --- | --- | | ||
| 4699 | | string \| nil | 编译后的 Lua 代码,如果编译失败则为 nil。 | | ||
| 4700 | | string \| nil | 错误消息,如果编译成功则为 nil。 | | ||
| 4701 | | {{string, integer, integer}} \| nil | 代码中出现的全局变量(带有名称、行和列),如果编译器选项 `lint_global` 为 false 则为 nil。 | | ||
| 4702 | |||
| 4703 | #### file_exist | ||
| 4704 | |||
| 4705 | **类型:** 函数。 | ||
| 4706 | |||
| 4707 | **描述:** | ||
| 4708 | |||
| 4709 | 检查源文件是否存在的函数。可以覆盖该函数以自定义行为。 | ||
| 4710 | |||
| 4711 | **签名:** | ||
| 4712 | ```lua | ||
| 4713 | file_exist: function(filename: string): boolean | ||
| 4714 | ``` | ||
| 4715 | |||
| 4716 | **参数:** | ||
| 4717 | |||
| 4718 | | 参数名 | 类型 | 描述 | | ||
| 4719 | | --- | --- | --- | | ||
| 4720 | | filename | string | 文件名。 | | ||
| 4721 | |||
| 4722 | **返回值:** | ||
| 4723 | |||
| 4724 | | 返回类型 | 描述 | | ||
| 4725 | | --- | --- | | ||
| 4726 | | boolean | 文件是否存在。 | | ||
| 4727 | |||
| 4728 | #### read_file | ||
| 4729 | |||
| 4730 | **类型:** 函数。 | ||
| 4731 | |||
| 4732 | **描述:** | ||
| 4733 | |||
| 4734 | 读取源文件的函数。可以覆盖该函数以自定义行为。 | ||
| 4735 | |||
| 4736 | **签名:** | ||
| 4737 | ```lua | ||
| 4738 | read_file: function(filename: string): string | ||
| 4739 | ``` | ||
| 4740 | |||
| 4741 | **参数:** | ||
| 4742 | |||
| 4743 | | 参数名 | 类型 | 描述 | | ||
| 4744 | | --- | --- | --- | | ||
| 4745 | | filename | string | 文件名。 | | ||
| 4746 | |||
| 4747 | **返回值:** | ||
| 4748 | |||
| 4749 | | 返回类型 | 描述 | | ||
| 4750 | | --- | --- | | ||
| 4751 | | string | 文件内容。 | | ||
| 4752 | |||
| 4753 | #### insert_loader | ||
| 4754 | |||
| 4755 | **类型:** 函数。 | ||
| 4756 | |||
| 4757 | **描述:** | ||
| 4758 | |||
| 4759 | 将 YueScript 加载器插入到 Lua 包加载器(搜索器)中。 | ||
| 4760 | |||
| 4761 | **签名:** | ||
| 4762 | ```lua | ||
| 4763 | insert_loader: function(pos?: integer): boolean | ||
| 4764 | ``` | ||
| 4765 | |||
| 4766 | **参数:** | ||
| 4767 | |||
| 4768 | | 参数名 | 类型 | 描述 | | ||
| 4769 | | --- | --- | --- | | ||
| 4770 | | pos | integer | [可选] 要插入加载器的位置。默认为 3。 | | ||
| 4771 | |||
| 4772 | **返回值:** | ||
| 4773 | |||
| 4774 | | 返回类型 | 描述 | | ||
| 4775 | | --- | --- | | ||
| 4776 | | boolean | 是否成功插入加载器。如果加载器已经插入,则返回失败。 | | ||
| 4777 | |||
| 4778 | #### remove_loader | ||
| 4779 | |||
| 4780 | **类型:** 函数。 | ||
| 4781 | |||
| 4782 | **描述:** | ||
| 4783 | |||
| 4784 | 从 Lua 包加载器(搜索器)中移除 YueScript 加载器。 | ||
| 4785 | |||
| 4786 | **签名:** | ||
| 4787 | ```lua | ||
| 4788 | remove_loader: function(): boolean | ||
| 4789 | ``` | ||
| 4790 | |||
| 4791 | **返回值:** | ||
| 4792 | |||
| 4793 | | 返回类型 | 描述 | | ||
| 4794 | | --- | --- | | ||
| 4795 | | boolean | 是否成功移除加载器。如果加载器未插入,则返回失败。 | | ||
| 4796 | |||
| 4797 | #### loadstring | ||
| 4798 | |||
| 4799 | **类型:** 函数。 | ||
| 4800 | |||
| 4801 | **描述:** | ||
| 4802 | |||
| 4803 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 4804 | |||
| 4805 | **签名:** | ||
| 4806 | ```lua | ||
| 4807 | loadstring: function(input: string, chunkname: string, env: table, config?: Config): | ||
| 4808 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4809 | --[[error]] string | nil | ||
| 4810 | ``` | ||
| 4811 | |||
| 4812 | **参数:** | ||
| 4813 | |||
| 4814 | | 参数名 | 类型 | 描述 | | ||
| 4815 | | --- | --- | --- | | ||
| 4816 | | input | string | YueScript 代码。 | | ||
| 4817 | | chunkname | string | 代码块的名称。 | | ||
| 4818 | | env | table | 环境表。 | | ||
| 4819 | | config | Config | [可选] 编译器选项。 | | ||
| 4820 | |||
| 4821 | **返回值:** | ||
| 4822 | |||
| 4823 | | 返回类型 | 描述 | | ||
| 4824 | | --- | --- | | ||
| 4825 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 4826 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 4827 | |||
| 4828 | #### loadstring | ||
| 4829 | |||
| 4830 | **类型:** 函数。 | ||
| 4831 | |||
| 4832 | **描述:** | ||
| 4833 | |||
| 4834 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 4835 | |||
| 4836 | **签名:** | ||
| 4837 | ```lua | ||
| 4838 | loadstring: function(input: string, chunkname: string, config?: Config): | ||
| 4839 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4840 | --[[error]] string | nil | ||
| 4841 | ``` | ||
| 4842 | |||
| 4843 | **参数:** | ||
| 4844 | |||
| 4845 | | 参数名 | 类型 | 描述 | | ||
| 4846 | | --- | --- | --- | | ||
| 4847 | | input | string | YueScript 代码。 | | ||
| 4848 | | chunkname | string | 代码块的名称。 | | ||
| 4849 | | config | Config | [可选] 编译器选项。 | | ||
| 4850 | |||
| 4851 | **返回值:** | ||
| 4852 | |||
| 4853 | | 返回类型 | 描述 | | ||
| 4854 | | --- | --- | | ||
| 4855 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 4856 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 4857 | |||
| 4858 | #### loadstring | ||
| 4859 | |||
| 4860 | **类型:** 函数。 | ||
| 4861 | |||
| 4862 | **描述:** | ||
| 4863 | |||
| 4864 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 4865 | |||
| 4866 | **签名:** | ||
| 4867 | ```lua | ||
| 4868 | loadstring: function(input: string, config?: Config): | ||
| 4869 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 4870 | --[[error]] string | nil | ||
| 4871 | ``` | ||
| 4872 | |||
| 4873 | **参数:** | ||
| 4874 | |||
| 4875 | | 参数名 | 类型 | 描述 | | ||
| 4876 | | --- | --- | --- | | ||
| 4877 | | input | string | YueScript 代码。 | | ||
| 4878 | | config | Config | [可选] 编译器选项。 | | ||
| 4879 | |||
| 4880 | **返回值:** | ||
| 4881 | |||
| 4882 | | 返回类型 | 描述 | | ||
| 4883 | | --- | --- | | ||
| 4884 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 4885 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 4886 | |||
| 4887 | #### loadfile | ||
| 4888 | |||
| 4889 | **类型:** 函数。 | ||
| 4890 | |||
| 4891 | **描述:** | ||
| 4892 | |||
| 4893 | 将 YueScript 代码文件加载为一个函数。 | ||
| 4894 | |||
| 4895 | **签名:** | ||
| 4896 | ```lua | ||
| 4897 | loadfile: function(filename: string, env: table, config?: Config): | ||
| 4898 | nil | function(...: any): (any...), | ||
| 4899 | string | nil | ||
| 4900 | ``` | ||
| 4901 | |||
| 4902 | **参数:** | ||
| 4903 | |||
| 4904 | | 参数名 | 类型 | 描述 | | ||
| 4905 | | --- | --- | --- | | ||
| 4906 | | filename | string | 文件名。 | | ||
| 4907 | | env | table | 环境表。 | | ||
| 4908 | | config | Config | [可选] 编译器选项。 | | ||
| 4909 | |||
| 4910 | **返回值:** | ||
| 4911 | |||
| 4912 | | 返回类型 | 描述 | | ||
| 4913 | | --- | --- | | ||
| 4914 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 4915 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 4916 | |||
| 4917 | #### loadfile | ||
| 4918 | |||
| 4919 | **类型:** 函数。 | ||
| 4920 | |||
| 4921 | **描述:** | ||
| 4922 | |||
| 4923 | 将 YueScript 代码文件加载为一个函数。 | ||
| 4924 | |||
| 4925 | **签名:** | ||
| 4926 | ```lua | ||
| 4927 | loadfile: function(filename: string, config?: Config): | ||
| 4928 | nil | function(...: any): (any...), | ||
| 4929 | string | nil | ||
| 4930 | ``` | ||
| 4931 | |||
| 4932 | **参数:** | ||
| 4933 | |||
| 4934 | | 参数名 | 类型 | 描述 | | ||
| 4935 | | --- | --- | --- | | ||
| 4936 | | filename | string | 文件名。 | | ||
| 4937 | | config | Config | [可选] 编译器选项。 | | ||
| 4938 | |||
| 4939 | **返回值:** | ||
| 4940 | |||
| 4941 | | 返回类型 | 描述 | | ||
| 4942 | | --- | --- | | ||
| 4943 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 4944 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 4945 | |||
| 4946 | #### dofile | ||
| 4947 | |||
| 4948 | **类型:** 函数。 | ||
| 4949 | |||
| 4950 | **描述:** | ||
| 4951 | |||
| 4952 | 将 YueScript 代码文件加载为一个函数并执行。 | ||
| 4953 | |||
| 4954 | **签名:** | ||
| 4955 | ```lua | ||
| 4956 | dofile: function(filename: string, env: table, config?: Config): any... | ||
| 4957 | ``` | ||
| 4958 | |||
| 4959 | **参数:** | ||
| 4960 | |||
| 4961 | | 参数名 | 类型 | 描述 | | ||
| 4962 | | --- | --- | --- | | ||
| 4963 | | filename | string | 文件名。 | | ||
| 4964 | | env | table | 环境表。 | | ||
| 4965 | | config | Config | [可选] 编译器选项。 | | ||
| 4966 | |||
| 4967 | **返回值:** | ||
| 4968 | |||
| 4969 | | 返回类型 | 描述 | | ||
| 4970 | | --- | --- | | ||
| 4971 | | any... | 加载的函数执行后的返回值。 | | ||
| 4972 | |||
| 4973 | #### dofile | ||
| 4974 | |||
| 4975 | **类型:** 函数。 | ||
| 4976 | |||
| 4977 | **描述:** | ||
| 4978 | |||
| 4979 | 将 YueScript 代码文件加载为一个函数并执行。 | ||
| 4980 | |||
| 4981 | **签名:** | ||
| 4982 | ```lua | ||
| 4983 | dofile: function(filename: string, config?: Config): any... | ||
| 4984 | ``` | ||
| 4985 | |||
| 4986 | **参数:** | ||
| 4987 | |||
| 4988 | | 参数名 | 类型 | 描述 | | ||
| 4989 | | --- | --- | --- | | ||
| 4990 | | filename | string | 文件名。 | | ||
| 4991 | | config | Config | [可选] 编译器选项。 | | ||
| 4992 | |||
| 4993 | **返回值:** | ||
| 4994 | |||
| 4995 | | 返回类型 | 描述 | | ||
| 4996 | | --- | --- | | ||
| 4997 | | any... | 加载的函数执行后的返回值。 | | ||
| 4998 | |||
| 4999 | #### find_modulepath | ||
| 5000 | |||
| 5001 | **类型:** 函数。 | ||
| 5002 | |||
| 5003 | **描述:** | ||
| 5004 | |||
| 5005 | 将 YueScript 模块名解析为文件路径。 | ||
| 5006 | |||
| 5007 | **签名:** | ||
| 5008 | ```lua | ||
| 5009 | find_modulepath: function(name: string): string | ||
| 5010 | ``` | ||
| 5011 | |||
| 5012 | **参数:** | ||
| 5013 | |||
| 5014 | | 参数名 | 类型 | 描述 | | ||
| 5015 | | --- | --- | --- | | ||
| 5016 | | name | string | 模块名。 | | ||
| 5017 | |||
| 5018 | **返回值:** | ||
| 5019 | |||
| 5020 | | 返回类型 | 描述 | | ||
| 5021 | | --- | --- | | ||
| 5022 | | string | 文件路径。 | | ||
| 5023 | |||
| 5024 | #### pcall | ||
| 5025 | |||
| 5026 | **类型:** 函数。 | ||
| 5027 | |||
| 5028 | **描述:** | ||
| 5029 | |||
| 5030 | 在保护模式下调用一个函数。 | ||
| 5031 | 会捕获任何错误,执行成功则返回成功状态和结果,否则为失败状态和错误信息。 | ||
| 5032 | 当发生错误时,将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 5033 | |||
| 5034 | **签名:** | ||
| 5035 | ```lua | ||
| 5036 | pcall: function(f: function, ...: any): boolean, any... | ||
| 5037 | ``` | ||
| 5038 | |||
| 5039 | **参数:** | ||
| 5040 | |||
| 5041 | | 参数名 | 类型 | 描述 | | ||
| 5042 | | --- | --- | --- | | ||
| 5043 | | f | function | 要调用的函数。 | | ||
| 5044 | | ... | any | 要传递给函数的参数。 | | ||
| 5045 | |||
| 5046 | **返回值:** | ||
| 5047 | |||
| 5048 | | 返回类型 | 描述 | | ||
| 5049 | | --- | --- | | ||
| 5050 | | boolean, ... | 状态码和函数结果或错误信息。 | | ||
| 5051 | |||
| 5052 | #### require | ||
| 5053 | |||
| 5054 | **类型:** 函数。 | ||
| 5055 | |||
| 5056 | **描述:** | ||
| 5057 | |||
| 5058 | 加载给定的模块。可以是 Lua 模块或 YueScript 模块。 | ||
| 5059 | 如果模块是 YueScript 模块且加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 5060 | |||
| 5061 | **签名:** | ||
| 5062 | ```lua | ||
| 5063 | require: function(name: string): any... | ||
| 5064 | ``` | ||
| 5065 | |||
| 5066 | **参数:** | ||
| 5067 | |||
| 5068 | | 参数名 | 类型 | 描述 | | ||
| 5069 | | --- | --- | --- | | ||
| 5070 | | modname | string | 要加载的模块名。 | | ||
| 5071 | |||
| 5072 | **返回值:** | ||
| 5073 | |||
| 5074 | | 返回类型 | 描述 | | ||
| 5075 | | --- | --- | | ||
| 5076 | | any | 如果模块已经加载,则返回 package.loaded[modname] 中存储的值。否则,尝试查找加载器并返回 package.loaded[modname] 的最终值和加载器数据作为第二个结果。 | | ||
| 5077 | |||
| 5078 | #### p | ||
| 5079 | |||
| 5080 | **类型:** 函数。 | ||
| 5081 | |||
| 5082 | **描述:** | ||
| 5083 | |||
| 5084 | 检查传递的值的内部结构,并打印值出它的字符串表示。 | ||
| 5085 | |||
| 5086 | **签名:** | ||
| 5087 | ```lua | ||
| 5088 | p: function(...: any) | ||
| 5089 | ``` | ||
| 5090 | |||
| 5091 | **参数:** | ||
| 5092 | |||
| 5093 | | 参数名 | 类型 | 描述 | | ||
| 5094 | | --- | --- | --- | | ||
| 5095 | | ... | any | 要检查的值。 | | ||
| 5096 | |||
| 5097 | #### options | ||
| 5098 | |||
| 5099 | **类型:** 成员变量。 | ||
| 5100 | |||
| 5101 | **描述:** | ||
| 5102 | |||
| 5103 | 当前编译器选项。 | ||
| 5104 | |||
| 5105 | **签名:** | ||
| 5106 | ```lua | ||
| 5107 | options: Config.Options | ||
| 5108 | ``` | ||
| 5109 | |||
| 5110 | #### traceback | ||
| 5111 | |||
| 5112 | **类型:** 函数。 | ||
| 5113 | |||
| 5114 | **描述:** | ||
| 5115 | |||
| 5116 | 重写堆栈跟踪中的行号为 YueScript 代码中的原始行号的 traceback 函数。 | ||
| 5117 | |||
| 5118 | **签名:** | ||
| 5119 | ```lua | ||
| 5120 | traceback: function(message: string): string | ||
| 5121 | ``` | ||
| 5122 | |||
| 5123 | **参数:** | ||
| 5124 | |||
| 5125 | | 参数名 | 类型 | 描述 | | ||
| 5126 | | --- | --- | --- | | ||
| 5127 | | message | string | 堆栈跟踪消息。 | | ||
| 5128 | |||
| 5129 | **返回值:** | ||
| 5130 | |||
| 5131 | | 返回类型 | 描述 | | ||
| 5132 | | --- | --- | | ||
| 5133 | | string | 重写后的堆栈跟踪消息。 | | ||
| 5134 | |||
| 5135 | #### is_ast | ||
| 5136 | |||
| 5137 | **类型:** 函数。 | ||
| 5138 | |||
| 5139 | **描述:** | ||
| 5140 | |||
| 5141 | 检查代码是否匹配指定的 AST。 | ||
| 5142 | |||
| 5143 | **签名:** | ||
| 5144 | ```lua | ||
| 5145 | is_ast: function(astName: string, code: string): boolean | ||
| 5146 | ``` | ||
| 5147 | |||
| 5148 | **参数:** | ||
| 5149 | |||
| 5150 | | 参数名 | 类型 | 描述 | | ||
| 5151 | | --- | --- | --- | | ||
| 5152 | | astName | string | AST 名称。 | | ||
| 5153 | | code | string | 代码。 | | ||
| 5154 | |||
| 5155 | **返回值:** | ||
| 5156 | |||
| 5157 | | 返回类型 | 描述 | | ||
| 5158 | | --- | --- | | ||
| 5159 | | boolean | 代码是否匹配 AST。 | | ||
| 5160 | |||
| 5161 | #### AST | ||
| 5162 | |||
| 5163 | **类型:** 成员变量。 | ||
| 5164 | |||
| 5165 | **描述:** | ||
| 5166 | |||
| 5167 | AST 类型定义,带有名称、行、列和子节点。 | ||
| 5168 | |||
| 5169 | **签名:** | ||
| 5170 | ```lua | ||
| 5171 | type AST = {string, integer, integer, any} | ||
| 5172 | ``` | ||
| 5173 | |||
| 5174 | #### to_ast | ||
| 5175 | |||
| 5176 | **类型:** 函数。 | ||
| 5177 | |||
| 5178 | **描述:** | ||
| 5179 | |||
| 5180 | 将代码转换为 AST。 | ||
| 5181 | |||
| 5182 | **签名:** | ||
| 5183 | ```lua | ||
| 5184 | to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean): | ||
| 5185 | --[[AST]] AST | nil, | ||
| 5186 | --[[error]] nil | string | ||
| 5187 | ``` | ||
| 5188 | |||
| 5189 | **参数:** | ||
| 5190 | |||
| 5191 | | 参数名 | 类型 | 描述 | | ||
| 5192 | | --- | --- | --- | | ||
| 5193 | | code | string | 代码。 | | ||
| 5194 | | flattenLevel | integer | [可选] 扁平化级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 | | ||
| 5195 | | astName | string | [可选] AST 名称。默认为 "File"。 | | ||
| 5196 | | reserveComment | boolean | [可选] 是否保留原始注释。默认为 false。 | | ||
| 5197 | |||
| 5198 | **返回值:** | ||
| 5199 | |||
| 5200 | | 返回类型 | 描述 | | ||
| 5201 | | --- | --- | | ||
| 5202 | | AST \| nil | AST,如果转换失败则为 nil。 | | ||
| 5203 | | string \| nil | 错误消息,如果转换成功则为 nil。 | | ||
| 5204 | |||
| 5205 | #### format | ||
| 5206 | |||
| 5207 | **类型:** 函数。 | ||
| 5208 | |||
| 5209 | **描述:** | ||
| 5210 | |||
| 5211 | 格式化 YueScript 代码。 | ||
| 5212 | |||
| 5213 | **签名:** | ||
| 5214 | ```lua | ||
| 5215 | format: function(code: string, tabSize?: number, reserveComment?: boolean): string | ||
| 5216 | ``` | ||
| 5217 | |||
| 5218 | **参数:** | ||
| 5219 | |||
| 5220 | | 参数名 | 类型 | 描述 | | ||
| 5221 | | --- | --- | --- | | ||
| 5222 | | code | string | 代码。 | | ||
| 5223 | | tabSize | integer | [可选] 制表符大小。默认为 4。 | | ||
| 5224 | | reserveComment | boolean | [可选] 是否保留原始注释。默认为 true。 | | ||
| 5225 | |||
| 5226 | **返回值:** | ||
| 5227 | |||
| 5228 | | 返回类型 | 描述 | | ||
| 5229 | | --- | --- | | ||
| 5230 | | string | 格式化后的代码。 | | ||
| 5231 | |||
| 5232 | #### __call | ||
| 5233 | |||
| 5234 | **类型:** 元方法。 | ||
| 5235 | |||
| 5236 | **描述:** | ||
| 5237 | |||
| 5238 | 导入 YueScript 模块。 | ||
| 5239 | 如果发生加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 5240 | |||
| 5241 | **签名:** | ||
| 5242 | ```lua | ||
| 5243 | metamethod __call: function(self: yue, module: string): any... | ||
| 5244 | ``` | ||
| 5245 | |||
| 5246 | **参数:** | ||
| 5247 | |||
| 5248 | | 参数名 | 类型 | 描述 | | ||
| 5249 | | --- | --- | --- | | ||
| 5250 | | module | string | 模块名。 | | ||
| 5251 | |||
| 5252 | **返回值:** | ||
| 5253 | |||
| 5254 | | 返回类型 | 描述 | | ||
| 5255 | | --- | --- | | ||
| 5256 | | any | 模块值。 | | ||
| 5257 | |||
| 5258 | ### Config | ||
| 5259 | |||
| 5260 | **描述:** | ||
| 5261 | |||
| 5262 | 编译器编译选项。 | ||
| 5263 | |||
| 5264 | #### lint_global | ||
| 5265 | |||
| 5266 | **类型:** 成员变量。 | ||
| 5267 | |||
| 5268 | **描述:** | ||
| 5269 | |||
| 5270 | 编译器是否应该收集代码中出现的全局变量。 | ||
| 5271 | |||
| 5272 | **签名:** | ||
| 5273 | ```lua | ||
| 5274 | lint_global: boolean | ||
| 5275 | ``` | ||
| 5276 | |||
| 5277 | #### implicit_return_root | ||
| 5278 | |||
| 5279 | **类型:** 成员变量。 | ||
| 5280 | |||
| 5281 | **描述:** | ||
| 5282 | |||
| 5283 | 编译器是否应该对根层级的代码块进行隐式的表达式返回。 | ||
| 5284 | |||
| 5285 | **签名:** | ||
| 5286 | ```lua | ||
| 5287 | implicit_return_root: boolean | ||
| 5288 | ``` | ||
| 5289 | |||
| 5290 | #### reserve_line_number | ||
| 5291 | |||
| 5292 | **类型:** 成员变量。 | ||
| 5293 | |||
| 5294 | **描述:** | ||
| 5295 | |||
| 5296 | 编译器是否应该在编译后的代码中保留原始行号。 | ||
| 5297 | |||
| 5298 | **签名:** | ||
| 5299 | ```lua | ||
| 5300 | reserve_line_number: boolean | ||
| 5301 | ``` | ||
| 5302 | |||
| 5303 | #### reserve_comment | ||
| 5304 | |||
| 5305 | **类型:** 成员变量。 | ||
| 5306 | |||
| 5307 | **描述:** | ||
| 5308 | |||
| 5309 | 编译器是否应该在编译后的代码中保留原始注释。 | ||
| 5310 | |||
| 5311 | **签名:** | ||
| 5312 | ```lua | ||
| 5313 | reserve_comment: boolean | ||
| 5314 | ``` | ||
| 5315 | |||
| 5316 | #### space_over_tab | ||
| 5317 | |||
| 5318 | **类型:** 成员变量。 | ||
| 5319 | |||
| 5320 | **描述:** | ||
| 5321 | |||
| 5322 | 编译器是否应该在编译后的代码中使用空格字符而不是制表符字符。 | ||
| 5323 | |||
| 5324 | **签名:** | ||
| 5325 | ```lua | ||
| 5326 | space_over_tab: boolean | ||
| 5327 | ``` | ||
| 5328 | |||
| 5329 | #### same_module | ||
| 5330 | |||
| 5331 | **类型:** 成员变量。 | ||
| 5332 | |||
| 5333 | **描述:** | ||
| 5334 | |||
| 5335 | 编译器是否应该将要编译的代码视为当前正在编译的模块。仅供编译器内部使用。 | ||
| 5336 | |||
| 5337 | **签名:** | ||
| 5338 | ```lua | ||
| 5339 | same_module: boolean | ||
| 5340 | ``` | ||
| 5341 | |||
| 5342 | #### line_offset | ||
| 5343 | |||
| 5344 | **类型:** 成员变量。 | ||
| 5345 | |||
| 5346 | **描述:** | ||
| 5347 | |||
| 5348 | 编译器错误消息是否应该包含行号偏移量。仅供编译器内部使用。 | ||
| 5349 | |||
| 5350 | **签名:** | ||
| 5351 | ```lua | ||
| 5352 | line_offset: integer | ||
| 5353 | ``` | ||
| 5354 | |||
| 5355 | #### yue.Config.LuaTarget | ||
| 5356 | |||
| 5357 | **类型:** 枚举。 | ||
| 5358 | |||
| 5359 | **描述:** | ||
| 5360 | |||
| 5361 | 目标 Lua 版本枚举。 | ||
| 5362 | |||
| 5363 | **签名:** | ||
| 5364 | ```lua | ||
| 5365 | enum LuaTarget | ||
| 5366 | "5.1" | ||
| 5367 | "5.2" | ||
| 5368 | "5.3" | ||
| 5369 | "5.4" | ||
| 5370 | "5.5" | ||
| 5371 | end | ||
| 5372 | ``` | ||
| 5373 | |||
| 5374 | #### options | ||
| 5375 | |||
| 5376 | **类型:** 成员变量。 | ||
| 5377 | |||
| 5378 | **描述:** | ||
| 5379 | |||
| 5380 | 要传递给编译函数的额外选项。 | ||
| 5381 | |||
| 5382 | **签名:** | ||
| 5383 | ```lua | ||
| 5384 | options: Options | ||
| 5385 | ``` | ||
| 5386 | |||
| 5387 | ### Options | ||
| 5388 | |||
| 5389 | **描述:** | ||
| 5390 | |||
| 5391 | 额外编译器选项定义。 | ||
| 5392 | |||
| 5393 | #### target | ||
| 5394 | |||
| 5395 | **类型:** 成员变量。 | ||
| 5396 | |||
| 5397 | **描述:** | ||
| 5398 | |||
| 5399 | 编译目标 Lua 版本。 | ||
| 5400 | |||
| 5401 | **签名:** | ||
| 5402 | ```lua | ||
| 5403 | target: LuaTarget | ||
| 5404 | ``` | ||
| 5405 | |||
| 5406 | #### path | ||
| 5407 | |||
| 5408 | **类型:** 成员变量。 | ||
| 5409 | |||
| 5410 | **描述:** | ||
| 5411 | |||
| 5412 | 额外模块搜索路径。 | ||
| 5413 | |||
| 5414 | **签名:** | ||
| 5415 | ```lua | ||
| 5416 | path: string | ||
| 5417 | ``` | ||
| 5418 | |||
| 5419 | #### dump_locals | ||
| 5420 | |||
| 5421 | **类型:** 成员变量。 | ||
| 5422 | |||
| 5423 | **描述:** | ||
| 5424 | |||
| 5425 | 是否在回溯错误消息中输出代码块的局部变量。默认为 false。 | ||
| 5426 | |||
| 5427 | **签名:** | ||
| 5428 | ```lua | ||
| 5429 | dump_locals: boolean | ||
| 5430 | ``` | ||
| 5431 | |||
| 5432 | #### simplified | ||
| 5433 | |||
| 5434 | **类型:** 成员变量。 | ||
| 5435 | |||
| 5436 | **描述:** | ||
| 5437 | |||
| 5438 | 是否简化输出的错误消息。默认为 true。 | ||
| 5439 | |||
| 5440 | **签名:** | ||
| 5441 | ```lua | ||
| 5442 | simplified: boolean | ||
| 5443 | ``` | ||
| 5444 | |||
| 5445 | ## MIT 许可证 | ||
| 5446 | |||
| 5447 | 版权 (c) 2017-2025 李瑾 \<dragon-fly@qq.com\> | ||
| 5448 | |||
| 5449 | 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,以及再授权被配发了本软件的人如上的权利,须在下列条件下: | ||
| 5450 | 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | ||
| 5451 | 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | ||
| 5452 | |||
| 5453 | <CompilerModal /> | ||
diff --git a/doc/docs/zh/doc/installation.md b/doc/docs/zh/doc/installation.md new file mode 100644 index 0000000..618da2a --- /dev/null +++ b/doc/docs/zh/doc/installation.md | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # 安装 | ||
| 2 | |||
| 3 | ## Lua 模块 | ||
| 4 | |||
| 5 |  安装 [luarocks](https://luarocks.org),一个 Lua 模块的包管理器。然后作为 Lua 模块和可执行文件安装它: | ||
| 6 | |||
| 7 | ```shell | ||
| 8 | luarocks install yuescript | ||
| 9 | ``` | ||
| 10 | |||
| 11 |  或者你可以自己构建 `yue.so` 文件: | ||
| 12 | |||
| 13 | ```shell | ||
| 14 | make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
| 15 | ``` | ||
| 16 | |||
| 17 |  然后从路径 **bin/shared/yue.so** 获取二进制文件。 | ||
| 18 | |||
| 19 | ## 构建二进制工具 | ||
| 20 | |||
| 21 |  克隆项目仓库,然后构建并安装可执行文件: | ||
| 22 | |||
| 23 | ```shell | ||
| 24 | make install | ||
| 25 | ``` | ||
| 26 | |||
| 27 |  构建不带宏功能的月之脚本编译工具: | ||
| 28 | |||
| 29 | ```shell | ||
| 30 | make install NO_MACRO=true | ||
| 31 | ``` | ||
| 32 | |||
| 33 |  构建不带内置Lua二进制文件的月之脚本编译工具: | ||
| 34 | |||
| 35 | ```shell | ||
| 36 | make install NO_LUA=true | ||
| 37 | ``` | ||
| 38 | |||
| 39 | ## 下载预编译的二进制程序 | ||
| 40 | |||
| 41 |  你可以下载预编译的二进制程序,包括兼容不同 Lua 版本的二进制可执行文件和库文件。 | ||
| 42 | |||
| 43 |  在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程序。 | ||
diff --git a/doc/docs/zh/doc/introduction.md b/doc/docs/zh/doc/introduction.md new file mode 100644 index 0000000..827d163 --- /dev/null +++ b/doc/docs/zh/doc/introduction.md | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | # 介绍 | ||
| 2 | |||
| 3 | 月之脚本(YueScript)是一种动态语言,可以编译为 Lua。它是 [MoonScript](https://github.com/leafo/moonscript) 的方言。用月之脚本编写的代码既有表现力又非常简洁。它适合编写一些更易于维护的代码,并在嵌入 Lua 的环境中运行,如游戏或网站服务器。 | ||
| 4 | |||
| 5 | Yue(月)是中文中“月亮”的名称。 | ||
| 6 | |||
| 7 | ## 月之脚本概览 | ||
| 8 | ```yuescript | ||
| 9 | -- 导入语法 | ||
| 10 | import p, to_lua from "yue" | ||
| 11 | |||
| 12 | -- 隐式对象 | ||
| 13 | inventory = | ||
| 14 | equipment: | ||
| 15 | - "sword" | ||
| 16 | - "shield" | ||
| 17 | items: | ||
| 18 | - name: "potion" | ||
| 19 | count: 10 | ||
| 20 | - name: "bread" | ||
| 21 | count: 3 | ||
| 22 | |||
| 23 | -- 列表推导 | ||
| 24 | map = (arr, action) -> | ||
| 25 | [action item for item in *arr] | ||
| 26 | |||
| 27 | filter = (arr, cond) -> | ||
| 28 | [item for item in *arr when cond item] | ||
| 29 | |||
| 30 | reduce = (arr, init, action): init -> | ||
| 31 | init = action init, item for item in *arr | ||
| 32 | |||
| 33 | -- 管道操作符 | ||
| 34 | [1, 2, 3] | ||
| 35 | |> map (x) -> x * 2 | ||
| 36 | |> filter (x) -> x > 4 | ||
| 37 | |> reduce 0, (a, b) -> a + b | ||
| 38 | |||
| 39 | |||
| 40 | -- 元表操作 | ||
| 41 | apple = | ||
| 42 | size: 15 | ||
| 43 | <index>: | ||
| 44 | color: 0x00ffff | ||
| 45 | |||
| 46 | with apple | ||
| 47 | p .size, .color, .<index> if .<>? | ||
| 48 | |||
| 49 | -- 类似js的导出语法 | ||
| 50 | export 🌛 = "月之脚本" | ||
| 51 | ``` | ||
| 52 | <YueDisplay> | ||
| 53 | |||
| 54 | ```yue | ||
| 55 | -- 导入语法 | ||
| 56 | import p, to_lua from "yue" | ||
| 57 | |||
| 58 | -- 隐式对象 | ||
| 59 | inventory = | ||
| 60 | equipment: | ||
| 61 | - "sword" | ||
| 62 | - "shield" | ||
| 63 | items: | ||
| 64 | - name: "potion" | ||
| 65 | count: 10 | ||
| 66 | - name: "bread" | ||
| 67 | count: 3 | ||
| 68 | |||
| 69 | -- 列表推导 | ||
| 70 | map = (arr, action) -> | ||
| 71 | [action item for item in *arr] | ||
| 72 | |||
| 73 | filter = (arr, cond) -> | ||
| 74 | [item for item in *arr when cond item] | ||
| 75 | |||
| 76 | reduce = (arr, init, action): init -> | ||
| 77 | init = action init, item for item in *arr | ||
| 78 | |||
| 79 | -- 管道操作符 | ||
| 80 | [1, 2, 3] | ||
| 81 | |> map (x) -> x * 2 | ||
| 82 | |> filter (x) -> x > 4 | ||
| 83 | |> reduce 0, (a, b) -> a + b | ||
| 84 | |||
| 85 | |||
| 86 | -- 元表操作 | ||
| 87 | apple = | ||
| 88 | size: 15 | ||
| 89 | <index>: | ||
| 90 | color: 0x00ffff | ||
| 91 | |||
| 92 | with apple | ||
| 93 | p .size, .color, .<index> if .<>? | ||
| 94 | |||
| 95 | -- 类似js的导出语法 | ||
| 96 | export 🌛 = "月之脚本" | ||
| 97 | ``` | ||
| 98 | |||
| 99 | </YueDisplay> | ||
| 100 | |||
| 101 | ## 关于 Dora SSR | ||
| 102 | |||
| 103 | 月之脚本是与开源游戏引擎 [Dora SSR](https://github.com/Dora-SSR/Dora-SSR) 一起开发和维护的。它已被用于创建引擎工具、游戏原型和演示,在实际的游戏项目中验证其能力,同时它也帮助增强了 Dora SSR 游戏引擎的开发体验。 | ||
diff --git a/doc/docs/zh/doc/licence-mit.md b/doc/docs/zh/doc/licence-mit.md new file mode 100644 index 0000000..1a07518 --- /dev/null +++ b/doc/docs/zh/doc/licence-mit.md | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # MIT 许可证 | ||
| 2 | |||
| 3 | 版权 (c) 2017-2026 李瑾 \<dragon-fly@qq.com\> | ||
| 4 | |||
| 5 | 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,以及再授权被配发了本软件的人如上的权利,须在下列条件下: | ||
| 6 | 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | ||
| 7 | 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | ||
| 8 | |||
| 9 | <CompilerModal /> | ||
diff --git a/doc/docs/zh/doc/line-decorators.md b/doc/docs/zh/doc/line-decorators.md new file mode 100644 index 0000000..86a1bd9 --- /dev/null +++ b/doc/docs/zh/doc/line-decorators.md | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | # 代码行修饰 | ||
| 2 | |||
| 3 |   为了方便编写代码,循环语句和 if 语句可以应用于单行代码语句的末尾: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | print "你好,世界" if name == "Rob" | ||
| 7 | ``` | ||
| 8 | <YueDisplay> | ||
| 9 | |||
| 10 | ```yue | ||
| 11 | print "你好,世界" if name == "Rob" | ||
| 12 | ``` | ||
| 13 | |||
| 14 | </YueDisplay> | ||
| 15 | |||
| 16 |   修饰 for 循环的示例: | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | print "项目: ", item for item in *items | ||
| 20 | ``` | ||
| 21 | <YueDisplay> | ||
| 22 | |||
| 23 | ```yue | ||
| 24 | print "项目: ", item for item in *items | ||
| 25 | ``` | ||
| 26 | |||
| 27 | </YueDisplay> | ||
| 28 | |||
| 29 |   修饰 while 循环的示例: | ||
| 30 | |||
| 31 | ```yuescript | ||
| 32 | game\update! while game\isRunning! | ||
| 33 | |||
| 34 | reader\parse_line! until reader\eof! | ||
| 35 | ``` | ||
| 36 | <YueDisplay> | ||
| 37 | |||
| 38 | ```yue | ||
| 39 | game\update! while game\isRunning! | ||
| 40 | |||
| 41 | reader\parse_line! until reader\eof! | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/literals.md b/doc/docs/zh/doc/literals.md new file mode 100644 index 0000000..1592bae --- /dev/null +++ b/doc/docs/zh/doc/literals.md | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | # 字面量 | ||
| 2 | |||
| 3 |   Lua 中的所有基本字面量都可以在月之脚本中使用。包括数字、字符串、布尔值和 **nil**。 | ||
| 4 | |||
| 5 |   但与 Lua 不同的是,单引号和双引号字符串内部允许有换行: | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | some_string = "这是一个字符串 | ||
| 9 | 并包括一个换行。" | ||
| 10 | |||
| 11 | -- 使用#{}语法可以将表达式插入到字符串字面量中。 | ||
| 12 | -- 字符串插值只在双引号字符串中可用。 | ||
| 13 | print "我有#{math.random! * 100}%的把握。" | ||
| 14 | ``` | ||
| 15 | <YueDisplay> | ||
| 16 | |||
| 17 | ```yue | ||
| 18 | some_string = "这是一个字符串 | ||
| 19 | 并包括一个换行。" | ||
| 20 | |||
| 21 | -- 使用#{}语法可以将表达式插入到字符串字面量中。 | ||
| 22 | -- 字符串插值只在双引号字符串中可用。 | ||
| 23 | print "我有#{math.random! * 100}%的把握。" | ||
| 24 | ``` | ||
| 25 | |||
| 26 | </YueDisplay> | ||
| 27 | |||
| 28 | ## 数字字面量 | ||
| 29 | |||
| 30 |   你可以在数字字面量中使用下划线来增加可读性。 | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | integer = 1_000_000 | ||
| 34 | hex = 0xEF_BB_BF | ||
| 35 | binary = 0B10011 | ||
| 36 | ``` | ||
| 37 | <YueDisplay> | ||
| 38 | |||
| 39 | |||
| 40 | ```yue | ||
| 41 | integer = 1_000_000 | ||
| 42 | hex = 0xEF_BB_BF | ||
| 43 | binary = 0B10011 | ||
| 44 | ``` | ||
| 45 | |||
| 46 | </YueDisplay> | ||
| 47 | |||
| 48 | ## YAML 风格字符串 | ||
| 49 | |||
| 50 |   使用 `|` 前缀标记一个多行 YAML 风格字符串: | ||
| 51 | |||
| 52 | ```yuescript | ||
| 53 | str = | | ||
| 54 | key: value | ||
| 55 | list: | ||
| 56 | - item1 | ||
| 57 | - #{expr} | ||
| 58 | ``` | ||
| 59 | <YueDisplay> | ||
| 60 | |||
| 61 | ```yue | ||
| 62 | str = | | ||
| 63 | key: value | ||
| 64 | list: | ||
| 65 | - item1 | ||
| 66 | - #{expr} | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
| 70 | |||
| 71 |   其效果类似于原生 Lua 的多行拼接,所有文本(含换行)将被保留下来,并支持 `#{...}` 语法,通过 `tostring(expr)` 插入表达式结果。 | ||
| 72 | |||
| 73 |   YAML 风格的多行字符串会自动检测首行后最小的公共缩进,并从所有行中删除该前缀空白字符。这让你可以在代码中对齐文本,但输出字符串不会带多余缩进。 | ||
| 74 | |||
| 75 | ```yuescript | ||
| 76 | fn = -> | ||
| 77 | str = | | ||
| 78 | foo: | ||
| 79 | bar: baz | ||
| 80 | return str | ||
| 81 | ``` | ||
| 82 | <YueDisplay> | ||
| 83 | |||
| 84 | ```yue | ||
| 85 | fn = -> | ||
| 86 | str = | | ||
| 87 | foo: | ||
| 88 | bar: baz | ||
| 89 | return str | ||
| 90 | ``` | ||
| 91 | |||
| 92 | </YueDisplay> | ||
| 93 | |||
| 94 |   输出字符串中的 foo: 对齐到行首,不会带有函数缩进空格。保留内部缩进的相对结构,适合书写结构化嵌套样式的内容。 | ||
| 95 | |||
| 96 |   支持自动处理字符中的引号、反斜杠等特殊符号,无需手动转义: | ||
| 97 | |||
| 98 | ```yuescript | ||
| 99 | str = | | ||
| 100 | path: "C:\Program Files\App" | ||
| 101 | note: 'He said: "#{Hello}!"' | ||
| 102 | ``` | ||
| 103 | <YueDisplay> | ||
| 104 | |||
| 105 | ```yue | ||
| 106 | str = | | ||
| 107 | path: "C:\Program Files\App" | ||
| 108 | note: 'He said: "#{Hello}!"' | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/macro.md b/doc/docs/zh/doc/macro.md new file mode 100644 index 0000000..924b3ab --- /dev/null +++ b/doc/docs/zh/doc/macro.md | |||
| @@ -0,0 +1,276 @@ | |||
| 1 | # 宏 | ||
| 2 | |||
| 3 | ## 常见用法 | ||
| 4 | |||
| 5 |   宏函数用于在编译时执行一段代码来生成新的代码,并将生成的代码插入到最终编译结果中。 | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | macro PI2 = -> math.pi * 2 | ||
| 9 | area = $PI2 * 5 | ||
| 10 | |||
| 11 | macro HELLO = -> "'你好 世界'" | ||
| 12 | print $HELLO | ||
| 13 | |||
| 14 | macro config = (debugging) -> | ||
| 15 | global debugMode = debugging == "true" | ||
| 16 | "" | ||
| 17 | |||
| 18 | macro asserts = (cond) -> | ||
| 19 | debugMode and "assert #{cond}" or "" | ||
| 20 | |||
| 21 | macro assert = (cond) -> | ||
| 22 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 23 | |||
| 24 | $config true | ||
| 25 | $asserts item ~= nil | ||
| 26 | |||
| 27 | $config false | ||
| 28 | value = $assert item | ||
| 29 | |||
| 30 | -- 宏函数参数传递的表达式会被转换为字符串 | ||
| 31 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 32 | if $and f1!, f2!, f3! | ||
| 33 | print "OK" | ||
| 34 | ``` | ||
| 35 | <YueDisplay> | ||
| 36 | |||
| 37 | ```yue | ||
| 38 | macro PI2 = -> math.pi * 2 | ||
| 39 | area = $PI2 * 5 | ||
| 40 | |||
| 41 | macro HELLO = -> "'你好 世界'" | ||
| 42 | print $HELLO | ||
| 43 | |||
| 44 | macro config = (debugging) -> | ||
| 45 | global debugMode = debugging == "true" | ||
| 46 | "" | ||
| 47 | |||
| 48 | macro asserts = (cond) -> | ||
| 49 | debugMode and "assert #{cond}" or "" | ||
| 50 | |||
| 51 | macro assert = (cond) -> | ||
| 52 | debugMode and "assert #{cond}" or "#{cond}" | ||
| 53 | |||
| 54 | $config true | ||
| 55 | $asserts item ~= nil | ||
| 56 | |||
| 57 | $config false | ||
| 58 | value = $assert item | ||
| 59 | |||
| 60 | -- 宏函数参数传递的表达式会被转换为字符串 | ||
| 61 | macro and = (...) -> "#{ table.concat {...}, ' and ' }" | ||
| 62 | if $and f1!, f2!, f3! | ||
| 63 | print "OK" | ||
| 64 | ``` | ||
| 65 | |||
| 66 | </YueDisplay> | ||
| 67 | |||
| 68 | ## 直接插入代码 | ||
| 69 | |||
| 70 |   宏函数可以返回一个包含月之脚本代码的字符串,或是一个包含 Lua 代码字符串的配置表。 | ||
| 71 | |||
| 72 | ```yuescript | ||
| 73 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 74 | $yueFunc funcA | ||
| 75 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | ||
| 76 | |||
| 77 | macro luaFunc = (var) -> { | ||
| 78 | code: "local function #{var}() end" | ||
| 79 | type: "lua" | ||
| 80 | } | ||
| 81 | $luaFunc funcB | ||
| 82 | funcB = -> "无法访问宏生成 Lua 代码里定义的变量" | ||
| 83 | |||
| 84 | macro lua = (code) -> { | ||
| 85 | :code | ||
| 86 | type: "lua" | ||
| 87 | } | ||
| 88 | |||
| 89 | -- raw字符串的开始和结束符号会自动被去除了再传入宏函数 | ||
| 90 | $lua[==[ | ||
| 91 | -- 插入原始Lua代码 | ||
| 92 | if cond then | ||
| 93 | print("输出") | ||
| 94 | end | ||
| 95 | ]==] | ||
| 96 | ``` | ||
| 97 | <YueDisplay> | ||
| 98 | |||
| 99 | ```yue | ||
| 100 | macro yueFunc = (var) -> "local #{var} = ->" | ||
| 101 | $yueFunc funcA | ||
| 102 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | ||
| 103 | |||
| 104 | macro luaFunc = (var) -> { | ||
| 105 | code: "local function #{var}() end" | ||
| 106 | type: "lua" | ||
| 107 | } | ||
| 108 | $luaFunc funcB | ||
| 109 | funcB = -> "无法访问宏生成 Lua 代码里定义的变量" | ||
| 110 | |||
| 111 | macro lua = (code) -> { | ||
| 112 | :code | ||
| 113 | type: "lua" | ||
| 114 | } | ||
| 115 | |||
| 116 | -- raw字符串的开始和结束符号会自动被去除了再传入宏函数 | ||
| 117 | $lua[==[ | ||
| 118 | -- 插入原始Lua代码 | ||
| 119 | if cond then | ||
| 120 | print("输出") | ||
| 121 | end | ||
| 122 | ]==] | ||
| 123 | ``` | ||
| 124 | |||
| 125 | </YueDisplay> | ||
| 126 | |||
| 127 | ## 导出宏 | ||
| 128 | |||
| 129 |   宏函数可以从一个模块中导出,并在另一个模块中导入。你必须将导出的宏函数放在一个单独的文件中使用,而且只有宏定义、宏导入和宏展开可以放入这个宏导出模块中。 | ||
| 130 | |||
| 131 | ```yuescript | ||
| 132 | -- 文件: utils.yue | ||
| 133 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 134 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 135 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 136 | #{action}" | ||
| 137 | |||
| 138 | -- 文件 main.yue | ||
| 139 | import "utils" as { | ||
| 140 | $, -- 表示导入所有宏的符号 | ||
| 141 | $foreach: $each -- 重命名宏 $foreach 为 $each | ||
| 142 | } | ||
| 143 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 144 | ``` | ||
| 145 | <YueDisplay> | ||
| 146 | |||
| 147 | ```yue | ||
| 148 | -- 文件: utils.yue | ||
| 149 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | ||
| 150 | export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]" | ||
| 151 | export macro foreach = (items, action) -> "for _ in *#{items} | ||
| 152 | #{action}" | ||
| 153 | -- 文件 main.yue | ||
| 154 | -- 在浏览器中不支持import函数,请在真实环境中尝试 | ||
| 155 | --[[ | ||
| 156 | import "utils" as { | ||
| 157 | $, -- 表示导入所有宏的符号 | ||
| 158 | $foreach: $each -- 重命名宏 $foreach 为 $each | ||
| 159 | } | ||
| 160 | [1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
| 161 | ]] | ||
| 162 | ``` | ||
| 163 | |||
| 164 | </YueDisplay> | ||
| 165 | |||
| 166 | ## 内置宏 | ||
| 167 | |||
| 168 |   月之脚本中有一些内置可以直接使用的宏,但你可以通过声明相同名称的宏来覆盖它们。 | ||
| 169 | |||
| 170 | ```yuescript | ||
| 171 | print $FILE -- 获取当前模块名称的字符串 | ||
| 172 | print $LINE -- 获取当前代码行数:2 | ||
| 173 | ``` | ||
| 174 | <YueDisplay> | ||
| 175 | |||
| 176 | ```yue | ||
| 177 | print $FILE -- 获取当前模块名称的字符串 | ||
| 178 | print $LINE -- 获取当前代码行数:2 | ||
| 179 | ``` | ||
| 180 | |||
| 181 | </YueDisplay> | ||
| 182 | |||
| 183 | ## 用宏生成宏 | ||
| 184 | |||
| 185 |   在月之脚本中,宏函数允许你在编译时生成代码。通过嵌套的宏函数,你可以创建更复杂的生成模式。这个特性允许你定义一个宏函数,用它来生成另一个宏函数,从而实现更加动态的代码生成。 | ||
| 186 | |||
| 187 | ```yuescript | ||
| 188 | macro Enum = (...) -> | ||
| 189 | items = {...} | ||
| 190 | itemSet = {item, true for item in *items} | ||
| 191 | (item) -> | ||
| 192 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 193 | "\"#{item}\"" | ||
| 194 | |||
| 195 | macro BodyType = $Enum( | ||
| 196 | Static | ||
| 197 | Dynamic | ||
| 198 | Kinematic | ||
| 199 | ) | ||
| 200 | |||
| 201 | print "有效的枚举类型:", $BodyType Static | ||
| 202 | -- print "编译报错的枚举类型:", $BodyType Unknown | ||
| 203 | ``` | ||
| 204 | <YueDisplay> | ||
| 205 | |||
| 206 | ```yue | ||
| 207 | macro Enum = (...) -> | ||
| 208 | items = {...} | ||
| 209 | itemSet = {item, true for item in *items} | ||
| 210 | (item) -> | ||
| 211 | error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] | ||
| 212 | "\"#{item}\"" | ||
| 213 | |||
| 214 | macro BodyType = $Enum( | ||
| 215 | Static | ||
| 216 | Dynamic | ||
| 217 | Kinematic | ||
| 218 | ) | ||
| 219 | |||
| 220 | print "有效的枚举类型:", $BodyType Static | ||
| 221 | -- print "编译报错的枚举类型:", $BodyType Unknown | ||
| 222 | ``` | ||
| 223 | |||
| 224 | </YueDisplay> | ||
| 225 | |||
| 226 | ## 宏参数检查 | ||
| 227 | |||
| 228 |   可以直接在参数列表中声明期望的 AST 节点类型,并在编译时检查传入的宏参数是否符合预期。 | ||
| 229 | |||
| 230 | ```yuescript | ||
| 231 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 232 | print( | ||
| 233 | #{num} | ||
| 234 | #{str} | ||
| 235 | ) | ||
| 236 | |||
| 237 | $printNumAndStr 123, "hello" | ||
| 238 | ``` | ||
| 239 | <YueDisplay> | ||
| 240 | |||
| 241 | ```yue | ||
| 242 | macro printNumAndStr = (num `Num, str `String) -> | | ||
| 243 | print( | ||
| 244 | #{num} | ||
| 245 | #{str} | ||
| 246 | ) | ||
| 247 | |||
| 248 | $printNumAndStr 123, "hello" | ||
| 249 | ``` | ||
| 250 | |||
| 251 | </YueDisplay> | ||
| 252 | |||
| 253 |   如果需要做更加灵活的参数检查操作,可以使用内置的 `$is_ast` 宏函数在合适的位置进行手动检查。 | ||
| 254 | |||
| 255 | ```yuescript | ||
| 256 | macro printNumAndStr = (num, str) -> | ||
| 257 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 258 | error "expected String as second argument" unless $is_ast String, str | ||
| 259 | "print(#{num}, #{str})" | ||
| 260 | |||
| 261 | $printNumAndStr 123, "hello" | ||
| 262 | ``` | ||
| 263 | <YueDisplay> | ||
| 264 | |||
| 265 | ```yue | ||
| 266 | macro printNumAndStr = (num, str) -> | ||
| 267 | error "expected Num as first argument" unless $is_ast Num, num | ||
| 268 | error "expected String as second argument" unless $is_ast String, str | ||
| 269 | "print(#{num}, #{str})" | ||
| 270 | |||
| 271 | $printNumAndStr 123, "hello" | ||
| 272 | ``` | ||
| 273 | |||
| 274 | </YueDisplay> | ||
| 275 | |||
| 276 |   更多关于可用 AST 节点的详细信息,请参考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) 中大写的规则定义。 | ||
diff --git a/doc/docs/zh/doc/module.md b/doc/docs/zh/doc/module.md new file mode 100644 index 0000000..bae6618 --- /dev/null +++ b/doc/docs/zh/doc/module.md | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | # 模块 | ||
| 2 | |||
| 3 | ## 导入 | ||
| 4 | |||
| 5 |   导入语句是一个语法糖,用于需要引入一个模块或者从已导入的模块中提取子项目。从模块导入的变量默认为不可修改的常量。 | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | -- 用作表解构 | ||
| 9 | do | ||
| 10 | import insert, concat from table | ||
| 11 | -- 当给 insert, concat 变量赋值时,编译器会报告错误 | ||
| 12 | import C, Ct, Cmt from require "lpeg" | ||
| 13 | -- 快捷写法引入模块的子项 | ||
| 14 | import x, y, z from 'mymodule' | ||
| 15 | -- 使用Python风格的导入 | ||
| 16 | from 'module' import a, b, c | ||
| 17 | |||
| 18 | -- 快捷地导入一个模块 | ||
| 19 | do | ||
| 20 | import 'module' | ||
| 21 | import 'module_x' | ||
| 22 | import "d-a-s-h-e-s" | ||
| 23 | import "module.part" | ||
| 24 | |||
| 25 | -- 导入模块后起一个别名使用,或是进行导入模块表的解构 | ||
| 26 | do | ||
| 27 | import "player" as PlayerModule | ||
| 28 | import "lpeg" as :C, :Ct, :Cmt | ||
| 29 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 30 | ``` | ||
| 31 | <YueDisplay> | ||
| 32 | |||
| 33 | ```yue | ||
| 34 | -- 用作表解构 | ||
| 35 | do | ||
| 36 | import insert, concat from table | ||
| 37 | -- 当给 insert, concat 变量赋值时,编译器会报告错误 | ||
| 38 | import C, Ct, Cmt from require "lpeg" | ||
| 39 | -- 快捷写法引入模块的子项 | ||
| 40 | import x, y, z from 'mymodule' | ||
| 41 | -- 使用Python风格的导入 | ||
| 42 | from 'module' import a, b, c | ||
| 43 | |||
| 44 | -- 快捷地导入一个模块 | ||
| 45 | do | ||
| 46 | import 'module' | ||
| 47 | import 'module_x' | ||
| 48 | import "d-a-s-h-e-s" | ||
| 49 | import "module.part" | ||
| 50 | |||
| 51 | -- 导入模块后起一个别名使用,或是进行导入模块表的解构 | ||
| 52 | do | ||
| 53 | import "player" as PlayerModule | ||
| 54 | import "lpeg" as :C, :Ct, :Cmt | ||
| 55 | import "export" as {one, two, Something:{umm:{ch}}} | ||
| 56 | ``` | ||
| 57 | |||
| 58 | </YueDisplay> | ||
| 59 | |||
| 60 | ## 导入全局变量 | ||
| 61 | |||
| 62 |   你可以使用 `import` 将指定的全局变量导入到本地变量中。当导入一系列对全局变量的链式访问时,最后一个访问的字段将被赋值给本地变量。 | ||
| 63 | |||
| 64 | ```yuescript | ||
| 65 | do | ||
| 66 | import tostring | ||
| 67 | import table.concat | ||
| 68 | print concat ["a", tostring 1] | ||
| 69 | ``` | ||
| 70 | <YueDisplay> | ||
| 71 | |||
| 72 | ```yue | ||
| 73 | do | ||
| 74 | import tostring | ||
| 75 | import table.concat | ||
| 76 | print concat ["a", tostring 1] | ||
| 77 | ``` | ||
| 78 | |||
| 79 | </YueDisplay> | ||
| 80 | |||
| 81 | ### 自动全局变量导入 | ||
| 82 | |||
| 83 |   在一个代码块的顶部写 `import global`,会将当前作用域中尚未显式声明或赋值过的变量名,自动导入为本地常量,并在该语句的位置绑定到同名的全局变量。 | ||
| 84 | |||
| 85 |   但是在同一作用域中被显式声明为全局的变量不会被自动导入,因此可以继续进行赋值操作。 | ||
| 86 | |||
| 87 | ```yuescript | ||
| 88 | do | ||
| 89 | import global | ||
| 90 | print "hello" | ||
| 91 | math.random 3 | ||
| 92 | -- print = nil -- 报错:自动导入的全局变量为常量 | ||
| 93 | |||
| 94 | do | ||
| 95 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 96 | import global | ||
| 97 | global FLAG | ||
| 98 | print FLAG | ||
| 99 | FLAG = 123 | ||
| 100 | ``` | ||
| 101 | <YueDisplay> | ||
| 102 | |||
| 103 | ```yue | ||
| 104 | do | ||
| 105 | import global | ||
| 106 | print "hello" | ||
| 107 | math.random 3 | ||
| 108 | -- print = nil -- 报错:自动导入的全局变量是常量 | ||
| 109 | |||
| 110 | do | ||
| 111 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 112 | import global | ||
| 113 | global FLAG | ||
| 114 | print FLAG | ||
| 115 | FLAG = 123 | ||
| 116 | ``` | ||
| 117 | |||
| 118 | </YueDisplay> | ||
| 119 | |||
| 120 | ## 导出 | ||
| 121 | |||
| 122 |   导出语句提供了一种简洁的方式来定义当前的模块。 | ||
| 123 | |||
| 124 | ### 命名导出 | ||
| 125 | |||
| 126 |   带命名的导出将定义一个局部变量,并在导出的表中添加一个同名的字段。 | ||
| 127 | |||
| 128 | ```yuescript | ||
| 129 | export a, b, c = 1, 2, 3 | ||
| 130 | export cool = "cat" | ||
| 131 | |||
| 132 | export What = if this | ||
| 133 | "abc" | ||
| 134 | else | ||
| 135 | "def" | ||
| 136 | |||
| 137 | export y = -> | ||
| 138 | hallo = 3434 | ||
| 139 | |||
| 140 | export class Something | ||
| 141 | umm: "cool" | ||
| 142 | ``` | ||
| 143 | <YueDisplay> | ||
| 144 | |||
| 145 | ```yue | ||
| 146 | export a, b, c = 1, 2, 3 | ||
| 147 | export cool = "cat" | ||
| 148 | |||
| 149 | export What = if this | ||
| 150 | "abc" | ||
| 151 | else | ||
| 152 | "def" | ||
| 153 | |||
| 154 | export y = -> | ||
| 155 | hallo = 3434 | ||
| 156 | |||
| 157 | export class Something | ||
| 158 | umm: "cool" | ||
| 159 | ``` | ||
| 160 | |||
| 161 | </YueDisplay> | ||
| 162 | |||
| 163 |   使用解构进行命名导出。 | ||
| 164 | |||
| 165 | ```yuescript | ||
| 166 | export :loadstring, to_lua: tolua = yue | ||
| 167 | export {itemA: {:fieldA = '默认值'}} = tb | ||
| 168 | ``` | ||
| 169 | <YueDisplay> | ||
| 170 | |||
| 171 | ```yue | ||
| 172 | export :loadstring, to_lua: tolua = yue | ||
| 173 | export {itemA: {:fieldA = '默认值'}} = tb | ||
| 174 | ``` | ||
| 175 | |||
| 176 | </YueDisplay> | ||
| 177 | |||
| 178 |   从模块导出命名项目时,可以不用创建局部变量。 | ||
| 179 | |||
| 180 | ```yuescript | ||
| 181 | export.itemA = tb | ||
| 182 | export.<index> = items | ||
| 183 | export["a-b-c"] = 123 | ||
| 184 | ``` | ||
| 185 | <YueDisplay> | ||
| 186 | |||
| 187 | ```yue | ||
| 188 | export.itemA = tb | ||
| 189 | export.<index> = items | ||
| 190 | export["a-b-c"] = 123 | ||
| 191 | ``` | ||
| 192 | |||
| 193 | </YueDisplay> | ||
| 194 | |||
| 195 | ### 未命名导出 | ||
| 196 | |||
| 197 |   未命名导出会将要导出的目标项目添加到导出表的数组部分。 | ||
| 198 | |||
| 199 | ```yuescript | ||
| 200 | d, e, f = 3, 2, 1 | ||
| 201 | export d, e, f | ||
| 202 | |||
| 203 | export if this | ||
| 204 | 123 | ||
| 205 | else | ||
| 206 | 456 | ||
| 207 | |||
| 208 | export with tmp | ||
| 209 | j = 2000 | ||
| 210 | ``` | ||
| 211 | <YueDisplay> | ||
| 212 | |||
| 213 | ```yue | ||
| 214 | d, e, f = 3, 2, 1 | ||
| 215 | export d, e, f | ||
| 216 | |||
| 217 | export if this | ||
| 218 | 123 | ||
| 219 | else | ||
| 220 | 456 | ||
| 221 | |||
| 222 | export with tmp | ||
| 223 | j = 2000 | ||
| 224 | ``` | ||
| 225 | |||
| 226 | </YueDisplay> | ||
| 227 | |||
| 228 | ### 默认导出 | ||
| 229 | |||
| 230 |   在导出语句中使用 **default** 关键字,来替换导出的表为一个目标的对象。 | ||
| 231 | |||
| 232 | ```yuescript | ||
| 233 | export default -> | ||
| 234 | print "你好" | ||
| 235 | 123 | ||
| 236 | ``` | ||
| 237 | <YueDisplay> | ||
| 238 | |||
| 239 | ```yue | ||
| 240 | export default -> | ||
| 241 | print "你好" | ||
| 242 | 123 | ||
| 243 | ``` | ||
| 244 | |||
| 245 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/object-oriented-programming.md b/doc/docs/zh/doc/object-oriented-programming.md new file mode 100644 index 0000000..9eb94d8 --- /dev/null +++ b/doc/docs/zh/doc/object-oriented-programming.md | |||
| @@ -0,0 +1,550 @@ | |||
| 1 | # 面向对象编程 | ||
| 2 | |||
| 3 |   在以下的示例中,月之脚本生成的 Lua 代码可能看起来会很复杂。所以最好主要关注月之脚本代码层面的意义,然后如果你想知道关于面向对象功能的实现细节,再查看 Lua 代码。 | ||
| 4 | |||
| 5 |   一个简单的类: | ||
| 6 | |||
| 7 | ```yuescript | ||
| 8 | class Inventory | ||
| 9 | new: => | ||
| 10 | @items = {} | ||
| 11 | |||
| 12 | add_item: (name) => | ||
| 13 | if @items[name] | ||
| 14 | @items[name] += 1 | ||
| 15 | else | ||
| 16 | @items[name] = 1 | ||
| 17 | ``` | ||
| 18 | <YueDisplay> | ||
| 19 | |||
| 20 | ```yue | ||
| 21 | class Inventory | ||
| 22 | new: => | ||
| 23 | @items = {} | ||
| 24 | |||
| 25 | add_item: (name) => | ||
| 26 | if @items[name] | ||
| 27 | @items[name] += 1 | ||
| 28 | else | ||
| 29 | @items[name] = 1 | ||
| 30 | ``` | ||
| 31 | |||
| 32 | </YueDisplay> | ||
| 33 | |||
| 34 |   在月之脚本中采用面向对象的编程方式时,通常会使用类声明语句结合 Lua 表格字面量来做类定义。这个类的定义包含了它的所有方法和属性。在这种结构中,键名为 “new” 的成员扮演了一个重要的角色,是作为构造函数来使用。 | ||
| 35 | |||
| 36 |   值得注意的是,类中的方法都采用了粗箭头函数语法。当在类的实例上调用方法时,该实例会自动作为第一个参数被传入,因此粗箭头函数用于生成一个名为 “self” 的参数。 | ||
| 37 | |||
| 38 |   此外,“@” 前缀在变量名上起到了简化作用,代表 “self”。例如,`@items` 就等同于 `self.items`。 | ||
| 39 | |||
| 40 |   为了创建类的一个新实例,可以将类名当作一个函数来调用,这样就可以生成并返回一个新的实例。 | ||
| 41 | |||
| 42 | ```yuescript | ||
| 43 | inv = Inventory! | ||
| 44 | inv\add_item "t-shirt" | ||
| 45 | inv\add_item "pants" | ||
| 46 | ``` | ||
| 47 | <YueDisplay> | ||
| 48 | |||
| 49 | |||
| 50 | ```yue | ||
| 51 | inv = Inventory! | ||
| 52 | inv\add_item "t-shirt" | ||
| 53 | inv\add_item "pants" | ||
| 54 | ``` | ||
| 55 | |||
| 56 | </YueDisplay> | ||
| 57 | |||
| 58 |   在月之脚本的类中,由于需要将类的实例作为参数传入到调用的方法中,因此使用了 **\\** 操作符做类的成员函数调用。 | ||
| 59 | |||
| 60 |   需要特别注意的是,类的所有属性在其实例之间是共享的。这对于函数类型的成员属性通常不会造成问题,但对于其他类型的属性,可能会导致意外的结果。 | ||
| 61 | |||
| 62 |   例如,在下面的示例中,clothes 属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影响到其他所有实例。 | ||
| 63 | |||
| 64 | ```yuescript | ||
| 65 | class Person | ||
| 66 | clothes: [] | ||
| 67 | give_item: (name) => | ||
| 68 | table.insert @clothes, name | ||
| 69 | |||
| 70 | a = Person! | ||
| 71 | b = Person! | ||
| 72 | |||
| 73 | a\give_item "pants" | ||
| 74 | b\give_item "shirt" | ||
| 75 | |||
| 76 | -- 会同时打印出裤子和衬衫 | ||
| 77 | print item for item in *a.clothes | ||
| 78 | ``` | ||
| 79 | <YueDisplay> | ||
| 80 | |||
| 81 | ```yue | ||
| 82 | class Person | ||
| 83 | clothes: [] | ||
| 84 | give_item: (name) => | ||
| 85 | table.insert @clothes, name | ||
| 86 | |||
| 87 | a = Person! | ||
| 88 | b = Person! | ||
| 89 | |||
| 90 | a\give_item "pants" | ||
| 91 | b\give_item "shirt" | ||
| 92 | |||
| 93 | -- 会同时打印出裤子和衬衫 | ||
| 94 | print item for item in *a.clothes | ||
| 95 | ``` | ||
| 96 | |||
| 97 | </YueDisplay> | ||
| 98 | |||
| 99 |   避免这个问题的正确方法是在构造函数中创建对象的可变状态: | ||
| 100 | |||
| 101 | ```yuescript | ||
| 102 | class Person | ||
| 103 | new: => | ||
| 104 | @clothes = [] | ||
| 105 | ``` | ||
| 106 | <YueDisplay> | ||
| 107 | |||
| 108 | ```yue | ||
| 109 | class Person | ||
| 110 | new: => | ||
| 111 | @clothes = [] | ||
| 112 | ``` | ||
| 113 | |||
| 114 | </YueDisplay> | ||
| 115 | |||
| 116 | ## 继承 | ||
| 117 | |||
| 118 |   `extends` 关键字可以在类声明中使用,以继承另一个类的属性和方法。 | ||
| 119 | |||
| 120 | ```yuescript | ||
| 121 | class BackPack extends Inventory | ||
| 122 | size: 10 | ||
| 123 | add_item: (name) => | ||
| 124 | if #@items > size then error "背包已满" | ||
| 125 | super name | ||
| 126 | ``` | ||
| 127 | <YueDisplay> | ||
| 128 | |||
| 129 | ```yue | ||
| 130 | class BackPack extends Inventory | ||
| 131 | size: 10 | ||
| 132 | add_item: (name) => | ||
| 133 | if #@items > size then error "背包已满" | ||
| 134 | super name | ||
| 135 | ``` | ||
| 136 | |||
| 137 | </YueDisplay> | ||
| 138 | |||
| 139 |   在这一部分,我们对月之脚本中的 `Inventory` 类进行了扩展,加入了对可以携带物品数量的限制。 | ||
| 140 | |||
| 141 |   在这个特定的例子中,子类并没有定义自己的构造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在子类中定义了构造函数,我们可以利用 `super` 方法来调用并执行父类的构造函数。 | ||
| 142 | |||
| 143 |   此外,当一个类继承自另一个类时,它会尝试调用父类上的 `__inherited` 方法(如果这个方法存在的话),以此来向父类发送通知。这个 `__inherited` 函数接受两个参数:被继承的父类和继承的子类。 | ||
| 144 | |||
| 145 | ```yuescript | ||
| 146 | class Shelf | ||
| 147 | @__inherited: (child) => | ||
| 148 | print @__name, "被", child.__name, "继承" | ||
| 149 | |||
| 150 | -- 将打印: Shelf 被 Cupboard 继承 | ||
| 151 | class Cupboard extends Shelf | ||
| 152 | ``` | ||
| 153 | <YueDisplay> | ||
| 154 | |||
| 155 | ```yue | ||
| 156 | class Shelf | ||
| 157 | @__inherited: (child) => | ||
| 158 | print @__name, "被", child.__name, "继承" | ||
| 159 | |||
| 160 | -- 将打印: Shelf 被 Cupboard 继承 | ||
| 161 | class Cupboard extends Shelf | ||
| 162 | ``` | ||
| 163 | |||
| 164 | </YueDisplay> | ||
| 165 | |||
| 166 | ## super 关键字 | ||
| 167 | |||
| 168 |   `super` 是一个特别的关键字,它有两种不同的使用方式:既可以当作一个对象来看待,也可以像调用函数那样使用。它仅在类的内部使用时具有特殊的功能。 | ||
| 169 | |||
| 170 |   当 `super` 被作为一个函数调用时,它将调用父类中与之同名的函数。此时,当前的 `self` 会自动作为第一个参数传递,正如上面提到的继承示例所展示的那样。 | ||
| 171 | |||
| 172 |   在将 `super` 当作普通值使用时,它实际上是对父类对象的引用。通过这种方式,我们可以访问父类中可能被子类覆盖的值,就像访问任何普通对象一样。 | ||
| 173 | |||
| 174 |   此外,当使用 `\` 操作符与 `super` 一起使用时,`self`将被插入为第一个参数,而不是使用 `super` 本身的值。而在使用`.`操作符来检索函数时,则会返回父类中的原始函数。 | ||
| 175 | |||
| 176 |   下面是一些使用 `super` 的不同方法的示例: | ||
| 177 | |||
| 178 | ```yuescript | ||
| 179 | class MyClass extends ParentClass | ||
| 180 | a_method: => | ||
| 181 | -- 以下效果相同: | ||
| 182 | super "你好", "世界" | ||
| 183 | super\a_method "你好", "世界" | ||
| 184 | super.a_method self, "你好", "世界" | ||
| 185 | |||
| 186 | -- super 作为值等于父类: | ||
| 187 | assert super == ParentClass | ||
| 188 | ``` | ||
| 189 | <YueDisplay> | ||
| 190 | |||
| 191 | ```yue | ||
| 192 | class MyClass extends ParentClass | ||
| 193 | a_method: => | ||
| 194 | -- 以下效果相同: | ||
| 195 | super "你好", "世界" | ||
| 196 | super\a_method "你好", "世界" | ||
| 197 | super.a_method self, "你好", "世界" | ||
| 198 | |||
| 199 | -- super 作为值等于父类: | ||
| 200 | assert super == ParentClass | ||
| 201 | ``` | ||
| 202 | |||
| 203 | </YueDisplay> | ||
| 204 | |||
| 205 |   **super** 也可以用在函数存根的左侧。唯一的主要区别是,生成的函数不是绑定到 super 的值,而是绑定到 self。 | ||
| 206 | |||
| 207 | ## 类型 | ||
| 208 | |||
| 209 |   每个类的实例都带有它的类型。这存储在特殊的 \_\_class 属性中。此属性会保存类对象。类对象是我们用来构建新实例的对象。我们还可以索引类对象以检索类方法和属性。 | ||
| 210 | |||
| 211 | ```yuescript | ||
| 212 | b = BackPack! | ||
| 213 | assert b.__class == BackPack | ||
| 214 | |||
| 215 | print BackPack.size -- 打印 10 | ||
| 216 | ``` | ||
| 217 | <YueDisplay> | ||
| 218 | |||
| 219 | ```yue | ||
| 220 | b = BackPack! | ||
| 221 | assert b.__class == BackPack | ||
| 222 | |||
| 223 | print BackPack.size -- 打印 10 | ||
| 224 | ``` | ||
| 225 | |||
| 226 | </YueDisplay> | ||
| 227 | |||
| 228 | ## 类对象 | ||
| 229 | |||
| 230 |   在月之脚本中,当我们编写类的定义语句时,实际上是在创建一个类对象。这个类对象被保存在一个与该类同名的变量中。 | ||
| 231 | |||
| 232 |   类对象具有函数的特性,可以被调用来创建新的实例。这正是我们在之前示例中所展示的创建类实例的方式。 | ||
| 233 | |||
| 234 |   一个类由两个表构成:类表本身和一个基表。基表作为所有实例的元表。在类声明中列出的所有属性都存放在基表中。 | ||
| 235 | |||
| 236 |   如果在类对象的元表中找不到某个属性,系统会从基表中检索该属性。这就意味着我们可以直接从类本身访问到其方法和属性。 | ||
| 237 | |||
| 238 |   需要特别注意的是,对类对象的赋值并不会影响到基表,因此这不是向实例添加新方法的正确方式。相反,需要直接修改基表。关于这点,可以参考下面的 “__base” 字段。 | ||
| 239 | |||
| 240 |   此外,类对象包含几个特殊的属性:当类被声明时,类的名称会作为一个字符串存储在类对象的 “__name” 字段中。 | ||
| 241 | |||
| 242 | ```yuescript | ||
| 243 | print BackPack.__name -- 打印 Backpack | ||
| 244 | ``` | ||
| 245 | <YueDisplay> | ||
| 246 | |||
| 247 | ```yue | ||
| 248 | print BackPack.__name -- 打印 Backpack | ||
| 249 | ``` | ||
| 250 | |||
| 251 | </YueDisplay> | ||
| 252 | |||
| 253 |   基础对象被保存在一个名为 `__base` 的特殊表中。我们可以编辑这个表,以便为那些已经创建出来的实例和还未创建的实例增加新的功能。 | ||
| 254 | |||
| 255 |   另外,如果一个类是从另一个类派生而来的,那么其父类对象则会被存储在名为 `__parent` 的地方。这种机制允许在类之间实现继承和功能扩展。 | ||
| 256 | |||
| 257 | ## 类变量 | ||
| 258 | |||
| 259 |   我们可以直接在类对象中创建变量,而不是在类的基对象中,通过在类声明中的属性名前使用 @。 | ||
| 260 | |||
| 261 | ```yuescript | ||
| 262 | class Things | ||
| 263 | @some_func: => print "Hello from", @__name | ||
| 264 | |||
| 265 | Things\some_func! | ||
| 266 | |||
| 267 | -- 类变量在实例中不可见 | ||
| 268 | assert Things().some_func == nil | ||
| 269 | ``` | ||
| 270 | <YueDisplay> | ||
| 271 | |||
| 272 | ```yue | ||
| 273 | class Things | ||
| 274 | @some_func: => print "Hello from", @__name | ||
| 275 | |||
| 276 | Things\some_func! | ||
| 277 | |||
| 278 | -- 类变量在实例中不可见 | ||
| 279 | assert Things().some_func == nil | ||
| 280 | ``` | ||
| 281 | |||
| 282 | </YueDisplay> | ||
| 283 | |||
| 284 |   在表达式中,我们可以使用 @@ 来访问存储在 `self.__class` 中的值。因此,`@@hello` 是 `self.__class.hello` 的简写。 | ||
| 285 | |||
| 286 | ```yuescript | ||
| 287 | class Counter | ||
| 288 | @count: 0 | ||
| 289 | |||
| 290 | new: => | ||
| 291 | @@count += 1 | ||
| 292 | |||
| 293 | Counter! | ||
| 294 | Counter! | ||
| 295 | |||
| 296 | print Counter.count -- 输出 2 | ||
| 297 | ``` | ||
| 298 | <YueDisplay> | ||
| 299 | |||
| 300 | ```yue | ||
| 301 | class Counter | ||
| 302 | @count: 0 | ||
| 303 | |||
| 304 | new: => | ||
| 305 | @@count += 1 | ||
| 306 | |||
| 307 | Counter! | ||
| 308 | Counter! | ||
| 309 | |||
| 310 | print Counter.count -- 输出 2 | ||
| 311 | ``` | ||
| 312 | |||
| 313 | </YueDisplay> | ||
| 314 | |||
| 315 |   @@ 的调用语义与 @ 类似。调用 @@ 时,会使用 Lua 的冒号语法将类作为第一个参数传入。 | ||
| 316 | |||
| 317 | ```yuescript | ||
| 318 | @@hello 1,2,3,4 | ||
| 319 | ``` | ||
| 320 | <YueDisplay> | ||
| 321 | |||
| 322 | ```yue | ||
| 323 | @@hello 1,2,3,4 | ||
| 324 | ``` | ||
| 325 | |||
| 326 | </YueDisplay> | ||
| 327 | |||
| 328 | ## 类声明语句 | ||
| 329 | |||
| 330 |   在类声明的主体中,除了键/值对外,我们还可以编写普通的表达式。在这种类声明体中的普通代码的上下文中,self 等于类对象,而不是实例对象。 | ||
| 331 | |||
| 332 |   以下是创建类变量的另一种方法: | ||
| 333 | |||
| 334 | ```yuescript | ||
| 335 | class Things | ||
| 336 | @class_var = "hello world" | ||
| 337 | ``` | ||
| 338 | <YueDisplay> | ||
| 339 | |||
| 340 | ```yue | ||
| 341 | class Things | ||
| 342 | @class_var = "hello world" | ||
| 343 | ``` | ||
| 344 | |||
| 345 | </YueDisplay> | ||
| 346 | |||
| 347 |   这些表达式会在所有属性被添加到类的基对象后执行。 | ||
| 348 | |||
| 349 |   在类的主体中声明的所有变量都会限制作用域只在类声明的范围。这对于放置只有类方法可以访问的私有值或辅助函数很方便: | ||
| 350 | |||
| 351 | ```yuescript | ||
| 352 | class MoreThings | ||
| 353 | secret = 123 | ||
| 354 | log = (msg) -> print "LOG:", msg | ||
| 355 | |||
| 356 | some_method: => | ||
| 357 | log "hello world: " .. secret | ||
| 358 | ``` | ||
| 359 | <YueDisplay> | ||
| 360 | |||
| 361 | ```yue | ||
| 362 | class MoreThings | ||
| 363 | secret = 123 | ||
| 364 | log = (msg) -> print "LOG:", msg | ||
| 365 | |||
| 366 | some_method: => | ||
| 367 | log "hello world: " .. secret | ||
| 368 | ``` | ||
| 369 | |||
| 370 | </YueDisplay> | ||
| 371 | |||
| 372 | ## @ 和 @@ 值 | ||
| 373 | |||
| 374 |   当 @ 和 @@ 前缀在一个名字前时,它们分别代表在 self 和 self.\_\_class 中访问的那个名字。 | ||
| 375 | |||
| 376 |   如果它们单独使用,它们是 self 和 self.\_\_class 的别名。 | ||
| 377 | |||
| 378 | ```yuescript | ||
| 379 | assert @ == self | ||
| 380 | assert @@ == self.__class | ||
| 381 | ``` | ||
| 382 | <YueDisplay> | ||
| 383 | |||
| 384 | ```yue | ||
| 385 | assert @ == self | ||
| 386 | assert @@ == self.__class | ||
| 387 | ``` | ||
| 388 | |||
| 389 | </YueDisplay> | ||
| 390 | |||
| 391 |   例如,使用 @@ 从实例方法快速创建同一类的新实例的方法: | ||
| 392 | |||
| 393 | ```yuescript | ||
| 394 | some_instance_method = (...) => @@ ... | ||
| 395 | ``` | ||
| 396 | <YueDisplay> | ||
| 397 | |||
| 398 | ```yue | ||
| 399 | some_instance_method = (...) => @@ ... | ||
| 400 | ``` | ||
| 401 | |||
| 402 | </YueDisplay> | ||
| 403 | |||
| 404 | ## 构造属性提升 | ||
| 405 | |||
| 406 |   为了减少编写简单值对象定义的代码。你可以这样简单写一个类: | ||
| 407 | |||
| 408 | ```yuescript | ||
| 409 | class Something | ||
| 410 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 411 | |||
| 412 | -- 这是以下声明的简写形式 | ||
| 413 | |||
| 414 | class Something | ||
| 415 | new: (foo, bar, biz, baz) => | ||
| 416 | @foo = foo | ||
| 417 | @bar = bar | ||
| 418 | @@biz = biz | ||
| 419 | @@baz = baz | ||
| 420 | ``` | ||
| 421 | <YueDisplay> | ||
| 422 | |||
| 423 | ```yue | ||
| 424 | class Something | ||
| 425 | new: (@foo, @bar, @@biz, @@baz) => | ||
| 426 | |||
| 427 | -- 这是以下声明的简写形式 | ||
| 428 | |||
| 429 | class Something | ||
| 430 | new: (foo, bar, biz, baz) => | ||
| 431 | @foo = foo | ||
| 432 | @bar = bar | ||
| 433 | @@biz = biz | ||
| 434 | @@baz = baz | ||
| 435 | ``` | ||
| 436 | |||
| 437 | </YueDisplay> | ||
| 438 | |||
| 439 |   你也可以使用这种语法为一个函数初始化传入对象的字段。 | ||
| 440 | |||
| 441 | ```yuescript | ||
| 442 | new = (@fieldA, @fieldB) => @ | ||
| 443 | obj = new {}, 123, "abc" | ||
| 444 | print obj | ||
| 445 | ``` | ||
| 446 | <YueDisplay> | ||
| 447 | |||
| 448 | ```yue | ||
| 449 | new = (@fieldA, @fieldB) => @ | ||
| 450 | obj = new {}, 123, "abc" | ||
| 451 | print obj | ||
| 452 | ``` | ||
| 453 | |||
| 454 | </YueDisplay> | ||
| 455 | |||
| 456 | ## 类表达式 | ||
| 457 | |||
| 458 |   类声明的语法也可以作为一个表达式使用,可以赋值给一个变量或者被返回语句返回。 | ||
| 459 | |||
| 460 | ```yuescript | ||
| 461 | x = class Bucket | ||
| 462 | drops: 0 | ||
| 463 | add_drop: => @drops += 1 | ||
| 464 | ``` | ||
| 465 | <YueDisplay> | ||
| 466 | |||
| 467 | ```yue | ||
| 468 | x = class Bucket | ||
| 469 | drops: 0 | ||
| 470 | add_drop: => @drops += 1 | ||
| 471 | ``` | ||
| 472 | |||
| 473 | </YueDisplay> | ||
| 474 | |||
| 475 | ## 匿名类 | ||
| 476 | |||
| 477 |   声明类时可以省略名称。如果类的表达式不在赋值语句中,\_\_name 属性将为 nil。如果出现在赋值语句中,赋值操作左侧的名称将代替 nil。 | ||
| 478 | |||
| 479 | ```yuescript | ||
| 480 | BigBucket = class extends Bucket | ||
| 481 | add_drop: => @drops += 10 | ||
| 482 | |||
| 483 | assert Bucket.__name == "BigBucket" | ||
| 484 | ``` | ||
| 485 | <YueDisplay> | ||
| 486 | |||
| 487 | ```yue | ||
| 488 | BigBucket = class extends Bucket | ||
| 489 | add_drop: => @drops += 10 | ||
| 490 | |||
| 491 | assert Bucket.__name == "BigBucket" | ||
| 492 | ``` | ||
| 493 | |||
| 494 | </YueDisplay> | ||
| 495 | |||
| 496 |   你甚至可以省略掉主体,这意味着你可以这样写一个空白的匿名类: | ||
| 497 | |||
| 498 | ```yuescript | ||
| 499 | x = class | ||
| 500 | ``` | ||
| 501 | <YueDisplay> | ||
| 502 | |||
| 503 | ```yue | ||
| 504 | x = class | ||
| 505 | ``` | ||
| 506 | |||
| 507 | </YueDisplay> | ||
| 508 | |||
| 509 | ## 类混合 | ||
| 510 | |||
| 511 |   你可以通过使用 `using` 关键字来实现类混合。这意味着你可以从一个普通 Lua 表格或已定义的类对象中,复制函数到你创建的新类中。当你使用普通 Lua 表格进行类混合时,你有机会用自己的实现来重写类的索引方法(例如元方法 `__index`)。然而,当你从一个类对象做混合时,需要注意的是该类对象的元方法将不会被复制到新类。 | ||
| 512 | |||
| 513 | ```yuescript | ||
| 514 | MyIndex = __index: var: 1 | ||
| 515 | |||
| 516 | class X using MyIndex | ||
| 517 | func: => | ||
| 518 | print 123 | ||
| 519 | |||
| 520 | x = X! | ||
| 521 | print x.var | ||
| 522 | |||
| 523 | class Y using X | ||
| 524 | |||
| 525 | y = Y! | ||
| 526 | y\func! | ||
| 527 | |||
| 528 | assert y.__class.__parent ~= X -- X 不是 Y 的父类 | ||
| 529 | ``` | ||
| 530 | <YueDisplay> | ||
| 531 | |||
| 532 | ```yue | ||
| 533 | MyIndex = __index: var: 1 | ||
| 534 | |||
| 535 | class X using MyIndex | ||
| 536 | func: => | ||
| 537 | print 123 | ||
| 538 | |||
| 539 | x = X! | ||
| 540 | print x.var | ||
| 541 | |||
| 542 | class Y using X | ||
| 543 | |||
| 544 | y = Y! | ||
| 545 | y\func! | ||
| 546 | |||
| 547 | assert y.__class.__parent ~= X -- X 不是 Y 的父类 | ||
| 548 | ``` | ||
| 549 | |||
| 550 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/operator.md b/doc/docs/zh/doc/operator.md new file mode 100644 index 0000000..6c9fc5b --- /dev/null +++ b/doc/docs/zh/doc/operator.md | |||
| @@ -0,0 +1,461 @@ | |||
| 1 | # 操作符 | ||
| 2 | |||
| 3 |   Lua 的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\** 或 **::** 均可用于编写链式函数调用,如写作 `tb\func!` 或 `tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | tb\func! if tb ~= nil | ||
| 7 | tb::func! if tb != nil | ||
| 8 | ``` | ||
| 9 | <YueDisplay> | ||
| 10 | |||
| 11 | ```yue | ||
| 12 | tb\func! if tb ~= nil | ||
| 13 | tb::func! if tb != nil | ||
| 14 | ``` | ||
| 15 | |||
| 16 | </YueDisplay> | ||
| 17 | |||
| 18 | ## 链式比较 | ||
| 19 | |||
| 20 |   你可以在月之脚本中进行比较表达式的链式书写: | ||
| 21 | |||
| 22 | ```yuescript | ||
| 23 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 24 | -- 输出:true | ||
| 25 | |||
| 26 | a = 5 | ||
| 27 | print 1 <= a <= 10 | ||
| 28 | -- 输出:true | ||
| 29 | ``` | ||
| 30 | <YueDisplay> | ||
| 31 | |||
| 32 | ```yue | ||
| 33 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | ||
| 34 | -- 输出:true | ||
| 35 | |||
| 36 | a = 5 | ||
| 37 | print 1 <= a <= 10 | ||
| 38 | -- 输出:true | ||
| 39 | ``` | ||
| 40 | |||
| 41 | </YueDisplay> | ||
| 42 | |||
| 43 |   可以注意一下链式比较表达式的求值行为: | ||
| 44 | |||
| 45 | ```yuescript | ||
| 46 | v = (x) -> | ||
| 47 | print x | ||
| 48 | x | ||
| 49 | |||
| 50 | print v(1) < v(2) <= v(3) | ||
| 51 | --[[ | ||
| 52 | 输出: | ||
| 53 | 2 | ||
| 54 | 1 | ||
| 55 | 3 | ||
| 56 | true | ||
| 57 | ]] | ||
| 58 | |||
| 59 | print v(1) > v(2) <= v(3) | ||
| 60 | --[[ | ||
| 61 | 输出: | ||
| 62 | 2 | ||
| 63 | 1 | ||
| 64 | false | ||
| 65 | ]] | ||
| 66 | ``` | ||
| 67 | <YueDisplay> | ||
| 68 | |||
| 69 | ```yue | ||
| 70 | v = (x) -> | ||
| 71 | print x | ||
| 72 | x | ||
| 73 | |||
| 74 | print v(1) < v(2) <= v(3) | ||
| 75 | --[[ | ||
| 76 | 输出: | ||
| 77 | 2 | ||
| 78 | 1 | ||
| 79 | 3 | ||
| 80 | true | ||
| 81 | ]] | ||
| 82 | |||
| 83 | print v(1) > v(2) <= v(3) | ||
| 84 | --[[ | ||
| 85 | 输出: | ||
| 86 | 2 | ||
| 87 | 1 | ||
| 88 | false | ||
| 89 | ]] | ||
| 90 | ``` | ||
| 91 | |||
| 92 | </YueDisplay> | ||
| 93 | |||
| 94 |   在上面的例子里,中间的表达式 `v(2)` 仅被计算一次,如果把表达式写成 `v(1) < v(2) and v(2) <= v(3)` 的方式,中间的 `v(2)` 才会被计算两次。在链式比较中,求值的顺序往往是未定义的。所以强烈建议不要在链式比较中使用具有副作用(比如做打印操作)的表达式。如果需要使用有副作用的函数,应明确使用短路 `and` 运算符来做连接。 | ||
| 95 | |||
| 96 | ## 表追加 | ||
| 97 | |||
| 98 |   **[] =** 操作符用于向 Lua 表的最后插入值。 | ||
| 99 | |||
| 100 | ```yuescript | ||
| 101 | tab = [] | ||
| 102 | tab[] = "Value" | ||
| 103 | ``` | ||
| 104 | <YueDisplay> | ||
| 105 | |||
| 106 | ```yue | ||
| 107 | tab = [] | ||
| 108 | tab[] = "Value" | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
| 112 | |||
| 113 |   你还可以使用展开操作符 `...` 来将一个列表中的所有元素追加到另一个列表中: | ||
| 114 | |||
| 115 | ```yuescript | ||
| 116 | tbA = [1, 2, 3] | ||
| 117 | tbB = [4, 5, 6] | ||
| 118 | tbA[] = ...tbB | ||
| 119 | -- tbA 现在为 [1, 2, 3, 4, 5, 6] | ||
| 120 | ``` | ||
| 121 | <YueDisplay> | ||
| 122 | |||
| 123 | ```yue | ||
| 124 | tbA = [1, 2, 3] | ||
| 125 | tbB = [4, 5, 6] | ||
| 126 | tbA[] = ...tbB | ||
| 127 | -- tbA 现在为 [1, 2, 3, 4, 5, 6] | ||
| 128 | ``` | ||
| 129 | |||
| 130 | </YueDisplay> | ||
| 131 | |||
| 132 | ## 表扩展 | ||
| 133 | |||
| 134 |   你可以使用前置 `...` 操作符在 Lua 表中插入数组表或哈希表。 | ||
| 135 | |||
| 136 | ```yuescript | ||
| 137 | parts = | ||
| 138 | * "shoulders" | ||
| 139 | * "knees" | ||
| 140 | lyrics = | ||
| 141 | * "head" | ||
| 142 | * ...parts | ||
| 143 | * "and" | ||
| 144 | * "toes" | ||
| 145 | |||
| 146 | copy = {...other} | ||
| 147 | |||
| 148 | a = {1, 2, 3, x: 1} | ||
| 149 | b = {4, 5, y: 1} | ||
| 150 | merge = {...a, ...b} | ||
| 151 | ``` | ||
| 152 | <YueDisplay> | ||
| 153 | |||
| 154 | ```yue | ||
| 155 | parts = | ||
| 156 | * "shoulders" | ||
| 157 | * "knees" | ||
| 158 | lyrics = | ||
| 159 | * "head" | ||
| 160 | * ...parts | ||
| 161 | * "and" | ||
| 162 | * "toes" | ||
| 163 | |||
| 164 | copy = {...other} | ||
| 165 | |||
| 166 | a = {1, 2, 3, x: 1} | ||
| 167 | b = {4, 5, y: 1} | ||
| 168 | merge = {...a, ...b} | ||
| 169 | ``` | ||
| 170 | |||
| 171 | </YueDisplay> | ||
| 172 | |||
| 173 | ## 表反向索引 | ||
| 174 | |||
| 175 |   你可以使用 **#** 操作符来反向索引表中的元素。 | ||
| 176 | |||
| 177 | ```yuescript | ||
| 178 | last = data.items[#] | ||
| 179 | second_last = data.items[#-1] | ||
| 180 | data.items[#] = 1 | ||
| 181 | ``` | ||
| 182 | <YueDisplay> | ||
| 183 | |||
| 184 | ```yue | ||
| 185 | last = data.items[#] | ||
| 186 | second_last = data.items[#-1] | ||
| 187 | data.items[#] = 1 | ||
| 188 | ``` | ||
| 189 | |||
| 190 | </YueDisplay> | ||
| 191 | |||
| 192 | ## 元表 | ||
| 193 | |||
| 194 |   **<>** 操作符可提供元表操作的快捷方式。 | ||
| 195 | |||
| 196 | ### 元表创建 | ||
| 197 | |||
| 198 |   使用空括号 **<>** 或被 **<>** 包围的元方法键创建普通的 Lua 表。 | ||
| 199 | |||
| 200 | ```yuescript | ||
| 201 | mt = {} | ||
| 202 | add = (right) => <>: mt, value: @value + right.value | ||
| 203 | mt.__add = add | ||
| 204 | |||
| 205 | a = <>: mt, value: 1 | ||
| 206 | -- 使用与临时变量名相同的字段名,将临时变量赋值给元表 | ||
| 207 | b = :<add>, value: 2 | ||
| 208 | c = <add>: mt.__add, value: 3 | ||
| 209 | |||
| 210 | d = a + b + c | ||
| 211 | print d.value | ||
| 212 | |||
| 213 | close _ = <close>: -> print "超出范围" | ||
| 214 | ``` | ||
| 215 | <YueDisplay> | ||
| 216 | |||
| 217 | ```yue | ||
| 218 | mt = {} | ||
| 219 | add = (right) => <>: mt, value: @value + right.value | ||
| 220 | mt.__add = add | ||
| 221 | |||
| 222 | a = <>: mt, value: 1 | ||
| 223 | -- 使用与临时变量名相同的字段名,将临时变量赋值给元表 | ||
| 224 | b = :<add>, value: 2 | ||
| 225 | c = <add>: mt.__add, value: 3 | ||
| 226 | |||
| 227 | d = a + b + c | ||
| 228 | print d.value | ||
| 229 | |||
| 230 | close _ = <close>: -> print "超出范围" | ||
| 231 | ``` | ||
| 232 | |||
| 233 | </YueDisplay> | ||
| 234 | |||
| 235 | ### 元表访问 | ||
| 236 | |||
| 237 |   使用 **<>** 或被 **<>** 包围的元方法名或在 **<>** 中编写某些表达式来访问元表。 | ||
| 238 | |||
| 239 | ```yuescript | ||
| 240 | -- 使用包含字段 "value" 的元表创建 | ||
| 241 | tb = <"value">: 123 | ||
| 242 | tb.<index> = tb.<> | ||
| 243 | print tb.value | ||
| 244 | |||
| 245 | tb.<> = __index: {item: "hello"} | ||
| 246 | print tb.item | ||
| 247 | ``` | ||
| 248 | <YueDisplay> | ||
| 249 | |||
| 250 | |||
| 251 | ```yue | ||
| 252 | -- 使用包含字段 "value" 的元表创建 | ||
| 253 | tb = <"value">: 123 | ||
| 254 | tb.<index> = tb.<> | ||
| 255 | print tb.value | ||
| 256 | tb.<> = __index: {item: "hello"} | ||
| 257 | print tb.item | ||
| 258 | ``` | ||
| 259 | |||
| 260 | </YueDisplay> | ||
| 261 | |||
| 262 | ### 元表解构 | ||
| 263 | |||
| 264 |   使用被 **<>** 包围的元方法键解构元表。 | ||
| 265 | |||
| 266 | ```yuescript | ||
| 267 | {item, :new, :<close>, <index>: getter} = tb | ||
| 268 | print item, new, close, getter | ||
| 269 | ``` | ||
| 270 | <YueDisplay> | ||
| 271 | |||
| 272 | ```yue | ||
| 273 | {item, :new, :<close>, <index>: getter} = tb | ||
| 274 | print item, new, close, getter | ||
| 275 | ``` | ||
| 276 | |||
| 277 | </YueDisplay> | ||
| 278 | |||
| 279 | ## 存在性 | ||
| 280 | |||
| 281 |   **?** 运算符可以在多种上下文中用来检查存在性。 | ||
| 282 | |||
| 283 | ```yuescript | ||
| 284 | func?! | ||
| 285 | print abc?["你好 世界"]?.xyz | ||
| 286 | |||
| 287 | x = tab?.value | ||
| 288 | len = utf8?.len or string?.len or (o) -> #o | ||
| 289 | |||
| 290 | if print and x? | ||
| 291 | print x | ||
| 292 | |||
| 293 | with? io.open "test.txt", "w" | ||
| 294 | \write "你好" | ||
| 295 | \close! | ||
| 296 | ``` | ||
| 297 | <YueDisplay> | ||
| 298 | |||
| 299 | ```yue | ||
| 300 | func?! | ||
| 301 | print abc?["你好 世界"]?.xyz | ||
| 302 | |||
| 303 | x = tab?.value | ||
| 304 | len = utf8?.len or string?.len or (o) -> #o | ||
| 305 | |||
| 306 | if print and x? | ||
| 307 | print x | ||
| 308 | |||
| 309 | with? io.open "test.txt", "w" | ||
| 310 | \write "你好" | ||
| 311 | \close! | ||
| 312 | ``` | ||
| 313 | |||
| 314 | </YueDisplay> | ||
| 315 | |||
| 316 | ## 管道 | ||
| 317 | |||
| 318 |   与其使用一系列嵌套的函数调用,你还可以考虑使用运算符 **|>** 来传递值。 | ||
| 319 | |||
| 320 | ```yuescript | ||
| 321 | "你好" |> print | ||
| 322 | 1 |> print 2 -- 将管道项作为第一个参数插入 | ||
| 323 | 2 |> print 1, _, 3 -- 带有占位符的管道 | ||
| 324 | |||
| 325 | -- 多行的管道表达式 | ||
| 326 | readFile "example.txt" | ||
| 327 | |> extract language, {} | ||
| 328 | |> parse language | ||
| 329 | |> emit | ||
| 330 | |> render | ||
| 331 | |||
| 332 | ``` | ||
| 333 | <YueDisplay> | ||
| 334 | |||
| 335 | ```yue | ||
| 336 | "你好" |> print | ||
| 337 | 1 |> print 2 -- 将管道项作为第一个参数插入 | ||
| 338 | 2 |> print 1, _, 3 -- 带有占位符的管道 | ||
| 339 | -- 多行的管道表达式 | ||
| 340 | readFile "example.txt" | ||
| 341 | |> extract language, {} | ||
| 342 | |> parse language | ||
| 343 | |> emit | ||
| 344 | |> render | ||
| 345 | |||
| 346 | ``` | ||
| 347 | |||
| 348 | </YueDisplay> | ||
| 349 | |||
| 350 | ## 空值合并 | ||
| 351 | |||
| 352 |   如果其左操作数不是 **nil**,则nil合并运算符 **??** 返回其左操作数的值;否则,它将计算右操作数并返回其结果。如果左操作数计算结果为非 nil 的值,**??** 运算符将不再计算其右操作数。 | ||
| 353 | |||
| 354 | ```yuescript | ||
| 355 | local a, b, c, d | ||
| 356 | a = b ?? c ?? d | ||
| 357 | func a ?? {} | ||
| 358 | |||
| 359 | a ??= false | ||
| 360 | ``` | ||
| 361 | <YueDisplay> | ||
| 362 | |||
| 363 | ```yue | ||
| 364 | local a, b, c, d | ||
| 365 | a = b ?? c ?? d | ||
| 366 | func a ?? {} | ||
| 367 | a ??= false | ||
| 368 | ``` | ||
| 369 | |||
| 370 | </YueDisplay> | ||
| 371 | |||
| 372 | ## 隐式对象 | ||
| 373 | |||
| 374 |   你可以在表格块内使用符号 **\*** 或是 **-** 开始编写一系列隐式结构。如果你正在创建隐式对象,对象的字段必须具有相同的缩进。 | ||
| 375 | |||
| 376 | ```yuescript | ||
| 377 | -- 赋值时使用隐式对象 | ||
| 378 | list = | ||
| 379 | * 1 | ||
| 380 | * 2 | ||
| 381 | * 3 | ||
| 382 | |||
| 383 | -- 函数调用时使用隐式对象 | ||
| 384 | func | ||
| 385 | * 1 | ||
| 386 | * 2 | ||
| 387 | * 3 | ||
| 388 | |||
| 389 | -- 返回时使用隐式对象 | ||
| 390 | f = -> | ||
| 391 | return | ||
| 392 | * 1 | ||
| 393 | * 2 | ||
| 394 | * 3 | ||
| 395 | |||
| 396 | -- 表格时使用隐式对象 | ||
| 397 | tb = | ||
| 398 | name: "abc" | ||
| 399 | |||
| 400 | values: | ||
| 401 | - "a" | ||
| 402 | - "b" | ||
| 403 | - "c" | ||
| 404 | |||
| 405 | objects: | ||
| 406 | - name: "a" | ||
| 407 | value: 1 | ||
| 408 | func: => @value + 1 | ||
| 409 | tb: | ||
| 410 | fieldA: 1 | ||
| 411 | |||
| 412 | - name: "b" | ||
| 413 | value: 2 | ||
| 414 | func: => @value + 2 | ||
| 415 | tb: { } | ||
| 416 | ``` | ||
| 417 | <YueDisplay> | ||
| 418 | |||
| 419 | ```yue | ||
| 420 | -- 赋值时使用隐式对象 | ||
| 421 | list = | ||
| 422 | * 1 | ||
| 423 | * 2 | ||
| 424 | * 3 | ||
| 425 | |||
| 426 | -- 函数调用时使用隐式对象 | ||
| 427 | func | ||
| 428 | * 1 | ||
| 429 | * 2 | ||
| 430 | * 3 | ||
| 431 | |||
| 432 | -- 返回时使用隐式对象 | ||
| 433 | f = -> | ||
| 434 | return | ||
| 435 | * 1 | ||
| 436 | * 2 | ||
| 437 | * 3 | ||
| 438 | |||
| 439 | -- 表格时使用隐式对象 | ||
| 440 | tb = | ||
| 441 | name: "abc" | ||
| 442 | |||
| 443 | values: | ||
| 444 | - "a" | ||
| 445 | - "b" | ||
| 446 | - "c" | ||
| 447 | |||
| 448 | objects: | ||
| 449 | - name: "a" | ||
| 450 | value: 1 | ||
| 451 | func: => @value + 1 | ||
| 452 | tb: | ||
| 453 | fieldA: 1 | ||
| 454 | |||
| 455 | - name: "b" | ||
| 456 | value: 2 | ||
| 457 | func: => @value + 2 | ||
| 458 | tb: { } | ||
| 459 | ``` | ||
| 460 | |||
| 461 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/switch.md b/doc/docs/zh/doc/switch.md new file mode 100644 index 0000000..700bc2a --- /dev/null +++ b/doc/docs/zh/doc/switch.md | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | # switch 语句 | ||
| 2 | |||
| 3 |   switch 语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和 if 语句一样,switch 语句在最后可以接一个 else 代码块来处理没有匹配的情况。在生成的 Lua 代码中,进行比较是使用 == 操作符完成的。switch 语句中也可以使用赋值表达式来储存临时变量值。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | switch name := "Dan" | ||
| 7 | when "Robert" | ||
| 8 | print "你是Robert" | ||
| 9 | when "Dan", "Daniel" | ||
| 10 | print "你的名字是Dan" | ||
| 11 | else | ||
| 12 | print "我不认识你,你的名字是#{name}" | ||
| 13 | ``` | ||
| 14 | <YueDisplay> | ||
| 15 | |||
| 16 | ```yue | ||
| 17 | switch name := "Dan" | ||
| 18 | when "Robert" | ||
| 19 | print "你是Robert" | ||
| 20 | when "Dan", "Daniel" | ||
| 21 | print "你的名字是Dan" | ||
| 22 | else | ||
| 23 | print "我不认识你,你的名字是#{name}" | ||
| 24 | ``` | ||
| 25 | |||
| 26 | </YueDisplay> | ||
| 27 | |||
| 28 |   switch 语句的 when 子句中可以通过使用逗号分隔的列表来匹配多个值。 | ||
| 29 | |||
| 30 |   switch 语句也可以作为表达式使用,下面我们可以将 switch 语句返回的结果分配给一个变量: | ||
| 31 | |||
| 32 | ```yuescript | ||
| 33 | b = 1 | ||
| 34 | next_number = switch b | ||
| 35 | when 1 | ||
| 36 | 2 | ||
| 37 | when 2 | ||
| 38 | 3 | ||
| 39 | else | ||
| 40 | error "数字数得太大了!" | ||
| 41 | ``` | ||
| 42 | <YueDisplay> | ||
| 43 | |||
| 44 | ```yue | ||
| 45 | b = 1 | ||
| 46 | next_number = switch b | ||
| 47 | when 1 | ||
| 48 | 2 | ||
| 49 | when 2 | ||
| 50 | 3 | ||
| 51 | else | ||
| 52 | error "数字数得太大了!" | ||
| 53 | ``` | ||
| 54 | |||
| 55 | </YueDisplay> | ||
| 56 | |||
| 57 |   我们可以使用 then 关键字在 when 子句的同一行上编写处理代码。else 代码块的后续代码中要写在同一行上不需要额外的关键字。 | ||
| 58 | |||
| 59 | ```yuescript | ||
| 60 | msg = switch math.random(1, 5) | ||
| 61 | when 1 then "你很幸运" | ||
| 62 | when 2 then "你差点很幸运" | ||
| 63 | else "不太幸运" | ||
| 64 | ``` | ||
| 65 | <YueDisplay> | ||
| 66 | |||
| 67 | ```yue | ||
| 68 | msg = switch math.random(1, 5) | ||
| 69 | when 1 then "你很幸运" | ||
| 70 | when 2 then "你差点很幸运" | ||
| 71 | else "不太幸运" | ||
| 72 | ``` | ||
| 73 | |||
| 74 | </YueDisplay> | ||
| 75 | |||
| 76 |   如果在编写 switch 语句时希望少写一个缩进,那么你可以把第一个 when 子句放在 switch 开始语句的第一行,然后后续的子语句就都可以都少写一个缩进。 | ||
| 77 | |||
| 78 | ```yuescript | ||
| 79 | switch math.random(1, 5) | ||
| 80 | when 1 | ||
| 81 | print "你很幸运" -- 两个缩进级别 | ||
| 82 | else | ||
| 83 | print "不太幸运" | ||
| 84 | |||
| 85 | switch math.random(1, 5) when 1 | ||
| 86 | print "你很幸运" -- 一个缩进级别 | ||
| 87 | else | ||
| 88 | print "不太幸运" | ||
| 89 | ``` | ||
| 90 | <YueDisplay> | ||
| 91 | |||
| 92 | ```yue | ||
| 93 | switch math.random(1, 5) | ||
| 94 | when 1 | ||
| 95 | print "你很幸运" -- 两个缩进级别 | ||
| 96 | else | ||
| 97 | print "不太幸运" | ||
| 98 | |||
| 99 | switch math.random(1, 5) when 1 | ||
| 100 | print "你很幸运" -- 一个缩进级别 | ||
| 101 | else | ||
| 102 | print "不太幸运" | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
| 106 | |||
| 107 |   值得注意的是,在生成 Lua 代码时,我们要做检查的目标变量会放在 == 表达式的右侧。当你希望给 when 子句的比较对象定义一个 \_\_eq 元方法来重载判断逻辑时,可能会有用。 | ||
| 108 | |||
| 109 | ## 表格匹配 | ||
| 110 | |||
| 111 |   在 switch 的 when 子句中,如果期待检查目标是一个表格,且可以通过特定的结构进行解构并获得非 nil 值,那么你可以尝试使用表格匹配的语法。 | ||
| 112 | |||
| 113 | ```yuescript | ||
| 114 | items = | ||
| 115 | * x: 100 | ||
| 116 | y: 200 | ||
| 117 | * width: 300 | ||
| 118 | height: 400 | ||
| 119 | |||
| 120 | for item in *items | ||
| 121 | switch item | ||
| 122 | when :x, :y | ||
| 123 | print "Vec2 #{x}, #{y}" | ||
| 124 | when :width, :height | ||
| 125 | print "尺寸 #{width}, #{height}" | ||
| 126 | ``` | ||
| 127 | <YueDisplay> | ||
| 128 | |||
| 129 | ```yue | ||
| 130 | items = | ||
| 131 | * x: 100 | ||
| 132 | y: 200 | ||
| 133 | * width: 300 | ||
| 134 | height: 400 | ||
| 135 | |||
| 136 | for item in *items | ||
| 137 | switch item | ||
| 138 | when :x, :y | ||
| 139 | print "Vec2 #{x}, #{y}" | ||
| 140 | when :width, :height | ||
| 141 | print "尺寸 #{width}, #{height}" | ||
| 142 | ``` | ||
| 143 | |||
| 144 | </YueDisplay> | ||
| 145 | |||
| 146 |   你可以使用默认值来选择性地解构表格的某些字段。 | ||
| 147 | |||
| 148 | ```yuescript | ||
| 149 | item = {} | ||
| 150 | |||
| 151 | {pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos') | ||
| 152 | |||
| 153 | switch item | ||
| 154 | when {pos: {:x = 50, :y = 200}} | ||
| 155 | print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过 | ||
| 156 | ``` | ||
| 157 | <YueDisplay> | ||
| 158 | |||
| 159 | ```yue | ||
| 160 | item = {} | ||
| 161 | |||
| 162 | {pos: {:x = 50, :y = 200}} = item -- 获取错误:尝试索引nil值(字段'pos') | ||
| 163 | |||
| 164 | switch item | ||
| 165 | when {pos: {:x = 50, :y = 200}} | ||
| 166 | print "Vec2 #{x}, #{y}" -- 表格解构仍然会通过 | ||
| 167 | ``` | ||
| 168 | |||
| 169 | </YueDisplay> | ||
| 170 | |||
| 171 |   你也可以匹配数组元素、表格字段,甚至使用数组或表格字面量来匹配嵌套的结构。 | ||
| 172 | |||
| 173 |   匹配数组元素。 | ||
| 174 | |||
| 175 | ```yuescript | ||
| 176 | switch tb | ||
| 177 | when [1, 2, 3] | ||
| 178 | print "1, 2, 3" | ||
| 179 | when [1, b, 3] | ||
| 180 | print "1, #{b}, 3" | ||
| 181 | when [1, 2, b = 3] -- 变量b有默认值 | ||
| 182 | print "1, 2, #{b}" | ||
| 183 | ``` | ||
| 184 | <YueDisplay> | ||
| 185 | |||
| 186 | ```yue | ||
| 187 | switch tb | ||
| 188 | when [1, 2, 3] | ||
| 189 | print "1, 2, 3" | ||
| 190 | when [1, b, 3] | ||
| 191 | print "1, #{b}, 3" | ||
| 192 | when [1, 2, b = 3] -- 变量b有默认值 | ||
| 193 | print "1, 2, #{b}" | ||
| 194 | ``` | ||
| 195 | |||
| 196 | </YueDisplay> | ||
| 197 | |||
| 198 |   匹配表格字段。 | ||
| 199 | |||
| 200 | ```yuescript | ||
| 201 | switch tb | ||
| 202 | when success: true, :result | ||
| 203 | print "成功", result | ||
| 204 | when success: false | ||
| 205 | print "失败", result | ||
| 206 | else | ||
| 207 | print "无效值" | ||
| 208 | ``` | ||
| 209 | <YueDisplay> | ||
| 210 | |||
| 211 | ```yue | ||
| 212 | switch tb | ||
| 213 | when success: true, :result | ||
| 214 | print "成功", result | ||
| 215 | when success: false | ||
| 216 | print "失败", result | ||
| 217 | else | ||
| 218 | print "无效值" | ||
| 219 | ``` | ||
| 220 | |||
| 221 | </YueDisplay> | ||
| 222 | |||
| 223 |   匹配嵌套的表格结构。 | ||
| 224 | |||
| 225 | ```yuescript | ||
| 226 | switch tb | ||
| 227 | when data: {type: "success", :content} | ||
| 228 | print "成功", content | ||
| 229 | when data: {type: "error", :content} | ||
| 230 | print "失败", content | ||
| 231 | else | ||
| 232 | print "无效值" | ||
| 233 | ``` | ||
| 234 | <YueDisplay> | ||
| 235 | |||
| 236 | ```yue | ||
| 237 | switch tb | ||
| 238 | when data: {type: "success", :content} | ||
| 239 | print "成功", content | ||
| 240 | when data: {type: "error", :content} | ||
| 241 | print "失败", content | ||
| 242 | else | ||
| 243 | print "无效值" | ||
| 244 | ``` | ||
| 245 | |||
| 246 | </YueDisplay> | ||
| 247 | |||
| 248 |   匹配表格数组。 | ||
| 249 | |||
| 250 | ```yuescript | ||
| 251 | switch tb | ||
| 252 | when [ | ||
| 253 | {a: 1, b: 2} | ||
| 254 | {a: 3, b: 4} | ||
| 255 | {a: 5, b: 6} | ||
| 256 | fourth | ||
| 257 | ] | ||
| 258 | print "匹配成功", fourth | ||
| 259 | ``` | ||
| 260 | <YueDisplay> | ||
| 261 | |||
| 262 | ```yue | ||
| 263 | switch tb | ||
| 264 | when [ | ||
| 265 | {a: 1, b: 2} | ||
| 266 | {a: 3, b: 4} | ||
| 267 | {a: 5, b: 6} | ||
| 268 | fourth | ||
| 269 | ] | ||
| 270 | print "匹配成功", fourth | ||
| 271 | ``` | ||
| 272 | |||
| 273 | </YueDisplay> | ||
| 274 | |||
| 275 |   匹配一个列表并捕获特定范围内的元素。 | ||
| 276 | |||
| 277 | ```yuescript | ||
| 278 | segments = ["admin", "users", "logs", "view"] | ||
| 279 | switch segments | ||
| 280 | when [...groups, resource, action] | ||
| 281 | print "Group:", groups -- 打印: {"admin", "users"} | ||
| 282 | print "Resource:", resource -- 打印: "logs" | ||
| 283 | print "Action:", action -- 打印: "view" | ||
| 284 | ``` | ||
| 285 | <YueDisplay> | ||
| 286 | |||
| 287 | ```yue | ||
| 288 | segments = ["admin", "users", "logs", "view"] | ||
| 289 | switch segments | ||
| 290 | when [...groups, resource, action] | ||
| 291 | print "Group:", groups -- 打印: {"admin", "users"} | ||
| 292 | print "Resource:", resource -- 打印: "logs" | ||
| 293 | print "Action:", action -- 打印: "view" | ||
| 294 | ``` | ||
| 295 | |||
| 296 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/table-literals.md b/doc/docs/zh/doc/table-literals.md new file mode 100644 index 0000000..a111950 --- /dev/null +++ b/doc/docs/zh/doc/table-literals.md | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | # 表格字面量 | ||
| 2 | |||
| 3 |   和 Lua 一样,表格可以通过花括号进行定义。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | some_values = [1, 2, 3, 4] | ||
| 7 | ``` | ||
| 8 | <YueDisplay> | ||
| 9 | |||
| 10 | ```yue | ||
| 11 | some_values = [1, 2, 3, 4] | ||
| 12 | ``` | ||
| 13 | |||
| 14 | </YueDisplay> | ||
| 15 | |||
| 16 |   但与Lua不同的是,给表格中的键赋值是用 **:**(而不是 **=**)。 | ||
| 17 | |||
| 18 | ```yuescript | ||
| 19 | some_values = { | ||
| 20 | name: "Bill", | ||
| 21 | age: 200, | ||
| 22 | ["favorite food"]: "rice" | ||
| 23 | } | ||
| 24 | ``` | ||
| 25 | <YueDisplay> | ||
| 26 | |||
| 27 | ```yue | ||
| 28 | some_values = { | ||
| 29 | name: "Bill", | ||
| 30 | age: 200, | ||
| 31 | ["favorite food"]: "rice" | ||
| 32 | } | ||
| 33 | ``` | ||
| 34 | |||
| 35 | </YueDisplay> | ||
| 36 | |||
| 37 |   如果只分配一个键值对的表格,可以省略花括号。 | ||
| 38 | |||
| 39 | ```yuescript | ||
| 40 | profile = | ||
| 41 | height: "4英尺", | ||
| 42 | shoe_size: 13, | ||
| 43 | favorite_foods: ["冰淇淋", "甜甜圈"] | ||
| 44 | ``` | ||
| 45 | <YueDisplay> | ||
| 46 | |||
| 47 | ```yue | ||
| 48 | profile = | ||
| 49 | height: "4英尺", | ||
| 50 | shoe_size: 13, | ||
| 51 | favorite_foods: ["冰淇淋", "甜甜圈"] | ||
| 52 | ``` | ||
| 53 | |||
| 54 | </YueDisplay> | ||
| 55 | |||
| 56 |   可以使用换行符而不使用逗号(或两者都用)来分隔表格中的值: | ||
| 57 | |||
| 58 | ```yuescript | ||
| 59 | values = { | ||
| 60 | 1, 2, 3, 4 | ||
| 61 | 5, 6, 7, 8 | ||
| 62 | name: "超人" | ||
| 63 | occupation: "打击犯罪" | ||
| 64 | } | ||
| 65 | ``` | ||
| 66 | <YueDisplay> | ||
| 67 | |||
| 68 | ```yue | ||
| 69 | values = { | ||
| 70 | 1, 2, 3, 4 | ||
| 71 | 5, 6, 7, 8 | ||
| 72 | name: "超人" | ||
| 73 | occupation: "打击犯罪" | ||
| 74 | } | ||
| 75 | ``` | ||
| 76 | |||
| 77 | </YueDisplay> | ||
| 78 | |||
| 79 |   创建单行表格字面量时,也可以省略花括号: | ||
| 80 | |||
| 81 | ```yuescript | ||
| 82 | my_function dance: "探戈", partner: "无" | ||
| 83 | |||
| 84 | y = type: "狗", legs: 4, tails: 1 | ||
| 85 | ``` | ||
| 86 | <YueDisplay> | ||
| 87 | |||
| 88 | ```yue | ||
| 89 | my_function dance: "探戈", partner: "无" | ||
| 90 | |||
| 91 | y = type: "狗", legs: 4, tails: 1 | ||
| 92 | ``` | ||
| 93 | |||
| 94 | </YueDisplay> | ||
| 95 | |||
| 96 |   表格字面量的键可以使用 Lua 语言的关键字,而无需转义: | ||
| 97 | |||
| 98 | ```yuescript | ||
| 99 | tbl = { | ||
| 100 | do: "某事" | ||
| 101 | end: "饥饿" | ||
| 102 | } | ||
| 103 | ``` | ||
| 104 | <YueDisplay> | ||
| 105 | |||
| 106 | ```yue | ||
| 107 | tbl = { | ||
| 108 | do: "某事" | ||
| 109 | end: "饥饿" | ||
| 110 | } | ||
| 111 | ``` | ||
| 112 | |||
| 113 | </YueDisplay> | ||
| 114 | |||
| 115 |   如果你要构造一个由变量组成的表,并希望键与变量名相同,那么可以使用 **:** 前缀操作符: | ||
| 116 | |||
| 117 | ```yuescript | ||
| 118 | hair = "金色" | ||
| 119 | height = 200 | ||
| 120 | person = { :hair, :height, shoe_size: 40 } | ||
| 121 | |||
| 122 | print_table :hair, :height | ||
| 123 | ``` | ||
| 124 | <YueDisplay> | ||
| 125 | |||
| 126 | ```yue | ||
| 127 | hair = "金色" | ||
| 128 | height = 200 | ||
| 129 | person = { :hair, :height, shoe_size: 40 } | ||
| 130 | |||
| 131 | print_table :hair, :height | ||
| 132 | ``` | ||
| 133 | |||
| 134 | </YueDisplay> | ||
| 135 | |||
| 136 |   如果你希望表中字段的键是某个表达式的结果,那么可以用 **[ ]** 包裹它,就像在 Lua 中一样。如果键中有任何特殊字符,也可以直接使用字符串字面量作为键,省略方括号。 | ||
| 137 | |||
| 138 | ```yuescript | ||
| 139 | t = { | ||
| 140 | [1 + 2]: "你好" | ||
| 141 | "你好 世界": true | ||
| 142 | } | ||
| 143 | ``` | ||
| 144 | <YueDisplay> | ||
| 145 | |||
| 146 | ```yue | ||
| 147 | t = { | ||
| 148 | [1 + 2]: "你好" | ||
| 149 | "你好 世界": true | ||
| 150 | } | ||
| 151 | ``` | ||
| 152 | |||
| 153 | </YueDisplay> | ||
| 154 | |||
| 155 |   Lua 的表同时具有数组部分和哈希部分,但有时候你会希望在书写 Lua 表时,对 Lua 表做数组和哈希不同用法的语义区分。然后你可以用 **[ ]** 而不是 **{ }** 来编写表示数组的 Lua 表,并且不允许在数组 Lua 表中写入任何键值对。 | ||
| 156 | |||
| 157 | ```yuescript | ||
| 158 | some_values = [ 1, 2, 3, 4 ] | ||
| 159 | list_with_one_element = [ 1, ] | ||
| 160 | ``` | ||
| 161 | <YueDisplay> | ||
| 162 | |||
| 163 | ```yue | ||
| 164 | some_values = [ 1, 2, 3, 4 ] | ||
| 165 | list_with_one_element = [ 1, ] | ||
| 166 | ``` | ||
| 167 | |||
| 168 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/the-using-clause-controlling-destructive-assignment.md b/doc/docs/zh/doc/the-using-clause-controlling-destructive-assignment.md new file mode 100644 index 0000000..722de6f --- /dev/null +++ b/doc/docs/zh/doc/the-using-clause-controlling-destructive-assignment.md | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | # 使用 using 语句:防止破坏性赋值 | ||
| 2 | |||
| 3 |   Lua 的变量作用域是降低代码复杂度的重要工具。然而,随着代码量的增加,维护这些变量可能变得更加困难。比如,看看下面的代码片段: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 100 | ||
| 7 | |||
| 8 | -- 许多代码行... | ||
| 9 | |||
| 10 | my_func = -> | ||
| 11 | i = 10 | ||
| 12 | while i > 0 | ||
| 13 | print i | ||
| 14 | i -= 1 | ||
| 15 | |||
| 16 | my_func! | ||
| 17 | |||
| 18 | print i -- 将打印 0 | ||
| 19 | ``` | ||
| 20 | <YueDisplay> | ||
| 21 | |||
| 22 | ```yue | ||
| 23 | i = 100 | ||
| 24 | |||
| 25 | -- 许多代码行... | ||
| 26 | |||
| 27 | my_func = -> | ||
| 28 | i = 10 | ||
| 29 | while i > 0 | ||
| 30 | print i | ||
| 31 | i -= 1 | ||
| 32 | |||
| 33 | my_func! | ||
| 34 | |||
| 35 | print i -- 将打印 0 | ||
| 36 | ``` | ||
| 37 | |||
| 38 | </YueDisplay> | ||
| 39 | |||
| 40 |   在 `my_func` 中,我们不小心覆盖了变量 `i` 的值。虽然在这个例子中这个问题很明显,但在一个庞大的或者是由多人共同维护的代码库中,很难追踪每个变量的声明情况。 | ||
| 41 | |||
| 42 |   如果我们可以明确指出哪些变量是我们想在当前作用域内修改的,并且防止我们不小心更改了其他作用域中同名的变量,那将大有裨益。 | ||
| 43 | |||
| 44 |   `using` 语句就是为此而生。`using nil` 确保函数内部的赋值不会意外地影响到外部作用域的变量。我们只需将 `using` 子句放在函数的参数列表之后;若函数没有参数,则直接放在括号内即可。 | ||
| 45 | |||
| 46 | ```yuescript | ||
| 47 | i = 100 | ||
| 48 | |||
| 49 | my_func = (using nil) -> | ||
| 50 | i = "hello" -- 这里创建了一个新的局部变量 | ||
| 51 | |||
| 52 | my_func! | ||
| 53 | print i -- 打印 100,i 没有受到影响 | ||
| 54 | ``` | ||
| 55 | <YueDisplay> | ||
| 56 | |||
| 57 | ```yue | ||
| 58 | i = 100 | ||
| 59 | |||
| 60 | my_func = (using nil) -> | ||
| 61 | i = "hello" -- 这里创建了一个新的局部变量 | ||
| 62 | |||
| 63 | my_func! | ||
| 64 | print i -- 打印 100,i 没有受到影响 | ||
| 65 | ``` | ||
| 66 | |||
| 67 | </YueDisplay> | ||
| 68 | |||
| 69 |   using子句中可以填写多个用逗号分隔名称。指定可以访问和修改的外部变量的名称: | ||
| 70 | |||
| 71 | ```yuescript | ||
| 72 | tmp = 1213 | ||
| 73 | i, k = 100, 50 | ||
| 74 | |||
| 75 | my_func = (add using k, i) -> | ||
| 76 | tmp = tmp + add -- 创建了一个新的局部tmp | ||
| 77 | i += tmp | ||
| 78 | k += tmp | ||
| 79 | |||
| 80 | my_func(22) | ||
| 81 | print i, k -- 这些已经被更新 | ||
| 82 | ``` | ||
| 83 | <YueDisplay> | ||
| 84 | |||
| 85 | ```yue | ||
| 86 | tmp = 1213 | ||
| 87 | i, k = 100, 50 | ||
| 88 | |||
| 89 | my_func = (add using k, i) -> | ||
| 90 | tmp = tmp + add -- 创建了一个新的局部tmp | ||
| 91 | i += tmp | ||
| 92 | k += tmp | ||
| 93 | |||
| 94 | my_func(22) | ||
| 95 | print i, k -- 这些已经被更新 | ||
| 96 | ``` | ||
| 97 | |||
| 98 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/the-yuescript-library.md b/doc/docs/zh/doc/the-yuescript-library.md new file mode 100644 index 0000000..54e26f7 --- /dev/null +++ b/doc/docs/zh/doc/the-yuescript-library.md | |||
| @@ -0,0 +1,821 @@ | |||
| 1 | # 月之脚本语言库 | ||
| 2 | |||
| 3 | 在 Lua 中使用 `local yue = require("yue")` 来访问。 | ||
| 4 | |||
| 5 | ## yue | ||
| 6 | |||
| 7 | **描述:** | ||
| 8 | |||
| 9 | 月之脚本语言库。 | ||
| 10 | |||
| 11 | ### version | ||
| 12 | |||
| 13 | **类型:** 成员变量。 | ||
| 14 | |||
| 15 | **描述:** | ||
| 16 | |||
| 17 | 月之脚本版本。 | ||
| 18 | |||
| 19 | **签名:** | ||
| 20 | ```lua | ||
| 21 | version: string | ||
| 22 | ``` | ||
| 23 | |||
| 24 | ### dirsep | ||
| 25 | |||
| 26 | **类型:** 成员变量。 | ||
| 27 | |||
| 28 | **描述:** | ||
| 29 | |||
| 30 | 当前平台的文件分隔符。 | ||
| 31 | |||
| 32 | **签名:** | ||
| 33 | ```lua | ||
| 34 | dirsep: string | ||
| 35 | ``` | ||
| 36 | |||
| 37 | ### yue_compiled | ||
| 38 | |||
| 39 | **类型:** 成员变量。 | ||
| 40 | |||
| 41 | **描述:** | ||
| 42 | |||
| 43 | 编译模块代码缓存。 | ||
| 44 | |||
| 45 | **签名:** | ||
| 46 | ```lua | ||
| 47 | yue_compiled: {string: string} | ||
| 48 | ``` | ||
| 49 | |||
| 50 | ### to_lua | ||
| 51 | |||
| 52 | **类型:** 函数。 | ||
| 53 | |||
| 54 | **描述:** | ||
| 55 | |||
| 56 | 月之脚本的编译函数。它将 YueScript 代码编译为 Lua 代码。 | ||
| 57 | |||
| 58 | **签名:** | ||
| 59 | ```lua | ||
| 60 | to_lua: function(code: string, config?: Config): | ||
| 61 | --[[codes]] string | nil, | ||
| 62 | --[[error]] string | nil, | ||
| 63 | --[[globals]] {{string, integer, integer}} | nil | ||
| 64 | ``` | ||
| 65 | |||
| 66 | **参数:** | ||
| 67 | |||
| 68 | | 参数名 | 类型 | 描述 | | ||
| 69 | | --- | --- | --- | | ||
| 70 | | code | string | YueScript 代码。 | | ||
| 71 | | config | Config | [可选] 编译器选项。 | | ||
| 72 | |||
| 73 | **返回值:** | ||
| 74 | |||
| 75 | | 返回类型 | 描述 | | ||
| 76 | | --- | --- | | ||
| 77 | | string \| nil | 编译后的 Lua 代码,如果编译失败则为 nil。 | | ||
| 78 | | string \| nil | 错误消息,如果编译成功则为 nil。 | | ||
| 79 | | {{string, integer, integer}} \| nil | 代码中出现的全局变量(带有名称、行和列),如果编译器选项 `lint_global` 为 false 则为 nil。 | | ||
| 80 | |||
| 81 | ### file_exist | ||
| 82 | |||
| 83 | **类型:** 函数。 | ||
| 84 | |||
| 85 | **描述:** | ||
| 86 | |||
| 87 | 检查源文件是否存在的函数。可以覆盖该函数以自定义行为。 | ||
| 88 | |||
| 89 | **签名:** | ||
| 90 | ```lua | ||
| 91 | file_exist: function(filename: string): boolean | ||
| 92 | ``` | ||
| 93 | |||
| 94 | **参数:** | ||
| 95 | |||
| 96 | | 参数名 | 类型 | 描述 | | ||
| 97 | | --- | --- | --- | | ||
| 98 | | filename | string | 文件名。 | | ||
| 99 | |||
| 100 | **返回值:** | ||
| 101 | |||
| 102 | | 返回类型 | 描述 | | ||
| 103 | | --- | --- | | ||
| 104 | | boolean | 文件是否存在。 | | ||
| 105 | |||
| 106 | ### read_file | ||
| 107 | |||
| 108 | **类型:** 函数。 | ||
| 109 | |||
| 110 | **描述:** | ||
| 111 | |||
| 112 | 读取源文件的函数。可以覆盖该函数以自定义行为。 | ||
| 113 | |||
| 114 | **签名:** | ||
| 115 | ```lua | ||
| 116 | read_file: function(filename: string): string | ||
| 117 | ``` | ||
| 118 | |||
| 119 | **参数:** | ||
| 120 | |||
| 121 | | 参数名 | 类型 | 描述 | | ||
| 122 | | --- | --- | --- | | ||
| 123 | | filename | string | 文件名。 | | ||
| 124 | |||
| 125 | **返回值:** | ||
| 126 | |||
| 127 | | 返回类型 | 描述 | | ||
| 128 | | --- | --- | | ||
| 129 | | string | 文件内容。 | | ||
| 130 | |||
| 131 | ### insert_loader | ||
| 132 | |||
| 133 | **类型:** 函数。 | ||
| 134 | |||
| 135 | **描述:** | ||
| 136 | |||
| 137 | 将 YueScript 加载器插入到 Lua 包加载器(搜索器)中。 | ||
| 138 | |||
| 139 | **签名:** | ||
| 140 | ```lua | ||
| 141 | insert_loader: function(pos?: integer): boolean | ||
| 142 | ``` | ||
| 143 | |||
| 144 | **参数:** | ||
| 145 | |||
| 146 | | 参数名 | 类型 | 描述 | | ||
| 147 | | --- | --- | --- | | ||
| 148 | | pos | integer | [可选] 要插入加载器的位置。默认为 3。 | | ||
| 149 | |||
| 150 | **返回值:** | ||
| 151 | |||
| 152 | | 返回类型 | 描述 | | ||
| 153 | | --- | --- | | ||
| 154 | | boolean | 是否成功插入加载器。如果加载器已经插入,则返回失败。 | | ||
| 155 | |||
| 156 | ### remove_loader | ||
| 157 | |||
| 158 | **类型:** 函数。 | ||
| 159 | |||
| 160 | **描述:** | ||
| 161 | |||
| 162 | 从 Lua 包加载器(搜索器)中移除 YueScript 加载器。 | ||
| 163 | |||
| 164 | **签名:** | ||
| 165 | ```lua | ||
| 166 | remove_loader: function(): boolean | ||
| 167 | ``` | ||
| 168 | |||
| 169 | **返回值:** | ||
| 170 | |||
| 171 | | 返回类型 | 描述 | | ||
| 172 | | --- | --- | | ||
| 173 | | boolean | 是否成功移除加载器。如果加载器未插入,则返回失败。 | | ||
| 174 | |||
| 175 | ### loadstring | ||
| 176 | |||
| 177 | **类型:** 函数。 | ||
| 178 | |||
| 179 | **描述:** | ||
| 180 | |||
| 181 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 182 | |||
| 183 | **签名:** | ||
| 184 | ```lua | ||
| 185 | loadstring: function(input: string, chunkname: string, env: table, config?: Config): | ||
| 186 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 187 | --[[error]] string | nil | ||
| 188 | ``` | ||
| 189 | |||
| 190 | **参数:** | ||
| 191 | |||
| 192 | | 参数名 | 类型 | 描述 | | ||
| 193 | | --- | --- | --- | | ||
| 194 | | input | string | YueScript 代码。 | | ||
| 195 | | chunkname | string | 代码块的名称。 | | ||
| 196 | | env | table | 环境表。 | | ||
| 197 | | config | Config | [可选] 编译器选项。 | | ||
| 198 | |||
| 199 | **返回值:** | ||
| 200 | |||
| 201 | | 返回类型 | 描述 | | ||
| 202 | | --- | --- | | ||
| 203 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 204 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 205 | |||
| 206 | ### loadstring | ||
| 207 | |||
| 208 | **类型:** 函数。 | ||
| 209 | |||
| 210 | **描述:** | ||
| 211 | |||
| 212 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 213 | |||
| 214 | **签名:** | ||
| 215 | ```lua | ||
| 216 | loadstring: function(input: string, chunkname: string, config?: Config): | ||
| 217 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 218 | --[[error]] string | nil | ||
| 219 | ``` | ||
| 220 | |||
| 221 | **参数:** | ||
| 222 | |||
| 223 | | 参数名 | 类型 | 描述 | | ||
| 224 | | --- | --- | --- | | ||
| 225 | | input | string | YueScript 代码。 | | ||
| 226 | | chunkname | string | 代码块的名称。 | | ||
| 227 | | config | Config | [可选] 编译器选项。 | | ||
| 228 | |||
| 229 | **返回值:** | ||
| 230 | |||
| 231 | | 返回类型 | 描述 | | ||
| 232 | | --- | --- | | ||
| 233 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 234 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 235 | |||
| 236 | ### loadstring | ||
| 237 | |||
| 238 | **类型:** 函数。 | ||
| 239 | |||
| 240 | **描述:** | ||
| 241 | |||
| 242 | 将 YueScript 代码字符串加载为一个函数。 | ||
| 243 | |||
| 244 | **签名:** | ||
| 245 | ```lua | ||
| 246 | loadstring: function(input: string, config?: Config): | ||
| 247 | --[[loaded function]] nil | function(...: any): (any...), | ||
| 248 | --[[error]] string | nil | ||
| 249 | ``` | ||
| 250 | |||
| 251 | **参数:** | ||
| 252 | |||
| 253 | | 参数名 | 类型 | 描述 | | ||
| 254 | | --- | --- | --- | | ||
| 255 | | input | string | YueScript 代码。 | | ||
| 256 | | config | Config | [可选] 编译器选项。 | | ||
| 257 | |||
| 258 | **返回值:** | ||
| 259 | |||
| 260 | | 返回类型 | 描述 | | ||
| 261 | | --- | --- | | ||
| 262 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 263 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 264 | |||
| 265 | ### loadfile | ||
| 266 | |||
| 267 | **类型:** 函数。 | ||
| 268 | |||
| 269 | **描述:** | ||
| 270 | |||
| 271 | 将 YueScript 代码文件加载为一个函数。 | ||
| 272 | |||
| 273 | **签名:** | ||
| 274 | ```lua | ||
| 275 | loadfile: function(filename: string, env: table, config?: Config): | ||
| 276 | nil | function(...: any): (any...), | ||
| 277 | string | nil | ||
| 278 | ``` | ||
| 279 | |||
| 280 | **参数:** | ||
| 281 | |||
| 282 | | 参数名 | 类型 | 描述 | | ||
| 283 | | --- | --- | --- | | ||
| 284 | | filename | string | 文件名。 | | ||
| 285 | | env | table | 环境表。 | | ||
| 286 | | config | Config | [可选] 编译器选项。 | | ||
| 287 | |||
| 288 | **返回值:** | ||
| 289 | |||
| 290 | | 返回类型 | 描述 | | ||
| 291 | | --- | --- | | ||
| 292 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 293 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 294 | |||
| 295 | ### loadfile | ||
| 296 | |||
| 297 | **类型:** 函数。 | ||
| 298 | |||
| 299 | **描述:** | ||
| 300 | |||
| 301 | 将 YueScript 代码文件加载为一个函数。 | ||
| 302 | |||
| 303 | **签名:** | ||
| 304 | ```lua | ||
| 305 | loadfile: function(filename: string, config?: Config): | ||
| 306 | nil | function(...: any): (any...), | ||
| 307 | string | nil | ||
| 308 | ``` | ||
| 309 | |||
| 310 | **参数:** | ||
| 311 | |||
| 312 | | 参数名 | 类型 | 描述 | | ||
| 313 | | --- | --- | --- | | ||
| 314 | | filename | string | 文件名。 | | ||
| 315 | | config | Config | [可选] 编译器选项。 | | ||
| 316 | |||
| 317 | **返回值:** | ||
| 318 | |||
| 319 | | 返回类型 | 描述 | | ||
| 320 | | --- | --- | | ||
| 321 | | function \| nil | 加载的函数,如果加载失败则为 nil。 | | ||
| 322 | | string \| nil | 错误消息,如果加载成功则为 nil。 | | ||
| 323 | |||
| 324 | ### dofile | ||
| 325 | |||
| 326 | **类型:** 函数。 | ||
| 327 | |||
| 328 | **描述:** | ||
| 329 | |||
| 330 | 将 YueScript 代码文件加载为一个函数并执行。 | ||
| 331 | |||
| 332 | **签名:** | ||
| 333 | ```lua | ||
| 334 | dofile: function(filename: string, env: table, config?: Config): any... | ||
| 335 | ``` | ||
| 336 | |||
| 337 | **参数:** | ||
| 338 | |||
| 339 | | 参数名 | 类型 | 描述 | | ||
| 340 | | --- | --- | --- | | ||
| 341 | | filename | string | 文件名。 | | ||
| 342 | | env | table | 环境表。 | | ||
| 343 | | config | Config | [可选] 编译器选项。 | | ||
| 344 | |||
| 345 | **返回值:** | ||
| 346 | |||
| 347 | | 返回类型 | 描述 | | ||
| 348 | | --- | --- | | ||
| 349 | | any... | 加载的函数执行后的返回值。 | | ||
| 350 | |||
| 351 | ### dofile | ||
| 352 | |||
| 353 | **类型:** 函数。 | ||
| 354 | |||
| 355 | **描述:** | ||
| 356 | |||
| 357 | 将 YueScript 代码文件加载为一个函数并执行。 | ||
| 358 | |||
| 359 | **签名:** | ||
| 360 | ```lua | ||
| 361 | dofile: function(filename: string, config?: Config): any... | ||
| 362 | ``` | ||
| 363 | |||
| 364 | **参数:** | ||
| 365 | |||
| 366 | | 参数名 | 类型 | 描述 | | ||
| 367 | | --- | --- | --- | | ||
| 368 | | filename | string | 文件名。 | | ||
| 369 | | config | Config | [可选] 编译器选项。 | | ||
| 370 | |||
| 371 | **返回值:** | ||
| 372 | |||
| 373 | | 返回类型 | 描述 | | ||
| 374 | | --- | --- | | ||
| 375 | | any... | 加载的函数执行后的返回值。 | | ||
| 376 | |||
| 377 | ### find_modulepath | ||
| 378 | |||
| 379 | **类型:** 函数。 | ||
| 380 | |||
| 381 | **描述:** | ||
| 382 | |||
| 383 | 将 YueScript 模块名解析为文件路径。 | ||
| 384 | |||
| 385 | **签名:** | ||
| 386 | ```lua | ||
| 387 | find_modulepath: function(name: string): string | ||
| 388 | ``` | ||
| 389 | |||
| 390 | **参数:** | ||
| 391 | |||
| 392 | | 参数名 | 类型 | 描述 | | ||
| 393 | | --- | --- | --- | | ||
| 394 | | name | string | 模块名。 | | ||
| 395 | |||
| 396 | **返回值:** | ||
| 397 | |||
| 398 | | 返回类型 | 描述 | | ||
| 399 | | --- | --- | | ||
| 400 | | string | 文件路径。 | | ||
| 401 | |||
| 402 | ### pcall | ||
| 403 | |||
| 404 | **类型:** 函数。 | ||
| 405 | |||
| 406 | **描述:** | ||
| 407 | |||
| 408 | 在保护模式下调用一个函数。 | ||
| 409 | 会捕获任何错误,执行成功则返回成功状态和结果,否则为失败状态和错误信息。 | ||
| 410 | 当发生错误时,将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 411 | |||
| 412 | **签名:** | ||
| 413 | ```lua | ||
| 414 | pcall: function(f: function, ...: any): boolean, any... | ||
| 415 | ``` | ||
| 416 | |||
| 417 | **参数:** | ||
| 418 | |||
| 419 | | 参数名 | 类型 | 描述 | | ||
| 420 | | --- | --- | --- | | ||
| 421 | | f | function | 要调用的函数。 | | ||
| 422 | | ... | any | 要传递给函数的参数。 | | ||
| 423 | |||
| 424 | **返回值:** | ||
| 425 | |||
| 426 | | 返回类型 | 描述 | | ||
| 427 | | --- | --- | | ||
| 428 | | boolean, ... | 状态码和函数结果或错误信息。 | | ||
| 429 | |||
| 430 | ### require | ||
| 431 | |||
| 432 | **类型:** 函数。 | ||
| 433 | |||
| 434 | **描述:** | ||
| 435 | |||
| 436 | 加载给定的模块。可以是 Lua 模块或 YueScript 模块。 | ||
| 437 | 如果模块是 YueScript 模块且加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 438 | |||
| 439 | **签名:** | ||
| 440 | ```lua | ||
| 441 | require: function(name: string): any... | ||
| 442 | ``` | ||
| 443 | |||
| 444 | **参数:** | ||
| 445 | |||
| 446 | | 参数名 | 类型 | 描述 | | ||
| 447 | | --- | --- | --- | | ||
| 448 | | modname | string | 要加载的模块名。 | | ||
| 449 | |||
| 450 | **返回值:** | ||
| 451 | |||
| 452 | | 返回类型 | 描述 | | ||
| 453 | | --- | --- | | ||
| 454 | | any | 如果模块已经加载,则返回 package.loaded[modname] 中存储的值。否则,尝试查找加载器并返回 package.loaded[modname] 的最终值和加载器数据作为第二个结果。 | | ||
| 455 | |||
| 456 | ### p | ||
| 457 | |||
| 458 | **类型:** 函数。 | ||
| 459 | |||
| 460 | **描述:** | ||
| 461 | |||
| 462 | 检查传递的值的内部结构,并打印值出它的字符串表示。 | ||
| 463 | |||
| 464 | **签名:** | ||
| 465 | ```lua | ||
| 466 | p: function(...: any) | ||
| 467 | ``` | ||
| 468 | |||
| 469 | **参数:** | ||
| 470 | |||
| 471 | | 参数名 | 类型 | 描述 | | ||
| 472 | | --- | --- | --- | | ||
| 473 | | ... | any | 要检查的值。 | | ||
| 474 | |||
| 475 | ### options | ||
| 476 | |||
| 477 | **类型:** 成员变量。 | ||
| 478 | |||
| 479 | **描述:** | ||
| 480 | |||
| 481 | 当前编译器选项。 | ||
| 482 | |||
| 483 | **签名:** | ||
| 484 | ```lua | ||
| 485 | options: Config.Options | ||
| 486 | ``` | ||
| 487 | |||
| 488 | ### traceback | ||
| 489 | |||
| 490 | **类型:** 函数。 | ||
| 491 | |||
| 492 | **描述:** | ||
| 493 | |||
| 494 | 重写堆栈跟踪中的行号为 YueScript 代码中的原始行号的 traceback 函数。 | ||
| 495 | |||
| 496 | **签名:** | ||
| 497 | ```lua | ||
| 498 | traceback: function(message: string): string | ||
| 499 | ``` | ||
| 500 | |||
| 501 | **参数:** | ||
| 502 | |||
| 503 | | 参数名 | 类型 | 描述 | | ||
| 504 | | --- | --- | --- | | ||
| 505 | | message | string | 堆栈跟踪消息。 | | ||
| 506 | |||
| 507 | **返回值:** | ||
| 508 | |||
| 509 | | 返回类型 | 描述 | | ||
| 510 | | --- | --- | | ||
| 511 | | string | 重写后的堆栈跟踪消息。 | | ||
| 512 | |||
| 513 | ### is_ast | ||
| 514 | |||
| 515 | **类型:** 函数。 | ||
| 516 | |||
| 517 | **描述:** | ||
| 518 | |||
| 519 | 检查代码是否匹配指定的 AST。 | ||
| 520 | |||
| 521 | **签名:** | ||
| 522 | ```lua | ||
| 523 | is_ast: function(astName: string, code: string): boolean | ||
| 524 | ``` | ||
| 525 | |||
| 526 | **参数:** | ||
| 527 | |||
| 528 | | 参数名 | 类型 | 描述 | | ||
| 529 | | --- | --- | --- | | ||
| 530 | | astName | string | AST 名称。 | | ||
| 531 | | code | string | 代码。 | | ||
| 532 | |||
| 533 | **返回值:** | ||
| 534 | |||
| 535 | | 返回类型 | 描述 | | ||
| 536 | | --- | --- | | ||
| 537 | | boolean | 代码是否匹配 AST。 | | ||
| 538 | |||
| 539 | ### AST | ||
| 540 | |||
| 541 | **类型:** 成员变量。 | ||
| 542 | |||
| 543 | **描述:** | ||
| 544 | |||
| 545 | AST 类型定义,带有名称、行、列和子节点。 | ||
| 546 | |||
| 547 | **签名:** | ||
| 548 | ```lua | ||
| 549 | type AST = {string, integer, integer, any} | ||
| 550 | ``` | ||
| 551 | |||
| 552 | ### to_ast | ||
| 553 | |||
| 554 | **类型:** 函数。 | ||
| 555 | |||
| 556 | **描述:** | ||
| 557 | |||
| 558 | 将代码转换为 AST。 | ||
| 559 | |||
| 560 | **签名:** | ||
| 561 | ```lua | ||
| 562 | to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean): | ||
| 563 | --[[AST]] AST | nil, | ||
| 564 | --[[error]] nil | string | ||
| 565 | ``` | ||
| 566 | |||
| 567 | **参数:** | ||
| 568 | |||
| 569 | | 参数名 | 类型 | 描述 | | ||
| 570 | | --- | --- | --- | | ||
| 571 | | code | string | 代码。 | | ||
| 572 | | flattenLevel | integer | [可选] 扁平化级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 | | ||
| 573 | | astName | string | [可选] AST 名称。默认为 "File"。 | | ||
| 574 | | reserveComment | boolean | [可选] 是否保留原始注释。默认为 false。 | | ||
| 575 | |||
| 576 | **返回值:** | ||
| 577 | |||
| 578 | | 返回类型 | 描述 | | ||
| 579 | | --- | --- | | ||
| 580 | | AST \| nil | AST,如果转换失败则为 nil。 | | ||
| 581 | | string \| nil | 错误消息,如果转换成功则为 nil。 | | ||
| 582 | |||
| 583 | ### format | ||
| 584 | |||
| 585 | **类型:** 函数。 | ||
| 586 | |||
| 587 | **描述:** | ||
| 588 | |||
| 589 | 格式化 YueScript 代码。 | ||
| 590 | |||
| 591 | **签名:** | ||
| 592 | ```lua | ||
| 593 | format: function(code: string, tabSize?: number, reserveComment?: boolean): string | ||
| 594 | ``` | ||
| 595 | |||
| 596 | **参数:** | ||
| 597 | |||
| 598 | | 参数名 | 类型 | 描述 | | ||
| 599 | | --- | --- | --- | | ||
| 600 | | code | string | 代码。 | | ||
| 601 | | tabSize | integer | [可选] 制表符大小。默认为 4。 | | ||
| 602 | | reserveComment | boolean | [可选] 是否保留原始注释。默认为 true。 | | ||
| 603 | |||
| 604 | **返回值:** | ||
| 605 | |||
| 606 | | 返回类型 | 描述 | | ||
| 607 | | --- | --- | | ||
| 608 | | string | 格式化后的代码。 | | ||
| 609 | |||
| 610 | ### __call | ||
| 611 | |||
| 612 | **类型:** 元方法。 | ||
| 613 | |||
| 614 | **描述:** | ||
| 615 | |||
| 616 | 导入 YueScript 模块。 | ||
| 617 | 如果发生加载失败,则将错误信息中的代码行号重写为 YueScript 代码中的原始行号。 | ||
| 618 | |||
| 619 | **签名:** | ||
| 620 | ```lua | ||
| 621 | metamethod __call: function(self: yue, module: string): any... | ||
| 622 | ``` | ||
| 623 | |||
| 624 | **参数:** | ||
| 625 | |||
| 626 | | 参数名 | 类型 | 描述 | | ||
| 627 | | --- | --- | --- | | ||
| 628 | | module | string | 模块名。 | | ||
| 629 | |||
| 630 | **返回值:** | ||
| 631 | |||
| 632 | | 返回类型 | 描述 | | ||
| 633 | | --- | --- | | ||
| 634 | | any | 模块值。 | | ||
| 635 | |||
| 636 | ## Config | ||
| 637 | |||
| 638 | **描述:** | ||
| 639 | |||
| 640 | 编译器编译选项。 | ||
| 641 | |||
| 642 | ### lint_global | ||
| 643 | |||
| 644 | **类型:** 成员变量。 | ||
| 645 | |||
| 646 | **描述:** | ||
| 647 | |||
| 648 | 编译器是否应该收集代码中出现的全局变量。 | ||
| 649 | |||
| 650 | **签名:** | ||
| 651 | ```lua | ||
| 652 | lint_global: boolean | ||
| 653 | ``` | ||
| 654 | |||
| 655 | ### implicit_return_root | ||
| 656 | |||
| 657 | **类型:** 成员变量。 | ||
| 658 | |||
| 659 | **描述:** | ||
| 660 | |||
| 661 | 编译器是否应该对根层级的代码块进行隐式的表达式返回。 | ||
| 662 | |||
| 663 | **签名:** | ||
| 664 | ```lua | ||
| 665 | implicit_return_root: boolean | ||
| 666 | ``` | ||
| 667 | |||
| 668 | ### reserve_line_number | ||
| 669 | |||
| 670 | **类型:** 成员变量。 | ||
| 671 | |||
| 672 | **描述:** | ||
| 673 | |||
| 674 | 编译器是否应该在编译后的代码中保留原始行号。 | ||
| 675 | |||
| 676 | **签名:** | ||
| 677 | ```lua | ||
| 678 | reserve_line_number: boolean | ||
| 679 | ``` | ||
| 680 | |||
| 681 | ### reserve_comment | ||
| 682 | |||
| 683 | **类型:** 成员变量。 | ||
| 684 | |||
| 685 | **描述:** | ||
| 686 | |||
| 687 | 编译器是否应该在编译后的代码中保留原始注释。 | ||
| 688 | |||
| 689 | **签名:** | ||
| 690 | ```lua | ||
| 691 | reserve_comment: boolean | ||
| 692 | ``` | ||
| 693 | |||
| 694 | ### space_over_tab | ||
| 695 | |||
| 696 | **类型:** 成员变量。 | ||
| 697 | |||
| 698 | **描述:** | ||
| 699 | |||
| 700 | 编译器是否应该在编译后的代码中使用空格字符而不是制表符字符。 | ||
| 701 | |||
| 702 | **签名:** | ||
| 703 | ```lua | ||
| 704 | space_over_tab: boolean | ||
| 705 | ``` | ||
| 706 | |||
| 707 | ### same_module | ||
| 708 | |||
| 709 | **类型:** 成员变量。 | ||
| 710 | |||
| 711 | **描述:** | ||
| 712 | |||
| 713 | 编译器是否应该将要编译的代码视为当前正在编译的模块。仅供编译器内部使用。 | ||
| 714 | |||
| 715 | **签名:** | ||
| 716 | ```lua | ||
| 717 | same_module: boolean | ||
| 718 | ``` | ||
| 719 | |||
| 720 | ### line_offset | ||
| 721 | |||
| 722 | **类型:** 成员变量。 | ||
| 723 | |||
| 724 | **描述:** | ||
| 725 | |||
| 726 | 编译器错误消息是否应该包含行号偏移量。仅供编译器内部使用。 | ||
| 727 | |||
| 728 | **签名:** | ||
| 729 | ```lua | ||
| 730 | line_offset: integer | ||
| 731 | ``` | ||
| 732 | |||
| 733 | ### yue.Config.LuaTarget | ||
| 734 | |||
| 735 | **类型:** 枚举。 | ||
| 736 | |||
| 737 | **描述:** | ||
| 738 | |||
| 739 | 目标 Lua 版本枚举。 | ||
| 740 | |||
| 741 | **签名:** | ||
| 742 | ```lua | ||
| 743 | enum LuaTarget | ||
| 744 | "5.1" | ||
| 745 | "5.2" | ||
| 746 | "5.3" | ||
| 747 | "5.4" | ||
| 748 | "5.5" | ||
| 749 | end | ||
| 750 | ``` | ||
| 751 | |||
| 752 | ### options | ||
| 753 | |||
| 754 | **类型:** 成员变量。 | ||
| 755 | |||
| 756 | **描述:** | ||
| 757 | |||
| 758 | 要传递给编译函数的额外选项。 | ||
| 759 | |||
| 760 | **签名:** | ||
| 761 | ```lua | ||
| 762 | options: Options | ||
| 763 | ``` | ||
| 764 | |||
| 765 | ## Options | ||
| 766 | |||
| 767 | **描述:** | ||
| 768 | |||
| 769 | 额外编译器选项定义。 | ||
| 770 | |||
| 771 | ### target | ||
| 772 | |||
| 773 | **类型:** 成员变量。 | ||
| 774 | |||
| 775 | **描述:** | ||
| 776 | |||
| 777 | 编译目标 Lua 版本。 | ||
| 778 | |||
| 779 | **签名:** | ||
| 780 | ```lua | ||
| 781 | target: LuaTarget | ||
| 782 | ``` | ||
| 783 | |||
| 784 | ### path | ||
| 785 | |||
| 786 | **类型:** 成员变量。 | ||
| 787 | |||
| 788 | **描述:** | ||
| 789 | |||
| 790 | 额外模块搜索路径。 | ||
| 791 | |||
| 792 | **签名:** | ||
| 793 | ```lua | ||
| 794 | path: string | ||
| 795 | ``` | ||
| 796 | |||
| 797 | ### dump_locals | ||
| 798 | |||
| 799 | **类型:** 成员变量。 | ||
| 800 | |||
| 801 | **描述:** | ||
| 802 | |||
| 803 | 是否在回溯错误消息中输出代码块的局部变量。默认为 false。 | ||
| 804 | |||
| 805 | **签名:** | ||
| 806 | ```lua | ||
| 807 | dump_locals: boolean | ||
| 808 | ``` | ||
| 809 | |||
| 810 | ### simplified | ||
| 811 | |||
| 812 | **类型:** 成员变量。 | ||
| 813 | |||
| 814 | **描述:** | ||
| 815 | |||
| 816 | 是否简化输出的错误消息。默认为 true。 | ||
| 817 | |||
| 818 | **签名:** | ||
| 819 | ```lua | ||
| 820 | simplified: boolean | ||
| 821 | ``` | ||
diff --git a/doc/docs/zh/doc/try.md b/doc/docs/zh/doc/try.md new file mode 100644 index 0000000..b4de24d --- /dev/null +++ b/doc/docs/zh/doc/try.md | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | # 错误处理 | ||
| 2 | |||
| 3 |   用于统一进行 Lua 错误处理的便捷语法。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | try | ||
| 7 | func 1, 2, 3 | ||
| 8 | catch err | ||
| 9 | print yue.traceback err | ||
| 10 | |||
| 11 | success, result = try | ||
| 12 | func 1, 2, 3 | ||
| 13 | catch err | ||
| 14 | yue.traceback err | ||
| 15 | |||
| 16 | try func 1, 2, 3 | ||
| 17 | catch err | ||
| 18 | print yue.traceback err | ||
| 19 | |||
| 20 | success, result = try func 1, 2, 3 | ||
| 21 | |||
| 22 | try | ||
| 23 | print "尝试中" | ||
| 24 | func 1, 2, 3 | ||
| 25 | |||
| 26 | -- 使用if赋值模式 | ||
| 27 | if success, result := try func 1, 2, 3 | ||
| 28 | catch err | ||
| 29 | print yue.traceback err | ||
| 30 | print result | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | try | ||
| 36 | func 1, 2, 3 | ||
| 37 | catch err | ||
| 38 | print yue.traceback err | ||
| 39 | |||
| 40 | success, result = try | ||
| 41 | func 1, 2, 3 | ||
| 42 | catch err | ||
| 43 | yue.traceback err | ||
| 44 | |||
| 45 | try func 1, 2, 3 | ||
| 46 | catch err | ||
| 47 | print yue.traceback err | ||
| 48 | |||
| 49 | success, result = try func 1, 2, 3 | ||
| 50 | |||
| 51 | try | ||
| 52 | print "尝试中" | ||
| 53 | func 1, 2, 3 | ||
| 54 | |||
| 55 | -- 使用if赋值模式 | ||
| 56 | if success, result := try func 1, 2, 3 | ||
| 57 | catch err | ||
| 58 | print yue.traceback err | ||
| 59 | print result | ||
| 60 | ``` | ||
| 61 | |||
| 62 | </YueDisplay> | ||
| 63 | |||
| 64 | ## 错误处理简化 | ||
| 65 | |||
| 66 |   `try?` 是 `try` 的功能简化语法,它不再返回 `try` 语句的布尔状态,并在成功时直接返回 `try` 代码块的结果,失败时返回 `nil` 值而非错误对象。 | ||
| 67 | |||
| 68 | ```yuescript | ||
| 69 | a, b, c = try? func! | ||
| 70 | |||
| 71 | -- 与空值合并运算符一起使用 | ||
| 72 | a = (try? func!) ?? "default" | ||
| 73 | |||
| 74 | -- 作为函数参数 | ||
| 75 | f try? func! | ||
| 76 | |||
| 77 | -- 带 catch 块的 try! | ||
| 78 | f try? | ||
| 79 | print 123 | ||
| 80 | func! | ||
| 81 | catch e | ||
| 82 | print e | ||
| 83 | e | ||
| 84 | ``` | ||
| 85 | <YueDisplay> | ||
| 86 | |||
| 87 | ```yue | ||
| 88 | a, b, c = try? func! | ||
| 89 | |||
| 90 | -- 与空值合并运算符一起使用 | ||
| 91 | a = (try? func!) ?? "default" | ||
| 92 | |||
| 93 | -- 作为函数参数 | ||
| 94 | f try? func! | ||
| 95 | |||
| 96 | -- 带 catch 块的 try! | ||
| 97 | f try? | ||
| 98 | print 123 | ||
| 99 | func! | ||
| 100 | catch e | ||
| 101 | print e | ||
| 102 | e | ||
| 103 | ``` | ||
| 104 | |||
| 105 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/usage.md b/doc/docs/zh/doc/usage.md new file mode 100644 index 0000000..b9d84d4 --- /dev/null +++ b/doc/docs/zh/doc/usage.md | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | # 使用方法 | ||
| 2 | |||
| 3 | ## Lua 模块 | ||
| 4 | |||
| 5 |   在 Lua 中使用月之脚本模块: | ||
| 6 | |||
| 7 | * **用法 1** | ||
| 8 | |||
| 9 |   在 Lua 中引入 "你的脚本入口文件.yue"。 | ||
| 10 | |||
| 11 | ```Lua | ||
| 12 | require("yue")("你的脚本入口文件") | ||
| 13 | ``` | ||
| 14 | |||
| 15 |   当你在同一路径下把 "你的脚本入口文件.yue" 编译成了 "你的脚本入口文件.lua" 时,仍然可以使用这个代码加载 .lua 代码文件。在其余的月之脚本文件中,只需正常使用 **require** 或 **import** 进行脚本引用即可。错误消息中的代码行号也会被正确处理。 | ||
| 16 | |||
| 17 | * **用法 2** | ||
| 18 | |||
| 19 |   手动引入月之脚本模块并重写错误消息来帮助调试。 | ||
| 20 | ```lua | ||
| 21 | local yue = require("yue") | ||
| 22 | yue.insert_loaders() | ||
| 23 | local success, result = xpcall(function() | ||
| 24 | return require("yuescript_module_name") | ||
| 25 | end, function(err) | ||
| 26 | return yue.traceback(err) | ||
| 27 | end) | ||
| 28 | ``` | ||
| 29 | |||
| 30 | * **用法 3** | ||
| 31 | |||
| 32 |   在 Lua 中使用月之脚本编译器功能。 | ||
| 33 | ```lua | ||
| 34 | local yue = require("yue") | ||
| 35 | local codes, err, globals = yue.to_lua([[ | ||
| 36 | f = -> | ||
| 37 | print "hello world" | ||
| 38 | f! | ||
| 39 | ]],{ | ||
| 40 | implicit_return_root = true, | ||
| 41 | reserve_line_number = true, | ||
| 42 | lint_global = true, | ||
| 43 | space_over_tab = false, | ||
| 44 | options = { | ||
| 45 | target = "5.4", | ||
| 46 | path = "/script" | ||
| 47 | } | ||
| 48 | }) | ||
| 49 | ``` | ||
| 50 | |||
| 51 | ## 月之脚本编译工具 | ||
| 52 | |||
| 53 |   使用月之脚本编译工具: | ||
| 54 | |||
| 55 | ```shell | ||
| 56 | > yue -h | ||
| 57 | 命令行用法: yue | ||
| 58 | [选项] [<文件/目录>] ... | ||
| 59 | yue -e <代码或文件> [参数...] | ||
| 60 | yue -w [<目录>] [选项] | ||
| 61 | yue - | ||
| 62 | |||
| 63 | 说明: | ||
| 64 | - '-' 或 '--' 必须作为唯一且第一个参数,用于读取标准输入。 | ||
| 65 | - '-o/--output' 不能与多个输入文件一起使用。 | ||
| 66 | - '-w/--watch' 仅能用于目录,不能用于单个文件。 | ||
| 67 | - 使用 '-e/--execute' 时,后续的参数将作为脚本参数传递。 | ||
| 68 | |||
| 69 | 选项: | ||
| 70 | -h, --help 显示帮助信息并退出 | ||
| 71 | -e <字符串>, --execute <字符串> 执行文件或原始代码 | ||
| 72 | -m, --minify 生成压缩(最小化)代码 | ||
| 73 | -r, --rewrite 重写输出以匹配原始代码行号 | ||
| 74 | -t <目标路径>, --output-to <目标路径> | ||
| 75 | 指定编译后文件的输出路径 | ||
| 76 | -o <文件>, --output <文件> 将输出写入文件 | ||
| 77 | -p, --print 输出到标准输出 | ||
| 78 | -b, --benchmark 输出编译耗时(不写入文件) | ||
| 79 | -g, --globals 显示用到的全局变量及其所在的名称、行号、列号 | ||
| 80 | -s, --spaces 用空格代替制表符(tab)输出代码 | ||
| 81 | -l, --line-numbers 输出源代码的行号 | ||
| 82 | -j, --no-implicit-return 禁用文件末尾的隐式返回 | ||
| 83 | -c, --reserve-comments 保留源代码中的注释 | ||
| 84 | -w [<目录>], --watch [<目录>] | ||
| 85 | 监视目录变化并自动编译 | ||
| 86 | -v, --version 显示版本信息 | ||
| 87 | - 从标准输入读取,输出到标准输出(仅能作为唯一参数) | ||
| 88 | -- 等同于 '-',为兼容旧版本保留 | ||
| 89 | |||
| 90 | --target <版本> 指定生成代码的 Lua 版本 (只能为 5.1 ~ 5.5) | ||
| 91 | --path <路径字符串> 附加一个 Lua 搜索路径到 package.path | ||
| 92 | --<键>=<值> 以 key=value 形式传递编译器选项(保持已有用法) | ||
| 93 | |||
| 94 | 不带选项直接运行可进入交互模式(REPL),在交互模式里输入单独的符号 '$' | ||
| 95 | 可用于开始或结束多行模式。 | ||
| 96 | ``` | ||
| 97 | |||
| 98 |   使用案例: | ||
| 99 | |||
| 100 |   递归编译当前路径下扩展名为 **.yue** 的每个月之脚本文件: **yue .** | ||
| 101 | |||
| 102 |   编译并将结果保存到目标路径: **yue -t /target/path/ .** | ||
| 103 | |||
| 104 |   编译并保留调试信息: **yue -l .** | ||
| 105 | |||
| 106 |   编译并生成压缩代码: **yue -m .** | ||
| 107 | |||
| 108 |   直接执行代码: **yue -e 'print 123'** | ||
| 109 | |||
| 110 |   执行一个月之脚本文件: **yue -e main.yue** | ||
diff --git a/doc/docs/zh/doc/varargs-assignment.md b/doc/docs/zh/doc/varargs-assignment.md new file mode 100644 index 0000000..6cc4278 --- /dev/null +++ b/doc/docs/zh/doc/varargs-assignment.md | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # 可变参数赋值 | ||
| 2 | |||
| 3 |   你可以将函数返回的结果赋值给一个可变参数符号 `...`。然后使用 Lua 的方式访问其内容。 | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | list = [1, 2, 3, 4, 5] | ||
| 7 | fn = (ok) -> ok, table.unpack list | ||
| 8 | ok, ... = fn true | ||
| 9 | count = select '#', ... | ||
| 10 | first = select 1, ... | ||
| 11 | print ok, count, first | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | list = [1, 2, 3, 4, 5] | ||
| 17 | fn = (ok) -> ok, table.unpack list | ||
| 18 | ok, ... = fn true | ||
| 19 | count = select '#', ... | ||
| 20 | first = select 1, ... | ||
| 21 | print ok, count, first | ||
| 22 | ``` | ||
| 23 | |||
| 24 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/while-loop.md b/doc/docs/zh/doc/while-loop.md new file mode 100644 index 0000000..5995890 --- /dev/null +++ b/doc/docs/zh/doc/while-loop.md | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | # while 循环 | ||
| 2 | |||
| 3 |   在月之脚本中的 while 循环支持几种不同的写法: | ||
| 4 | |||
| 5 | ```yuescript | ||
| 6 | i = 10 | ||
| 7 | while i > 0 | ||
| 8 | print i | ||
| 9 | i -= 1 | ||
| 10 | |||
| 11 | while running == true do my_function! | ||
| 12 | ``` | ||
| 13 | <YueDisplay> | ||
| 14 | |||
| 15 | ```yue | ||
| 16 | i = 10 | ||
| 17 | while i > 0 | ||
| 18 | print i | ||
| 19 | i -= 1 | ||
| 20 | |||
| 21 | while running == true do my_function! | ||
| 22 | ``` | ||
| 23 | |||
| 24 | </YueDisplay> | ||
| 25 | |||
| 26 | ```yuescript | ||
| 27 | i = 10 | ||
| 28 | until i == 0 | ||
| 29 | print i | ||
| 30 | i -= 1 | ||
| 31 | |||
| 32 | until running == false do my_function! | ||
| 33 | ``` | ||
| 34 | <YueDisplay> | ||
| 35 | |||
| 36 | ```yue | ||
| 37 | i = 10 | ||
| 38 | until i == 0 | ||
| 39 | print i | ||
| 40 | i -= 1 | ||
| 41 | until running == false do my_function! | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
| 45 | |||
| 46 |   像 for 循环的语法一样,while 循环也可以作为一个表达式使用。为了使函数返回 while 循环的累积列表值,必须明确使用返回语句返回 while 循环表达式。 | ||
| 47 | |||
| 48 | ## repeat 循环 | ||
| 49 | |||
| 50 |   repeat 循环是从 Lua 语言中搬过来的相似语法: | ||
| 51 | |||
| 52 | ```yuescript | ||
| 53 | i = 10 | ||
| 54 | repeat | ||
| 55 | print i | ||
| 56 | i -= 1 | ||
| 57 | until i == 0 | ||
| 58 | ``` | ||
| 59 | <YueDisplay> | ||
| 60 | |||
| 61 | ```yue | ||
| 62 | i = 10 | ||
| 63 | repeat | ||
| 64 | print i | ||
| 65 | i -= 1 | ||
| 66 | until i == 0 | ||
| 67 | ``` | ||
| 68 | |||
| 69 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/whitespace.md b/doc/docs/zh/doc/whitespace.md new file mode 100644 index 0000000..1886e23 --- /dev/null +++ b/doc/docs/zh/doc/whitespace.md | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # 空白 | ||
| 2 | |||
| 3 |   月之脚本是一个对空白敏感的语言。你必须在相同的缩进中使用空格 **' '** 或制表符 **'\t'** 来编写一些代码块,如函数体、值列表和一些控制块。包含不同空白的表达式可能意味着不同的事情。制表符被视为4个空格,但最好不要混合使用空格和制表符。 | ||
| 4 | |||
| 5 | ## 语句分隔符 | ||
| 6 | |||
| 7 |   一条语句通常以换行结束。你也可以使用分号 `;` 显式结束一条语句,从而在同一行中编写多条语句: | ||
| 8 | |||
| 9 | ```yuescript | ||
| 10 | a = 1; b = 2; print a + b | ||
| 11 | ``` | ||
| 12 | <YueDisplay> | ||
| 13 | |||
| 14 | ```yue | ||
| 15 | a = 1; b = 2; print a + b | ||
| 16 | ``` | ||
| 17 | |||
| 18 | </YueDisplay> | ||
| 19 | |||
| 20 | ## 多行链式调用 | ||
| 21 | |||
| 22 |   你可以使用相同的缩进来编写多行链式函数调用。 | ||
| 23 | |||
| 24 | ```yuescript | ||
| 25 | Rx.Observable | ||
| 26 | .fromRange 1, 8 | ||
| 27 | \filter (x) -> x % 2 == 0 | ||
| 28 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 29 | \map (value) -> value .. '!' | ||
| 30 | \subscribe print | ||
| 31 | ``` | ||
| 32 | <YueDisplay> | ||
| 33 | |||
| 34 | ```yue | ||
| 35 | Rx.Observable | ||
| 36 | .fromRange 1, 8 | ||
| 37 | \filter (x) -> x % 2 == 0 | ||
| 38 | \concat Rx.Observable.of 'who do we appreciate' | ||
| 39 | \map (value) -> value .. '!' | ||
| 40 | \subscribe print | ||
| 41 | ``` | ||
| 42 | |||
| 43 | </YueDisplay> | ||
diff --git a/doc/docs/zh/doc/with-statement.md b/doc/docs/zh/doc/with-statement.md new file mode 100644 index 0000000..fbd3633 --- /dev/null +++ b/doc/docs/zh/doc/with-statement.md | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | # with 语句 | ||
| 2 | |||
| 3 | |||
| 4 | 在编写 Lua 代码时,我们在创建对象后的常见操作是立即调用这个对象一系列操作函数并设置一系列属性。 | ||
| 5 | |||
| 6 | 这导致在代码中多次重复引用对象的名称,增加了不必要的文本噪音。一个常见的解决方案是在创建对象时,在构造函数传入一个表,该表包含要覆盖设置的键和值的集合。这样做的缺点是该对象的构造函数必须支持这种初始化形式。 | ||
| 7 | |||
| 8 | with 块有助于简化编写这样的代码。在 with 块内,我们可以使用以 . 或 \ 开头的特殊语句,这些语句代表我们正在使用的对象的操作。 | ||
| 9 | |||
| 10 | 例如,我们可以这样处理一个新创建的对象: | ||
| 11 | |||
| 12 | ```yuescript | ||
| 13 | with Person! | ||
| 14 | .name = "Oswald" | ||
| 15 | \add_relative my_dad | ||
| 16 | \save! | ||
| 17 | print .name | ||
| 18 | ``` | ||
| 19 | <YueDisplay> | ||
| 20 | |||
| 21 | ```yue | ||
| 22 | with Person! | ||
| 23 | .name = "Oswald" | ||
| 24 | \add_relative my_dad | ||
| 25 | \save! | ||
| 26 | print .name | ||
| 27 | ``` | ||
| 28 | |||
| 29 | </YueDisplay> | ||
| 30 | |||
| 31 | with 语句也可以用作一个表达式,并返回它的代码块正在处理的对象。 | ||
| 32 | |||
| 33 | ```yuescript | ||
| 34 | file = with File "favorite_foods.txt" | ||
| 35 | \set_encoding "utf8" | ||
| 36 | ``` | ||
| 37 | <YueDisplay> | ||
| 38 | |||
| 39 | ```yue | ||
| 40 | file = with File "favorite_foods.txt" | ||
| 41 | \set_encoding "utf8" | ||
| 42 | ``` | ||
| 43 | |||
| 44 | </YueDisplay> | ||
| 45 | |||
| 46 | 或者… | ||
| 47 | |||
| 48 | ```yuescript | ||
| 49 | create_person = (name, relatives) -> | ||
| 50 | with Person! | ||
| 51 | .name = name | ||
| 52 | \add_relative relative for relative in *relatives | ||
| 53 | |||
| 54 | me = create_person "Leaf", [dad, mother, sister] | ||
| 55 | ``` | ||
| 56 | <YueDisplay> | ||
| 57 | |||
| 58 | ```yue | ||
| 59 | create_person = (name, relatives) -> | ||
| 60 | with Person! | ||
| 61 | .name = name | ||
| 62 | \add_relative relative for relative in *relatives | ||
| 63 | |||
| 64 | me = create_person "Leaf", [dad, mother, sister] | ||
| 65 | ``` | ||
| 66 | |||
| 67 | </YueDisplay> | ||
| 68 | |||
| 69 | 在此用法中,with 可以被视为K组合子(k-combinator)的一种特殊形式。 | ||
| 70 | |||
| 71 | 如果你想给表达式另外起一个名称的话,with 语句中的表达式也可以是一个赋值语句。 | ||
| 72 | |||
| 73 | ```yuescript | ||
| 74 | with str := "你好" | ||
| 75 | print "原始:", str | ||
| 76 | print "大写:", \upper! | ||
| 77 | ``` | ||
| 78 | <YueDisplay> | ||
| 79 | |||
| 80 | ```yue | ||
| 81 | with str := "你好" | ||
| 82 | print "原始:", str | ||
| 83 | print "大写:", \upper! | ||
| 84 | ``` | ||
| 85 | |||
| 86 | </YueDisplay> | ||
| 87 | |||
| 88 | 你可以在 `with` 语句中使用 `[]` 访问特殊键。 | ||
| 89 | |||
| 90 | ```yuescript | ||
| 91 | with tb | ||
| 92 | [1] = 1 | ||
| 93 | print [2] | ||
| 94 | with [abc] | ||
| 95 | [3] = [2]\func! | ||
| 96 | ["key-name"] = value | ||
| 97 | [] = "abc" -- 追加到 "tb" | ||
| 98 | ``` | ||
| 99 | <YueDisplay> | ||
| 100 | |||
| 101 | ```yue | ||
| 102 | with tb | ||
| 103 | [1] = 1 | ||
| 104 | print [2] | ||
| 105 | with [abc] | ||
| 106 | [3] = [2]\func! | ||
| 107 | ["key-name"] = value | ||
| 108 | [] = "abc" -- 追加到 "tb" | ||
| 109 | ``` | ||
| 110 | |||
| 111 | </YueDisplay> | ||
| 112 | |||
| 113 | `with?` 是 `with` 语法的一个增强版本,引入了存在性检查,用于在不显式判空的情况下安全访问可能为 nil 的对象。 | ||
| 114 | |||
| 115 | ```yuescript | ||
| 116 | with? obj | ||
| 117 | print obj.name | ||
| 118 | ``` | ||
| 119 | <YueDisplay> | ||
| 120 | |||
| 121 | ```yue | ||
| 122 | with? obj | ||
| 123 | print obj.name | ||
| 124 | ``` | ||
| 125 | |||
| 126 | </YueDisplay> | ||
diff --git a/doc/docs/zh/index.md b/doc/docs/zh/index.md index 9068956..ea42085 100644 --- a/doc/docs/zh/index.md +++ b/doc/docs/zh/index.md | |||
| @@ -17,7 +17,6 @@ features: | |||
| 17 | details: 管道、模式匹配、切片与解构,同时保留 Lua 互操作性。 | 17 | details: 管道、模式匹配、切片与解构,同时保留 Lua 互操作性。 |
| 18 | - title: 快速迭代 | 18 | - title: 快速迭代 |
| 19 | details: 虚心接受用户反馈,以帮助改进和加速语言的开发和演进! | 19 | details: 虚心接受用户反馈,以帮助改进和加速语言的开发和演进! |
| 20 | footer: MIT Licensed | Copyright © 2017-2026 Li Jin | ||
| 21 | --- | 20 | --- |
| 22 | 21 | ||
| 23 | ### 版权和协议 | 22 | ### 版权和协议 |
