/** * @file SCL grammar for tree-sitter * @author Jacob Signorovitch * @license MIT */ /// // @ts-check module.exports = grammar({ name: "scl", conflicts: ($) => [[$.params, $._exp]], rules: { source_file: ($) => repeat($._exp), _exp: ($) => choice( $.num, $.bool, $.word, $.binexp, $.eqexp, $.vardef, $.callexp, $.funcdef, $.lambda, $.seqexp, $.ifexp, $.tern_ifexp, $.block, $.parexp, ), num: (_) => /\d+/, bool: (_) => choice("T", "F"), word: (_) => /[a-zA-Z_]\w*/, seqexp: ($) => prec.left( -1, // lowest seq(field("first", $._exp), repeat1(seq(";", field("rest", $._exp)))), ), vardef: ($) => prec.right(1, seq(field("name", $.word), "=", field("value", $._exp))), eqexp: ($) => prec.left(2, seq(field("left", $._exp), "==", field("right", $._exp))), binexp: ($) => choice( prec.left( 3, seq( field("left", $._exp), field("op", choice("+", "-")), field("right", $._exp), ), ), prec.left( 4, seq( field("left", $._exp), field("op", choice("*", "/")), field("right", $._exp), ), ), ), callexp: ($) => prec.left( 5, seq(field("fn", $.word), "(", optional(commaSep($._exp)), ")"), ), funcdef: ($) => prec.right( 6, seq( field("name", $.word), field("params", $.params), field("body", $._exp), ), ), lambda: ($) => prec.right( 6, seq("\\", field("params", $.params), field("body", $._exp)), ), parexp: ($) => seq("(", $._exp, ")"), block: ($) => seq("{", repeat($._exp), "}"), params: ($) => seq("(", optional(commaSep($.word)), ")"), ifexp: ($) => prec.right( seq( "if", field("cond", $._exp), field("then", $._exp), optional("else"), field("else", $._exp), ), ), tern_ifexp: ($) => seq( "?", field("cond", $._exp), field("then", $._exp), field("else", $._exp), ), }, }); function commaSep(rule) { return seq(rule, repeat(seq(",", rule))); }