1# The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison) 2# from this grammar file. Jison is a bottom-up parser generator, similar in 3# style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript. 4# It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](https://en.wikipedia.org/wiki/LR_grammar) 5# type grammars. To create the Jison parser, we list the pattern to match 6# on the left-hand side, and the action to take (usually the creation of syntax 7# tree nodes) on the right. As the parser runs, it 8# shifts tokens from our token stream, from left to right, and 9# [attempts to match](https://en.wikipedia.org/wiki/Bottom-up_parsing) 10# the token sequence against the rules below. When a match can be made, it 11# reduces into the [nonterminal](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols) 12# (the enclosing name at the top), and we proceed from there. 13# 14# If you run the `cake build:parser` command, Jison constructs a parse table 15# from our rules and saves it into `lib/parser.js`. 16 17# The only dependency is on the **Jison.Parser**. 18{Parser} = require 'jison' 19 20# Jison DSL 21# --------- 22 23# Since we're going to be wrapped in a function by Jison in any case, if our 24# action immediately returns a value, we can optimize by removing the function 25# wrapper and just returning the value directly. 26unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/ 27 28# Our handy DSL for Jison grammar generation, thanks to 29# [Tim Caswell](https://github.com/creationix). For every rule in the grammar, 30# we pass the pattern-defining string, the action to run, and extra options, 31# optionally. If no action is specified, we simply pass the value of the 32# previous nonterminal. 33o = (patternString, action, options) -> 34 patternString = patternString.replace /\s{2,}/g, ' ' 35 patternCount = patternString.split(' ').length 36 if action 37 # This code block does string replacements in the generated `parser.js` 38 # file, replacing the calls to the `LOC` function and other strings as 39 # listed below. 40 action = if match = unwrap.exec action then match[1] else "(#{action}())" 41 42 # All runtime functions we need are defined on `yy` 43 action = action.replace /\bnew /g, '$&yy.' 44 action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&' 45 46 # Returns strings of functions to add to `parser.js` which add extra data 47 # that nodes may have, such as comments or location data. Location data 48 # is added to the first parameter passed in, and the parameter is returned. 49 # If the parameter is not a node, it will just be passed through unaffected. 50 getAddDataToNodeFunctionString = (first, last, forceUpdateLocation = yes) -> 51 "yy.addDataToNode(yy, @#{first}, #{if first[0] is '$' then '$$' else '$'}#{first}, #{if last then "@#{last}, #{if last[0] is '$' then '$$' else '$'}#{last}" else 'null, null'}, #{if forceUpdateLocation then 'true' else 'false'})" 52 53 # This code replaces the calls to `LOC` with the `yy.addDataToNode` string 54 # defined above. The `LOC` function, when used below in the grammar rules, 55 # is used to make sure that newly created node class objects get correct 56 # location data assigned to them. By default, the grammar will assign the 57 # location data spanned by *all* of the tokens on the left (e.g. a string 58 # such as `'Body TERMINATOR Line'`) to the “top-level” node returned by 59 # the grammar rule (the function on the right). But for “inner” node class 60 # objects created by grammar rules, they won’t get correct location data 61 # assigned to them without adding `LOC`. 62 63 # For example, consider the grammar rule `'NEW_TARGET . Property'`, which 64 # is handled by a function that returns 65 # `new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)`. 66 # The `1` in `LOC(1)` refers to the first token (`NEW_TARGET`) and the `3` 67 # in `LOC(3)` refers to the third token (`Property`). In order for the 68 # `new IdentifierLiteral` to get assigned the location data corresponding 69 # to `new` in the source code, we use 70 # `LOC(1)(new IdentifierLiteral ...)` to mean “assign the location data of 71 # the *first* token of this grammar rule (`NEW_TARGET`) to this 72 # `new IdentifierLiteral`”. The `LOC(3)` means “assign the location data of 73 # the *third* token of this grammar rule (`Property`) to this 74 # `new Access`”. 75 returnsLoc = /^LOC/.test action 76 action = action.replace /LOC\(([0-9]*)\)/g, getAddDataToNodeFunctionString('$1') 77 # A call to `LOC` with two arguments, e.g. `LOC(2,4)`, sets the location 78 # data for the generated node on both of the referenced tokens (the second 79 # and fourth in this example). 80 action = action.replace /LOC\(([0-9]*),\s*([0-9]*)\)/g, getAddDataToNodeFunctionString('$1', '$2') 81 performActionFunctionString = "$$ = #{getAddDataToNodeFunctionString(1, patternCount, not returnsLoc)}(#{action});" 82 else 83 performActionFunctionString = '$$ = $1;' 84 85 [patternString, performActionFunctionString, options] 86 87# Grammatical Rules 88# ----------------- 89 90# In all of the rules that follow, you'll see the name of the nonterminal as 91# the key to a list of alternative matches. With each match's action, the 92# dollar-sign variables are provided by Jison as references to the value of 93# their numeric position, so in this rule: 94# 95# 'Expression UNLESS Expression' 96# 97# `$1` would be the value of the first `Expression`, `$2` would be the token 98# for the `UNLESS` terminal, and `$3` would be the value of the second 99# `Expression`. 100grammar = 101 102 # The **Root** is the top-level node in the syntax tree. Since we parse bottom-up, 103 # all parsing must end here. 104 Root: [ 105 o '', -> new Root new Block 106 o 'Body', -> new Root $1 107 ] 108 109 # Any list of statements and expressions, separated by line breaks or semicolons. 110 Body: [ 111 o 'Line', -> Block.wrap [$1] 112 o 'Body TERMINATOR Line', -> $1.push $3 113 o 'Body TERMINATOR' 114 ] 115 116 # Block and statements, which make up a line in a body. FuncDirective is a 117 # statement, but not included in Statement because that results in an ambiguous 118 # grammar. 119 Line: [ 120 o 'Expression' 121 o 'ExpressionLine' 122 o 'Statement' 123 o 'FuncDirective' 124 ] 125 126 FuncDirective: [ 127 o 'YieldReturn' 128 o 'AwaitReturn' 129 ] 130 131 # Pure statements which cannot be expressions. 132 Statement: [ 133 o 'Return' 134 o 'STATEMENT', -> new StatementLiteral $1 135 o 'Import' 136 o 'Export' 137 ] 138 139 # All the different types of expressions in our language. The basic unit of 140 # CoffeeScript is the **Expression** -- everything that can be an expression 141 # is one. Blocks serve as the building blocks of many other rules, making 142 # them somewhat circular. 143 Expression: [ 144 o 'Value' 145 o 'Code' 146 o 'Operation' 147 o 'Assign' 148 o 'If' 149 o 'Try' 150 o 'While' 151 o 'For' 152 o 'Switch' 153 o 'Class' 154 o 'Throw' 155 o 'Yield' 156 ] 157 158 # Expressions which are written in single line and would otherwise require being 159 # wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`, 160 # `for x in do (obj) -> f obj when x > 8 then f x` 161 ExpressionLine: [ 162 o 'CodeLine' 163 o 'IfLine' 164 o 'OperationLine' 165 ] 166 167 Yield: [ 168 o 'YIELD', -> new Op $1, new Value new Literal '' 169 o 'YIELD Expression', -> new Op $1, $2 170 o 'YIELD INDENT Object OUTDENT', -> new Op $1, $3 171 o 'YIELD FROM Expression', -> new Op $1.concat($2), $3 172 ] 173 174 # An indented block of expressions. Note that the [Rewriter](rewriter.html) 175 # will convert some postfix forms into blocks for us, by adjusting the 176 # token stream. 177 Block: [ 178 o 'INDENT OUTDENT', -> new Block 179 o 'INDENT Body OUTDENT', -> $2 180 ] 181 182 Identifier: [ 183 o 'IDENTIFIER', -> new IdentifierLiteral $1 184 o 'JSX_TAG', -> new JSXTag $1.toString(), 185 tagNameLocationData: $1.tagNameToken[2] 186 closingTagOpeningBracketLocationData: $1.closingTagOpeningBracketToken?[2] 187 closingTagSlashLocationData: $1.closingTagSlashToken?[2] 188 closingTagNameLocationData: $1.closingTagNameToken?[2] 189 closingTagClosingBracketLocationData: $1.closingTagClosingBracketToken?[2] 190 ] 191 192 Property: [ 193 o 'PROPERTY', -> new PropertyName $1.toString() 194 ] 195 196 # Alphanumerics are separated from the other **Literal** matchers because 197 # they can also serve as keys in object literals. 198 AlphaNumeric: [ 199 o 'NUMBER', -> new NumberLiteral $1.toString(), parsedValue: $1.parsedValue 200 o 'String' 201 ] 202 203 String: [ 204 o 'STRING', -> 205 new StringLiteral( 206 $1.slice 1, -1 # strip artificial quotes and unwrap to primitive string 207 quote: $1.quote 208 initialChunk: $1.initialChunk 209 finalChunk: $1.finalChunk 210 indent: $1.indent 211 double: $1.double 212 heregex: $1.heregex 213 ) 214 o 'STRING_START Interpolations STRING_END', -> new StringWithInterpolations Block.wrap($2), quote: $1.quote, startQuote: LOC(1)(new Literal $1.toString()) 215 ] 216 217 Interpolations: [ 218 o 'InterpolationChunk', -> [$1] 219 o 'Interpolations InterpolationChunk', -> $1.concat $2 220 ] 221 222 InterpolationChunk: [ 223 o 'INTERPOLATION_START Body INTERPOLATION_END', -> new Interpolation $2 224 o 'INTERPOLATION_START INDENT Body OUTDENT INTERPOLATION_END', -> new Interpolation $3 225 o 'INTERPOLATION_START INTERPOLATION_END', -> new Interpolation 226 o 'String', -> $1 227 ] 228 229 # The .toString() calls here and elsewhere are to convert `String` objects 230 # back to primitive strings now that we've retrieved stowaway extra properties 231 Regex: [ 232 o 'REGEX', -> new RegexLiteral $1.toString(), delimiter: $1.delimiter, heregexCommentTokens: $1.heregexCommentTokens 233 o 'REGEX_START Invocation REGEX_END', -> new RegexWithInterpolations $2, heregexCommentTokens: $3.heregexCommentTokens 234 ] 235 236 # All of our immediate values. Generally these can be passed straight 237 # through and printed to JavaScript. 238 Literal: [ 239 o 'AlphaNumeric' 240 o 'JS', -> new PassthroughLiteral $1.toString(), here: $1.here, generated: $1.generated 241 o 'Regex' 242 o 'UNDEFINED', -> new UndefinedLiteral $1 243 o 'NULL', -> new NullLiteral $1 244 o 'BOOL', -> new BooleanLiteral $1.toString(), originalValue: $1.original 245 o 'INFINITY', -> new InfinityLiteral $1.toString(), originalValue: $1.original 246 o 'NAN', -> new NaNLiteral $1 247 ] 248 249 # Assignment of a variable, property, or index to a value. 250 Assign: [ 251 o 'Assignable = Expression', -> new Assign $1, $3 252 o 'Assignable = TERMINATOR Expression', -> new Assign $1, $4 253 o 'Assignable = INDENT Expression OUTDENT', -> new Assign $1, $4 254 ] 255 256 # Assignment when it happens within an object literal. The difference from 257 # the ordinary **Assign** is that these allow numbers and strings as keys. 258 AssignObj: [ 259 o 'ObjAssignable', -> new Value $1 260 o 'ObjRestValue' 261 o 'ObjAssignable : Expression', -> new Assign LOC(1)(new Value $1), $3, 'object', 262 operatorToken: LOC(2)(new Literal $2) 263 o 'ObjAssignable : 264 INDENT Expression OUTDENT', -> new Assign LOC(1)(new Value $1), $4, 'object', 265 operatorToken: LOC(2)(new Literal $2) 266 o 'SimpleObjAssignable = Expression', -> new Assign LOC(1)(new Value $1), $3, null, 267 operatorToken: LOC(2)(new Literal $2) 268 o 'SimpleObjAssignable = 269 INDENT Expression OUTDENT', -> new Assign LOC(1)(new Value $1), $4, null, 270 operatorToken: LOC(2)(new Literal $2) 271 ] 272 273 SimpleObjAssignable: [ 274 o 'Identifier' 275 o 'Property' 276 o 'ThisProperty' 277 ] 278 279 ObjAssignable: [ 280 o 'SimpleObjAssignable' 281 o '[ Expression ]', -> new Value new ComputedPropertyName $2 282 o '@ [ Expression ]', -> new Value LOC(1)(new ThisLiteral $1), [LOC(3)(new ComputedPropertyName($3))], 'this' 283 o 'AlphaNumeric' 284 ] 285 286 # Object literal spread properties. 287 ObjRestValue: [ 288 o 'SimpleObjAssignable ...', -> new Splat new Value $1 289 o '... SimpleObjAssignable', -> new Splat new Value($2), postfix: no 290 o 'ObjSpreadExpr ...', -> new Splat $1 291 o '... ObjSpreadExpr', -> new Splat $2, postfix: no 292 ] 293 294 ObjSpreadExpr: [ 295 o 'ObjSpreadIdentifier' 296 o 'Object' 297 o 'Parenthetical' 298 o 'Super' 299 o 'This' 300 o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1 301 o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2 302 o 'SimpleObjAssignable OptFuncExist Arguments', -> new Call (new Value $1), $3, $2.soak 303 o 'ObjSpreadExpr OptFuncExist Arguments', -> new Call $1, $3, $2.soak 304 ] 305 306 ObjSpreadIdentifier: [ 307 o 'SimpleObjAssignable Accessor', -> (new Value $1).add $2 308 o 'ObjSpreadExpr Accessor', -> (new Value $1).add $2 309 ] 310 311 # A return statement from a function body. 312 Return: [ 313 o 'RETURN Expression', -> new Return $2 314 o 'RETURN INDENT Object OUTDENT', -> new Return new Value $3 315 o 'RETURN', -> new Return 316 ] 317 318 YieldReturn: [ 319 o 'YIELD RETURN Expression', -> new YieldReturn $3, returnKeyword: LOC(2)(new Literal $2) 320 o 'YIELD RETURN', -> new YieldReturn null, returnKeyword: LOC(2)(new Literal $2) 321 ] 322 323 AwaitReturn: [ 324 o 'AWAIT RETURN Expression', -> new AwaitReturn $3, returnKeyword: LOC(2)(new Literal $2) 325 o 'AWAIT RETURN', -> new AwaitReturn null, returnKeyword: LOC(2)(new Literal $2) 326 ] 327 328 # The **Code** node is the function literal. It’s defined by an indented block 329 # of **Block** preceded by a function arrow, with an optional parameter list. 330 Code: [ 331 o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4, LOC(1)(new Literal $1) 332 o 'FuncGlyph Block', -> new Code [], $2, $1 333 ] 334 335 # The Codeline is the **Code** node with **Line** instead of indented **Block**. 336 CodeLine: [ 337 o 'PARAM_START ParamList PARAM_END FuncGlyph Line', -> new Code $2, LOC(5)(Block.wrap [$5]), $4, 338 LOC(1)(new Literal $1) 339 o 'FuncGlyph Line', -> new Code [], LOC(2)(Block.wrap [$2]), $1 340 ] 341 342 # CoffeeScript has two different symbols for functions. `->` is for ordinary 343 # functions, and `=>` is for functions bound to the current value of *this*. 344 FuncGlyph: [ 345 o '->', -> new FuncGlyph $1 346 o '=>', -> new FuncGlyph $1 347 ] 348 349 # An optional, trailing comma. 350 OptComma: [ 351 o '' 352 o ',' 353 ] 354 355 # The list of parameters that a function accepts can be of any length. 356 ParamList: [ 357 o '', -> [] 358 o 'Param', -> [$1] 359 o 'ParamList , Param', -> $1.concat $3 360 o 'ParamList OptComma TERMINATOR Param', -> $1.concat $4 361 o 'ParamList OptComma INDENT ParamList OptComma OUTDENT', -> $1.concat $4 362 ] 363 364 # A single parameter in a function definition can be ordinary, or a splat 365 # that hoovers up the remaining arguments. 366 Param: [ 367 o 'ParamVar', -> new Param $1 368 o 'ParamVar ...', -> new Param $1, null, on 369 o '... ParamVar', -> new Param $2, null, postfix: no 370 o 'ParamVar = Expression', -> new Param $1, $3 371 o '...', -> new Expansion 372 ] 373 374 # Function Parameters 375 ParamVar: [ 376 o 'Identifier' 377 o 'ThisProperty' 378 o 'Array' 379 o 'Object' 380 ] 381 382 # A splat that occurs outside of a parameter list. 383 Splat: [ 384 o 'Expression ...', -> new Splat $1 385 o '... Expression', -> new Splat $2, {postfix: no} 386 ] 387 388 # Variables and properties that can be assigned to. 389 SimpleAssignable: [ 390 o 'Identifier', -> new Value $1 391 o 'Value Accessor', -> $1.add $2 392 o 'Code Accessor', -> new Value($1).add $2 393 o 'ThisProperty' 394 ] 395 396 # Everything that can be assigned to. 397 Assignable: [ 398 o 'SimpleAssignable' 399 o 'Array', -> new Value $1 400 o 'Object', -> new Value $1 401 ] 402 403 # The types of things that can be treated as values -- assigned to, invoked 404 # as functions, indexed into, named as a class, etc. 405 Value: [ 406 o 'Assignable' 407 o 'Literal', -> new Value $1 408 o 'Parenthetical', -> new Value $1 409 o 'Range', -> new Value $1 410 o 'Invocation', -> new Value $1 411 o 'DoIife', -> new Value $1 412 o 'This' 413 o 'Super', -> new Value $1 414 o 'MetaProperty', -> new Value $1 415 ] 416 417 # A `super`-based expression that can be used as a value. 418 Super: [ 419 o 'SUPER . Property', -> new Super LOC(3)(new Access $3), LOC(1)(new Literal $1) 420 o 'SUPER INDEX_START Expression INDEX_END', -> new Super LOC(3)(new Index $3), LOC(1)(new Literal $1) 421 o 'SUPER INDEX_START INDENT Expression OUTDENT INDEX_END', -> new Super LOC(4)(new Index $4), LOC(1)(new Literal $1) 422 ] 423 424 # A “meta-property” access e.g. `new.target` or `import.meta`, where 425 # something that looks like a property is referenced on a keyword. 426 MetaProperty: [ 427 o 'NEW_TARGET . Property', -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3) 428 o 'IMPORT_META . Property', -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3) 429 ] 430 431 # The general group of accessors into an object, by property, by prototype 432 # or by array index or slice. 433 Accessor: [ 434 o '. Property', -> new Access $2 435 o '?. Property', -> new Access $2, soak: yes 436 o ':: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes), LOC(2)(new Access $2)] 437 o '?:: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes, soak: yes), LOC(2)(new Access $2)] 438 o '::', -> new Access new PropertyName('prototype'), shorthand: yes 439 o '?::', -> new Access new PropertyName('prototype'), shorthand: yes, soak: yes 440 o 'Index' 441 ] 442 443 # Indexing into an object or array using bracket notation. 444 Index: [ 445 o 'INDEX_START IndexValue INDEX_END', -> $2 446 o 'INDEX_START INDENT IndexValue OUTDENT INDEX_END', -> $3 447 o 'INDEX_SOAK Index', -> extend $2, soak: yes 448 ] 449 450 IndexValue: [ 451 o 'Expression', -> new Index $1 452 o 'Slice', -> new Slice $1 453 ] 454 455 # In CoffeeScript, an object literal is simply a list of assignments. 456 Object: [ 457 o '{ AssignList OptComma }', -> new Obj $2, $1.generated 458 ] 459 460 # Assignment of properties within an object literal can be separated by 461 # comma, as in JavaScript, or simply by newline. 462 AssignList: [ 463 o '', -> [] 464 o 'AssignObj', -> [$1] 465 o 'AssignList , AssignObj', -> $1.concat $3 466 o 'AssignList OptComma TERMINATOR AssignObj', -> $1.concat $4 467 o 'AssignList OptComma INDENT AssignList OptComma OUTDENT', -> $1.concat $4 468 ] 469 470 # Class definitions have optional bodies of prototype property assignments, 471 # and optional references to the superclass. 472 Class: [ 473 o 'CLASS', -> new Class 474 o 'CLASS Block', -> new Class null, null, $2 475 o 'CLASS EXTENDS Expression', -> new Class null, $3 476 o 'CLASS EXTENDS Expression Block', -> new Class null, $3, $4 477 o 'CLASS SimpleAssignable', -> new Class $2 478 o 'CLASS SimpleAssignable Block', -> new Class $2, null, $3 479 o 'CLASS SimpleAssignable EXTENDS Expression', -> new Class $2, $4 480 o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5 481 ] 482 483 Import: [ 484 o 'IMPORT String', -> new ImportDeclaration null, $2 485 o 'IMPORT ImportDefaultSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, null), $4 486 o 'IMPORT ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause(null, $2), $4 487 o 'IMPORT { } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5 488 o 'IMPORT { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7 489 o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, $4), $6 490 o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9 491 ] 492 493 ImportSpecifierList: [ 494 o 'ImportSpecifier', -> [$1] 495 o 'ImportSpecifierList , ImportSpecifier', -> $1.concat $3 496 o 'ImportSpecifierList OptComma TERMINATOR ImportSpecifier', -> $1.concat $4 497 o 'INDENT ImportSpecifierList OptComma OUTDENT', -> $2 498 o 'ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', -> $1.concat $4 499 ] 500 501 ImportSpecifier: [ 502 o 'Identifier', -> new ImportSpecifier $1 503 o 'Identifier AS Identifier', -> new ImportSpecifier $1, $3 504 o 'DEFAULT', -> new ImportSpecifier LOC(1)(new DefaultLiteral $1) 505 o 'DEFAULT AS Identifier', -> new ImportSpecifier LOC(1)(new DefaultLiteral($1)), $3 506 ] 507 508 ImportDefaultSpecifier: [ 509 o 'Identifier', -> new ImportDefaultSpecifier $1 510 ] 511 512 ImportNamespaceSpecifier: [ 513 o 'IMPORT_ALL AS Identifier', -> new ImportNamespaceSpecifier new Literal($1), $3 514 ] 515 516 Export: [ 517 o 'EXPORT { }', -> new ExportNamedDeclaration new ExportSpecifierList [] 518 o 'EXPORT { ExportSpecifierList OptComma }', -> new ExportNamedDeclaration new ExportSpecifierList $3 519 o 'EXPORT Class', -> new ExportNamedDeclaration $2 520 o 'EXPORT Identifier = Expression', -> new ExportNamedDeclaration LOC(2,4)(new Assign $2, $4, null, 521 moduleDeclaration: 'export') 522 o 'EXPORT Identifier = TERMINATOR Expression', -> new ExportNamedDeclaration LOC(2,5)(new Assign $2, $5, null, 523 moduleDeclaration: 'export') 524 o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration LOC(2,6)(new Assign $2, $5, null, 525 moduleDeclaration: 'export') 526 o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3 527 o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4 528 o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4 529 o 'EXPORT { } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5 530 o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7 531 ] 532 533 ExportSpecifierList: [ 534 o 'ExportSpecifier', -> [$1] 535 o 'ExportSpecifierList , ExportSpecifier', -> $1.concat $3 536 o 'ExportSpecifierList OptComma TERMINATOR ExportSpecifier', -> $1.concat $4 537 o 'INDENT ExportSpecifierList OptComma OUTDENT', -> $2 538 o 'ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', -> $1.concat $4 539 ] 540 541 ExportSpecifier: [ 542 o 'Identifier', -> new ExportSpecifier $1 543 o 'Identifier AS Identifier', -> new ExportSpecifier $1, $3 544 o 'Identifier AS DEFAULT', -> new ExportSpecifier $1, LOC(3)(new DefaultLiteral $3) 545 o 'DEFAULT', -> new ExportSpecifier LOC(1)(new DefaultLiteral $1) 546 o 'DEFAULT AS Identifier', -> new ExportSpecifier LOC(1)(new DefaultLiteral($1)), $3 547 ] 548 549 # Ordinary function invocation, or a chained series of calls. 550 Invocation: [ 551 o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2.soak 552 o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2.soak 553 o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1 554 o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2 555 ] 556 557 # An optional existence check on a function. 558 OptFuncExist: [ 559 o '', -> soak: no 560 o 'FUNC_EXIST', -> soak: yes 561 ] 562 563 # The list of arguments to a function call. 564 Arguments: [ 565 o 'CALL_START CALL_END', -> [] 566 o 'CALL_START ArgList OptComma CALL_END', -> $2.implicit = $1.generated; $2 567 ] 568 569 # A reference to the *this* current object. 570 This: [ 571 o 'THIS', -> new Value new ThisLiteral $1 572 o '@', -> new Value new ThisLiteral $1 573 ] 574 575 # A reference to a property on *this*. 576 ThisProperty: [ 577 o '@ Property', -> new Value LOC(1)(new ThisLiteral $1), [LOC(2)(new Access($2))], 'this' 578 ] 579 580 # The array literal. 581 Array: [ 582 o '[ ]', -> new Arr [] 583 o '[ Elisions ]', -> new Arr $2 584 o '[ ArgElisionList OptElisions ]', -> new Arr [].concat $2, $3 585 ] 586 587 # Inclusive and exclusive range dots. 588 RangeDots: [ 589 o '..', -> exclusive: no 590 o '...', -> exclusive: yes 591 ] 592 593 # The CoffeeScript range literal. 594 Range: [ 595 o '[ Expression RangeDots Expression ]', -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive' 596 o '[ ExpressionLine RangeDots Expression ]', -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive' 597 ] 598 599 # Array slice literals. 600 Slice: [ 601 o 'Expression RangeDots Expression', -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive' 602 o 'Expression RangeDots', -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive' 603 o 'ExpressionLine RangeDots Expression', -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive' 604 o 'ExpressionLine RangeDots', -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive' 605 o 'RangeDots Expression', -> new Range null, $2, if $1.exclusive then 'exclusive' else 'inclusive' 606 o 'RangeDots', -> new Range null, null, if $1.exclusive then 'exclusive' else 'inclusive' 607 ] 608 609 # The **ArgList** is the list of objects passed into a function call 610 # (i.e. comma-separated expressions). Newlines work as well. 611 ArgList: [ 612 o 'Arg', -> [$1] 613 o 'ArgList , Arg', -> $1.concat $3 614 o 'ArgList OptComma TERMINATOR Arg', -> $1.concat $4 615 o 'INDENT ArgList OptComma OUTDENT', -> $2 616 o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4 617 ] 618 619 # Valid arguments are Blocks or Splats. 620 Arg: [ 621 o 'Expression' 622 o 'ExpressionLine' 623 o 'Splat' 624 o '...', -> new Expansion 625 ] 626 627 # The **ArgElisionList** is the list of objects, contents of an array literal 628 # (i.e. comma-separated expressions and elisions). Newlines work as well. 629 ArgElisionList: [ 630 o 'ArgElision' 631 o 'ArgElisionList , ArgElision', -> $1.concat $3 632 o 'ArgElisionList OptComma TERMINATOR ArgElision', -> $1.concat $4 633 o 'INDENT ArgElisionList OptElisions OUTDENT', -> $2.concat $3 634 o 'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', -> $1.concat $2, $4, $5 635 ] 636 637 ArgElision: [ 638 o 'Arg', -> [$1] 639 o 'Elisions Arg', -> $1.concat $2 640 ] 641 642 OptElisions: [ 643 o 'OptComma', -> [] 644 o ', Elisions', -> [].concat $2 645 ] 646 647 Elisions: [ 648 o 'Elision', -> [$1] 649 o 'Elisions Elision', -> $1.concat $2 650 ] 651 652 Elision: [ 653 o ',', -> new Elision 654 o 'Elision TERMINATOR', -> $1 655 ] 656 657 # Just simple, comma-separated, required arguments (no fancy syntax). We need 658 # this to be separate from the **ArgList** for use in **Switch** blocks, where 659 # having the newlines wouldn't make sense. 660 SimpleArgs: [ 661 o 'Expression' 662 o 'ExpressionLine' 663 o 'SimpleArgs , Expression', -> [].concat $1, $3 664 o 'SimpleArgs , ExpressionLine', -> [].concat $1, $3 665 ] 666 667 # The variants of *try/catch/finally* exception handling blocks. 668 Try: [ 669 o 'TRY Block', -> new Try $2 670 o 'TRY Block Catch', -> new Try $2, $3 671 o 'TRY Block FINALLY Block', -> new Try $2, null, $4, LOC(3)(new Literal $3) 672 o 'TRY Block Catch FINALLY Block', -> new Try $2, $3, $5, LOC(4)(new Literal $4) 673 ] 674 675 # A catch clause names its error and runs a block of code. 676 Catch: [ 677 o 'CATCH Identifier Block', -> new Catch $3, $2 678 o 'CATCH Object Block', -> new Catch $3, LOC(2)(new Value($2)) 679 o 'CATCH Block', -> new Catch $2 680 ] 681 682 # Throw an exception object. 683 Throw: [ 684 o 'THROW Expression', -> new Throw $2 685 o 'THROW INDENT Object OUTDENT', -> new Throw new Value $3 686 ] 687 688 # Parenthetical expressions. Note that the **Parenthetical** is a **Value**, 689 # not an **Expression**, so if you need to use an expression in a place 690 # where only values are accepted, wrapping it in parentheses will always do 691 # the trick. 692 Parenthetical: [ 693 o '( Body )', -> new Parens $2 694 o '( INDENT Body OUTDENT )', -> new Parens $3 695 ] 696 697 # The condition portion of a while loop. 698 WhileLineSource: [ 699 o 'WHILE ExpressionLine', -> new While $2 700 o 'WHILE ExpressionLine WHEN ExpressionLine', -> new While $2, guard: $4 701 o 'UNTIL ExpressionLine', -> new While $2, invert: true 702 o 'UNTIL ExpressionLine WHEN ExpressionLine', -> new While $2, invert: true, guard: $4 703 ] 704 705 WhileSource: [ 706 o 'WHILE Expression', -> new While $2 707 o 'WHILE Expression WHEN Expression', -> new While $2, guard: $4 708 o 'WHILE ExpressionLine WHEN Expression', -> new While $2, guard: $4 709 o 'UNTIL Expression', -> new While $2, invert: true 710 o 'UNTIL Expression WHEN Expression', -> new While $2, invert: true, guard: $4 711 o 'UNTIL ExpressionLine WHEN Expression', -> new While $2, invert: true, guard: $4 712 ] 713 714 # The while loop can either be normal, with a block of expressions to execute, 715 # or postfix, with a single expression. There is no do..while. 716 While: [ 717 o 'WhileSource Block', -> $1.addBody $2 718 o 'WhileLineSource Block', -> $1.addBody $2 719 o 'Statement WhileSource', -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1]) 720 o 'Expression WhileSource', -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1]) 721 o 'Loop', -> $1 722 ] 723 724 Loop: [ 725 o 'LOOP Block', -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody $2 726 o 'LOOP Expression', -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody LOC(2) Block.wrap [$2] 727 ] 728 729 # Array, object, and range comprehensions, at the most generic level. 730 # Comprehensions can either be normal, with a block of expressions to execute, 731 # or postfix, with a single expression. 732 For: [ 733 o 'Statement ForBody', -> $2.postfix = yes; $2.addBody $1 734 o 'Expression ForBody', -> $2.postfix = yes; $2.addBody $1 735 o 'ForBody Block', -> $1.addBody $2 736 o 'ForLineBody Block', -> $1.addBody $2 737 ] 738 739 ForBody: [ 740 o 'FOR Range', -> new For [], source: (LOC(2) new Value($2)) 741 o 'FOR Range BY Expression', -> new For [], source: (LOC(2) new Value($2)), step: $4 742 o 'ForStart ForSource', -> $1.addSource $2 743 ] 744 745 ForLineBody: [ 746 o 'FOR Range BY ExpressionLine', -> new For [], source: (LOC(2) new Value($2)), step: $4 747 o 'ForStart ForLineSource', -> $1.addSource $2 748 ] 749 750 ForStart: [ 751 o 'FOR ForVariables', -> new For [], name: $2[0], index: $2[1] 752 o 'FOR AWAIT ForVariables', -> 753 [name, index] = $3 754 new For [], {name, index, await: yes, awaitTag: (LOC(2) new Literal($2))} 755 o 'FOR OWN ForVariables', -> 756 [name, index] = $3 757 new For [], {name, index, own: yes, ownTag: (LOC(2) new Literal($2))} 758 ] 759 760 # An array of all accepted values for a variable inside the loop. 761 # This enables support for pattern matching. 762 ForValue: [ 763 o 'Identifier' 764 o 'ThisProperty' 765 o 'Array', -> new Value $1 766 o 'Object', -> new Value $1 767 ] 768 769 # An array or range comprehension has variables for the current element 770 # and (optional) reference to the current index. Or, *key, value*, in the case 771 # of object comprehensions. 772 ForVariables: [ 773 o 'ForValue', -> [$1] 774 o 'ForValue , ForValue', -> [$1, $3] 775 ] 776 777 # The source of a comprehension is an array or object with an optional guard 778 # clause. If it’s an array comprehension, you can also choose to step through 779 # in fixed-size increments. 780 ForSource: [ 781 o 'FORIN Expression', -> source: $2 782 o 'FOROF Expression', -> source: $2, object: yes 783 o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4 784 o 'FORIN ExpressionLine WHEN Expression', -> source: $2, guard: $4 785 o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes 786 o 'FOROF ExpressionLine WHEN Expression', -> source: $2, guard: $4, object: yes 787 o 'FORIN Expression BY Expression', -> source: $2, step: $4 788 o 'FORIN ExpressionLine BY Expression', -> source: $2, step: $4 789 o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6 790 o 'FORIN ExpressionLine WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6 791 o 'FORIN Expression WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6 792 o 'FORIN ExpressionLine WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6 793 o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6 794 o 'FORIN ExpressionLine BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6 795 o 'FORIN Expression BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6 796 o 'FORIN ExpressionLine BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6 797 o 'FORFROM Expression', -> source: $2, from: yes 798 o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes 799 o 'FORFROM ExpressionLine WHEN Expression', -> source: $2, guard: $4, from: yes 800 ] 801 802 ForLineSource: [ 803 o 'FORIN ExpressionLine', -> source: $2 804 o 'FOROF ExpressionLine', -> source: $2, object: yes 805 o 'FORIN Expression WHEN ExpressionLine', -> source: $2, guard: $4 806 o 'FORIN ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4 807 o 'FOROF Expression WHEN ExpressionLine', -> source: $2, guard: $4, object: yes 808 o 'FOROF ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, object: yes 809 o 'FORIN Expression BY ExpressionLine', -> source: $2, step: $4 810 o 'FORIN ExpressionLine BY ExpressionLine', -> source: $2, step: $4 811 o 'FORIN Expression WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6 812 o 'FORIN ExpressionLine WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6 813 o 'FORIN Expression WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6 814 o 'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6 815 o 'FORIN Expression BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6 816 o 'FORIN ExpressionLine BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6 817 o 'FORIN Expression BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6 818 o 'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6 819 o 'FORFROM ExpressionLine', -> source: $2, from: yes 820 o 'FORFROM Expression WHEN ExpressionLine', -> source: $2, guard: $4, from: yes 821 o 'FORFROM ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, from: yes 822 ] 823 824 Switch: [ 825 o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4 826 o 'SWITCH ExpressionLine INDENT Whens OUTDENT', -> new Switch $2, $4 827 o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, LOC(5,6) $6 828 o 'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, LOC(5,6) $6 829 o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3 830 o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, LOC(4,5) $5 831 ] 832 833 Whens: [ 834 o 'When', -> [$1] 835 o 'Whens When', -> $1.concat $2 836 ] 837 838 # An individual **When** clause, with action. 839 When: [ 840 o 'LEADING_WHEN SimpleArgs Block', -> new SwitchWhen $2, $3 841 o 'LEADING_WHEN SimpleArgs Block TERMINATOR', -> LOC(1, 3) new SwitchWhen $2, $3 842 ] 843 844 # The most basic form of *if* is a condition and an action. The following 845 # if-related rules are broken up along these lines in order to avoid 846 # ambiguity. 847 IfBlock: [ 848 o 'IF Expression Block', -> new If $2, $3, type: $1 849 o 'IfBlock ELSE IF Expression Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3 850 ] 851 852 # The full complement of *if* expressions, including postfix one-liner 853 # *if* and *unless*. 854 If: [ 855 o 'IfBlock' 856 o 'IfBlock ELSE Block', -> $1.addElse $3 857 o 'Statement POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true 858 o 'Expression POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true 859 ] 860 861 IfBlockLine: [ 862 o 'IF ExpressionLine Block', -> new If $2, $3, type: $1 863 o 'IfBlockLine ELSE IF ExpressionLine Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3 864 ] 865 866 IfLine: [ 867 o 'IfBlockLine' 868 o 'IfBlockLine ELSE Block', -> $1.addElse $3 869 o 'Statement POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true 870 o 'Expression POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true 871 ] 872 873 # Arithmetic and logical operators, working on one or more operands. 874 # Here they are grouped by order of precedence. The actual precedence rules 875 # are defined at the bottom of the page. It would be shorter if we could 876 # combine most of these rules into a single generic *Operand OpSymbol Operand* 877 # -type rule, but in order to make the precedence binding possible, separate 878 # rules are necessary. 879 OperationLine: [ 880 o 'UNARY ExpressionLine', -> new Op $1, $2 881 o 'DO ExpressionLine', -> new Op $1, $2 882 o 'DO_IIFE CodeLine', -> new Op $1, $2 883 ] 884 885 Operation: [ 886 o 'UNARY Expression', -> new Op $1.toString(), $2, undefined, undefined, originalOperator: $1.original 887 o 'DO Expression', -> new Op $1, $2 888 o 'UNARY_MATH Expression', -> new Op $1, $2 889 o '- Expression', (-> new Op '-', $2), prec: 'UNARY_MATH' 890 o '+ Expression', (-> new Op '+', $2), prec: 'UNARY_MATH' 891 892 o 'AWAIT Expression', -> new Op $1, $2 893 o 'AWAIT INDENT Object OUTDENT', -> new Op $1, $3 894 895 o '-- SimpleAssignable', -> new Op '--', $2 896 o '++ SimpleAssignable', -> new Op '++', $2 897 o 'SimpleAssignable --', -> new Op '--', $1, null, true 898 o 'SimpleAssignable ++', -> new Op '++', $1, null, true 899 900 # [The existential operator](https://coffeescript.org/#existential-operator). 901 o 'Expression ?', -> new Existence $1 902 903 o 'Expression + Expression', -> new Op '+' , $1, $3 904 o 'Expression - Expression', -> new Op '-' , $1, $3 905 906 o 'Expression MATH Expression', -> new Op $2, $1, $3 907 o 'Expression ** Expression', -> new Op $2, $1, $3 908 o 'Expression SHIFT Expression', -> new Op $2, $1, $3 909 o 'Expression COMPARE Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original 910 o 'Expression & Expression', -> new Op $2, $1, $3 911 o 'Expression ^ Expression', -> new Op $2, $1, $3 912 o 'Expression | Expression', -> new Op $2, $1, $3 913 o 'Expression && Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original 914 o 'Expression || Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original 915 o 'Expression BIN? Expression', -> new Op $2, $1, $3 916 o 'Expression RELATION Expression', -> new Op $2.toString(), $1, $3, undefined, invertOperator: $2.invert?.original ? $2.invert 917 918 o 'SimpleAssignable COMPOUND_ASSIGN 919 Expression', -> new Assign $1, $3, $2.toString(), originalContext: $2.original 920 o 'SimpleAssignable COMPOUND_ASSIGN 921 INDENT Expression OUTDENT', -> new Assign $1, $4, $2.toString(), originalContext: $2.original 922 o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR 923 Expression', -> new Assign $1, $4, $2.toString(), originalContext: $2.original 924 ] 925 926 DoIife: [ 927 o 'DO_IIFE Code', -> new Op $1 , $2 928 ] 929 930# Precedence 931# ---------- 932 933# Operators at the top of this list have higher precedence than the ones lower 934# down. Following these rules is what makes `2 + 3 * 4` parse as: 935# 936# 2 + (3 * 4) 937# 938# And not: 939# 940# (2 + 3) * 4 941operators = [ 942 ['right', 'DO_IIFE'] 943 ['left', '.', '?.', '::', '?::'] 944 ['left', 'CALL_START', 'CALL_END'] 945 ['nonassoc', '++', '--'] 946 ['left', '?'] 947 ['right', 'UNARY', 'DO'] 948 ['right', 'AWAIT'] 949 ['right', '**'] 950 ['right', 'UNARY_MATH'] 951 ['left', 'MATH'] 952 ['left', '+', '-'] 953 ['left', 'SHIFT'] 954 ['left', 'RELATION'] 955 ['left', 'COMPARE'] 956 ['left', '&'] 957 ['left', '^'] 958 ['left', '|'] 959 ['left', '&&'] 960 ['left', '||'] 961 ['left', 'BIN?'] 962 ['nonassoc', 'INDENT', 'OUTDENT'] 963 ['right', 'YIELD'] 964 ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'] 965 ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'] 966 ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT'] 967 ['left', 'POST_IF'] 968] 969 970# Wrapping Up 971# ----------- 972 973# Finally, now that we have our **grammar** and our **operators**, we can create 974# our **Jison.Parser**. We do this by processing all of our rules, recording all 975# terminals (every symbol which does not appear as the name of a rule above) 976# as "tokens". 977tokens = [] 978for name, alternatives of grammar 979 grammar[name] = for alt in alternatives 980 for token in alt[0].split ' ' 981 tokens.push token unless grammar[token] 982 alt[1] = "return #{alt[1]}" if name is 'Root' 983 alt 984 985# Initialize the **Parser** with our list of terminal **tokens**, our **grammar** 986# rules, and the name of the root. Reverse the operators because Jison orders 987# precedence from low to high, and we have it high to low 988# (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)). 989exports.parser = new Parser 990 tokens : tokens.join ' ' 991 bnf : grammar 992 operators : operators.reverse() 993 startSymbol : 'Root' 994