Skip to content

Instantly share code, notes, and snippets.

@conartist6
Last active October 9, 2021 03:55
Show Gist options
  • Save conartist6/9ce56e4de54bba2bb4f8ddfe5ba0f5ba to your computer and use it in GitHub Desktop.
Save conartist6/9ce56e4de54bba2bb4f8ddfe5ba0f5ba to your computer and use it in GitHub Desktop.
Basic moo/nearley parser for JS errors
@{%
const lexer = moo.states({
error: {
CausedBy: { match: /^\s*[cC]ause(?:d [bB]y)?:/, value: () => "Caused by:" },
At: { match: /^[ \t]*at /, push: "frame", value: () => "at " },
Space: /[ \t]+/,
Newline: { match: "\n", lineBreaks: true },
// Any line ending with file:line:col is a stack frame
// file:line:col may be wrapped in parens, or may be the literal 'native'
Text: /.+$/,
},
frame: {
CN: ":",
LP: "(",
RP: ")",
Number: { match: /\d+/, value: (str) => parseInt(str, 10)},
NL: { match: "\n", lineBreaks: true, pop: true },
Space: /[ \t]+/,
FrameFragment: /[^(): \d\t\n]+/,
},
});
%}
@lexer lexer
Error -> Message (NL Stack):? (NL CausedBy Error):? {% (d) => {
const props = [{ message: d[0] }];
if (d[1]) props.push({ stack: d[1][1] });
if (d[2]) props.push({ cause: d[2][3] });
return Object.assign({}, ...props);
}%}
Message -> Text (NL _ Text):* {% (d) => d[0] + stringFrom(d[1].flat()) %}
Text -> _Text:+ {% (d) => stringFrom(d[0]) %}
_Text -> %Text {% (d) => d[0].text %}
Stack -> Frame (NL Frame):* {% (d) => [d[0], ...(d[1] ? d[1].map(d => d[1]) : [])] %}
Frame -> At FrameFragments _ LP FrameFragments CN Number CN Number RP {% (d) => ({ function: d[1], file: d[4], line: d[6], col: d[8] }) %}
| At FrameFragments CN Number CN Number {% (d) => ({ function: undefined, file: d[1], line: d[3], col: d[5] }) %}
FrameFragments -> (FrameFragment | Number | CN | LP | RP | _ ):* {% (d) => stringFrom(d[0].flat()) %}
FrameFragment -> %FrameFragment {% (d) => d[0].text %}
Number -> %Number {% (d) => d[0].value %}
At -> %At _:? {% () => null %}
CausedBy -> %CausedBy _ {% () => null %}
CN -> %CN {% (d) => d[0].text %} # Colon `:`
LP -> %LP {% (d) => d[0].text %} # Left paren `(`
RP -> %RP {% (d) => d[0].text %} # Right paren `)`
NL -> %NL {% (d) => d[0].text %} # Newline
_ -> %Space {% (d) => d[0].value %}
@{%
function stringFrom(iterable) {
let str = '';
for (const f of iterable) {
str += f;
}
return str;
}
%}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment