126 lines
2.4 KiB
JavaScript
126 lines
2.4 KiB
JavaScript
/**
|
|
* @file SCL grammar for tree-sitter
|
|
* @author Jacob Signorovitch <jacob.signorovitch@gmail.com>
|
|
* @license MIT
|
|
*/
|
|
|
|
/// <reference types="tree-sitter-cli/dsl" />
|
|
// @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)));
|
|
}
|