├── .gitattributes ├── .gitignore ├── .vscode └── c_cpp_properties.json ├── LICENSE ├── README.md ├── build.ps1 ├── corpus ├── commands.txt ├── comments.txt ├── expressions.txt └── type_definitions.txt ├── grammar.js ├── index.js ├── package-lock.json ├── package.json └── src └── scanner.c /.gitattributes: -------------------------------------------------------------------------------- 1 | src/node-types.json binary 2 | src/grammar.json binary 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.swp 3 | build 4 | *.gyp 5 | 6 | # see https://stackoverflow.com/a/5534865 7 | !src/ 8 | src/* 9 | !src/scanner.c 10 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "macFrameworkPath": [ 10 | "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks" 11 | ], 12 | "compilerPath": "/usr/bin/clang", 13 | "cStandard": "c11", 14 | "cppStandard": "c++17", 15 | "intelliSenseMode": "clang-x64" 16 | } 17 | ], 18 | "version": 4 19 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Microsoft Corporation 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell support for tree-sitter 2 | 3 | A [tree-sitter](http://tree-sitter.github.io/tree-sitter/) 4 | implemenation for [PowerShell](https://github.com/PowerShell/PowerShell). 5 | 6 | ## License 7 | 8 | See [LICENSE](LICENSE). 9 | 10 | ## Initial goal 11 | 12 | Parse the [big test file from EditorSyntax](https://github.com/PowerShell/EditorSyntax/blob/master/examples/TheBigTestFile.ps1) completely. 13 | 14 | ## TODO 15 | 16 | - Add tree-sitter [tests](https://tree-sitter.github.io/tree-sitter/creating-parsers#writing-unit-tests) 17 | - Add support for more syntax: 18 | + Statements 19 | * `switch` 20 | * `filter` 21 | * `using` 22 | * `throw` 23 | * `for` 24 | * `foreach` 25 | * `do`/`while`/`until` 26 | * `exit`/`return` 27 | * `break`/`continue` 28 | * `trap` 29 | * `try`/`catch`/`finally` 30 | * `data` 31 | * `workflow`/`parallel`/`sequence` 32 | * `configuration` 33 | + Expressions 34 | * `-not` 35 | * Unary `-` 36 | * `-ge`,`-gt`,`-le`,`-lt`,`-eq`,`-ne`,`-ceq`,`-ieq`, etc. 37 | * `+`,`-`,`*`,`/`,`%`,`-or`,`-and`,`-bor`,`-band`, etc. 38 | * Element access (`$x[$i]`) 39 | + Other syntax 40 | * Labels 41 | * Better whitespace handling 42 | * Herestrings 43 | * `#requires` 44 | * `#sig` 45 | * Pipeline redirection and jobs 46 | * Splatting 47 | * `&&`/`||` 48 | - Investigate possibility of dynamic keyword support 49 | 50 | 51 | ## End goal 52 | 53 | 90%+ compatibility with the PowerShell parser today. 54 | 55 | ## Getting started 56 | 57 | 1. `npm install` 58 | 1. `npm start file.ps1` 59 | 60 | If you want to just generate the parser, run `npm run generate`. 61 | 62 | If you want to just parse a script, run `npm run parse file.ps1` 63 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------------------------------ 2 | # Copyright (C) Microsoft. All rights reserved. 3 | # Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | # ------------------------------------------------------------------------------------------------------- 5 | 6 | param( 7 | [Parameter()] 8 | [switch] 9 | $Test, 10 | 11 | [Parameter()] 12 | [switch] 13 | $NoBuild, 14 | 15 | [Parameter()] 16 | [string[]] 17 | $Parse, 18 | 19 | [Parameter()] 20 | [switch] 21 | $TreeSitterDebug 22 | ) 23 | 24 | if (!$NoBuild) { 25 | npm run generate 26 | } 27 | 28 | if ($Test) { 29 | npm test 30 | } 31 | 32 | if ($Parse.Count -gt 0) { 33 | $d = if ($TreeSitterDebug) { 34 | "parse-debug" 35 | } else { 36 | "parse" 37 | } 38 | $Parse | ForEach-Object { 39 | npm run $d $_ 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /corpus/commands.txt: -------------------------------------------------------------------------------- 1 | === 2 | Plain cmdlet 3 | === 4 | 5 | Write-Something 6 | 7 | --- 8 | 9 | (program 10 | (pipeline_statement 11 | (command_expression 12 | (bareword_string)))) 13 | 14 | === 15 | Native command 16 | === 17 | 18 | net.exe 19 | 20 | --- 21 | 22 | (program 23 | (pipeline_statement 24 | (command_expression 25 | (bareword_string)))) 26 | 27 | === 28 | Cmdlet with arguments 29 | === 30 | 31 | Write-Output 'Hi' 32 | 33 | --- 34 | 35 | (program 36 | (pipeline_statement 37 | (command_expression 38 | (bareword_string) 39 | (command_argument 40 | (single_quote_string))))) 41 | 42 | === 43 | Cmdlet with parameters 44 | === 45 | 46 | Write-Output -InputObject 'Hi' 47 | 48 | --- 49 | 50 | (program 51 | (pipeline_statement 52 | (command_expression 53 | (bareword_string) 54 | (command_parameter) 55 | (command_argument 56 | (single_quote_string))))) 57 | 58 | === 59 | Cmdlet with multiple arguments and parameters 60 | === 61 | 62 | Invoke-Thing $argument1 -Parameter 'Thing' 63 | 64 | --- 65 | 66 | (program 67 | (pipeline_statement 68 | (command_expression 69 | (bareword_string) 70 | (command_argument 71 | (variable 72 | (simple_variable))) 73 | (command_parameter) 74 | (command_argument 75 | (single_quote_string))))) 76 | 77 | === 78 | Cmdlet with splatted parameters 79 | === 80 | 81 | Invoke-Thing @arguments 82 | 83 | --- 84 | 85 | (program 86 | (pipeline_statement 87 | (command_expression 88 | (bareword_string) 89 | (command_argument 90 | (splatted_variable))))) 91 | 92 | === 93 | Unix-like native command 94 | === 95 | 96 | git clone -b this_branch --single-branch https://github.com/PowerShell/PowerShell 97 | 98 | --- 99 | 100 | (program 101 | (pipeline_statement 102 | (command_expression 103 | (bareword_string) 104 | (command_argument 105 | (bareword_string)) 106 | (command_parameter) 107 | (command_argument 108 | (bareword_string)) 109 | (command_parameter) 110 | (command_argument 111 | (bareword_string))))) 112 | 113 | === 114 | Windows-style native command 115 | === 116 | 117 | net use e: \\usrsvr002\smithmark Ue345Ii /user:pdc01\msmith2 /savecred /p:yes 118 | 119 | --- 120 | 121 | (program 122 | (pipeline_statement 123 | (command_expression 124 | (bareword_string) 125 | (command_argument 126 | (bareword_string)) 127 | (command_argument 128 | (bareword_string)) 129 | (command_argument 130 | (bareword_string)) 131 | (command_argument 132 | (bareword_string)) 133 | (command_argument 134 | (bareword_string)) 135 | (command_argument 136 | (bareword_string)) 137 | (command_argument 138 | (bareword_string))))) 139 | -------------------------------------------------------------------------------- /corpus/comments.txt: -------------------------------------------------------------------------------- 1 | === 2 | Single inline commant 3 | === 4 | 5 | $x = 3 6 | 7 | # This is a comment 8 | 9 | Get-ChildItem . 10 | 11 | --- 12 | 13 | (program 14 | (assignment_statement 15 | (variable 16 | (simple_variable)) 17 | (pipeline_statement 18 | (number_expr))) 19 | (comment) 20 | (pipeline_statement 21 | (command_expression 22 | (bareword_string) 23 | (command_argument 24 | (bareword_string))))) 25 | 26 | === 27 | Single line block comment 28 | === 29 | 30 | $x = 3 31 | 32 | <# Block comment #> 33 | 34 | Get-ChildItem . 35 | 36 | --- 37 | 38 | (program 39 | (assignment_statement 40 | (variable 41 | (simple_variable)) 42 | (pipeline_statement 43 | (number_expr))) 44 | (comment) 45 | (pipeline_statement 46 | (command_expression 47 | (bareword_string) 48 | (command_argument 49 | (bareword_string))))) 50 | 51 | === 52 | Multi-line block comment 53 | === 54 | 55 | $x = 3 56 | 57 | <# 58 | 59 | Here 60 | 61 | is a 62 | 63 | longer 64 | 65 | comment #> 66 | 67 | Get-ChildItem . 68 | 69 | --- 70 | 71 | (program 72 | (assignment_statement 73 | (variable 74 | (simple_variable)) 75 | (pipeline_statement 76 | (number_expr))) 77 | (comment) 78 | (pipeline_statement 79 | (command_expression 80 | (bareword_string) 81 | (command_argument 82 | (bareword_string))))) 83 | 84 | === 85 | Pathological block comment #1 86 | === 87 | 88 | <##> 89 | 90 | --- 91 | 92 | (program 93 | (comment)) 94 | 95 | === 96 | Pathological block comment #2 97 | === 98 | 99 | <###> 100 | 101 | --- 102 | 103 | (program 104 | (comment)) 105 | -------------------------------------------------------------------------------- /corpus/expressions.txt: -------------------------------------------------------------------------------- 1 | === 2 | Integer 3 | === 4 | 5 | 239 6 | 7 | --- 8 | 9 | (program 10 | (pipeline_statement 11 | (number_expr))) 12 | 13 | === 14 | Float 15 | === 16 | 17 | 12.9191008 18 | 19 | --- 20 | 21 | (program 22 | (pipeline_statement 23 | (number_expr))) 24 | 25 | === 26 | Scientific notation 27 | === 28 | 29 | 6.022e23 30 | 31 | .12E4 32 | 33 | --- 34 | 35 | (program 36 | (pipeline_statement 37 | (number_expr)) 38 | (pipeline_statement 39 | (number_expr))) 40 | 41 | === 42 | Unsigned 43 | === 44 | 45 | 12u 46 | 47 | 42U 48 | 49 | --- 50 | 51 | (program 52 | (pipeline_statement 53 | (number_expr)) 54 | (pipeline_statement 55 | (number_expr))) 56 | 57 | === 58 | Byte size suffix 59 | === 60 | 61 | 12mb 62 | 63 | 12GB 64 | 65 | --- 66 | 67 | (program 68 | (pipeline_statement 69 | (number_expr)) 70 | (pipeline_statement 71 | (number_expr))) 72 | 73 | === 74 | Combined number format 75 | === 76 | 77 | .2e3ulMB 78 | 79 | --- 80 | 81 | (program 82 | (pipeline_statement 83 | (number_expr))) 84 | 85 | === 86 | Simple variable 87 | === 88 | 89 | $aSimpleVariable001 90 | 91 | $91 92 | 93 | $__Z 94 | 95 | $env:PROGRAM_LOCATION 96 | 97 | --- 98 | 99 | (program 100 | (pipeline_statement 101 | (variable 102 | (simple_variable))) 103 | (pipeline_statement 104 | (variable 105 | (simple_variable))) 106 | (pipeline_statement 107 | (variable 108 | (simple_variable))) 109 | (pipeline_statement 110 | (variable 111 | (simple_variable)))) 112 | 113 | === 114 | Special variables 115 | === 116 | 117 | $$ 118 | 119 | $^ 120 | 121 | $? 122 | 123 | --- 124 | 125 | (program 126 | (pipeline_statement 127 | (variable)) 128 | (pipeline_statement 129 | (variable)) 130 | (pipeline_statement 131 | (variable))) 132 | 133 | === 134 | Brace variable 135 | === 136 | 137 | ${Simple} 138 | 139 | ${More-interestin'} 140 | 141 | ${ 142 | Really && 143 | quite ^ 144 | unusual??? 145 | } 146 | 147 | --- 148 | 149 | (program 150 | (pipeline_statement 151 | (variable)) 152 | (pipeline_statement 153 | (variable)) 154 | (pipeline_statement 155 | (variable))) 156 | 157 | === 158 | Splat variable can't be by itself 159 | === 160 | 161 | @badByItself 162 | 163 | --- 164 | 165 | (program 166 | (ERROR 167 | (splatted_variable))) 168 | 169 | === 170 | Single-quoted string 171 | === 172 | 173 | 'Hello, &!@#(&)!I_@U!JJ!EN@!' 174 | 175 | --- 176 | 177 | (program 178 | (pipeline_statement 179 | (single_quote_string))) 180 | 181 | === 182 | Double-quoted string 183 | === 184 | 185 | "Hello friend! !@!_(@FK@L!:D [ 16 | $._expression, 17 | $._non_array_expression, 18 | $._expression_statement, 19 | $._definition_statement 20 | ], 21 | 22 | externals: $ => [ 23 | $._statement_terminator 24 | ], 25 | 26 | extras: $ => [ 27 | $.comment, 28 | /`?\s/, 29 | /[\uFEFF\u2060\u200B\u00A0]/ 30 | ], 31 | 32 | rules: { 33 | program: $ => seq( 34 | optional($.param_block), 35 | statement_sequence($) 36 | ), 37 | 38 | _statement: $ => choice( 39 | $._expression_statement, 40 | $._definition_statement 41 | ), 42 | 43 | _definition_statement: $ => choice( 44 | $.function_definition, 45 | $.filter_definition, 46 | $.class_definition, 47 | $.enum_definition 48 | ), 49 | 50 | function_definition: $ => seq( 51 | caseInsensitive('function'), 52 | /[_a-z+][_a-z0-9+]*/i, 53 | $.scriptblock 54 | ), 55 | 56 | filter_definition: $ => seq( 57 | caseInsensitive('filter'), 58 | /[_a-zA-Z+][_a-zA-Z0-9+]*/, 59 | $.scriptblock 60 | ), 61 | 62 | class_definition: $ => seq( 63 | caseInsensitive('class'), 64 | repeat($._newline), 65 | /[a-zA-Z_][a-zA-Z0-9_]+/, 66 | repeat($._newline), 67 | '{', 68 | repeat( 69 | seq( 70 | choice( 71 | seq($.class_property, $._statement_terminator), 72 | $.class_method 73 | ) 74 | ) 75 | ), 76 | '}' 77 | ), 78 | 79 | class_property: $ => seq( 80 | optional( 81 | seq( 82 | $.type_expr, 83 | ) 84 | ), 85 | $.simple_variable 86 | ), 87 | 88 | class_method: $ => seq( 89 | optional($.type_expr), 90 | $.bareword_string, 91 | '(', 92 | optional( 93 | seq( 94 | $.class_parameter, 95 | repeat( 96 | seq( 97 | ',', 98 | $.class_parameter 99 | ) 100 | ) 101 | ) 102 | ), 103 | ')', 104 | $.class_method_body 105 | ), 106 | 107 | class_parameter: $ => seq( 108 | optional($.type_expr), 109 | $.simple_variable 110 | ), 111 | 112 | class_method_body: $ => seq( 113 | '{', 114 | statement_sequence($), 115 | '}' 116 | ), 117 | 118 | enum_definition: $ => seq( 119 | caseInsensitive('enum'), 120 | /[a-zA-Z_][a-zA-Z0-9_]+/, 121 | '{', 122 | delimited_seq($.bareword_string, $._statement_terminator, true, true), 123 | '}' 124 | ), 125 | 126 | _expression_statement: $ => choice( 127 | $.assignment_statement, 128 | $.pipeline_statement, 129 | $.if_statement, 130 | $.while_statement, 131 | $.do_while_statement 132 | ), 133 | 134 | assignment_statement: $ => seq( 135 | $._attributed_variable, 136 | '=', 137 | $._expression_statement, 138 | ), 139 | 140 | pipeline_statement: $ => seq( 141 | $._pipeline_expression, 142 | repeat( 143 | seq( 144 | '|', 145 | $.command_expression 146 | ) 147 | ) 148 | ), 149 | 150 | if_statement: $ => seq( 151 | caseInsensitive('if'), 152 | '(', 153 | $.pipeline_statement, 154 | ')', 155 | '{', 156 | statement_sequence($), 157 | '}', 158 | repeat($.elseif_statement), 159 | optional($.else_statement) 160 | ), 161 | 162 | elseif_statement: $ => seq( 163 | caseInsensitive('elif'), 164 | '(', 165 | $.pipeline_statement, 166 | ')', 167 | '{', 168 | statement_sequence($), 169 | '}' 170 | ), 171 | 172 | else_statement: $ => seq( 173 | caseInsensitive('else'), 174 | '{', 175 | statement_sequence($), 176 | '}' 177 | ), 178 | 179 | while_statement: $ => seq( 180 | caseInsensitive('while'), 181 | '(', 182 | $.pipeline_statement, 183 | ')', 184 | '{', 185 | statement_sequence($), 186 | '}' 187 | ), 188 | 189 | do_while_statement: $ => seq( 190 | caseInsensitive('do'), 191 | '{', 192 | statement_sequence($), 193 | '}', 194 | caseInsensitive('while'), 195 | '(', 196 | $.pipeline_statement, 197 | ')' 198 | ), 199 | 200 | command_expression: $ => seq( 201 | choice( 202 | $.bareword_string, 203 | seq('&', $.property_name) 204 | ), 205 | repeat( 206 | choice( 207 | $.command_parameter, 208 | $.command_argument 209 | ) 210 | ) 211 | ), 212 | 213 | command_parameter: $ => /-[a-zA-Z_-]+/i, 214 | 215 | command_argument: $ => choice( 216 | $.bareword_string, 217 | $.number_expr, 218 | $._string_expr, 219 | $.variable, 220 | $.splatted_variable, 221 | $.scriptblock, 222 | $.hashtable_expression, 223 | $.subpipeline, 224 | $.subexpression 225 | ), 226 | 227 | parameter: $ => seq( 228 | /-[a-zA-Z_][a-zA-Z0-9_]*/i, 229 | optional( 230 | seq( 231 | ':', 232 | $._expression 233 | ) 234 | ) 235 | ), 236 | 237 | _non_array_expression: $ => choice( 238 | $.number_expr, 239 | $._string_expr, 240 | $._attributed_variable, 241 | $.scriptblock, 242 | $.type_expr, 243 | $.flat_array_expression, 244 | $.hashtable_expression, 245 | $.scriptblock, 246 | $.subpipeline, 247 | $.subexpression 248 | ), 249 | 250 | subpipeline: $ => seq( 251 | '(', 252 | $._pipeline_expression, 253 | ')' 254 | ), 255 | 256 | subexpression: $ => seq( 257 | '$(', 258 | $._statement, 259 | ')' 260 | ), 261 | 262 | _expression: $ => choice( 263 | $._non_array_expression, 264 | $.array_expression 265 | ), 266 | 267 | scriptblock: $ => seq( 268 | '{', 269 | optional($.param_block), 270 | statement_sequence($), 271 | '}' 272 | ), 273 | 274 | param_block: $ => seq( 275 | caseInsensitive('param'), 276 | '(', 277 | delimited_seq($.param_block_variable, ','), 278 | ')' 279 | ), 280 | 281 | param_block_variable: $ => seq( 282 | repeat( 283 | $._attribute, 284 | ), 285 | $.simple_variable 286 | ), 287 | 288 | 289 | _pipeline_expression: $ => choice( 290 | $._expression, 291 | $.command_expression 292 | ), 293 | 294 | array_expression: $ => seq( 295 | optional($._non_array_expression), 296 | repeat1( 297 | seq( 298 | ',', 299 | $._non_array_expression 300 | ) 301 | ) 302 | ), 303 | 304 | flat_array_expression: $ => seq( 305 | '@(', 306 | delimited_seq($._expression, $._statement_terminator), 307 | ')' 308 | ), 309 | 310 | hashtable_expression: $ => seq( 311 | '@{', 312 | repeat(seq($.hashtable_entry, $._statement_terminator)), 313 | '}' 314 | ), 315 | 316 | hashtable_entry: $ => seq( 317 | $.property_name, 318 | '=', 319 | $._expression 320 | ), 321 | 322 | property_name: $ => choice( 323 | $._string_expr, 324 | $.bareword_string, 325 | $.variable 326 | ), 327 | 328 | _attributed_variable: $ => seq( 329 | repeat($._attribute), 330 | $.variable 331 | ), 332 | 333 | variable: $ => seq( 334 | choice( 335 | $.simple_variable, 336 | $._braced_variable, 337 | $._special_variable 338 | ) 339 | ), 340 | 341 | simple_variable: $ => /\$[a-zA-Z0-9_:]+/i, 342 | 343 | splatted_variable: $ => /@[a-zA-Z0-9_:]+/i, 344 | 345 | _braced_variable: $ => /\${[^}]+}/, 346 | 347 | _special_variable: $ => choice( 348 | '$$', 349 | '$^', 350 | '$?' 351 | ), 352 | 353 | type_expr: $ => seq( 354 | '[', 355 | $._typename, 356 | ']' 357 | ), 358 | 359 | _typename: $ => choice( 360 | $._typename_simple, 361 | $._typename_array, 362 | $._typename_generic 363 | ), 364 | 365 | _typename_simple: $ => /[a-zA-Z_][a-zA-Z0-9_.]*/i, 366 | 367 | _typename_array: $ => seq( 368 | $._typename, 369 | '[]' 370 | ), 371 | 372 | _typename_generic: $ => seq( 373 | $._typename, 374 | '[', 375 | $._typename, 376 | repeat( 377 | seq( 378 | ',', 379 | $._typename 380 | ) 381 | ), 382 | ']' 383 | ), 384 | 385 | non_type_attribute: $ => seq( 386 | '[', 387 | $._typename_simple, 388 | '(', 389 | delimited_seq($._non_array_expression, ','), 390 | ')', 391 | ']' 392 | ), 393 | 394 | _attribute: $ => choice( 395 | $.type_expr, 396 | $.non_type_attribute 397 | ), 398 | 399 | number_expr: $ => token(prec(PREC.NUMBER, 400 | seq( 401 | choice( 402 | /\d+/, // Integers 403 | /\d*\.\d+/ // Floats 404 | ), 405 | optional(/(e|E)\d+/), // Scientific notation 406 | optional(/u|U/), // Unsigned 407 | optional(/l|L/), // Long 408 | optional(/(k|K|m|M|g|G|t|T)(b|B)/) // Disk size notation 409 | ) 410 | )), 411 | 412 | _string_expr: $ => choice( 413 | $.single_quote_string, 414 | $.double_quote_string 415 | ), 416 | 417 | single_quote_string: $ => prec(PREC.STRING, /'[^']*'/), 418 | 419 | double_quote_string: $ => prec(PREC.STRING, 420 | seq( 421 | '"', 422 | repeat( 423 | choice( 424 | /([^"$`]|`\$|`)+/, 425 | $.variable 426 | ) 427 | ), 428 | optional('$'), 429 | '"' 430 | ) 431 | ), 432 | 433 | bareword_string: $ => /[^0-9'"$^&|;()@\-%{}\[\]\s][^'"$^&|;()@!%{}\s]*/, 434 | 435 | comment: $ => token(prec(PREC.COMMENT, 436 | choice( 437 | /#.*/, 438 | seq( 439 | '<#', 440 | repeat( 441 | choice( 442 | /[^<]*/, 443 | /<[^#]*/ 444 | ) 445 | ), 446 | '#>' 447 | ) 448 | ))) 449 | }, 450 | }); 451 | 452 | function caseInsensitive (keyword) { 453 | return new RegExp(keyword 454 | .split('') 455 | .map(letter => `[${letter}${letter.toUpperCase()}]`) 456 | .join('') 457 | ) 458 | } 459 | 460 | function statement_sequence($) 461 | { 462 | return repeat( 463 | seq( 464 | $._statement, 465 | $._statement_terminator 466 | ) 467 | ) 468 | } 469 | 470 | function delimited_seq(rule, delimeter, oneOrMore, canFollowLast) 471 | { 472 | if (canFollowLast) 473 | { 474 | if (oneOrMore) 475 | { 476 | return repeat1( 477 | seq( 478 | rule, 479 | delimeter 480 | ) 481 | ); 482 | } 483 | 484 | return repeat( 485 | seq( 486 | rule, 487 | delimeter 488 | ) 489 | ); 490 | } 491 | 492 | let body = choice( 493 | rule, 494 | seq( 495 | rule, 496 | repeat( 497 | seq( 498 | delimeter, 499 | rule 500 | ) 501 | ) 502 | ) 503 | ); 504 | 505 | return oneOrMore 506 | ? body 507 | : optional(body); 508 | } 509 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------------------------------- 2 | // Copyright (C) Microsoft. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | //------------------------------------------------------------------------------------------------------- 5 | 6 | try { 7 | module.exports = require("./build/Release/tree_sitter_PowerShell_binding"); 8 | } catch (error) { 9 | try { 10 | module.exports = require("./build/Debug/tree_sitter_PowerShell_binding"); 11 | } catch (_) { 12 | throw error 13 | } 14 | } 15 | 16 | try { 17 | module.exports.nodeTypeInfo = require("./src/node-types.json"); 18 | } catch (_) {} 19 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-powershell", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "nan": { 8 | "version": "2.14.0", 9 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 10 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 11 | }, 12 | "tree-sitter-cli": { 13 | "version": "0.15.2", 14 | "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.15.2.tgz", 15 | "integrity": "sha512-nHxOsUIGH4c7OiNFWKoZcM0JDm0/21UNLIOSo/Vdf6ikbUh1v3h3mfK2x1Q2iA7Z3aG9iHdn+I80Yvu1PwZnQw==", 16 | "dev": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-powershell", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "generate": "tree-sitter generate", 8 | "test": "tree-sitter test", 9 | "parse": "tree-sitter parse", 10 | "parse-debug": "tree-sitter parse -d", 11 | "start": "npm run generate && npm run parse" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "nan": "^2.14.0" 17 | }, 18 | "devDependencies": { 19 | "tree-sitter-cli": "^0.15.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/scanner.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See the LICENSE file in the project root for full license information. 3 | 4 | #include 5 | #include 6 | 7 | enum TOKEN_TYPE { 8 | STATEMENT_TERMINATOR 9 | }; 10 | 11 | /* --- API --- */ 12 | 13 | void *tree_sitter_PowerShell_external_scanner_create(); 14 | 15 | void tree_sitter_PowerShell_external_scanner_destroy(void *p); 16 | 17 | unsigned tree_sitter_PowerShell_external_scanner_serialize(void *payload, char *buffer); 18 | 19 | void tree_sitter_PowerShell_external_scanner_deserialize(void *payload, const char *buffer, unsigned length); 20 | 21 | bool tree_sitter_PowerShell_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols); 22 | 23 | /* --- Internal Functions --- */ 24 | 25 | static void consume(TSLexer *lexer) 26 | { 27 | lexer->advance(lexer, /* skip */ false); 28 | } 29 | 30 | static bool scan_statement_terminator(void *payload, TSLexer *lexer, const bool *valid_symbols) 31 | { 32 | lexer->result_symbol = STATEMENT_TERMINATOR; 33 | 34 | // This token has no characters -- everything is lookahead to determine its existence 35 | lexer->mark_end(lexer); 36 | 37 | switch (lexer->lookahead) 38 | { 39 | case ';': 40 | consume(lexer); 41 | lexer->mark_end(lexer); 42 | 43 | case '\0': 44 | case '\n': 45 | case '}': 46 | case ')': 47 | return true; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | /* --- API Implementation --- */ 54 | 55 | bool tree_sitter_PowerShell_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) 56 | { 57 | return scan_statement_terminator(payload, lexer, valid_symbols); 58 | } 59 | 60 | void *tree_sitter_PowerShell_external_scanner_create() 61 | { 62 | return NULL; 63 | } 64 | 65 | void tree_sitter_PowerShell_external_scanner_destroy(void *p) 66 | { 67 | } 68 | 69 | unsigned tree_sitter_PowerShell_external_scanner_serialize(void *payload, char *buffer) 70 | { 71 | return 0; 72 | } 73 | 74 | void tree_sitter_PowerShell_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) 75 | { 76 | } 77 | --------------------------------------------------------------------------------