Untangle existing code for grammar

This commit is contained in:
Kirill Andreev 2020-08-11 16:37:53 +04:00
parent f1938eb2af
commit 78c408b76a
No known key found for this signature in database
GPG Key ID: CF7DA79DE4785A47

View File

@ -1,471 +1,373 @@
let sepBy1 = (sep, rule) =>
seq(
rule,
repeat(seq(sep, rule)),
optional(sep)
)
let sepBy1 = (sep, p) => seq(p, repeat(seq(sep, p)))
let sepBy = (sep, p) => optional(sepBy1(sep, p))
let sepBy = (sep, rule) => optional(sepBy1(sep, rule))
let par = x => seq('(', x, ')')
let brackets = x => seq('[', x, ']')
let ne_injection = (Kind, element) =>
choice(
seq(
Kind,
sepBy1(';', element),
'end',
),
seq(
Kind,
'[',
sepBy1(';', element),
']',
),
)
let injection = (Kind, element) =>
choice(
seq(
Kind,
sepBy(';', element),
'end',
),
seq(
Kind,
'[',
sepBy(';', element),
']',
),
)
let tuple = x => seq(x, ',', x, repeat(seq(',', x)))
let list__ = x => brackets(sepBy(';', x))
let nseq = x => seq(x, repeat(x))
let op = (l, x, r, def) =>
choice(
seq(l, x, r),
def,
)
let rop = (l, x, r) => op(l, x, r, r)
let lop = (l, x, r) => op(l, x, r, l)
function mkOp($, opExpr) {
return seq(
field("arg1", $._expr),
field("op", opExpr),
field("arg2", $._expr)
);
}
module.exports = grammar({
name: 'CAMLigo',
word: $ => $.Keyword,
extras: $ => [$.ocaml_comment, $.comment, /\s/],
conflicts: $ => [[$.call, $.if_then_else]],
name: 'CameLigo',
extras: $ => [$.comment, $.ocaml_comment, /\s/],
rules: {
// debug: $ => $.expr,
// contract: $ => repeat($.declaration),
contract: $ => $.expr,
contract: $ => repeat($._declaration),
expr: $ =>
choice(
$.let_expr,
$.op_call,
),
let_expr: $ =>
prec.left(0,
seq(
'let',
$.let_binding,
repeat($.attr),
'in',
$.expr,
),
),
op_call: $ =>
$.tuple,
tuple: $ => prec.left(2, rop($.tuple, ',', $.disj)),
disj: $ => prec.left(3, rop($.disj, $.or, $.conj)),
conj: $ => prec.left(4, rop($.conj, $.and, $.comp)),
comp: $ => prec.left(5, rop($.comp, $.compare, $.cat)),
cat: $ => prec.left(6, lop($.cons, $.catenate, $.cat)),
cons: $ => prec.right(7, lop($.add, $.consolidate, $.cons)),
add: $ => prec.left(8, rop($.add, $.plus, $.mult)),
mult: $ => prec.left(9, rop($.mult, $.times, $.unary)),
unary: $ =>
seq(
optional($.negate),
$.call,
),
or: $ => choice('||', 'or'),
and: $ => '&&',
compare: $ => choice('<', '<=', '>', '>=', '=', '<>'),
catenate: $ => '^',
consolidate: $ => '::',
plus: $ => choice('+', '-'),
times: $ => choice('*', '/', 'mod'),
negate: $ => choice('-', 'not'),
call: $ =>
prec.left(1,
choice(
seq($.call, $.term),
$.term,
),
),
term: $ =>
choice(
$.ref,
$.if_then_else,
$.literal,
$.match,
),
match: $ =>
prec.right(0,
seq(
'match',
$.expr,
'with',
optional('|'),
sepBy1('|', $.alt),
),
),
alt: $ =>
prec.right(0,
seq(
$.pattern,
'->',
$.expr,
),
),
literal: $ =>
choice(
$.Nat,
$.Int,
$.Tez,
$.String,
$.Bytes,
$.group,
$.annotation,
$.list,
$.lambda,
$.unit,
$.record,
$.record_update,
),
record: $ =>
seq(
'{',
sepBy1(';', $.record_field),
'}',
),
record_update: $ =>
seq(
'{',
$.name,
'with',
sepBy1(';', $.record_field_update),
'}',
),
record_field_update: $ =>
seq(
sepBy1('.', $.name),
'=',
$.expr,
),
record_field: $ =>
seq(
$.name,
'=',
$.expr,
),
unit: $ => seq('(', ')'),
lambda: $ =>
seq(
'fun',
repeat($.pattern_term),
'->',
$.expr,
),
list: $ =>
seq(
'[',
sepBy(';', $.expr),
']',
),
annotation: $ =>
seq(
'(',
$.expr,
':',
$.type_expr,
')',
),
group: $ =>
seq(
'(',
$.expr,
')',
),
if_then_else: $ =>
prec.right(0,
seq(
'if',
$.expr,
'then',
$.expr,
'else',
$.expr,
),
),
ref: $ =>
choice(
$.module_qualified,
$.struct_qualified,
$.name,
$.constr,
),
module_qualified: $ =>
seq(
$.constr,
'.',
$.name,
),
struct_qualified: $ =>
seq(
$.name,
nseq(seq('.', $.accessor)),
),
accessor: $ => choice($.name, $.Int),
declaration: $ =>
choice(
$.type_decl,
$.let_declaration,
),
type_decl: $ =>
seq(
'type',
$.type_name,
'=',
$.type_expr,
),
type_expr: $ =>
choice(
$.fun_type,
$.sum_type,
$.record_type,
),
fun_type: $ =>
seq(
$.cartesian,
optional(seq('->', $.fun_type)),
),
cartesian: $ =>
prec.left(1,
seq(
$.core_type,
optional(seq('*', sepBy('*', $.core_type))),
),
),
core_type: $ =>
choice(
$.type_name,
par($.type_expr),
$.module_type_name,
$.type_application
),
module_type_name: $ =>
seq(
$.module_name,
'.',
$.type_name,
),
type_application: $ =>
seq(
choice($.core_type, $.type_tuple),
$.type_name,
),
type_tuple: $ =>
par(tuple($.type_expr)),
sum_type: $ =>
seq(
optional('|'),
sepBy1('|', $.variant),
),
variant: $ =>
seq(
$.constr,
optional(seq('of', $.fun_type)),
),
record_type: $ =>
seq(
'{',
sepBy(';', $.field_decl),
'}',
),
field_decl: $ =>
seq(
$.field_name,
':',
$.type_expr,
),
let_declaration: $ =>
seq(
'let',
optional($.rec),
$.let_binding,
repeat($.attr),
),
let_binding: $ =>
choice(
seq(
$.name,
nseq($.pattern_term),
optional($.type_annotation),
'=',
$.expr,
),
seq(
$.pattern,
optional($.type_annotation),
'=',
$.expr,
),
),
type_annotation: $ => seq(':', $.type_expr),
pattern_term: $ =>
choice(
$.pattern_record,
$.constr,
$.pattern_list,
$.pattern_constant,
$.name,
$.pattern_grouped,
),
pattern_grouped: $ =>
seq(
'(',
$.pattern,
optional($.type_annotation),
')',
),
pattern_list: $ => list__($.pattern),
pattern_constant: $ =>
choice(
$.Nat,
$.String,
$.Bytes,
$.Int,
),
pattern_record: $ =>
seq(
'{',
sepBy1(';', $.pattern_record_field),
'}',
),
pattern_record_field: $ =>
seq(
$.name,
'=',
$.pattern,
),
pattern: $ => sepBy1('::', $.pattern_tuple),
pattern_tuple: $ => sepBy1(',', $.construct),
construct: $ =>
choice(
seq($.constr, nseq($.pattern_term)),
$.pattern_term,
),
///////////////////////////////////////////
type_name: $ => $.ident,
field_name: $ => $.ident,
fun_name: $ => $.ident,
struct_name: $ => $.ident,
var: $ => $.ident,
module_name: $ => $.Name_Capital,
constr: $ => $.Name_Capital,
ident: $ => $.Name,
name: $ => $.Name,
comment: $ => /\/\/[^\n]*\n/,
ocaml_comment: $ => seq(
'(*',
repeat(choice(
$.ocaml_comment,
/[^\(]|\(?!\*/,
)),
'*)'
_declaration: $ => choice(
$.let_decl,
$.type_decl
),
include: $ => seq('#include', $.String),
type_annot: $ => seq(
":",
field("annotExpr", $.type_expr)
),
String: $ => /\"(\\.|[^"])*\"/,
Int: $ => /-?([1-9][0-9_]*|0)/,
Nat: $ => /([1-9][0-9_]*|0)n/,
Tez: $ => /([1-9][0-9_]*|0)(\.[0-9_]+)?(tz|tez|mutez)/,
Bytes: $ => /0x[0-9a-fA-F]+/,
Name: $ => /[a-z][a-zA-Z0-9_]*/,
argument: $ => seq(
"(",
field("argPattern", $._pattern),
field("argAnnot", $.type_annot),
")"
),
let_decl: $ => seq(
"let",
field("binder", $._binder),
optional(field("bindAnnot", $.type_annot)),
"=",
field("letExpr",$._let_expr)
),
_binder: $ => choice(
field("letBinds", $.let_binds),
field("letPat", $.let_pat)
),
//========== EXPR ============
_let_expr: $ => choice(
$.let_expr1,
$._expr
),
let_binds: $ => prec(1, seq(
optional(field("recursive", "rec")),
field("bindName", $.Name),
repeat(field("bindArgument", $.argument))
)),
let_pat: $ => $._pattern,
let_expr1: $ => seq(
"let",
choice(field("letBinds", $.let_binds), field("letPat", $.let_pat)),
optional(field("bindAnnot", $.type_annot)),
"=",
field("letExpr",$._expr),
"in",
field("innerExpr", $._let_expr)
),
// [1;2]
list_pattern: $ => seq(
"[",
sepBy1(';', field("patternListItem", $._pattern)),
"]"
),
// a :: b
list_con_pattern: $ => prec.right(9, seq(
field("patX", $._pattern),
"::",
field("patXs", $._pattern)
)),
// a, b, c
tup_pattern: $ => prec.right(8,seq(
field("tuplePatternItem", $._pattern),
",",
sepBy1(",", field("tuplePatternItem", $._pattern))
)),
_pattern: $ => choice(
$.Name,
$.paren_pattern,
$.con_pattern,
$._literal,
$.list_pattern,
$.list_con_pattern,
$.tup_pattern,
"_"
),
con_pattern: $ => prec(10,
seq(
field("conPattern", $.data_con),
optional(field("conArgPattern",$._pattern))
)
),
paren_pattern: $ => seq(
"(",
field("innerPattern", $._pattern),
")"
),
call: $ => choice(
$.unary_op_app,
$._mod_op_app,
$._mul_op_app,
$._add_op_app,
$._list_con_op_app,
$._string_cat_op_app,
$._bool_op_app,
$._comp_op_app
),
_mod_op_app: $ => prec.left(16, mkOp($, "mod")),
_mul_op_app: $ => prec.left(15, mkOp($, choice("/", "*"))),
_add_op_app: $ => prec.left(14, mkOp($, choice("-", "+"))),
_list_con_op_app: $ => prec.right(13, mkOp($, "::")),
_string_cat_op_app: $ => prec.right(12, mkOp($, "^")),
_bool_op_app: $ => prec.left(11, mkOp($, choice("&&", "||"))),
_comp_op_app: $ => prec.left(10, mkOp($, choice("=", "<>", "==", "<", "<=", ">", ">="))),
// - a
unary_op_app: $ => prec(19, choice(
seq(field("unaryOp", "-"), field("arg", $._expr))),
),
// f a
fun_app: $ => prec.left(20, seq(field("appF", $.sub_expr), field("appArg",$.sub_expr))),
// a.0
index_accessor: $ => prec.right(21, seq(field("exp", $.sub_expr), ".", field("ix", $.sub_expr))),
// { p with a = b; c = d }
rec_expr: $ => seq(
"{",
optional(seq(field("updateTarget", $.Name), "with")),
field("assignment", $.rec_assignment),
repeat(seq(";", field("assignment", $.rec_assignment))),
optional(";"),
"}"
),
// a = b;
rec_assignment: $ => seq(
field("assignmentLabel", $._expr),
"=",
field("assignmentExpr", $._expr),
),
// if a then b else c
if_expr: $ => seq(
"if",
field("condition", $._expr),
"then",
field("thenBranch", $._expr),
"else",
field("elseBranch", $._expr)
),
// match x with ...
match_expr: $ => prec.right(1,seq(
"match",
field("matchTarget", $._expr),
"with",
optional('|'),
sepBy('|', field("matching", $.matching))
)),
// Dog as x -> f x
matching: $ => seq(
field("pattern", $._pattern),
"->",
field("matchingExpr", $._expr)
),
lambda_expr: $ => seq(
"fun",
repeat1(field("arg", $.argument)),
"->",
field("body", $._expr)
),
list_expr: $ => seq(
"[",
sepBy(";", field("item", $._expr)),
"]"
),
tup_expr: $ => prec.right(9,seq(
field("fst", $._expr),
",",
field("snd", $._expr),
)),
_expr: $ => choice(
$.call,
$.sub_expr,
$.tup_expr
),
sub_expr: $ => choice(
$.fun_app,
$.paren_expr,
$.Name,
$.Name_Capital,
$._literal,
$.rec_expr,
$.if_expr,
$.lambda_expr,
$.match_expr,
$.list_expr,
$.index_accessor
),
paren_expr: $ => seq(
"(",
field("innerExpr", $._expr),
optional(field("exprAnnot", $.type_annot)),
")"
),
//========== TYPE_EXPR ============
// t, test, string, integer
type_con: $ => $.TypeName,
// Red, Green, Blue, Cat
data_con: $ => $.Name_Capital,
// a t, (a, b) t
type_app: $ => prec(10,seq(
choice(
field("argument", $.type_expr),
seq(
"(",
sepBy1(",", field("argument", $.type_expr)),
")"
)
),
field("typeAppCon", $.type_con)
)),
// string * integer
type_product: $ => prec.right(5, seq(
field("fst", $.type_expr),
"*",
field("snd", $.type_expr)
)),
// int -> string
type_fun: $ => prec.right(8, seq(
field("domain", $.type_expr),
"->",
field("codomain", $.type_expr)
)),
type_expr: $ => choice(
$.type_fun,
$.type_product,
$.type_app,
$.type_con,
$.paren_type_expr,
),
paren_type_expr: $ => seq(
"(",
field("innerTypeExpr", $.type_expr),
")"
),
// Cat of string, Person of string * string
variant: $ => seq(
field("constructor", $.data_con),
optional(seq(
"of",
field("constructor_data", $.type_expr)
))
),
// Cat of string | Personn of string * string
type_sum: $ => seq(
sepBy1('|', field("variant", $.variant)),
),
// field : string * int
_label: $ => $.FieldName,
type_rec_field: $ => seq(
field("recLabel", $._label),
":",
field("labelType", $.type_expr)
),
// { field1 : a; field2 : b }
type_rec: $ => seq(
"{",
sepBy(";", field("recField", $.type_rec_field)),
optional(";"),
"}"
),
type_def_body: $ => choice(
$.type_sum,
$.type_expr,
$.type_rec
),
type_def: $ => seq(
field("typeName", $.type_con),
"=",
field("typeValue", $.type_def_body)
),
type_decl: $ => seq(
"type",
field("typeDef", $.type_def)
),
_literal: $ => choice(
$.String,
$.Int,
$.Nat,
$.Tez,
$.Bytes,
$.True,
$.False,
$.Unit
),
String: $ => /\"(\\.|[^"])*\"/,
Int: $ => /-?([1-9][0-9_]*|0)/,
Nat: $ => /([1-9][0-9_]*|0)n/,
Tez: $ => /([1-9][0-9_]*|0)(\.[0-9_]+)?(tz|tez|mutez)/,
Bytes: $ => /0x[0-9a-fA-F]+/,
Name: $ => /[a-z][a-zA-Z0-9_]*/,
TypeName: $ => /[a-z][a-zA-Z0-9_]*/,
FieldName: $ => /[a-z][a-zA-Z0-9_]*/,
Name_Capital: $ => /[A-Z][a-zA-Z0-9_]*/,
Keyword: $ => /[A-Za-z][a-z]*/,
Keyword: $ => /[A-Za-z][a-z]*/,
False: $ => 'False',
True: $ => 'True',
Unit: $ => 'Unit',
None: $ => 'None',
Some: $ => 'Some',
skip: $ => 'skip',
rec: $ => 'rec',
False: $ => 'false',
True: $ => 'true',
Unit: $ => '()',
attr: $ => seq('[@@', $.name, ']'),
comment: $ => /\/\/[^\n]*\n/,
ocaml_comment: $ =>
seq(
'(*',
repeat(choice(
$.ocaml_comment,
/'([^'\\]|\\[\\"'ntbr ]|\\[0-9][0-9][0-9]|\\x[0-9A-Fa-f][0-9A-Fa-f]|\\o[0-3][0-7][0-7])'/,
/"([^\\"]|\\(.|\n))*"/,
/[A-Za-z_][a-zA-Z0-9_']*/,
/[^('"{*A-Za-z_]+/,
'(', "'", '*',
)),
'*)'
),
}
});
});