pub const GRAMMAR: &str = "/**\n * @file Squirrel grammar for tree-sitter\n * @author Amaan Qureshi <amaanq12@gmail.com>\n * @license MIT\n * @see {@link http://squirrel-lang.org|official website}\n * @see {@link https://github.com/albertodemichelis/squirrel|official repository}\n * @see {@link http://squirrel-lang.org/squirreldoc/reference/index.html|official spec}\n */\n\n// deno-lint-ignore-file ban-ts-comment\n/* eslint-disable arrow-parens */\n/* eslint-disable camelcase */\n/* eslint-disable-next-line spaced-comment */\n/// <reference types=\"tree-sitter-cli/dsl\" />\n// @ts-check\n\n// http://squirrel-lang.org/squirreldoc/reference/language/expressions.html#operators-precedence\nconst PREC = {\n PAREN: -1,\n ASSIGN: 1,\n TERNARY: 2,\n LOGICAL_OR: 3,\n LOGICAL_AND: 4,\n IN: 4,\n INCLUSIVE_OR: 5,\n EXCLUSIVE_OR: 6,\n BITWISE_AND: 7,\n EQUALITY: 8,\n COMPARISON: 9,\n INSTANCEOF: 9,\n SHIFT: 10,\n ADDITIVE: 11,\n MULTIPLICATIVE: 12,\n UNARY: 13,\n CALL: 14,\n MEMBER: 15,\n};\n\n/**\n * Creates a rule to match zero or more of the rules optionally separated by a comma\n *\n * @param {Rule} rule\n *\n * @return {SeqRule}\n *\n */\nfunction optionalCommaSep(rule) {\n return sep1(rule, optional(\',\'));\n}\n\n/**\n * Creates a rule to match one or more of the rules separated by a comma\n *\n * @param {Rule} rule\n *\n * @return {SeqRule}\n *\n */\nfunction commaSep1(rule) {\n return sep1(rule, \',\');\n}\n\n/**\n * Creates a rule to match zero or more of the rules separated by a comma\n * @param {Rule} rule\n * @return {ChoiceRule}\n */\nfunction commaSep(rule) {\n return optional(commaSep1(rule));\n}\n\n/**\n* Creates a rule to match one or more of the rules separated by the separator\n*\n* @param {Rule} rule\n* @param {string|Rule} separator - The separator to use.\n*\n* @return {SeqRule}\n*\n*/\nfunction sep1(rule, separator) {\n return seq(rule, repeat(seq(separator, rule)));\n}\n\nmodule.exports = grammar({\n name: \'squirrel\',\n\n externals: $ => [\n $.verbatim_string,\n ],\n\n extras: $ => [\n $.comment,\n /\\s/,\n ],\n\n inline: $ => [\n $.expression_statement,\n $._statements,\n $._statement,\n ],\n\n supertypes: $ => [\n $.expression,\n $.primary_expression,\n // $._statement,\n ],\n\n word: $ => $.identifier,\n\n rules: {\n script: $ => optional($._statements),\n\n _statements: $ => repeat1($._statement),\n\n _statement: $ => choice(\n $.block,\n $.if_statement,\n $.while_statement,\n $.do_while_statement,\n $.switch_statement,\n $.for_statement,\n $.foreach_statement,\n $.break,\n $.continue,\n $.return,\n $.yield,\n $.local_declaration,\n $.var_statement,\n $.function_declaration,\n $.class_declaration,\n $.try_statement,\n $.throw_statement,\n $.const_declaration,\n $.enum_declaration,\n $.expression_statement,\n ),\n\n expression_statement: $ =>\n prec.right(choice(\n seq(\n $.expression,\n optional(\';\'),\n ),\n \';\',\n )),\n\n block: $ => seq(\n \'{\',\n repeat($._statement),\n \'}\',\n ),\n\n if_statement: $ => prec.right(1, seq(\n \'if\',\n field(\'condition\', $.parenthesized_expression),\n field(\'consequence\', $._statement),\n optional($.else_statement),\n )),\n else_statement: $ => prec.right(1, seq(\n \'else\',\n field(\'alternative\', $._statement),\n )),\n\n while_statement: $ => prec.right(seq(\n \'while\',\n \'(\', $.expression, \')\',\n optional($._statement),\n // optional(\';\'),\n )),\n\n do_while_statement: $ => prec.right(seq(\n \'do\',\n $._statement,\n \'while\',\n \'(\', $.expression, \')\',\n // optional(\';\'),\n )),\n\n switch_statement: $ => seq(\n \'switch\',\n \'(\', $.expression, \')\',\n \'{\',\n repeat($.case_statement),\n optional($.default_statement),\n \'}\',\n ),\n case_statement: $ => seq(\n \'case\',\n field(\'case\', $.expression),\n \':\',\n repeat($._statement),\n ),\n default_statement: $ => seq(\n \'default\',\n \':\',\n repeat($._statement),\n ),\n\n for_statement: $ => seq(\n \'for\',\n \'(\',\n field(\'initial\', optional(choice($.expression, $.local_declaration))),\n \';\',\n field(\'condition\', optional($.expression)),\n \';\',\n field(\'increment\', optional($.expression)),\n \')\',\n $._statement,\n ),\n\n foreach_statement: $ => seq(\n \'foreach\',\n \'(\',\n optional(seq(field(\'index\', $.identifier), \',\')),\n field(\'value\', $.identifier),\n \'in\',\n field(\'collection\', $.expression),\n \')\',\n $._statement,\n ),\n\n break: _ => seq(\'break\', \';\'),\n\n continue: _ => seq(\'continue\', \';\'),\n\n return: $ => prec.right(seq(\n \'return\',\n optional(choice($.expression, $.table)),\n // NOTE: Feels like it should be explicitly \';\' but some files omit this\n optional(\';\'),\n )),\n\n yield: $ => seq(\n \'yield\',\n optional($.expression),\n choice(\';\', \'\\n\'),\n ),\n\n resume_expression: $ => seq(\n \'resume\',\n $.expression,\n ),\n\n local_declaration: $ => prec.left(seq(\'local\', $._initz, optional(\';\'))),\n _initz: $ => prec.right(seq(\n $.identifier,\n optional(seq(choice(\'=\', \'<-\'), choice($.expression, $.table))),\n optional(seq(\',\', $._initz)),\n )),\n\n function_declaration: $ => seq(\n \'function\',\n $.identifier,\n repeat(seq(\'::\', $.identifier)),\n \'(\',\n optional($.parameters),\n \')\',\n $._statement,\n ),\n parameters: $ => commaSep1($.parameter),\n parameter: $ => choice(\n seq(\n $.identifier,\n optional(seq(\'=\', $.const_value)),\n ),\n \'...\',\n ),\n\n\n class_declaration: $ => seq(\n \'class\',\n $.identifier,\n repeat(seq(\'.\', $.identifier)),\n optional(seq(\'extends\', $.identifier)),\n optional($.attribute_declaration),\n \'{\',\n repeat($.member_declaration),\n \'}\',\n ),\n member_declaration: $ => seq(\n optional($.attribute_declaration),\n choice(\n seq(optional($.qualifier), $.identifier, \'=\', choice($.expression, $.table), optional(\';\')),\n seq(\'[\', $.expression, \']\', \'=\', $.expression, optional(\';\')),\n $.function_declaration,\n seq(\'constructor\', \'(\', optional($.parameters), \')\', $._statement),\n ),\n ),\n qualifier: _ => choice(\n \'static\',\n ),\n\n try_statement: $ => seq(\n \'try\',\n $._statement,\n $.catch_statement,\n ),\n catch_statement: $ => seq(\n \'catch\',\n \'(\',\n $.identifier,\n \')\',\n $._statement,\n ),\n\n throw_statement: $ => prec.right(seq(\n \'throw\',\n $.expression,\n optional(\';\'),\n )),\n\n const_declaration: $ => seq(\n \'const\',\n $.identifier,\n \'=\',\n $.const_value,\n // optional(\';\'),\n choice(\';\', \'\\n\'),\n ),\n const_value: $ => choice(\n $.array,\n $.table,\n $.integer,\n $.float,\n $.string,\n $.verbatim_string,\n $.char,\n $.bool,\n $.null,\n $.call_expression,\n $.identifier,\n $.global_variable,\n ),\n\n enum_declaration: $ => prec.right(seq(\n \'enum\',\n $.identifier,\n optional($.attribute_declaration),\n \'{\',\n commaSep1(seq($.identifier, optional(seq(\'=\', $.const_value)))),\n \'}\',\n optional(\';\'),\n )),\n\n attribute_declaration: $ => seq(\n \'</\',\n commaSep1(\n seq(\n field(\'left\', $.identifier),\n field(\'operator\', \'=\'),\n field(\'right\', $.const_value),\n ),\n ),\n \'/>\',\n ),\n\n expression: $ => choice(\n // $.table,\n $.delete_expression,\n $.clone_expression,\n $.array,\n $.assignment_expression,\n $.update_expression,\n $.resume_expression,\n $.primary_expression,\n ),\n\n primary_expression: $ => prec.right(choice(\n $.unary_expression,\n $.binary_expression,\n $.ternary_expression,\n $.anonymous_function,\n $.deref_expression,\n $.index_expression,\n $.call_expression,\n $.lambda_expression,\n $.parenthesized_expression,\n $.integer,\n $.float,\n $.string,\n $.verbatim_string,\n $.char,\n $.bool,\n $.null,\n $.identifier,\n $.global_variable,\n )),\n\n unary_expression: $ => prec.left(PREC.UNARY, choice(\n seq(\n field(\'operator\', choice(\'-\', \'~\', \'!\', \'typeof\', \'++\', \'--\')),\n field(\'operand\', choice($.expression, $.table)),\n optional(\';\'),\n ),\n seq(\n field(\'operand\', $.expression),\n field(\'operator\', choice(\'++\', \'--\')),\n optional(\';\'),\n ),\n )),\n\n binary_expression: $ => {\n const table = [\n [\'+\', PREC.ADDITIVE],\n [\'-\', PREC.ADDITIVE],\n [\'*\', PREC.MULTIPLICATIVE],\n [\'/\', PREC.MULTIPLICATIVE],\n [\'%\', PREC.MULTIPLICATIVE],\n [\'||\', PREC.LOGICAL_OR],\n [\'&&\', PREC.LOGICAL_AND],\n [\'in\', PREC.IN],\n [\'|\', PREC.INCLUSIVE_OR],\n [\'^\', PREC.EXCLUSIVE_OR],\n [\'&\', PREC.BITWISE_AND],\n [\'==\', PREC.EQUALITY],\n [\'!=\', PREC.EQUALITY],\n [\'<=>\', PREC.COMPARISON],\n [\'>\', PREC.COMPARISON],\n [\'>=\', PREC.COMPARISON],\n [\'<=\', PREC.COMPARISON],\n [\'<\', PREC.COMPARISON],\n [\'instanceof\', PREC.INSTANCEOF],\n [\'<<\', PREC.SHIFT],\n [\'>>\', PREC.SHIFT],\n [\'>>>\', PREC.SHIFT],\n ];\n\n return choice(...table.map(([operator, precedence]) => {\n return prec.left(precedence, seq(\n field(\'left\', $.expression),\n // @ts-ignore\n field(\'operator\', operator),\n field(\'right\', $.expression),\n optional(\';\'),\n ));\n }));\n },\n\n ternary_expression: $ => prec.right(PREC.TERNARY, seq(\n field(\'condition\', $.expression),\n \'?\',\n field(\'consequence\', choice($.expression, $.table)),\n \':\',\n field(\'alternative\', choice($.expression, $.table)),\n )),\n\n assignment_expression: $ => prec.right(PREC.ASSIGN, seq(\n field(\'left\', $.expression),\n field(\'operator\', \'=\'),\n field(\'right\', choice($.expression, $.table)),\n )),\n\n update_expression: $ => prec.right(PREC.ASSIGN, seq(\n field(\'left\', $.expression),\n field(\'operator\', choice(\n \'<-\',\n \'+=\',\n \'-=\',\n \'*=\',\n \'/=\',\n \'%=\',\n )),\n field(\'right\', choice($.expression, $.table)),\n )),\n\n table: $ => prec.right(seq(\n \'{\',\n optional($.table_slots),\n \'}\',\n optional(seq(\'.\', $.expression)),\n )),\n table_slots: $ => seq(\n optionalCommaSep($.table_slot),\n optional(\',\'),\n ),\n table_slot: $ => choice(\n seq($.identifier, \'=\', choice($.expression, $.table)),\n seq(\'[\', $.expression, \']\', \'=\', choice($.expression, $.table)),\n seq($.expression, \':\', choice($.expression, $.table)),\n $.function_declaration,\n ),\n\n delete_expression: $ => seq(\n \'delete\',\n $.expression,\n choice(\';\', \'\\n\'),\n ),\n\n var_statement: $ => (seq(\n \'var\',\n $.identifier,\n \'=\',\n $.expression,\n )),\n\n deref_expression: $ => prec(PREC.MEMBER, choice(\n seq(\n $.expression,\n \'.\',\n $.identifier,\n ),\n )),\n\n index_expression: $ => prec.left(PREC.MEMBER, seq(\n field(\'object\', $.expression),\n \'[\',\n field(\'index\', $.expression),\n \']\',\n )),\n\n call_expression: $ => prec.left(PREC.CALL, seq(\n choice(field(\'function\', $.expression), \'rawcall\'),\n \'(\',\n optional($.call_args),\n \')\',\n )),\n\n call_args: $ => commaSep1(choice(\n $.expression,\n $.table,\n )),\n anonymous_function: $ => seq(\n \'function\',\n \'(\',\n optional($.parameters),\n \')\',\n $._statement,\n ),\n\n lambda_expression: $ => seq(\n \'@\',\n \'(\',\n optional($.parameters),\n \')\',\n $.expression,\n ),\n\n parenthesized_expression: $ => prec(PREC.PAREN, seq(\n \'(\',\n $.expression,\n \')\',\n )),\n\n clone_expression: $ => prec.right(seq(\n \'clone\',\n $.expression,\n // optional(\';\'),\n )),\n\n array: $ => prec.right(seq(\n \'[\',\n commaSep($.expression),\n optional(\',\'),\n \']\',\n )),\n\n identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,\n global_variable: $ => seq(\'::\', $.identifier),\n\n // IntegerLiteral ::= [1-9][0-9]* | \'0x\' [0-9A-Fa-f]+ | \'\'\' [.]+ \'\'\' | 0[0-7]+\n integer: _ => token(choice(\n /0/,\n /-?[1-9][0-9]*/,\n /0[xX][0-9A-Fa-f]+/,\n /\'\'\'[.]+\'\'\'/,\n /0[0-7]+/,\n )),\n\n // FloatLiteral ::= [0-9]+ \'.\' [0-9]+\n // FloatLiteral ::= [0-9]+ \'.\' \'e\'|\'E\' \'+\'|\'-\' [0-9]+\n float: _ => token(choice(\n /-?[0-9]+\\.[0-9]+/,\n /[0-9]+\\.[eE][+-]?[0-9]+/,\n )),\n\n string: $ => seq(\n \'\"\',\n repeat(choice(\n $.string_content,\n $._escape_sequence,\n )),\n \'\"\',\n ),\n\n // Workaround to https://github.com/tree-sitter/tree-sitter/issues/1156\n // We give names to the token_ constructs containing a regexp\n // so as to obtain a node in the CST.\n string_content: _ => token.immediate(prec(1, /[^\"\\\\]+/)),\n\n char: $ => choice(\n seq(\n \'\\\'\',\n choice(\n $.escape_sequence,\n /[^\\\\\']/,\n ),\n \'\\\'\',\n ),\n // workaround because for some reason the char literal \'#\' is being interpreted as a comment\n \'\\\'#\\\'\',\n ),\n\n _escape_sequence: $ =>\n choice(\n prec(2, token.immediate(seq(\'\\\\\', /[^abfnrtvxu\'\\\"\\\\\\?]/))),\n prec(1, $.escape_sequence),\n ),\n\n escape_sequence: _ => token.immediate(seq(\n \'\\\\\',\n choice(\n /[^xu0-7]/,\n /[0-7]{1,3}/,\n /x[0-9a-fA-F]{2}/,\n /u[0-9a-fA-F]{4}/,\n /u{[0-9a-fA-F]+}/,\n ))),\n\n bool: _ => choice(\'true\', \'false\'),\n\n null: _ => \'null\',\n\n comment: _ =>\n token(\n choice(\n seq(\'#\', /.*/),\n seq(\'//\', /(\\\\(.|\\r?\\n)|[^\\\\\\n])*/),\n seq(\'/*\', /[^*]*\\*+([^/*][^*]*\\*+)*/, \'/\'),\n ),\n ),\n },\n});\n\nmodule.exports.PREC = PREC;\n";Expand description
The source of the Rust tree-sitter grammar description.