├── .editorconfig ├── .gitignore ├── .vscodeignore ├── BUILD.md ├── CHANGELOG.md ├── LICENSE ├── assets ├── icon.png ├── icon.svg └── sample.png ├── extension └── extension.ts ├── icons └── rhai.png ├── package.json ├── readme.md ├── syntax ├── rhai.JSON-tmLanguage ├── rhai.YAML-tmLanguage ├── rhai.configuration.json ├── rhai.markdown.json └── rhai.tmLanguage.json ├── test ├── array.rhai ├── assignment.rhai ├── comments.rhai ├── doc-comments.rhai ├── fibonacci.rhai ├── for1.rhai ├── for2.rhai ├── for3.rhai ├── function_decl1.rhai ├── function_decl2.rhai ├── function_decl3.rhai ├── function_decl4.rhai ├── if1.rhai ├── if2.rhai ├── loop.rhai ├── mat_mul.rhai ├── module.rhai ├── oop.rhai ├── op1.rhai ├── op2.rhai ├── op3.rhai ├── primes.rhai ├── speed_test.rhai ├── string.rhai ├── strings_map.rhai ├── switch.rhai └── while.rhai ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 4 5 | tab_width = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.YAML-tmLanguage] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [*.{json,awsl}] 14 | indent_style = space 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs 2 | .vscode 3 | .idea 4 | .vs 5 | *.iml 6 | 7 | # Node 8 | node_modules/ 9 | dist/ 10 | package-lock.json 11 | yarn.lock 12 | yarn-error.log 13 | 14 | # Release 15 | .vsixmanifest 16 | *.vsix 17 | *.tgz 18 | *.nb 19 | *.ps1 20 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | source/**/* 3 | images/**/* 4 | test/**/* 5 | 6 | .vscode 7 | .gitignore 8 | 9 | *.tgz 10 | **/*.ai 11 | yarn* 12 | 13 | **/*.ts 14 | **/ts*.json 15 | BUILD.md 16 | **/*.vsix 17 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | How to Build Extension from Source 2 | ================================= 3 | 4 | Prerequisites 5 | ------------- 6 | 7 | - Install [Node.js](https://nodejs.org) 8 | 9 | - Install [TypeScript](https://www.typescriptlang.org) 10 | 11 | ```sh 12 | npm install -g typescript 13 | ``` 14 | 15 | - Install [VSCE](https://github.com/Microsoft/vscode-vsce) 16 | 17 | ```sh 18 | npm install -g vsce 19 | ``` 20 | 21 | Fetch Node packages 22 | ------------------- 23 | 24 | ```sh 25 | npm install 26 | ``` 27 | 28 | Compile with TypeScript 29 | ----------------------- 30 | 31 | ```sh 32 | tsc 33 | ``` 34 | 35 | Compiled files are in the `dist` directory. 36 | 37 | Build VSIX package 38 | ------------------ 39 | 40 | ```sh 41 | vsce package 42 | ``` 43 | 44 | Compiled package is `vscode-rhai-`_version_`.vsix` within the main directory. 45 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Version 0.6.7 2 | ============= 3 | 4 | * Fixed recognition for `..=` (inclusive range) operator. 5 | * Fixed parsing for `|` in `switch` case conditions (previously parses as a closure). 6 | * White-spaces no longer highlights. 7 | 8 | 9 | Version 0.6.6 10 | ============= 11 | 12 | * Add the range operator `..` 13 | * Add elvis operators. 14 | 15 | 16 | Version 0.6.5 17 | ============= 18 | 19 | * Fix Highlighting styles of `private` and `fn`. 20 | * Recognize `Fn` as a reserved keyword. 21 | 22 | 23 | Version 0.6.4 24 | ============= 25 | 26 | * Remove keywords that are no longer reserved. 27 | 28 | 29 | Version 0.6.3 30 | ============= 31 | 32 | * Support untrusted workspaces. 33 | * Refine styling of automatic `global` modules. 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | ### 1. Definitions 5 | 6 | **1.1. “Contributor”** 7 | means each individual or legal entity that creates, contributes to 8 | the creation of, or owns Covered Software. 9 | 10 | **1.2. “Contributor Version”** 11 | means the combination of the Contributions of others (if any) used 12 | by a Contributor and that particular Contributor's Contribution. 13 | 14 | **1.3. “Contribution”** 15 | means Covered Software of a particular Contributor. 16 | 17 | **1.4. “Covered Software”** 18 | means Source Code Form to which the initial Contributor has attached 19 | the notice in Exhibit A, the Executable Form of such Source Code 20 | Form, and Modifications of such Source Code Form, in each case 21 | including portions thereof. 22 | 23 | **1.5. “Incompatible With Secondary Licenses”** 24 | means 25 | 26 | * **(a)** that the initial Contributor has attached the notice described 27 | in Exhibit B to the Covered Software; or 28 | * **(b)** that the Covered Software was made available under the terms of 29 | version 1.1 or earlier of the License, but not also under the 30 | terms of a Secondary License. 31 | 32 | **1.6. “Executable Form”** 33 | means any form of the work other than Source Code Form. 34 | 35 | **1.7. “Larger Work”** 36 | means a work that combines Covered Software with other material, in 37 | a separate file or files, that is not Covered Software. 38 | 39 | **1.8. “License”** 40 | means this document. 41 | 42 | **1.9. “Licensable”** 43 | means having the right to grant, to the maximum extent possible, 44 | whether at the time of the initial grant or subsequently, any and 45 | all of the rights conveyed by this License. 46 | 47 | **1.10. “Modifications”** 48 | means any of the following: 49 | 50 | * **(a)** any file in Source Code Form that results from an addition to, 51 | deletion from, or modification of the contents of Covered 52 | Software; or 53 | * **(b)** any new file in Source Code Form that contains any Covered 54 | Software. 55 | 56 | **1.11. “Patent Claims” of a Contributor** 57 | means any patent claim(s), including without limitation, method, 58 | process, and apparatus claims, in any patent Licensable by such 59 | Contributor that would be infringed, but for the grant of the 60 | License, by the making, using, selling, offering for sale, having 61 | made, import, or transfer of either its Contributions or its 62 | Contributor Version. 63 | 64 | **1.12. “Secondary License”** 65 | means either the GNU General Public License, Version 2.0, the GNU 66 | Lesser General Public License, Version 2.1, the GNU Affero General 67 | Public License, Version 3.0, or any later versions of those 68 | licenses. 69 | 70 | **1.13. “Source Code Form”** 71 | means the form of the work preferred for making modifications. 72 | 73 | **1.14. “You” (or “Your”)** 74 | means an individual or a legal entity exercising rights under this 75 | License. For legal entities, “You” includes any entity that 76 | controls, is controlled by, or is under common control with You. For 77 | purposes of this definition, “control” means **(a)** the power, direct 78 | or indirect, to cause the direction or management of such entity, 79 | whether by contract or otherwise, or **(b)** ownership of more than 80 | fifty percent (50%) of the outstanding shares or beneficial 81 | ownership of such entity. 82 | 83 | 84 | ### 2. License Grants and Conditions 85 | 86 | #### 2.1. Grants 87 | 88 | Each Contributor hereby grants You a world-wide, royalty-free, 89 | non-exclusive license: 90 | 91 | * **(a)** under intellectual property rights (other than patent or trademark) 92 | Licensable by such Contributor to use, reproduce, make available, 93 | modify, display, perform, distribute, and otherwise exploit its 94 | Contributions, either on an unmodified basis, with Modifications, or 95 | as part of a Larger Work; and 96 | * **(b)** under Patent Claims of such Contributor to make, use, sell, offer 97 | for sale, have made, import, and otherwise transfer either its 98 | Contributions or its Contributor Version. 99 | 100 | #### 2.2. Effective Date 101 | 102 | The licenses granted in Section 2.1 with respect to any Contribution 103 | become effective for each Contribution on the date the Contributor first 104 | distributes such Contribution. 105 | 106 | #### 2.3. Limitations on Grant Scope 107 | 108 | The licenses granted in this Section 2 are the only rights granted under 109 | this License. No additional rights or licenses will be implied from the 110 | distribution or licensing of Covered Software under this License. 111 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 112 | Contributor: 113 | 114 | * **(a)** for any code that a Contributor has removed from Covered Software; 115 | or 116 | * **(b)** for infringements caused by: **(i)** Your and any other third party's 117 | modifications of Covered Software, or **(ii)** the combination of its 118 | Contributions with other software (except as part of its Contributor 119 | Version); or 120 | * **(c)** under Patent Claims infringed by Covered Software in the absence of 121 | its Contributions. 122 | 123 | This License does not grant any rights in the trademarks, service marks, 124 | or logos of any Contributor (except as may be necessary to comply with 125 | the notice requirements in Section 3.4). 126 | 127 | #### 2.4. Subsequent Licenses 128 | 129 | No Contributor makes additional grants as a result of Your choice to 130 | distribute the Covered Software under a subsequent version of this 131 | License (see Section 10.2) or under the terms of a Secondary License (if 132 | permitted under the terms of Section 3.3). 133 | 134 | #### 2.5. Representation 135 | 136 | Each Contributor represents that the Contributor believes its 137 | Contributions are its original creation(s) or it has sufficient rights 138 | to grant the rights to its Contributions conveyed by this License. 139 | 140 | #### 2.6. Fair Use 141 | 142 | This License is not intended to limit any rights You have under 143 | applicable copyright doctrines of fair use, fair dealing, or other 144 | equivalents. 145 | 146 | #### 2.7. Conditions 147 | 148 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 149 | in Section 2.1. 150 | 151 | 152 | ### 3. Responsibilities 153 | 154 | #### 3.1. Distribution of Source Form 155 | 156 | All distribution of Covered Software in Source Code Form, including any 157 | Modifications that You create or to which You contribute, must be under 158 | the terms of this License. You must inform recipients that the Source 159 | Code Form of the Covered Software is governed by the terms of this 160 | License, and how they can obtain a copy of this License. You may not 161 | attempt to alter or restrict the recipients' rights in the Source Code 162 | Form. 163 | 164 | #### 3.2. Distribution of Executable Form 165 | 166 | If You distribute Covered Software in Executable Form then: 167 | 168 | * **(a)** such Covered Software must also be made available in Source Code 169 | Form, as described in Section 3.1, and You must inform recipients of 170 | the Executable Form how they can obtain a copy of such Source Code 171 | Form by reasonable means in a timely manner, at a charge no more 172 | than the cost of distribution to the recipient; and 173 | 174 | * **(b)** You may distribute such Executable Form under the terms of this 175 | License, or sublicense it under different terms, provided that the 176 | license for the Executable Form does not attempt to limit or alter 177 | the recipients' rights in the Source Code Form under this License. 178 | 179 | #### 3.3. Distribution of a Larger Work 180 | 181 | You may create and distribute a Larger Work under terms of Your choice, 182 | provided that You also comply with the requirements of this License for 183 | the Covered Software. If the Larger Work is a combination of Covered 184 | Software with a work governed by one or more Secondary Licenses, and the 185 | Covered Software is not Incompatible With Secondary Licenses, this 186 | License permits You to additionally distribute such Covered Software 187 | under the terms of such Secondary License(s), so that the recipient of 188 | the Larger Work may, at their option, further distribute the Covered 189 | Software under the terms of either this License or such Secondary 190 | License(s). 191 | 192 | #### 3.4. Notices 193 | 194 | You may not remove or alter the substance of any license notices 195 | (including copyright notices, patent notices, disclaimers of warranty, 196 | or limitations of liability) contained within the Source Code Form of 197 | the Covered Software, except that You may alter any license notices to 198 | the extent required to remedy known factual inaccuracies. 199 | 200 | #### 3.5. Application of Additional Terms 201 | 202 | You may choose to offer, and to charge a fee for, warranty, support, 203 | indemnity or liability obligations to one or more recipients of Covered 204 | Software. However, You may do so only on Your own behalf, and not on 205 | behalf of any Contributor. You must make it absolutely clear that any 206 | such warranty, support, indemnity, or liability obligation is offered by 207 | You alone, and You hereby agree to indemnify every Contributor for any 208 | liability incurred by such Contributor as a result of warranty, support, 209 | indemnity or liability terms You offer. You may include additional 210 | disclaimers of warranty and limitations of liability specific to any 211 | jurisdiction. 212 | 213 | 214 | ### 4. Inability to Comply Due to Statute or Regulation 215 | 216 | If it is impossible for You to comply with any of the terms of this 217 | License with respect to some or all of the Covered Software due to 218 | statute, judicial order, or regulation then You must: **(a)** comply with 219 | the terms of this License to the maximum extent possible; and **(b)** 220 | describe the limitations and the code they affect. Such description must 221 | be placed in a text file included with all distributions of the Covered 222 | Software under this License. Except to the extent prohibited by statute 223 | or regulation, such description must be sufficiently detailed for a 224 | recipient of ordinary skill to be able to understand it. 225 | 226 | 227 | ### 5. Termination 228 | 229 | **5.1.** The rights granted under this License will terminate automatically 230 | if You fail to comply with any of its terms. However, if You become 231 | compliant, then the rights granted under this License from a particular 232 | Contributor are reinstated **(a)** provisionally, unless and until such 233 | Contributor explicitly and finally terminates Your grants, and **(b)** on an 234 | ongoing basis, if such Contributor fails to notify You of the 235 | non-compliance by some reasonable means prior to 60 days after You have 236 | come back into compliance. Moreover, Your grants from a particular 237 | Contributor are reinstated on an ongoing basis if such Contributor 238 | notifies You of the non-compliance by some reasonable means, this is the 239 | first time You have received notice of non-compliance with this License 240 | from such Contributor, and You become compliant prior to 30 days after 241 | Your receipt of the notice. 242 | 243 | **5.2.** If You initiate litigation against any entity by asserting a patent 244 | infringement claim (excluding declaratory judgment actions, 245 | counter-claims, and cross-claims) alleging that a Contributor Version 246 | directly or indirectly infringes any patent, then the rights granted to 247 | You by any and all Contributors for the Covered Software under Section 248 | 2.1 of this License shall terminate. 249 | 250 | **5.3.** In the event of termination under Sections 5.1 or 5.2 above, all 251 | end user license agreements (excluding distributors and resellers) which 252 | have been validly granted by You or Your distributors under this License 253 | prior to termination shall survive termination. 254 | 255 | 256 | ### 6. Disclaimer of Warranty 257 | 258 | > Covered Software is provided under this License on an “as is” 259 | > basis, without warranty of any kind, either expressed, implied, or 260 | > statutory, including, without limitation, warranties that the 261 | > Covered Software is free of defects, merchantable, fit for a 262 | > particular purpose or non-infringing. The entire risk as to the 263 | > quality and performance of the Covered Software is with You. 264 | > Should any Covered Software prove defective in any respect, You 265 | > (not any Contributor) assume the cost of any necessary servicing, 266 | > repair, or correction. This disclaimer of warranty constitutes an 267 | > essential part of this License. No use of any Covered Software is 268 | > authorized under this License except under this disclaimer. 269 | 270 | ### 7. Limitation of Liability 271 | 272 | > Under no circumstances and under no legal theory, whether tort 273 | > (including negligence), contract, or otherwise, shall any 274 | > Contributor, or anyone who distributes Covered Software as 275 | > permitted above, be liable to You for any direct, indirect, 276 | > special, incidental, or consequential damages of any character 277 | > including, without limitation, damages for lost profits, loss of 278 | > goodwill, work stoppage, computer failure or malfunction, or any 279 | > and all other commercial damages or losses, even if such party 280 | > shall have been informed of the possibility of such damages. This 281 | > limitation of liability shall not apply to liability for death or 282 | > personal injury resulting from such party's negligence to the 283 | > extent applicable law prohibits such limitation. Some 284 | > jurisdictions do not allow the exclusion or limitation of 285 | > incidental or consequential damages, so this exclusion and 286 | > limitation may not apply to You. 287 | 288 | 289 | ### 8. Litigation 290 | 291 | Any litigation relating to this License may be brought only in the 292 | courts of a jurisdiction where the defendant maintains its principal 293 | place of business and such litigation shall be governed by laws of that 294 | jurisdiction, without reference to its conflict-of-law provisions. 295 | Nothing in this Section shall prevent a party's ability to bring 296 | cross-claims or counter-claims. 297 | 298 | 299 | ### 9. Miscellaneous 300 | 301 | This License represents the complete agreement concerning the subject 302 | matter hereof. If any provision of this License is held to be 303 | unenforceable, such provision shall be reformed only to the extent 304 | necessary to make it enforceable. Any law or regulation which provides 305 | that the language of a contract shall be construed against the drafter 306 | shall not be used to construe this License against a Contributor. 307 | 308 | 309 | ### 10. Versions of the License 310 | 311 | #### 10.1. New Versions 312 | 313 | Mozilla Foundation is the license steward. Except as provided in Section 314 | 10.3, no one other than the license steward has the right to modify or 315 | publish new versions of this License. Each version will be given a 316 | distinguishing version number. 317 | 318 | #### 10.2. Effect of New Versions 319 | 320 | You may distribute the Covered Software under the terms of the version 321 | of the License under which You originally received the Covered Software, 322 | or under the terms of any subsequent version published by the license 323 | steward. 324 | 325 | #### 10.3. Modified Versions 326 | 327 | If you create software not governed by this License, and you want to 328 | create a new license for such software, you may create and use a 329 | modified version of this License if you rename the license and remove 330 | any references to the name of the license steward (except to note that 331 | such modified license differs from this License). 332 | 333 | #### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 334 | 335 | If You choose to distribute Source Code Form that is Incompatible With 336 | Secondary Licenses under the terms of this version of the License, the 337 | notice described in Exhibit B of this License must be attached. 338 | 339 | ## Exhibit A - Source Code Form License Notice 340 | 341 | This Source Code Form is subject to the terms of the Mozilla Public 342 | License, v. 2.0. If a copy of the MPL was not distributed with this 343 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 344 | 345 | If it is not possible or desirable to put the notice in a particular 346 | file, then You may include the notice in a location (such as a LICENSE 347 | file in a relevant directory) where a recipient would be likely to look 348 | for such a notice. 349 | 350 | You may add additional accurate notices of copyright ownership. 351 | 352 | ## Exhibit B - “Incompatible With Secondary Licenses” Notice 353 | 354 | This Source Code Form is "Incompatible With Secondary Licenses", as 355 | defined by the Mozilla Public License, v. 2.0. 356 | 357 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhaiscript/vscode-rhai/e8c9e59963382613bffda137bc509f38ad64c78c/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /assets/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhaiscript/vscode-rhai/e8c9e59963382613bffda137bc509f38ad64c78c/assets/sample.png -------------------------------------------------------------------------------- /extension/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | import * as child_process from 'child_process' 3 | 4 | import 5 | { 6 | LanguageClient, 7 | LanguageClientOptions, 8 | Executable, 9 | } from 'vscode-languageclient' 10 | 11 | 12 | let client: LanguageClient 13 | 14 | function start_client() 15 | { 16 | let serverOptions: Executable = { 17 | command: 'rhai-lsp', 18 | } 19 | 20 | let clientOptions: LanguageClientOptions = { 21 | documentSelector: [{ scheme: 'file', language: 'rhai' }], 22 | } 23 | 24 | client = new LanguageClient( 25 | 'rhaiLanguageServer', 26 | 'Rhai Language Server', 27 | serverOptions, 28 | clientOptions, 29 | ) 30 | 31 | client.start() 32 | } 33 | 34 | 35 | async function is_installed(cmd: string): Promise 36 | { 37 | return new Promise((resolve) => 38 | { 39 | const checkCommand = process.platform === 'win32' ? 'where' : 'command -v' 40 | const proc = child_process.exec(`${checkCommand} ${cmd}`) 41 | proc.on('exit', (code) => { resolve(code === 0) }) 42 | }) 43 | } 44 | 45 | async function installServerBinary(): Promise 46 | { 47 | await is_installed('cargo') 48 | // cargo install 49 | // download from github 50 | const task = new vscode.Task( 51 | { type: 'cargo', task: 'install' }, 52 | vscode.workspace.workspaceFolders![0], 53 | 'Installing lsp server', 54 | 'rhai-lsp', 55 | new vscode.ShellExecution('cargo install rhai-lsp'), 56 | ) 57 | const promise = new Promise((resolve) => 58 | { 59 | vscode.tasks.onDidEndTask((e) => 60 | { 61 | if (e.execution.task === task) { 62 | e.execution.terminate() 63 | } 64 | }) 65 | vscode.tasks.onDidEndTaskProcess((e) => 66 | { 67 | resolve(e.exitCode === 0) 68 | }) 69 | }) 70 | vscode.tasks.executeTask(task) 71 | 72 | return promise 73 | } 74 | 75 | async function tryToInstallLanguageServer(configuration: vscode.WorkspaceConfiguration) 76 | { 77 | const selected = await vscode.window.showInformationMessage( 78 | 'Install rhai-lsp-server (Rust toolchain required) ?', 79 | 'Install', 80 | 'Never', 81 | ) 82 | if (selected === 'Install') { 83 | const installed = await installServerBinary() 84 | if (installed) { 85 | start_client() 86 | } 87 | } 88 | else if (selected === 'Never') { 89 | configuration.update('useLanguageServer', false) 90 | } 91 | } 92 | 93 | export async function activate(context: vscode.ExtensionContext) 94 | { 95 | const configuration = vscode.workspace.getConfiguration('notedown') 96 | const useLanguageServer = configuration.get('useLanguageServer') 97 | const shouldStartClient = useLanguageServer && (await is_installed('rhai-lsp')) 98 | if (shouldStartClient) { 99 | start_client() 100 | } else if (useLanguageServer) { 101 | // tryToInstallLanguageServer(configuration) 102 | } 103 | } 104 | 105 | export function deactivate(): Thenable | undefined 106 | { 107 | if (!client) { 108 | return undefined 109 | } 110 | return client.stop() 111 | } 112 | -------------------------------------------------------------------------------- /icons/rhai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhaiscript/vscode-rhai/e8c9e59963382613bffda137bc509f38ad64c78c/icons/rhai.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-rhai", 3 | "private": true, 4 | "displayName": "Rhai Language Support", 5 | "description": "Syntax highlighting for Rhai scripts", 6 | "publisher": "rhaiscript", 7 | "version": "0.6.8", 8 | "icon": "assets/icon.png", 9 | "homepage": "https://rhai.rs", 10 | "bugs": { 11 | "url": "https://github.com/rhaiscript/vscode-rhai/issues" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/rhaiscript/vscode-rhai.git" 16 | }, 17 | "categories": [ 18 | "Programming Languages", 19 | "Formatters" 20 | ], 21 | "capabilities": { 22 | "untrustedWorkspaces": { 23 | "supported": true 24 | } 25 | }, 26 | "scripts": { 27 | "build:syntax": "ts-node syntax/build.ts", 28 | "build:ts": "tsc -b", 29 | "build": "wee build:syntax -t && wee build:ts -t", 30 | "pack": "wee build && vsce package", 31 | "lint": "tslint **/*.ts --fix" 32 | }, 33 | "main": "./dist/extension.js", 34 | "engines": { 35 | "vscode": "^1.30.0" 36 | }, 37 | "activationEvents": [ 38 | "onLanguage:rhai" 39 | ], 40 | "contributes": { 41 | "languages": [ 42 | { 43 | "id": "rhai", 44 | "aliases": [ 45 | "Rhai" 46 | ], 47 | "extensions": [ 48 | ".rhai" 49 | ], 50 | "filenames": [], 51 | "filenamePatterns": [], 52 | "mimetypes": [], 53 | "icon": { 54 | "light": "./icons/rhai.png", 55 | "dark": "./icons/rhai.png" 56 | }, 57 | "configuration": "./syntax/rhai.configuration.json" 58 | } 59 | ], 60 | "grammars": [ 61 | { 62 | "language": "rhai", 63 | "scopeName": "source.rhai", 64 | "path": "./syntax/rhai.tmLanguage.json" 65 | }, 66 | { 67 | "scopeName": "markdown.rhai.codeblock", 68 | "path": "./syntax/rhai.markdown.json", 69 | "injectTo": [ 70 | "text.html.markdown" 71 | ], 72 | "embeddedLanguages": { 73 | "meta.embedded.block.rhai": "rhai" 74 | } 75 | } 76 | ], 77 | "commands": [ 78 | { 79 | "command": "rhai.format", 80 | "title": "Rhai: Format File" 81 | } 82 | ], 83 | "configuration": { 84 | "title": "Rhai", 85 | "properties": { 86 | "rhai.useLanguageServer": { 87 | "type": "boolean", 88 | "default": true, 89 | "description": "Use Rhai Language Server" 90 | }, 91 | "rhai.trace.server": { 92 | "type": "string", 93 | "default": "off", 94 | "enum": [ 95 | "off", 96 | "messages", 97 | "verbose" 98 | ], 99 | "description": "Traces the communication between VS Code and the language server.", 100 | "scope": "window" 101 | } 102 | } 103 | } 104 | }, 105 | "dependencies": { 106 | "vscode-languageclient": "^6.1.3" 107 | }, 108 | "devDependencies": { 109 | "@types/node": "^11.13.6", 110 | "@types/vscode": "^1.30.0", 111 | "tslint": "^6.0.0", 112 | "typescript": "^3.8.2" 113 | } 114 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Rhai Language Support for Visual Studio Code 2 | =========================================== 3 | 4 | [![License](https://img.shields.io/github/license/rhaiscript/vscode-rhai)](https://github.com/rhaiscript/vscode-rhai/blob/master/LICENSE.md) 5 | [![Installs](https://img.shields.io/visual-studio-marketplace/i/rhaiscript.vscode-rhai?logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=rhaiscript.vscode-rhai) 6 | [![Latest release](https://img.shields.io/github/release/rhaiscript/vscode-rhai.svg?logo=github)](https://github.com/rhaiscript/vscode-rhai/releases/latest) 7 | 8 | [![Rhai logo](https://rhai.rs/book/images/logo/rhai-banner-transparent-colour.png)](https://rhai.rs) 9 | 10 | [Rhai](https://rhai.rs) is an embedded scripting language and evaluation engine for Rust that gives 11 | a safe and easy way to add scripting to any application. 12 | 13 | 14 | Features 15 | -------- 16 | 17 | - [x] Syntax highlighting 18 | 19 | 20 | Todo List 21 | --------- 22 | 23 | - [ ] Auto formatter 24 | - [ ] Language server 25 | 26 | 27 | How to Install 28 | -------------- 29 | 30 | - Search for `Rhai Language Support` in Visual Studio Code. 31 | 32 | - Download directly from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=rhaiscript.vscode-rhai). 33 | 34 | 35 | Screenshot 36 | ---------- 37 | 38 | ![Sample](assets/sample.png) 39 | -------------------------------------------------------------------------------- /syntax/rhai.JSON-tmLanguage: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Rhai", 3 | "version": "v0.6.7", 4 | "fileTypes": [ 5 | "rhai" 6 | ], 7 | "uuid": "1e76f176-ee1c-4331-a781-eb21c0da77cf", 8 | "scopeName": "source.rhai", 9 | "information_for_contributors": [ 10 | "aster: galaster@foxmail.com", 11 | "schungx: schungx@live.com" 12 | ], 13 | "patterns": [ 14 | { 15 | "include": "#core" 16 | } 17 | ], 18 | "repository": { 19 | "core": { 20 | "patterns": [ 21 | { 22 | "include": "#expression" 23 | } 24 | ] 25 | }, 26 | "expression": { 27 | "patterns": [ 28 | { 29 | "include": "#literal-closure-labels" 30 | }, 31 | { 32 | "include": "#literal-labels" 33 | }, 34 | { 35 | "include": "#literal-keywords" 36 | }, 37 | { 38 | "include": "#support" 39 | }, 40 | { 41 | "include": "#literal-function" 42 | }, 43 | { 44 | "include": "#literal-closure" 45 | }, 46 | { 47 | "include": "#literal-constant" 48 | }, 49 | { 50 | "include": "#literal-template-string" 51 | }, 52 | { 53 | "include": "#literal-language-variable" 54 | }, 55 | { 56 | "include": "#literal-module" 57 | }, 58 | { 59 | "include": "#literal-method-call" 60 | }, 61 | { 62 | "include": "#literal-function-call" 63 | }, 64 | { 65 | "include": "#comments" 66 | }, 67 | { 68 | "include": "#brackets" 69 | }, 70 | { 71 | "include": "#literal-operators" 72 | }, 73 | { 74 | "include": "#literal-namespace" 75 | }, 76 | { 77 | "include": "#literal-variable" 78 | }, 79 | { 80 | "include": "#literal-punctuation" 81 | } 82 | ] 83 | }, 84 | "literal-constant": { 85 | "patterns": [ 86 | { 87 | "include": "#literal-number" 88 | }, 89 | { 90 | "include": "#literal-string" 91 | }, 92 | { 93 | "include": "#literal-language-constant" 94 | } 95 | ] 96 | }, 97 | "round-brackets": { 98 | "patterns": [ 99 | { 100 | "name": "meta.group.braces.round", 101 | "begin": "\\((?!\\*)", 102 | "beginCaptures": { 103 | "0": { 104 | "name": "meta.brace.round.rhai" 105 | } 106 | }, 107 | "end": "(?)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 381 | "beginCaptures": { 382 | "1": { 383 | "name": "punctuation.separator.switch.case.rhai" 384 | }, 385 | "2": { 386 | "name": "punctuation.definition.parameters.closure.begin.rhai" 387 | } 388 | }, 389 | "end": "(\\|)", 390 | "endCaptures": { 391 | "1": { 392 | "name": "punctuation.definition.parameters.closure.end.rhai" 393 | } 394 | }, 395 | "patterns": [ 396 | { 397 | "include": "#parameters-list" 398 | } 399 | ] 400 | } 401 | ] 402 | }, 403 | "literal-closure-labels": { 404 | "patterns": [ 405 | { 406 | "name": "meta.function.closure.rhai", 407 | "begin": "(\\b[_a-zA-Z]\\w*)\\s*(\\:)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 408 | "beginCaptures": { 409 | "1": { 410 | "name": "string.unquoted.label.rhai entity.name.function.method.rhai" 411 | }, 412 | "2": { 413 | "name": "punctuation.separator.key-value.rhai" 414 | }, 415 | "3": { 416 | "name": "punctuation.definition.parameters.closure.begin.rhai" 417 | } 418 | }, 419 | "end": "(\\|)", 420 | "endCaptures": { 421 | "1": { 422 | "name": "punctuation.definition.parameters.closure.end.rhai" 423 | } 424 | }, 425 | "patterns": [ 426 | { 427 | "include": "#parameters-list" 428 | } 429 | ] 430 | }, 431 | { 432 | "name": "meta.function.closure.rhai", 433 | "begin": "((\\\")((?:[^\"]|\\\\\")*)(\\\"))\\s*(:)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 434 | "beginCaptures": { 435 | "1": { 436 | "name": "string.quoted.double.rhai" 437 | }, 438 | "2": { 439 | "name": "punctuation.definition.string.begin.rhai" 440 | }, 441 | "3": { 442 | "name": "entity.name.function.method.rhai" 443 | }, 444 | "4": { 445 | "name": "punctuation.definition.string.end.rhai" 446 | }, 447 | "5": { 448 | "name": "punctuation.separator.key-value.rhai" 449 | }, 450 | "6": { 451 | "name": "punctuation.definition.parameters.closure.begin.rhai" 452 | } 453 | }, 454 | "end": "(\\|)", 455 | "endCaptures": { 456 | "1": { 457 | "name": "punctuation.definition.parameters.closure.end.rhai" 458 | } 459 | }, 460 | "patterns": [ 461 | { 462 | "include": "#parameters-list" 463 | } 464 | ] 465 | } 466 | ] 467 | }, 468 | "literal-function-call": { 469 | "patterns": [ 470 | { 471 | "name": "meta.function-call.without-arguments.rhai", 472 | "match": "(?x)\n ([_a-zA-Z]\\w*)(!)?\\s*\n (\\(\\s*\\))", 473 | "captures": { 474 | "1": { 475 | "name": "entity.name.function.rhai" 476 | }, 477 | "2": { 478 | "name": "punctuation.function-call.capture.rhai" 479 | }, 480 | "3": { 481 | "name": "meta.group.braces.round.function.arguments.rhai" 482 | } 483 | } 484 | }, 485 | { 486 | "name": "meta.function-call.with-arguments.rhai", 487 | "match": "(?x)\n ([_a-zA-Z]\\w*)(!)?\\s*\n (?=\\()", 488 | "captures": { 489 | "1": { 490 | "name": "entity.name.function.rhai" 491 | }, 492 | "2": { 493 | "name": "punctuation.function-call.capture.rhai" 494 | } 495 | } 496 | } 497 | ] 498 | }, 499 | "literal-method-call": { 500 | "patterns": [ 501 | { 502 | "name": "meta.function-call.method.without-arguments.rhai", 503 | "match": "(?x)\n (?<=(\\.|\\?\\.))\n \\s*([_a-zA-Z]\\w*)\\s*\n (\\(\\s*\\))", 504 | "captures": { 505 | "1": { 506 | "name": "entity.name.function.rhai" 507 | }, 508 | "2": { 509 | "name": "meta.group.braces.round.function.arguments.rhai" 510 | } 511 | } 512 | }, 513 | { 514 | "name": "meta.function-call.method.with-arguments.rhai", 515 | "match": "(?x)\n (?<=(\\.|\\?\\.))\n \\s*([_a-zA-Z]\\w*)\\s*\n (?=\\()", 516 | "captures": { 517 | "1": { 518 | "name": "entity.name.function.rhai" 519 | } 520 | } 521 | } 522 | ] 523 | }, 524 | "literal-language-variable": { 525 | "patterns": [ 526 | { 527 | "name": "variable.language.this.rhai", 528 | "match": "\\bthis\\b" 529 | } 530 | ] 531 | }, 532 | "literal-language-constant": { 533 | "patterns": [ 534 | { 535 | "name": "constant.language.boolean.true.rhai", 536 | "match": "\\btrue\\b" 537 | }, 538 | { 539 | "name": "constant.language.boolean.false.rhai", 540 | "match": "\\bfalse\\b" 541 | } 542 | ] 543 | }, 544 | "literal-language-namespace": { 545 | "patterns": [ 546 | { 547 | "match": "(?]) # assignment right-to-left both" 610 | }, 611 | { 612 | "name": "keyword.operator.assignment.augmented.rhai", 613 | "match": "(?x)\n %= | # assignment right-to-left both\n &= | # assignment right-to-left both\n \\*\\*=| # assignment right-to-left both\n (?>= # assignment right-to-left both" 614 | }, 615 | { 616 | "name": "keyword.operator.bitwise.rhai", 617 | "match": "(?x)\n << | # bitwise-shift left-to-right both\n >> | # bitwise-shift left-to-right both\n & | # bitwise-and left-to-right both\n \\^ | # bitwise-xor left-to-right both\n \\| # bitwise-or left-to-right both" 618 | }, 619 | { 620 | "name": "keyword.operator.relational.rhai", 621 | "match": "(?x)\n <= | # relational left-to-right both\n >= | # relational left-to-right both\n <(?!-) | # relational left-to-right both\n (? # relational left-to-right both" 622 | }, 623 | { 624 | "name": "keyword.operator.comparison.rhai", 625 | "match": "(?x)\n ==(?!=) | # equality left-to-right both\n !=(?!=) # equality left-to-right both" 626 | }, 627 | { 628 | "name": "keyword.operator.arithmetic.rhai", 629 | "match": "(?x)\n / | # division left-to-right both\n % | # modulus left-to-right both\n \\*\\* | # power left-to-right both\n \\*(?!\\)) | # multiplication left-to-right both\n \\+(?!\\+) | # addition left-to-right both\n -(?![>-]) # subtraction left-to-right both" 630 | }, 631 | { 632 | "name": "keyword.operator.range.exclusive.rhai", 633 | "match": "\\.\\.(?![\\.=])" 634 | }, 635 | { 636 | "name": "keyword.operator.range.inclusive.rhai", 637 | "match": "\\.\\.=" 638 | }, 639 | { 640 | "name": "keyword.operator.accessor.rhai punctuation.accessor.rhai", 641 | "match": "\\.(?!\\.)|\\?\\." 642 | }, 643 | { 644 | "name": "punctuation.separator.switch.case.rhai", 645 | "match": "=>" 646 | }, 647 | { 648 | "name": "invalid.illegal.operator.rhai", 649 | "match": "(\\(\\*|\\*\\)|\\+\\+|--|\\.\\.\\.+|~|#(?!{)|@|\\?|\\$(?!{)|->|<-|===|!==|\\:=|\\:\\:<)" 650 | } 651 | ] 652 | }, 653 | "literal-labels": { 654 | "patterns": [ 655 | { 656 | "begin": "(?x)\n (?- 164 | (?x) 165 | (?:\b(private)\s+)? 166 | \s*(fn) 167 | \s*([_a-zA-Z]\w*)\s* 168 | beginCaptures: 169 | '1': {name: storage.modifier.rhai} 170 | '2': {name: storage.type.function.rhai} 171 | '3': {name: entity.name.function.rhai} 172 | end: (?<=\)) 173 | patterns: 174 | - include: '#parameters-list' 175 | 176 | - name: keyword.other.function.rhai 177 | match: \b(fn)\b 178 | 179 | - name: keyword.other.modifier.rhai 180 | match: \b(private)\b 181 | 182 | literal-closure: 183 | patterns: 184 | # e.g. |args| { } 185 | - name: meta.function.closure.rhai 186 | begin: (\|)(?=\s*[_a-zA-Z\|]) 187 | beginCaptures: 188 | '1': {name: punctuation.definition.parameters.closure.begin.rhai} 189 | end: (\|) 190 | endCaptures: 191 | '1': {name: punctuation.definition.parameters.closure.end.rhai} 192 | patterns: 193 | - include: '#parameters-list' 194 | 195 | # e.g. play = |args| { } 196 | - name: meta.function.closure.rhai 197 | begin: (\b[_a-zA-Z]\w*)\s*(=)\s*(\|)(?=\s*[_a-zA-Z\|]) 198 | beginCaptures: 199 | '1': {name: entity.name.function.closure.rhai} 200 | '2': {name: keyword.operator.assignment.rhai} 201 | '3': {name: punctuation.definition.parameters.closure.begin.rhai} 202 | end: (\|) 203 | endCaptures: 204 | '1': {name: punctuation.definition.parameters.closure.end.rhai} 205 | patterns: 206 | - include: '#parameters-list' 207 | 208 | # e.g. => |args| { } 209 | - name: meta.function.closure.rhai 210 | begin: (=>)\s*(\|)(?=\s*[_a-zA-Z\|]) 211 | beginCaptures: 212 | '1': {name: punctuation.separator.switch.case.rhai} 213 | '2': {name: punctuation.definition.parameters.closure.begin.rhai} 214 | end: (\|) 215 | endCaptures: 216 | '1': {name: punctuation.definition.parameters.closure.end.rhai} 217 | patterns: 218 | - include: '#parameters-list' 219 | 220 | literal-closure-labels: 221 | patterns: 222 | # e.g. play: |args| { } 223 | - name: meta.function.closure.rhai 224 | begin: (\b[_a-zA-Z]\w*)\s*(\:)\s*(\|)(?=\s*[_a-zA-Z\|]) 225 | beginCaptures: 226 | '1': {name: string.unquoted.label.rhai entity.name.function.method.rhai} 227 | '2': {name: punctuation.separator.key-value.rhai} 228 | '3': {name: punctuation.definition.parameters.closure.begin.rhai} 229 | end: (\|) 230 | endCaptures: 231 | '1': {name: punctuation.definition.parameters.closure.end.rhai} 232 | patterns: 233 | - include: '#parameters-list' 234 | 235 | # e.g. "play": |args| { } 236 | - name: meta.function.closure.rhai 237 | begin: ((\")((?:[^"]|\\")*)(\"))\s*(:)\s*(\|)(?=\s*[_a-zA-Z\|]) 238 | beginCaptures: 239 | '1': {name: string.quoted.double.rhai} 240 | '2': {name: punctuation.definition.string.begin.rhai} 241 | '3': {name: entity.name.function.method.rhai} 242 | '4': {name: punctuation.definition.string.end.rhai} 243 | '5': {name: punctuation.separator.key-value.rhai} 244 | '6': {name: punctuation.definition.parameters.closure.begin.rhai} 245 | end: (\|) 246 | endCaptures: 247 | '1': {name: punctuation.definition.parameters.closure.end.rhai} 248 | patterns: 249 | - include: '#parameters-list' 250 | 251 | literal-function-call: 252 | patterns: 253 | - name: meta.function-call.without-arguments.rhai 254 | match: >- 255 | (?x) 256 | ([_a-zA-Z]\w*)(!)?\s* 257 | (\(\s*\)) 258 | captures: 259 | '1': {name: entity.name.function.rhai} 260 | '2': {name: punctuation.function-call.capture.rhai} 261 | '3': {name: meta.group.braces.round.function.arguments.rhai} 262 | 263 | - name: meta.function-call.with-arguments.rhai 264 | match: >- 265 | (?x) 266 | ([_a-zA-Z]\w*)(!)?\s* 267 | (?=\() 268 | captures: 269 | '1': {name: entity.name.function.rhai} 270 | '2': {name: punctuation.function-call.capture.rhai} 271 | 272 | literal-method-call: 273 | patterns: 274 | - name: meta.function-call.method.without-arguments.rhai 275 | match: >- 276 | (?x) 277 | (?<=(\.|\?\.)) 278 | \s*([_a-zA-Z]\w*)\s* 279 | (\(\s*\)) 280 | captures: 281 | '1': {name: entity.name.function.rhai} 282 | '2': {name: meta.group.braces.round.function.arguments.rhai} 283 | 284 | - name: meta.function-call.method.with-arguments.rhai 285 | match: >- 286 | (?x) 287 | (?<=(\.|\?\.)) 288 | \s*([_a-zA-Z]\w*)\s* 289 | (?=\() 290 | captures: 291 | '1': {name: entity.name.function.rhai} 292 | 293 | literal-language-variable: 294 | patterns: 295 | - name: variable.language.this.rhai 296 | match: \bthis\b 297 | 298 | literal-language-constant: 299 | patterns: 300 | - name: constant.language.boolean.true.rhai 301 | match: \btrue\b 302 | 303 | - name: constant.language.boolean.false.rhai 304 | match: \bfalse\b 305 | 306 | literal-language-namespace: 307 | patterns: 308 | - match: (?- 339 | (?x) 340 | !(?!=)| # logical-not right-to-left right 341 | && | # logical-and left-to-right both 342 | \|\| # logical-or left-to-right both 343 | - name: keyword.operator.containment.rhai 344 | match: >- 345 | (?x) 346 | \bin\b | # in left-to-right both 347 | \B!in\b # not-in left-to-right both 348 | - name: keyword.operator.coalesce.rhai 349 | match: >- 350 | (?x) 351 | \?\? # null-coalesce left-to-right both 352 | - name: keyword.operator.assignment.rhai 353 | match: >- 354 | (?x) 355 | =(?![=>]) # assignment right-to-left both 356 | - name: keyword.operator.assignment.augmented.rhai 357 | match: >- 358 | (?x) 359 | %= | # assignment right-to-left both 360 | &= | # assignment right-to-left both 361 | \*\*=| # assignment right-to-left both 362 | (?>= # assignment right-to-left both 370 | - name: keyword.operator.bitwise.rhai 371 | match: >- 372 | (?x) 373 | << | # bitwise-shift left-to-right both 374 | >> | # bitwise-shift left-to-right both 375 | & | # bitwise-and left-to-right both 376 | \^ | # bitwise-xor left-to-right both 377 | \| # bitwise-or left-to-right both 378 | - name: keyword.operator.relational.rhai 379 | match: >- 380 | (?x) 381 | <= | # relational left-to-right both 382 | >= | # relational left-to-right both 383 | <(?!-) | # relational left-to-right both 384 | (? # relational left-to-right both 385 | - name: keyword.operator.comparison.rhai 386 | match: >- 387 | (?x) 388 | ==(?!=) | # equality left-to-right both 389 | !=(?!=) # equality left-to-right both 390 | - name: keyword.operator.arithmetic.rhai 391 | match: >- 392 | (?x) 393 | / | # division left-to-right both 394 | % | # modulus left-to-right both 395 | \*\* | # power left-to-right both 396 | \*(?!\)) | # multiplication left-to-right both 397 | \+(?!\+) | # addition left-to-right both 398 | -(?![>-]) # subtraction left-to-right both 399 | - name: keyword.operator.range.exclusive.rhai 400 | match: \.\.(?![\.=]) 401 | - name: keyword.operator.range.inclusive.rhai 402 | match: \.\.= 403 | - name: keyword.operator.accessor.rhai punctuation.accessor.rhai 404 | match: \.(?!\.)|\?\. 405 | - name: punctuation.separator.switch.case.rhai 406 | match: => 407 | - name: invalid.illegal.operator.rhai 408 | match: (\(\*|\*\)|\+\+|--|\.\.\.+|~|#(?!{)|@|\?|\$(?!{)|->|<-|===|!==|\:=|\:\:<) 409 | 410 | literal-labels: 411 | patterns: 412 | - begin: >- 413 | (?x) 414 | (?- 431 | (?xi) 432 | (?: 433 | \b0b[0-1][_0-1]*| # binary 434 | \b0o[0-7][_0-7]*| # octal 435 | \b0x[\da-f][_\da-f]*| # hex 436 | (\B[+\-])?\b\d[_\d]*\.\d[_\d]*(e[+\-]?\d[_\d]*)?| # e.g. 999.999, 999.99e+123 437 | (\B[+\-])?\b\d[_\d]*\.(?!\.)\B| # e.g. 999. 438 | (\B[+\-])?\b\d[_\d]*(e[+\-]?\d[_\d]*)? # e.g. 999, 999e+123 439 | ) 440 | 441 | literal-punctuation: 442 | patterns: 443 | - name: punctuation.terminator.statement.rhai 444 | match: \; 445 | 446 | - name: meta.delimiter.comma.rhai 447 | match: \, 448 | 449 | literal-template-string: 450 | patterns: 451 | - name: string.interpolated.rhai 452 | begin: '`' 453 | beginCaptures: 454 | '0': {name: punctuation.definition.string.begin.rhai} 455 | end: '`' 456 | endCaptures: 457 | '0': {name: punctuation.definition.string.end.rhai} 458 | patterns: 459 | - include: '#string-content' 460 | - name: meta.interpolation.rhai 461 | begin: \${ 462 | beginCaptures: 463 | '0': {name: punctuation.section.interpolation.begin.rhai} 464 | end: '}' 465 | endCaptures: 466 | '0': {name: punctuation.section.interpolation.end.rhai} 467 | patterns: 468 | - include: '#expression' 469 | 470 | literal-string: 471 | patterns: 472 | - name: string.quoted.single.rhai 473 | match: ('([^'\\]|\\([tnr'\\]|x\h{2}|u\h{4}|U\h{8}))') 474 | patterns: 475 | - match: \\([tnr'\\]|x\h{2}|u\h{4}|U\h{8}) 476 | name: constant.character.escape.rhai 477 | 478 | - name: string.quoted.double.rhai 479 | begin: (") 480 | beginCaptures: 481 | '1': {name: punctuation.definition.string.begin.rhai} 482 | end: (") 483 | endCaptures: 484 | '1': {name: punctuation.definition.string.end.rhai} 485 | patterns: 486 | - include: '#string-content' 487 | - name: invalid.illegal.newline.rhai 488 | match: (?` \n\t", 67 | "surroundingPairs": [ 68 | [ 69 | "{", 70 | "}" 71 | ], 72 | [ 73 | "[", 74 | "]" 75 | ], 76 | [ 77 | "(", 78 | ")" 79 | ], 80 | [ 81 | "'", 82 | "'" 83 | ], 84 | [ 85 | "\"", 86 | "\"" 87 | ], 88 | [ 89 | "`", 90 | "`" 91 | ] 92 | ], 93 | "folding": { 94 | "markers": { 95 | "start": "^\\s*//\\s*#?region\\b", 96 | "end": "^\\s*//\\s*#?endregion\\b" 97 | } 98 | }, 99 | "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)", 100 | "indentationRules": { 101 | "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$", 102 | "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]].*$" 103 | } 104 | } -------------------------------------------------------------------------------- /syntax/rhai.markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "markdown.rhai.codeblock", 3 | "injectionSelector": "L:text.html.markdown", 4 | "patterns": [ 5 | { 6 | "name": "markup.fenced_code.block.rhai", 7 | "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rhai)((\\s+|:|\\{)[^`~]*)?$)", 8 | "beginCaptures": { 9 | "3": { 10 | "name": "punctuation.definition.markdown" 11 | }, 12 | "4": { 13 | "name": "fenced_code.block.language.markdown" 14 | }, 15 | "5": { 16 | "name": "fenced_code.block.language.attributes.markdown" 17 | } 18 | }, 19 | "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", 20 | "endCaptures": { 21 | "3": { 22 | "name": "punctuation.definition.markdown" 23 | } 24 | }, 25 | "patterns": [ 26 | { 27 | "begin": "(^|\\G)(\\s*)(.*)", 28 | "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", 29 | "contentName": "meta.embedded.block.rhai", 30 | "patterns": [ 31 | { 32 | "include": "source.rhai" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /syntax/rhai.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Rhai", 3 | "version": "v0.6.7", 4 | "fileTypes": [ 5 | "rhai" 6 | ], 7 | "uuid": "1e76f176-ee1c-4331-a781-eb21c0da77cf", 8 | "scopeName": "source.rhai", 9 | "information_for_contributors": [ 10 | "aster: galaster@foxmail.com", 11 | "schungx: schungx@live.com" 12 | ], 13 | "patterns": [ 14 | { 15 | "include": "#core" 16 | } 17 | ], 18 | "repository": { 19 | "core": { 20 | "patterns": [ 21 | { 22 | "include": "#expression" 23 | } 24 | ] 25 | }, 26 | "expression": { 27 | "patterns": [ 28 | { 29 | "include": "#literal-closure-labels" 30 | }, 31 | { 32 | "include": "#literal-labels" 33 | }, 34 | { 35 | "include": "#literal-keywords" 36 | }, 37 | { 38 | "include": "#support" 39 | }, 40 | { 41 | "include": "#literal-function" 42 | }, 43 | { 44 | "include": "#literal-closure" 45 | }, 46 | { 47 | "include": "#literal-constant" 48 | }, 49 | { 50 | "include": "#literal-template-string" 51 | }, 52 | { 53 | "include": "#literal-language-variable" 54 | }, 55 | { 56 | "include": "#literal-module" 57 | }, 58 | { 59 | "include": "#literal-method-call" 60 | }, 61 | { 62 | "include": "#literal-function-call" 63 | }, 64 | { 65 | "include": "#comments" 66 | }, 67 | { 68 | "include": "#brackets" 69 | }, 70 | { 71 | "include": "#literal-operators" 72 | }, 73 | { 74 | "include": "#literal-namespace" 75 | }, 76 | { 77 | "include": "#literal-variable" 78 | }, 79 | { 80 | "include": "#literal-punctuation" 81 | } 82 | ] 83 | }, 84 | "literal-constant": { 85 | "patterns": [ 86 | { 87 | "include": "#literal-number" 88 | }, 89 | { 90 | "include": "#literal-string" 91 | }, 92 | { 93 | "include": "#literal-language-constant" 94 | } 95 | ] 96 | }, 97 | "round-brackets": { 98 | "patterns": [ 99 | { 100 | "name": "meta.group.braces.round", 101 | "begin": "\\((?!\\*)", 102 | "beginCaptures": { 103 | "0": { 104 | "name": "meta.brace.round.rhai" 105 | } 106 | }, 107 | "end": "(?)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 381 | "beginCaptures": { 382 | "1": { 383 | "name": "punctuation.separator.switch.case.rhai" 384 | }, 385 | "2": { 386 | "name": "punctuation.definition.parameters.closure.begin.rhai" 387 | } 388 | }, 389 | "end": "(\\|)", 390 | "endCaptures": { 391 | "1": { 392 | "name": "punctuation.definition.parameters.closure.end.rhai" 393 | } 394 | }, 395 | "patterns": [ 396 | { 397 | "include": "#parameters-list" 398 | } 399 | ] 400 | } 401 | ] 402 | }, 403 | "literal-closure-labels": { 404 | "patterns": [ 405 | { 406 | "name": "meta.function.closure.rhai", 407 | "begin": "(\\b[_a-zA-Z]\\w*)\\s*(\\:)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 408 | "beginCaptures": { 409 | "1": { 410 | "name": "string.unquoted.label.rhai entity.name.function.method.rhai" 411 | }, 412 | "2": { 413 | "name": "punctuation.separator.key-value.rhai" 414 | }, 415 | "3": { 416 | "name": "punctuation.definition.parameters.closure.begin.rhai" 417 | } 418 | }, 419 | "end": "(\\|)", 420 | "endCaptures": { 421 | "1": { 422 | "name": "punctuation.definition.parameters.closure.end.rhai" 423 | } 424 | }, 425 | "patterns": [ 426 | { 427 | "include": "#parameters-list" 428 | } 429 | ] 430 | }, 431 | { 432 | "name": "meta.function.closure.rhai", 433 | "begin": "((\\\")((?:[^\"]|\\\\\")*)(\\\"))\\s*(:)\\s*(\\|)(?=\\s*[_a-zA-Z\\|])", 434 | "beginCaptures": { 435 | "1": { 436 | "name": "string.quoted.double.rhai" 437 | }, 438 | "2": { 439 | "name": "punctuation.definition.string.begin.rhai" 440 | }, 441 | "3": { 442 | "name": "entity.name.function.method.rhai" 443 | }, 444 | "4": { 445 | "name": "punctuation.definition.string.end.rhai" 446 | }, 447 | "5": { 448 | "name": "punctuation.separator.key-value.rhai" 449 | }, 450 | "6": { 451 | "name": "punctuation.definition.parameters.closure.begin.rhai" 452 | } 453 | }, 454 | "end": "(\\|)", 455 | "endCaptures": { 456 | "1": { 457 | "name": "punctuation.definition.parameters.closure.end.rhai" 458 | } 459 | }, 460 | "patterns": [ 461 | { 462 | "include": "#parameters-list" 463 | } 464 | ] 465 | } 466 | ] 467 | }, 468 | "literal-function-call": { 469 | "patterns": [ 470 | { 471 | "name": "meta.function-call.without-arguments.rhai", 472 | "match": "(?x)\n ([_a-zA-Z]\\w*)(!)?\\s*\n (\\(\\s*\\))", 473 | "captures": { 474 | "1": { 475 | "name": "entity.name.function.rhai" 476 | }, 477 | "2": { 478 | "name": "punctuation.function-call.capture.rhai" 479 | }, 480 | "3": { 481 | "name": "meta.group.braces.round.function.arguments.rhai" 482 | } 483 | } 484 | }, 485 | { 486 | "name": "meta.function-call.with-arguments.rhai", 487 | "match": "(?x)\n ([_a-zA-Z]\\w*)(!)?\\s*\n (?=\\()", 488 | "captures": { 489 | "1": { 490 | "name": "entity.name.function.rhai" 491 | }, 492 | "2": { 493 | "name": "punctuation.function-call.capture.rhai" 494 | } 495 | } 496 | } 497 | ] 498 | }, 499 | "literal-method-call": { 500 | "patterns": [ 501 | { 502 | "name": "meta.function-call.method.without-arguments.rhai", 503 | "match": "(?x)\n (?<=(\\.|\\?\\.))\n \\s*([_a-zA-Z]\\w*)\\s*\n (\\(\\s*\\))", 504 | "captures": { 505 | "1": { 506 | "name": "entity.name.function.rhai" 507 | }, 508 | "2": { 509 | "name": "meta.group.braces.round.function.arguments.rhai" 510 | } 511 | } 512 | }, 513 | { 514 | "name": "meta.function-call.method.with-arguments.rhai", 515 | "match": "(?x)\n (?<=(\\.|\\?\\.))\n \\s*([_a-zA-Z]\\w*)\\s*\n (?=\\()", 516 | "captures": { 517 | "1": { 518 | "name": "entity.name.function.rhai" 519 | } 520 | } 521 | } 522 | ] 523 | }, 524 | "literal-language-variable": { 525 | "patterns": [ 526 | { 527 | "name": "variable.language.this.rhai", 528 | "match": "\\bthis\\b" 529 | } 530 | ] 531 | }, 532 | "literal-language-constant": { 533 | "patterns": [ 534 | { 535 | "name": "constant.language.boolean.true.rhai", 536 | "match": "\\btrue\\b" 537 | }, 538 | { 539 | "name": "constant.language.boolean.false.rhai", 540 | "match": "\\bfalse\\b" 541 | } 542 | ] 543 | }, 544 | "literal-language-namespace": { 545 | "patterns": [ 546 | { 547 | "match": "(?]) # assignment right-to-left both" 610 | }, 611 | { 612 | "name": "keyword.operator.assignment.augmented.rhai", 613 | "match": "(?x)\n %= | # assignment right-to-left both\n &= | # assignment right-to-left both\n \\*\\*=| # assignment right-to-left both\n (?>= # assignment right-to-left both" 614 | }, 615 | { 616 | "name": "keyword.operator.bitwise.rhai", 617 | "match": "(?x)\n << | # bitwise-shift left-to-right both\n >> | # bitwise-shift left-to-right both\n & | # bitwise-and left-to-right both\n \\^ | # bitwise-xor left-to-right both\n \\| # bitwise-or left-to-right both" 618 | }, 619 | { 620 | "name": "keyword.operator.relational.rhai", 621 | "match": "(?x)\n <= | # relational left-to-right both\n >= | # relational left-to-right both\n <(?!-) | # relational left-to-right both\n (? # relational left-to-right both" 622 | }, 623 | { 624 | "name": "keyword.operator.comparison.rhai", 625 | "match": "(?x)\n ==(?!=) | # equality left-to-right both\n !=(?!=) # equality left-to-right both" 626 | }, 627 | { 628 | "name": "keyword.operator.arithmetic.rhai", 629 | "match": "(?x)\n / | # division left-to-right both\n % | # modulus left-to-right both\n \\*\\* | # power left-to-right both\n \\*(?!\\)) | # multiplication left-to-right both\n \\+(?!\\+) | # addition left-to-right both\n -(?![>-]) # subtraction left-to-right both" 630 | }, 631 | { 632 | "name": "keyword.operator.range.exclusive.rhai", 633 | "match": "\\.\\.(?![\\.=])" 634 | }, 635 | { 636 | "name": "keyword.operator.range.inclusive.rhai", 637 | "match": "\\.\\.=" 638 | }, 639 | { 640 | "name": "keyword.operator.accessor.rhai punctuation.accessor.rhai", 641 | "match": "\\.(?!\\.)|\\?\\." 642 | }, 643 | { 644 | "name": "punctuation.separator.switch.case.rhai", 645 | "match": "=>" 646 | }, 647 | { 648 | "name": "invalid.illegal.operator.rhai", 649 | "match": "(\\(\\*|\\*\\)|\\+\\+|--|\\.\\.\\.+|~|#(?!{)|@|\\?|\\$(?!{)|->|<-|===|!==|\\:=|\\:\\:<)" 650 | } 651 | ] 652 | }, 653 | "literal-labels": { 654 | "patterns": [ 655 | { 656 | "begin": "(?x)\n (? 100 { continue; } 9 | 10 | print(`(${i}, ${j}) = (${a}, ${b})`); 11 | } 12 | 13 | if a == 3 { break; } 14 | } 15 | //print(a); // <- if you uncomment this line, the script will fail to compile 16 | // because 'a' is not defined here 17 | 18 | for i in range(5, 0, -1) { // runs from 5 down to 1 19 | print(i); 20 | } 21 | -------------------------------------------------------------------------------- /test/for2.rhai: -------------------------------------------------------------------------------- 1 | // This script runs for-loops 2 | 3 | const MAX = 1_000_000; 4 | 5 | print(`Iterating an array with ${MAX} items...`); 6 | 7 | print("Ready... Go!"); 8 | 9 | let now = timestamp(); 10 | 11 | let list = []; 12 | 13 | // Loop over range 14 | for i in 0..MAX { 15 | list.push(i); 16 | } 17 | 18 | print(`Time = ${now.elapsed} seconds...`); 19 | 20 | let sum = 0; 21 | 22 | // Loop over array 23 | for i in list { 24 | sum += i; 25 | } 26 | 27 | print(`Sum = ${sum}`); 28 | print(`Finished. Total run time = ${now.elapsed} seconds.`); 29 | -------------------------------------------------------------------------------- /test/for3.rhai: -------------------------------------------------------------------------------- 1 | // This script runs for-loops with closures. 2 | 3 | const MAX = 100; 4 | const CHECK = ((MAX - 1) ** 2) * MAX; 5 | 6 | print("Ready... Go!"); 7 | 8 | let now = timestamp(); 9 | 10 | print(`Creating ${MAX} closures...`); 11 | 12 | let list = []; 13 | 14 | // Loop over range 15 | for i in 0..MAX { 16 | list.push(|| i ** 2); 17 | } 18 | 19 | print(`Time = ${now.elapsed} seconds...`); 20 | print(`Summing ${MAX} closures...`); 21 | 22 | let sum = 0; 23 | 24 | // Loop over array 25 | for f in list { 26 | sum += f.call(); 27 | } 28 | 29 | print(`Sum = ${sum} (should be ${CHECK})`); 30 | print(`Finished. Total run time = ${now.elapsed} seconds.`); 31 | -------------------------------------------------------------------------------- /test/function_decl1.rhai: -------------------------------------------------------------------------------- 1 | // This script defines a function and calls it. 2 | 3 | fn call_me() { 4 | return 3; 5 | } 6 | 7 | let result = call_me(); 8 | 9 | print(`call_me() should be 3: ${result}`); 10 | -------------------------------------------------------------------------------- /test/function_decl2.rhai: -------------------------------------------------------------------------------- 1 | // This script defines a function with two parameters and local variables. 2 | 3 | let a = 3; 4 | 5 | fn add(a, b) { 6 | a = 42; // notice that 'a' is passed by value 7 | a + b; // notice that the last value is returned even if terminated by a semicolon 8 | } 9 | 10 | let result = add(a, 4); 11 | 12 | print(`add(a, 4) should be 46: ${result}`); 13 | 14 | print(`a should still be 3: ${a}`); // prints 3: 'a' is never changed 15 | -------------------------------------------------------------------------------- /test/function_decl3.rhai: -------------------------------------------------------------------------------- 1 | // This script defines a function with many parameters. 2 | // 3 | 4 | const KEY = 38; 5 | 6 | fn f(a, b, c, d, e, f) { 7 | let x = global::KEY; // <- access global module 8 | a - b * c - d * e - f + x 9 | } 10 | 11 | let result = f(100, 5, 2, 9, 6, 32); 12 | 13 | print(`result should be 42: ${result}`); 14 | -------------------------------------------------------------------------------- /test/function_decl4.rhai: -------------------------------------------------------------------------------- 1 | // This script defines a function that acts as a method. 2 | 3 | // Use 'this' to refer to the object of a method call 4 | fn action(x, y) { 5 | this = this.abs() + x * y; // 'this' can be modified 6 | } 7 | 8 | let obj = -40; 9 | 10 | obj.action(1, 2); // call 'action' as method 11 | 12 | print(`obj should now be 42: ${obj}`); 13 | -------------------------------------------------------------------------------- /test/if1.rhai: -------------------------------------------------------------------------------- 1 | // This script runs if statements. 2 | 3 | let a = 42; 4 | let b = 123; 5 | let x = 999; 6 | 7 | if a > b { 8 | print("Oops! a > b"); 9 | } else if a < b { 10 | print("a < b, x should be 0"); 11 | 12 | let x = 0; // <- this 'x' shadows the global 'x' 13 | print(x); // should print 0 14 | } else { 15 | print("Oops! a == b"); 16 | } 17 | -------------------------------------------------------------------------------- /test/if2.rhai: -------------------------------------------------------------------------------- 1 | // This script runs an if expression. 2 | 3 | let a = 42; 4 | let b = 123; 5 | 6 | let x = if a <= b { // <- if-expression 7 | b - a 8 | } else { 9 | a - b 10 | } * 10; 11 | 12 | print(`x should be 810: ${x}`); 13 | -------------------------------------------------------------------------------- /test/loop.rhai: -------------------------------------------------------------------------------- 1 | // This script runs an infinite loop, ending it with a break statement. 2 | 3 | let x = 10; 4 | 5 | // simulate do..while using loop 6 | loop { 7 | print(x); 8 | 9 | x -= 1; 10 | 11 | if x <= 0 { break; } 12 | } 13 | 14 | export x as foo; 15 | -------------------------------------------------------------------------------- /test/mat_mul.rhai: -------------------------------------------------------------------------------- 1 | // This script simulates multi-dimensional matrix calculations. 2 | 3 | const SIZE = 50; 4 | 5 | fn new_mat(x, y) { 6 | let row = []; 7 | row.pad(y, 0.0); 8 | 9 | let matrix = []; 10 | matrix.pad(x, row); 11 | 12 | matrix 13 | } 14 | 15 | fn mat_gen() { 16 | const n = global::SIZE; 17 | const tmp = 1.0 / n / n; 18 | let m = new_mat(n, n); 19 | 20 | for i in 0..n { 21 | for j in 0..n { 22 | m[i][j] = tmp * (i - j) * (i + j); 23 | } 24 | } 25 | 26 | m 27 | } 28 | 29 | fn mat_mul(a, b) { 30 | let b2 = new_mat(a[0].len, b[0].len); 31 | 32 | for i in 0..a[0].len { 33 | for j in 0..b[0].len { 34 | b2[j][i] = b[i][j]; 35 | } 36 | } 37 | 38 | let c = new_mat(a.len, b[0].len); 39 | 40 | for i in 0..c.len { 41 | for j in 0..c[i].len { 42 | c[i][j] = 0.0; 43 | 44 | for z in 0..a[i].len { 45 | c[i][j] += a[i][z] * b2[j][z]; 46 | } 47 | } 48 | } 49 | 50 | c 51 | } 52 | 53 | const now = timestamp(); 54 | 55 | const a = mat_gen(); 56 | const b = mat_gen(); 57 | const c = mat_mul(a, b); 58 | 59 | /* 60 | for i in 0..SIZE) { 61 | print(c[i]); 62 | } 63 | */ 64 | 65 | print(`Finished. Run time = ${now.elapsed} seconds.`); 66 | -------------------------------------------------------------------------------- /test/module.rhai: -------------------------------------------------------------------------------- 1 | // This script imports an external script as a module. 2 | 3 | import "loop" as x; 4 | 5 | print(`Module test! foo = ${x::foo}`); 6 | -------------------------------------------------------------------------------- /test/oop.rhai: -------------------------------------------------------------------------------- 1 | // This script simulates object-oriented programming (OOP) techniques using closures. 2 | 3 | // External variable that will be captured. 4 | let last_value = (); 5 | 6 | // Define object 7 | let obj1 = #{ 8 | _data: 42, // data field 9 | get_data: || this._data, // property getter 10 | action: || print(`Data=${this._data}`), // method 11 | update: |x| { // property setter 12 | this._data = x; 13 | last_value = this._data; // capture 'last_value' 14 | this.action(); 15 | } 16 | }; 17 | 18 | if obj1.get_data() > 0 { // property access 19 | obj1.update(123); // call method 20 | } else { 21 | print("we have a problem here"); 22 | } 23 | 24 | // Define another object based on the first object 25 | let obj2 = #{ 26 | _data: 0, // data field - new value 27 | update: |x| { // property setter - another function 28 | this._data = x * 2; 29 | last_value = this._data; // capture 'last_value' 30 | this.action(); 31 | } 32 | }; 33 | obj2.fill_with(obj1); // add all other fields from obj1 34 | 35 | if obj2.get_data() > 0 { // property access 36 | print("we have another problem here"); 37 | } else { 38 | obj2.update(42); // call method 39 | } 40 | 41 | print(`Should be 84: ${last_value}`); 42 | -------------------------------------------------------------------------------- /test/op1.rhai: -------------------------------------------------------------------------------- 1 | // This script runs a single expression. 2 | 3 | print("The result should be 46:"); 4 | 5 | print(34 + 12); 6 | -------------------------------------------------------------------------------- /test/op2.rhai: -------------------------------------------------------------------------------- 1 | // This script runs a complex expression. 2 | 3 | print("The result should be 182:"); 4 | 5 | let x = 12 + 34 * 5; 6 | 7 | print(x); 8 | -------------------------------------------------------------------------------- /test/op3.rhai: -------------------------------------------------------------------------------- 1 | // This script runs a complex expression. 2 | 3 | print("The result should be 230:"); 4 | 5 | let x = (12 + 34) * 5; 6 | 7 | print(x); 8 | -------------------------------------------------------------------------------- /test/primes.rhai: -------------------------------------------------------------------------------- 1 | // This script uses the Sieve of Eratosthenes to calculate prime numbers. 2 | 3 | let now = timestamp(); 4 | 5 | const MAX_NUMBER_TO_CHECK = 1_000_000; // 9592 primes <= 100000 6 | 7 | let prime_mask = []; 8 | prime_mask.pad(MAX_NUMBER_TO_CHECK + 1, true); 9 | 10 | prime_mask[0] = false; 11 | prime_mask[1] = false; 12 | 13 | let total_primes_found = 0; 14 | 15 | for p in 2..=MAX_NUMBER_TO_CHECK { 16 | if !prime_mask[p] { continue; } 17 | 18 | //print(p); 19 | 20 | total_primes_found += 1; 21 | 22 | for i in range(2 * p, MAX_NUMBER_TO_CHECK + 1, p) { 23 | prime_mask[i] = false; 24 | } 25 | } 26 | 27 | print(`Total ${total_primes_found} primes <= ${MAX_NUMBER_TO_CHECK}`); 28 | print(`Run time = ${now.elapsed} seconds.`); 29 | 30 | if total_primes_found != 78_498 { 31 | print("The answer is WRONG! Should be 78,498!"); 32 | } 33 | -------------------------------------------------------------------------------- /test/speed_test.rhai: -------------------------------------------------------------------------------- 1 | // This script runs 1 million iterations to test the speed of the scripting engine. 2 | 3 | let now = timestamp(); 4 | let x = 1_000_000; 5 | 6 | print("Ready... Go!"); 7 | 8 | while x > 0 { 9 | x -= 1; 10 | } 11 | 12 | print(`Finished. Run time = ${now.elapsed} seconds.`); 13 | -------------------------------------------------------------------------------- /test/string.rhai: -------------------------------------------------------------------------------- 1 | // This script tests string operations. 2 | 3 | print("hello"); 4 | print("this\nis \\ nice"); // escape sequences 5 | print("0x40 hex is \x40"); // hex escape sequence 6 | print("Unicode fun: \u2764"); // Unicode escape sequence 7 | print("more fun: \U0001F603"); // Unicode escape sequence 8 | print("foo" + " " + "bar"); // string building using strings 9 | print("foo" < "bar"); // string comparison 10 | print("foo" >= "bar"); // string comparison 11 | print("the answer is " + 42); // string building using non-string types 12 | 13 | let s = "\u2764 hello, world! \U0001F603"; // string variable 14 | print(`length=${s.len}`); // should be 17 15 | 16 | s[s.len-3] = '?'; // change the string 17 | print(`Question: ${s}`); // should print 'Question: hello, world?' 18 | 19 | // Line continuation: 20 | let s = "This is a long \ 21 | string constructed using \ 22 | line continuation"; 23 | 24 | // String interpolation 25 | print(`One string: ${s}`); 26 | 27 | // Multi-line literal string: 28 | let s = ` 29 | \U0001F603 This is a multi-line 30 | "string" with \t\x20\r\n 31 | made using multi-line literal 32 | string syntax. 33 | `; 34 | 35 | print(s); 36 | 37 | // Interpolation 38 | let s = `This is interpolation ${ 39 | let x = `within ${let y = "yet another level \ 40 | of interpolation!"; y} interpolation`; 41 | x 42 | } within literal string.`; 43 | 44 | print(s); 45 | 46 | print(">>> END <<<"); 47 | -------------------------------------------------------------------------------- /test/strings_map.rhai: -------------------------------------------------------------------------------- 1 | // This script tests object maps and strings. 2 | 3 | print("Ready... Go!"); 4 | 5 | let now = timestamp(); 6 | 7 | let adverbs = [ "moderately", "really", "slightly", "very" ]; 8 | 9 | let adjectives = [ 10 | "abandoned", "able", "absolute", "academic", "acceptable", "acclaimed", 11 | "accomplished", "accurate", "aching", "acidic", "acrobatic", "active", 12 | "actual", "adept", "admirable", "admired", "adolescent", "adorable", "adored", 13 | "advanced", "adventurous", "affectionate", "afraid", "aged", "aggravating", 14 | "aggressive", "agile", "agitated", "agonizing", "agreeable", "ajar", 15 | "alarmed", "alarming", "alert", "alienated", "alive", "all", "altruistic", 16 | "amazing", "ambitious", "ample", "amused", "amusing", "anchored", "ancient", 17 | "angelic", "angry", "anguished", "animated", "annual", "another", "antique", 18 | "anxious", "any", "apprehensive", "appropriate", "apt", "arctic", "arid", 19 | "aromatic", "artistic", "ashamed", "assured", "astonishing", "athletic", 20 | "attached", "attentive", "attractive", "austere", "authentic", "authorized", 21 | "automatic", "avaricious", "average", "aware", "awesome", "awful", "awkward", 22 | "babyish", "back", "bad", "baggy", "bare", "barren", "basic", "beautiful", 23 | "belated", "beloved", "beneficial", "best", "better", "bewitched", "big", 24 | "big-hearted", "biodegradable", "bite-sized", "bitter", "black", 25 | "black-and-white", "bland", "blank", "blaring", "bleak", "blind", "blissful", 26 | "blond", "blue", "blushing", "bogus", "boiling", "bold", "bony", "boring", 27 | "bossy", "both", "bouncy", "bountiful", "bowed", "brave", "breakable", 28 | "brief", "bright", "brilliant", "brisk", "broken", "bronze", "brown", 29 | "bruised", "bubbly", "bulky", "bumpy", "buoyant", "burdensome", "burly", 30 | "bustling", "busy", "buttery", "buzzing", "calculating", "calm", "candid", 31 | "canine", "capital", "carefree", "careful", "careless", "caring", "cautious", 32 | "cavernous", "celebrated", "charming", "cheap", "cheerful", "cheery", "chief", 33 | "chilly", "chubby", "circular", "classic", "clean", "clear", "clear-cut", 34 | "clever", "close", "closed", "cloudy", "clueless", "clumsy", "cluttered", 35 | "coarse", "cold", "colorful", "colorless", "colossal", "comfortable", 36 | "common", "compassionate", "competent", "complete", "complex", "complicated", 37 | "composed", "concerned", "concrete", "confused", "conscious", "considerate", 38 | "constant", "content", "conventional", "cooked", "cool", "cooperative", 39 | "coordinated", "corny", "corrupt", "costly", "courageous", "courteous", 40 | "crafty" 41 | ]; 42 | 43 | let animals = [ 44 | "aardvark", "african buffalo", "albatross", "alligator", "alpaca", "ant", 45 | "anteater", "antelope", "ape", "armadillo", "baboon", "badger", "barracuda", 46 | "bat", "bear", "beaver", "bee", "bison", "black panther", "blue jay", "boar", 47 | "butterfly", "camel", "capybara", "carduelis", "caribou", "cassowary", "cat", 48 | "caterpillar", "cattle", "chamois", "cheetah", "chicken", "chimpanzee", 49 | "chinchilla", "chough", "clam", "cobra", "cockroach", "cod", "cormorant", 50 | "coyote", "crab", "crane", "crocodile", "crow", "curlew", "deer", "dinosaur", 51 | "dog", "dolphin", "domestic pig", "donkey", "dotterel", "dove", "dragonfly", 52 | "duck", "dugong", "dunlin", "eagle", "echidna", "eel", "elephant seal", 53 | "elephant", "elk", "emu", "falcon", "ferret", "finch", "fish", "flamingo", 54 | "fly", "fox", "frog", "gaur", "gazelle", "gerbil", "giant panda", "giraffe", 55 | "gnat", "goat", "goldfish", "goose", "gorilla", "goshawk", "grasshopper", 56 | "grouse", "guanaco", "guinea fowl", "guinea pig", "gull", "hamster", "hare", 57 | "hawk", "hedgehog", "heron", "herring", "hippopotamus", "hornet", "horse", 58 | "human", "hummingbird", "hyena", "ibex", "ibis", "jackal", "jaguar", "jay", 59 | "jellyfish", "kangaroo", "kingfisher", "koala", "komodo dragon", "kookabura", 60 | "kouprey", "kudu", "lapwing", "lark", "lemur", "leopard", "lion", "llama", 61 | "lobster", "locust", "loris", "louse", "lyrebird", "magpie", "mallard", 62 | "manatee", "mandrill", "mantis", "marten", "meerkat", "mink", "mole", 63 | "mongoose", "monkey", "moose", "mosquito", "mouse", "mule", "narwhal", "newt", 64 | "nightingale", "octopus", "okapi", "opossum", "oryx", "ostrich", "otter", 65 | "owl", "oyster", "parrot", "partridge", "peafowl", "pelican", "penguin", 66 | "pheasant", "pigeon", "pinniped", "polar bear", "pony", "porcupine", 67 | "porpoise", "prairie dog", "quail", "quelea", "quetzal", "rabbit", "raccoon", 68 | "ram", "rat", "raven", "red deer", "red panda", "reindeer", "rhinoceros", 69 | "rook", "salamander", "salmon", "sand dollar", "sandpiper", "sardine", 70 | "scorpion", "sea lion", "sea urchin", "seahorse", "shark", "sheep", "shrew", 71 | "skunk", "snail", "snake", "sparrow", "spider", "spoonbill", "squid", 72 | "wallaby", "wildebeest" 73 | ]; 74 | 75 | let keys = []; 76 | 77 | for animal in animals { 78 | for adjective in adjectives { 79 | for adverb in adverbs { 80 | keys.push(`${adverb} ${adjective} ${animal}`) 81 | } 82 | } 83 | } 84 | 85 | let map = #{}; 86 | 87 | let i = 0; 88 | 89 | for key in keys { 90 | map[key] = i; 91 | i += 1; 92 | } 93 | 94 | let sum = 0; 95 | 96 | for key in keys { 97 | sum += map[key]; 98 | } 99 | 100 | for key in keys { 101 | map.remove(key); 102 | } 103 | 104 | print(`Sum = ${sum}`); 105 | print(`Finished. Run time = ${now.elapsed} seconds.`); 106 | -------------------------------------------------------------------------------- /test/switch.rhai: -------------------------------------------------------------------------------- 1 | // This script runs a switch statement in a for-loop. 2 | 3 | let arr = [42, 123.456, "hello", true, "hey", 'x', 999, 1, 2, 3, 4]; 4 | 5 | for item in arr { 6 | switch item { 7 | // Match single character 8 | 'f' => |a, b| a !in b, 9 | // Match single integer 10 | 42 => print("The Answer!"), 11 | // Match a selection 12 | 1 | 2 | () | 3 | 4 => print("One two three four!"), 13 | // Match single floating-point number 14 | 123.456 => print(`Floating point... ${item}`), 15 | // Match single string 16 | "hello" => print(`${item} world!`), 17 | // Match another integer 18 | 999 => print(`Got 999: ${item}`), 19 | // Match range with condition 20 | 0..100 if item % 2 == 0 => print(`A small even number: ${item}`), 21 | // Match another range 22 | 0..100 => print(`A small odd number: ${item}`), 23 | // Default case 24 | _ => print(`Something else: <${item}> is ${type_of(item)}`) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/while.rhai: -------------------------------------------------------------------------------- 1 | // This script runs a while loop. 2 | 3 | let x = 10; 4 | 5 | while x > 0 { 6 | print(x); 7 | x -= 1; 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "extension" 4 | ], 5 | "compilerOptions": { 6 | "outDir": "dist", 7 | /* Basic Options */ 8 | "target": "ES5", 9 | "module": "commonjs", 10 | "lib": ["esnext", "dom"], /* Specify library files to be included in the compilation. */ 11 | // "allowJs": true, /* Allow javascript files to be compiled. */ 12 | // "checkJs": true, /* Report errors in .js files. */ 13 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 14 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 15 | "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 16 | "sourceMap": true, /* Generates corresponding '.map' file. */ 17 | // "outFile": "./", /* Concatenate and emit output to single file. */ 18 | // "outDir": "./", /* Redirect output structure to the directory. */ 19 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 20 | // "composite": true, /* Enable project compilation */ 21 | "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | //"resolveJsonModule": true, /* Import json as object. */ 45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 47 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 49 | // "typeRoots": [], /* List of folders to include type definitions from. */ 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | 61 | /* Experimental Options */ 62 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | }, 65 | "compileOnSave": true, 66 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "semicolon": [ 4 | true, 5 | "never" 6 | ], 7 | "quotemark": [ 8 | true, 9 | "single", 10 | "avoid-escape", 11 | "avoid-template" 12 | ], 13 | "indent": [ 14 | true, 15 | "spaces", 16 | 4 17 | ], 18 | "object-literal-key-quotes": [ 19 | true, 20 | "consistent-as-needed" 21 | ], 22 | "no-var-requires": true, 23 | "member-access": false, 24 | "trailing-comma": [ 25 | true, 26 | { 27 | "multiline": "always", 28 | "singleline": "never" 29 | } 30 | ] 31 | }, 32 | "linterOptions": { 33 | "exclude": [ 34 | "dist/**", 35 | "node_modules/**", 36 | "*.d.ts" 37 | ] 38 | } 39 | } --------------------------------------------------------------------------------