jq_bnf = {
const {name, t, s, split, prefer, first, repeat, seq, postprocess, stacked} = po;
const bnf = {
TopLevel: () => name("TopLevel", postprocess(
([module, imports, exp]) => ({module, imports, exp}),
[
bnf.Module,
bnf.Imports,
first(bnf.Exp, bnf.FuncDefs),
],
)),
Module: () => prefer(["module", bnf.Exp, ";"]),
Imports: () => repeat(bnf.Import),
FuncDefs: () => name("FuncDefs", repeat(bnf.FuncDef)),
Exp: () => name("Exp", postprocess(
([exp, optionality]) => ({exp, optionality}),
[first(bnf.ExpPre, bnf.ExpOps), prefer("?")]
)),
ExpPre: () => first(
name("FuncExp", postprocess(([first_funcdef, more_funcdefs, exp]) => ({funcdef:[first_funcdef, ...more_funcdefs], exp}),
[bnf.FuncDef, repeat(bnf.FuncDef), bnf.Exp])),
name("Reduce", postprocess(([_reduce, source, _as, matcher, _LParen, p, _RParen]) => {
const [init, _semi, body] = p.parse;
return {_reduce, source, _as, matcher, _LParen, init, _semi, body, _RParen};
},
["reduce", bnf.Term, "as", bnf.Patterns, "(", stacked([bnf.Exp, ";", bnf.Exp]), ")"])),
name("ForEach", postprocess(([_foreach, source, _as, matcher, _LParen, p, _RParen]) => {
const [init, _semi, update, thirdclause] = p.parse;
return {_foreach, source, _as, init, _semi, update, _LParen, extract: thirdclause ? thirdclause[1] : null, _RParen};
},
["foreach", bnf.Term, "as", bnf.Patterns, "(", stacked([bnf.Exp, ";", bnf.Exp, prefer([";", bnf.Exp])]), ")"])),
name("If", postprocess(
([a, b, c, d, e]) => e === "end" ? [a, b, c, d, e] : [a, b, c, d, ...e],
["if", bnf.Exp, "then", bnf.Exp, first(bnf.ElseBody, "end")]
)),
name("Try", postprocess(([_try, exp, catches]) => ({_try, exp, _catch: (catches||[null])[0], handler: (catches||[null,null])[1]}),
["try", bnf.Exp, prefer(["catch", bnf.Exp])]
)),
name("Label", ["label", "$", t(T.ident), "catch", bnf.Exp]),
),
ExpOps: () => split(
postprocess(
([unary_minuses, exp1]) => ({unary_minuses, exp1}),
[repeat("-"), first(bnf.ExpPre, postprocess(
([a, b]) => (b ? [a, ...b] : [a]),
[bnf.Term, prefer(["as", bnf.Patterns, "|", bnf.Exp])]
))] // TODO disallow this matching -'s with "as"
),
first("-", "-=", "*", "*=", "/", "%", "/=", "%=", "==", "!=", "<", ">", "<=", ">=","?", "=", "or", "and", "//", "//=", "|=", "|", ",", "+", "+=")
),
Import: () => [bnf.ImportWhat, bnf.Exp, ";"],
ImportWhat: () => [
"import",
bnf.ImportFrom,
prefer(["as", prefer("$"), t(T.ident)]),
],
ImportFrom: () => bnf.String(),
FuncDef: () => name("FuncDef", postprocess(([_def, name, args, _colon, body, _semi]) => (
{_def, name, ...(args ? {_open: args[0], params: args[1], _close: args[2]}
: {_open: null , params: [] , _close: null}), _colon, body, _semi}
), [
"def", t(T.ident), prefer(["(", bnf.Params, ")"]), ":", bnf.Exp, ";",
])),
Params: () => split(bnf.Param, ";"),
Param: () => first(
["$", first(t(T.ident), bnf.Keyword)],
t(T.ident),
),
String: () => name("String", postprocess(([fmt, start, text, end]) => ({fmt, start, text, end}), [
prefer(t(T.format)),
t(T.string_start),
bnf.QQString,
t(T.string_end),
])),
QQString: () => repeat(first(
[t(T.interp_start), bnf.Exp, ")"],
t(T.literal_text),
)),
ElseBody: () => postprocess(p => p.flat(), [
postprocess(p => p.flat(), repeat(["elif", bnf.Exp, "then", bnf.Exp])),
["else", bnf.Exp, "end"],
]),
ExpD: () => split(first(repeat("-"), bnf.Term), "|"),
FieldIndex: () => name("FieldIndex", [first(t(T.field), [".", bnf.String]), prefer("?")]),
Term: () => name("Term", postprocess(([head, tail]) => ([head, ...tail]),
[
first(
".",
"..",
["break", "$", t(T.ident)],
bnf.FieldIndex,
t(T.literal),
bnf.String,
t(T.format),
name("Parens", postprocess(([_open, body, _close]) => ({_open, body, _close}), ["(", stacked(bnf.Exp), ")"])),
name("List", postprocess(([_open, body, _close]) => ({_open, body, _close}), ["[", prefer(stacked(bnf.Exp)), "]"])),
name("Dict", postprocess(([_open, body, _close]) => ({_open, body, _close}), ["{", stacked(bnf.MkDict), "}"])),
["$", first(
[prefer(["$", "$", "$"]), [t(T.ident)]],
[bnf.Keyword],
)],
t(T.ident),
name("FunCall", postprocess(
([ident, _open, argpart, _close]) => ({ident, _open, args: argpart.parse, _close}),
[t(T.ident), "(", stacked(bnf.Args), ")"]
))
),
repeat(first(
bnf.FieldIndex,
name("Index", [prefer("."), "[", stacked(bnf.Exp), "]", prefer("?")]),
name("EachOf", ["[", "]", prefer("?")]),
name("RangeIndex", ["[", stacked([bnf.Exp, ":", prefer(bnf.Exp)]), "]", prefer("?")]),
name("RangeIndex", ["[", stacked([prefer(bnf.Exp), ":", bnf.Exp]), "]", prefer("?")]),
)),
]
)),
Args: () => split(bnf.Arg, ";"),
Arg: () => bnf.Exp,
Patterns: () => split(bnf.Pattern, "?//"),
Pattern: () => name("Pattern", first(
["$", t(T.ident)],
postprocess(([a, b, c])=>[a, ...b, c], ["[", bnf.ArrayPats, "]"]),
postprocess(([a, b, c])=>[a, ...b, c], ["{", bnf.ObjPats, "}"]),
)),
ArrayPats: () => split(bnf.Pattern, ","),
ObjPats: () => split(bnf.ObjPat, ","),
ObjPat: () => first(
["$", t(T.ident), prefer([":", bnf.Pattern])],
[
first(
t(T.ident),
bnf.Keyword,
bnf.String,
["(", stacked(bnf.Exp), ")"],
),
":",
bnf.Pattern,
],
),
Keyword: () => first("as", "def", "module", "import", "include", "if", "then", "else", "elif", "reduce", "foreach", "end", "and", "or", "try", "catch", "label", "break", "__loc__"),
MkDict: () => prefer(split(bnf.MkDictPair, ",")),
MkDictPair: () => first(
[first(t(T.ident), bnf.Keyword, bnf.String), ":", bnf.ExpD],
bnf.String,
["$", first(
[
t(T.ident),
prefer([":", bnf.ExpD]),
],
bnf.Keyword,
)],
t(T.ident),
bnf.Keyword,
["(", bnf.Exp, ")", ":", bnf.ExpD],
),
};
return bnf;
}