From 579ac2a9752a0ac212dea77b281417ee2b5dab14 Mon Sep 17 00:00:00 2001 From: Duologic Date: Tue, 18 Jul 2023 19:51:38 +0200 Subject: [PATCH 1/2] style: fmt --- Makefile | 3 + grammar.js | 223 +++++++++++++++++++++++++++++------------------------ 2 files changed, 126 insertions(+), 100 deletions(-) diff --git a/Makefile b/Makefile index 5783211..9cc974c 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,6 @@ generate: test: generate ${ts} test + +fmt: + npx prettier --tab-width 4 -w grammar.js diff --git a/grammar.js b/grammar.js index 9e02b63..a3553a3 100644 --- a/grammar.js +++ b/grammar.js @@ -24,7 +24,7 @@ module.exports = grammar({ name: "jsonnet", extras: ($) => [/\s/, $.comment], externals: ($) => [$._string_start, $._string_content, $._string_end], - word: $ => $._ident, + word: ($) => $._ident, inline: ($) => [$.h, $.objinside], conflicts: () => [], @@ -36,34 +36,34 @@ module.exports = grammar({ choice( seq("//", /.*/), seq("#", /.*/), - seq("/*", /[^*]*\*+([^/*][^*]*\*+)*/, "/") - ) + seq("/*", /[^*]*\*+([^/*][^*]*\*+)*/, "/"), + ), ), expr: ($) => - choice( - $.null, - $.true, - $.false, - $.self, - $.dollar, - $.string, - $.number, - seq("{", optional($.objinside), "}"), - seq("[", commaSep($.expr, true), "]"), + choice( + $.null, + $.true, + $.false, + $.self, + $.dollar, + $.string, + $.number, + seq("{", optional($.objinside), "}"), + seq("[", commaSep($.expr, true), "]"), + seq( + "[", + $.expr, + optional(","), + $.forspec, + optional($.compspec), + "]", + ), + prec(PREC.application_indexing, seq($.expr, ".", $.id)), + seq($.super, ".", $.id), + prec( + PREC.application_indexing, seq( - "[", - $.expr, - optional(","), - $.forspec, - optional($.compspec), - "]" - ), - prec(PREC.application_indexing, - seq($.expr, ".", $.id)), - seq($.super, ".", $.id), - prec(PREC.application_indexing, - seq( $.expr, "[", optional($.expr), @@ -71,38 +71,50 @@ module.exports = grammar({ seq( ":", optional($.expr), - optional(seq(":", optional($.expr))) - ) + optional(seq(":", optional($.expr))), + ), ), - "]" - )), - seq($.super, "[", $.expr, "]"), - prec(PREC.application_indexing, - seq($.expr, "(", optional($.args), ")", optional($.tailstrict))), - $.id, - $.local_bind, - prec.right(seq( + "]", + ), + ), + seq($.super, "[", $.expr, "]"), + prec( + PREC.application_indexing, + seq( + $.expr, + "(", + optional($.args), + ")", + optional($.tailstrict), + ), + ), + $.id, + $.local_bind, + prec.right( + seq( "if", field("condition", $.expr), "then", field("consequence", $.expr), - optional(seq("else", field("alternative", $.expr))) - )), - $._binary_expr, - prec(PREC.unary, - seq( - field("operator", $.unaryop), - field("argument", $.expr) - ) + optional(seq("else", field("alternative", $.expr))), + ), + ), + $._binary_expr, + prec( + PREC.unary, + seq( + field("operator", $.unaryop), + field("argument", $.expr), ), - seq($.expr, "{", $.objinside, "}"), - $.anonymous_function, - prec.right(seq($.assert, ";", $.expr)), - $.import, - $.importstr, - $.expr_error, - seq($.expr, "in", $.super), - seq("(", $.expr, ")") + ), + seq($.expr, "{", $.objinside, "}"), + $.anonymous_function, + prec.right(seq($.assert, ";", $.expr)), + $.import, + $.importstr, + $.expr_error, + seq($.expr, "in", $.super), + seq("(", $.expr, ")"), ), // Literals @@ -118,25 +130,30 @@ module.exports = grammar({ tailstrict: () => "tailstrict", _binary_expr: ($) => { - const table = [ - [PREC.multiplicative, choice("*", "/", "%")], - [PREC.additive, choice("+", "-")], - [PREC.bitshift, choice("<<", ">>")], - [PREC.comparison, choice("<", "<=", ">", ">=")], - [PREC.equality, choice("==", "!=")], - [PREC.bitand, '&'], - [PREC.bitxor, '^'], - [PREC.bitor, '|'], - [PREC.and, '&&'], - [PREC.or, '||'], - ]; - return choice(...table.map(([precedence, operator]) => - prec.left(precedence, seq( - field('left', $.expr), - field('operator', operator), - field('right', $.expr) - )) - )); + const table = [ + [PREC.multiplicative, choice("*", "/", "%")], + [PREC.additive, choice("+", "-")], + [PREC.bitshift, choice("<<", ">>")], + [PREC.comparison, choice("<", "<=", ">", ">=")], + [PREC.equality, choice("==", "!=")], + [PREC.bitand, "&"], + [PREC.bitxor, "^"], + [PREC.bitor, "|"], + [PREC.and, "&&"], + [PREC.or, "||"], + ]; + return choice( + ...table.map(([precedence, operator]) => + prec.left( + precedence, + seq( + field("left", $.expr), + field("operator", operator), + field("right", $.expr), + ), + ), + ), + ); }, unaryop: () => choice("-", "+", "!", "~"), @@ -151,8 +168,8 @@ module.exports = grammar({ "(", optional(field("params", $.params)), ")", - field("body", $.expr) - ) + field("body", $.expr), + ), ), // import string @@ -178,8 +195,8 @@ module.exports = grammar({ repeat(seq(",", $.objlocal)), optional(","), $.forspec, - optional($.compspec) - ) + optional($.compspec), + ), ), member: ($) => @@ -188,7 +205,7 @@ module.exports = grammar({ field: ($) => choice( seq($.fieldname, optional("+"), $.h, $.expr), - seq($.fieldname, "(", optional($.params), ")", $.h, $.expr) + seq($.fieldname, "(", optional($.params), ")", $.h, $.expr), ), h: () => choice(":", "::", ":::"), @@ -215,16 +232,16 @@ module.exports = grammar({ optional(field("params", $.params)), ")", "=", - field("body", $.expr) - ) - ) + field("body", $.expr), + ), + ), ), params: ($) => commaSep1($.param, true), param: ($) => seq( field("identifier", $.id), - optional(seq("=", field("value", $.expr))) + optional(seq("=", field("value", $.expr))), ), args: ($) => @@ -233,20 +250,20 @@ module.exports = grammar({ $.expr, repeat(seq(",", $.expr)), repeat(seq(",", $.named_argument)), - optional(",") + optional(","), ), seq( $.named_argument, repeat(seq(",", $.named_argument)), - optional(",") - ) + optional(","), + ), ), named_argument: ($) => seq($.id, "=", $.expr), id: ($) => $._ident, - // This use of an intermediate rule for identifiers is to - // overcome some limitations in ocaml-tree-sitter-semgrep. - // Indeed, ocaml-tree-sitter-semgrep can't override terminals (here was id) - // that are also mentioned in the 'word:' directive. + // This use of an intermediate rule for identifiers is to + // overcome some limitations in ocaml-tree-sitter-semgrep. + // Indeed, ocaml-tree-sitter-semgrep can't override terminals (here was id) + // that are also mentioned in the 'word:' directive. _ident: () => /[_a-zA-Z][_a-zA-Z0-9]*/, // COPIED FROM: tree-sitter-json @@ -256,7 +273,7 @@ module.exports = grammar({ const decimal_digits = /\d+/; const signed_integer = seq( optional(choice("-", "+")), - decimal_digits + decimal_digits, ); const exponent_part = seq(choice("e", "E"), signed_integer); @@ -266,7 +283,7 @@ module.exports = grammar({ const decimal_integer_literal = seq( optional(choice("-", "+")), - choice("0", seq(/[1-9]/, optional(decimal_digits))) + choice("0", seq(/[1-9]/, optional(decimal_digits))), ); const decimal_literal = choice( @@ -274,10 +291,10 @@ module.exports = grammar({ decimal_integer_literal, ".", optional(decimal_digits), - optional(exponent_part) + optional(exponent_part), ), seq(".", decimal_digits, optional(exponent_part)), - seq(decimal_integer_literal, optional(exponent_part)) + seq(decimal_integer_literal, optional(exponent_part)), ); return token( @@ -285,8 +302,8 @@ module.exports = grammar({ hex_literal, decimal_literal, binary_literal, - octal_literal - ) + octal_literal, + ), ); }, @@ -296,33 +313,33 @@ module.exports = grammar({ seq( optional("@"), alias($._single, $.string_start), - alias($._single, $.string_end) + alias($._single, $.string_end), ), seq( optional("@"), alias($._single, $.string_start), alias($._str_single, $.string_content), - alias($._single, $.string_end) + alias($._single, $.string_end), ), // Double Quotes seq( optional("@"), alias($._double, $.string_start), - alias($._double, $.string_end) + alias($._double, $.string_end), ), seq( optional("@"), alias($._double, $.string_start), alias($._str_double, $.string_content), - alias($._double, $.string_end) + alias($._double, $.string_end), ), // ||| Quotes seq( optional("@"), alias($._string_start, $.string_start), alias($._string_content, $.string_content), - alias($._string_end, $.string_end) - ) + alias($._string_end, $.string_end), + ), ), _single: () => "'", @@ -330,12 +347,18 @@ module.exports = grammar({ _str_double: ($) => repeat1( - choice(token.immediate(prec(1, /[^\\"\n]+/)), $.escape_sequence) + choice( + token.immediate(prec(1, /[^\\"\n]+/)), + $.escape_sequence, + ), ), _str_single: ($) => repeat1( - choice(token.immediate(prec(1, /[^\\'\n]+/)), $.escape_sequence) + choice( + token.immediate(prec(1, /[^\\'\n]+/)), + $.escape_sequence, + ), ), escape_sequence: () => From b260c3da2ea43dd93eab3e980c8237d1536e3002 Mon Sep 17 00:00:00 2001 From: Duologic Date: Tue, 18 Jul 2023 20:20:29 +0200 Subject: [PATCH 2/2] refactor: cleaner $.expr + match order to abstract syntax (from jsonnet spec) --- grammar.js | 185 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 79 deletions(-) diff --git a/grammar.js b/grammar.js index a3553a3..1069920 100644 --- a/grammar.js +++ b/grammar.js @@ -49,72 +49,27 @@ module.exports = grammar({ $.dollar, $.string, $.number, - seq("{", optional($.objinside), "}"), - seq("[", commaSep($.expr, true), "]"), - seq( - "[", - $.expr, - optional(","), - $.forspec, - optional($.compspec), - "]", - ), - prec(PREC.application_indexing, seq($.expr, ".", $.id)), - seq($.super, ".", $.id), - prec( - PREC.application_indexing, - seq( - $.expr, - "[", - optional($.expr), - optional( - seq( - ":", - optional($.expr), - optional(seq(":", optional($.expr))), - ), - ), - "]", - ), - ), - seq($.super, "[", $.expr, "]"), - prec( - PREC.application_indexing, - seq( - $.expr, - "(", - optional($.args), - ")", - optional($.tailstrict), - ), - ), + $._object, + $._array, + $._array_for, + $._expr_id, + $._expr_expr, + $._super_id, + $._super_expr, + $._expr_args, $.id, $.local_bind, - prec.right( - seq( - "if", - field("condition", $.expr), - "then", - field("consequence", $.expr), - optional(seq("else", field("alternative", $.expr))), - ), - ), + $._conditional, $._binary_expr, - prec( - PREC.unary, - seq( - field("operator", $.unaryop), - field("argument", $.expr), - ), - ), - seq($.expr, "{", $.objinside, "}"), + $._unary_expr, + $._expr_objinside, $.anonymous_function, - prec.right(seq($.assert, ";", $.expr)), + $._assert_expr, $.import, $.importstr, $.expr_error, - seq($.expr, "in", $.super), - seq("(", $.expr, ")"), + $._expr_super, + $._parenthesis, ), // Literals @@ -129,6 +84,73 @@ module.exports = grammar({ local: () => "local", tailstrict: () => "tailstrict", + // Types + number: ($) => $._number, + string: ($) => $._string, + _object: ($) => seq("{", optional($.objinside), "}"), + _array: ($) => seq("[", commaSep($.expr, true), "]"), + + _array_for: ($) => + seq( + "[", + $.expr, + optional(","), + $.forspec, + optional($.compspec), + "]", + ), + + _expr_id: ($) => + prec(PREC.application_indexing, seq($.expr, ".", $.id)), + + _expr_expr: ($) => + prec( + PREC.application_indexing, + seq( + $.expr, + "[", + optional($.expr), + optional( + seq( + ":", + optional($.expr), + optional(seq(":", optional($.expr))), + ), + ), + "]", + ), + ), + + _super_id: ($) => seq($.super, ".", $.id), + _super_expr: ($) => seq($.super, "[", $.expr, "]"), + + _expr_args: ($) => + prec( + PREC.application_indexing, + seq($.expr, "(", optional($.args), ")", optional($.tailstrict)), + ), + + id: ($) => $._ident, + // This use of an intermediate rule for identifiers is to + // overcome some limitations in ocaml-tree-sitter-semgrep. + // Indeed, ocaml-tree-sitter-semgrep can't override terminals (here was id) + // that are also mentioned in the 'word:' directive. + _ident: () => /[_a-zA-Z][_a-zA-Z0-9]*/, + + local_bind: ($) => + prec.right(seq($.local, commaSep1($.bind, false), ";", $.expr)), + + _conditional: ($) => + prec.right( + seq( + "if", + field("condition", $.expr), + "then", + field("consequence", $.expr), + optional(seq("else", field("alternative", $.expr))), + ), + ), + _binary_expr: ($) => { const table = [ [PREC.multiplicative, choice("*", "/", "%")], @@ -156,10 +178,15 @@ module.exports = grammar({ ); }, + _unary_expr: ($) => + prec( + PREC.unary, + seq(field("operator", $.unaryop), field("argument", $.expr)), + ), + unaryop: () => choice("-", "+", "!", "~"), - local_bind: ($) => - prec.right(seq($.local, commaSep1($.bind, false), ";", $.expr)), + _expr_objinside: ($) => seq($.expr, "{", $.objinside, "}"), anonymous_function: ($) => prec.right( @@ -172,6 +199,8 @@ module.exports = grammar({ ), ), + _assert_expr: ($) => prec.right(seq($.assert, ";", $.expr)), + // import string import: ($) => seq("import", $.string), @@ -181,6 +210,10 @@ module.exports = grammar({ // error expr expr_error: ($) => prec.right(seq("error", $.expr)), + _expr_super: ($) => seq($.expr, "in", $.super), + + _parenthesis: ($) => seq("(", $.expr, ")"), + objinside: ($) => choice( // seq($.member, repeat(seq(",", $.member)), optional(",")), @@ -210,9 +243,6 @@ module.exports = grammar({ h: () => choice(":", "::", ":::"), - // assert in objects - assert: ($) => seq("assert", $.expr, optional(seq(":", $.expr))), - objlocal: ($) => seq($.local, $.bind), compspec: ($) => repeat1(choice($.forspec, $.ifspec)), @@ -222,6 +252,9 @@ module.exports = grammar({ fieldname: ($) => prec.right(choice($.id, $.string, seq("[", $.expr, "]"))), + // assert in objects + assert: ($) => seq("assert", $.expr, optional(seq(":", $.expr))), + bind: ($) => choice( seq($.id, "=", $.expr), @@ -237,13 +270,6 @@ module.exports = grammar({ ), ), - params: ($) => commaSep1($.param, true), - param: ($) => - seq( - field("identifier", $.id), - optional(seq("=", field("value", $.expr))), - ), - args: ($) => choice( seq( @@ -259,15 +285,16 @@ module.exports = grammar({ ), ), named_argument: ($) => seq($.id, "=", $.expr), - id: ($) => $._ident, - // This use of an intermediate rule for identifiers is to - // overcome some limitations in ocaml-tree-sitter-semgrep. - // Indeed, ocaml-tree-sitter-semgrep can't override terminals (here was id) - // that are also mentioned in the 'word:' directive. - _ident: () => /[_a-zA-Z][_a-zA-Z0-9]*/, + + params: ($) => commaSep1($.param, true), + param: ($) => + seq( + field("identifier", $.id), + optional(seq("=", field("value", $.expr))), + ), // COPIED FROM: tree-sitter-json - number: () => { + _number: () => { const hex_literal = seq(choice("0x", "0X"), /[\da-fA-F]+/); const decimal_digits = /\d+/; @@ -307,7 +334,7 @@ module.exports = grammar({ ); }, - string: ($) => + _string: ($) => choice( // Single Quotes seq(