Skip to content

Instantly share code, notes, and snippets.

@Zemnmez
Last active October 27, 2021 23:18
Show Gist options
  • Save Zemnmez/64e41b713c5c5e91b2a114f72cc3517c to your computer and use it in GitHub Desktop.
Save Zemnmez/64e41b713c5c5e91b2a114f72cc3517c to your computer and use it in GitHub Desktop.
fuck
class ErrorWrapper<E extends Error> extends Error {
override get message() { return this.wraps.message }
override get name() { return this.wraps.name }
constructor(public readonly wraps: E) {
super(wraps.message);
}
}
/**
* ParseError represents an Error that occurred purely as
* a result of failing to parse, as opposed to a fatal error.
*
* If a ParseError occurs, parsing will continue using other
* symbols.
*/
class ParseError<E extends Error> extends ErrorWrapper<E> {
readonly isParseError = true
override get name() { return `ParseError<${this.wraps.name}>` }
}
/**
* FatalError represents an Error that ends parsing.
*/
class FatalError<E extends Error> extends ErrorWrapper<E> {
readonly isFatalError = true
override get name() { return `FatalError<${this.wraps.name}>`}
}
/**
* A Parser takes a series of input tokens and returns an Output token
* as well as a new slice of input tokens.
*/
interface Parser<Input extends readonly unknown[], Output, MyParseError extends Error = never, MyFatalError extends Error = never> {
(i: Input): [
/** The nuber of input tokens read */
nRead: number,
/** The output token produced */
out: Output,
] | ParseError<MyParseError> | FatalError<MyFatalError>;
}
class ErrorExpected<R extends string> extends Error {
override get name() { return `ErrorExpected<${this.expected}>` }
constructor(public readonly expected: R) {
super(`Expected: ${expected}`)
}
}
interface Rune<R extends string> extends Parser<readonly string[], R, ErrorExpected<R>> {
}
/**
* Rune represents a single character, as is given when a string is
* spread into an array (`[..."hello"]`)
*/
function Rune<R extends string>(r: R): Parser<readonly string[], R, ErrorExpected<R>> {
return function(i) {
if (i[0] !== r) return new ParseError(new ErrorExpected(r));
return [1, r]
}
}
type Sequence<
First extends Parser<readonly any[], unknown, Error, Error>,
Second extends Parser<readonly any[], unknown, Error, Error>
> =
First extends Parser<infer First$Input, infer First$Output, infer First$MyParseError, infer First$MyFatalError>
? Second extends Parser<infer Second$Input, infer Second$Output, infer Second$MyParseError, infer Second$MyFatalError>
? Parser<
/* Input */ First$Input & Second$Input,
/* Output */ [First$Output, Second$Output],
/* MyParseError */ First$MyParseError | Second$MyParseError,
/* MyFatalError */ First$MyFatalError | Second$MyFatalError>
: never
: never
;
function Sequence<
First extends Parser<readonly any[], unknown, Error, Error>,
Second extends Parser<readonly any[], unknown, Error, Error>
>(a: First, b: Second): Sequence<First, Second>
function Sequence<
A extends Parser<A$Input, A$Output, A$MyParseError, A$MyFatalError>,
B extends Parser<B$Input, B$Output, B$MyParseError, B$MyFatalError>,
A$Input extends readonly AV[], A$Output, A$MyParseError extends Error, A$MyFatalError extends Error, AV,
B$Input extends readonly BV[], B$Output, B$MyParseError extends Error, B$MyFatalError extends Error, BV,
>(a: A, b: B): Parser<
/* input */ A$Input & B$Input,
/* output */[A$Output, B$Output],
/* MyParseError */ A$MyParseError| B$MyParseError,
/* MyFatalError */ A$MyFatalError | B$MyFatalError> {
return function(i) {
const aRet = a(i);
if (aRet instanceof Error) {
return aRet;
};
if (!(aRet instanceof Array))debugger;
const [ a$nRead, a$Out ] = aRet;
const bRet = b(i.slice(a$nRead) as any as A$Input & B$Input);
if (bRet instanceof Error) {
return bRet
}
const [ b$nRead, b$Out ] = bRet;
return [ a$nRead + b$nRead, [a$Out, b$Out] ]
}
};
type Either<
First extends Parser<readonly any[], any, Error, Error>,
Second extends Parser<readonly any[], any, Error, Error>
> =
First extends Parser<infer First$Input, infer First$Output, infer First$MyParseError, infer First$MyFatalError>
? Second extends Parser<infer Second$Input, infer Second$Output, infer Second$MyParseError, infer Second$MyFatalError>
? Parser<
/* Input */ First$Input & Second$Input,
/* Output */ First$Output | Second$Output,
/* MyParseError */ First$MyParseError | Second$MyParseError,
/* MyFatalError */ First$MyFatalError | Second$MyFatalError>
: never
: never
;
class Errors<E extends Error[]> extends Error {
override get name() { return `Errors<[${this.errors.map(e => e.name).join(", ")}]`}
constructor(public readonly errors: E) {
super(`Errors: ${errors}`)
}
}
function Either<
First extends Parser<readonly any[], any, Error, Error>,
Second extends Parser<readonly any[], any, Error, Error>
>(a: First, b: Second): Either<First, Second>
function Either<
A extends Parser<A$Input, A$Output, A$MyParseError, A$MyFatalError>,
B extends Parser<B$Input, B$Output, B$MyParseError, B$MyFatalError>,
A$Input extends readonly AV[], A$Output, A$MyParseError extends Error, A$MyFatalError extends Error, AV,
B$Input extends readonly BV[], B$Output, B$MyParseError extends Error, B$MyFatalError extends Error, BV
>(a: A, b: B): Parser<
/* input */ A$Input & B$Input,
/* output */ A$Output | B$Output,
/* MyParseError */ Errors<[ ParseError<A$MyParseError>, ParseError<B$MyParseError>]>,
/* MyFatalError */ A$MyFatalError | B$MyFatalError> {
return function(i) {
const aRet = a(i);
if (aRet instanceof Error) {
if (aRet instanceof FatalError) return aRet;
// otherwise aRet is a ParseError, and we can try again
} else {
// success!
return aRet;
}
const bRet = b(i);
if (bRet instanceof Error) {
if (bRet instanceof FatalError) return bRet;
return new ParseError(new Errors([ aRet, bRet ]))
}
return bRet
}
}
function Repeat<A extends Parser<readonly any[], unknown, Error, Error>>(a: A):
A extends Parser<infer input, infer output, infer parseError, infer fatalError>
? Parser<input, output[], parseError, fatalError>
: never;
function Repeat<
A extends Parser<A$Input, A$Output, A$MyParseError, A$MyFatalError>,
A$Input extends readonly AV[], A$Output, A$MyParseError extends Error, A$MyFatalError extends Error, AV
>(a: A): Parser<A$Input, A$Output[], A$MyParseError, A$MyFatalError> {
return function(i) {
let outs: A$Output[] = [];
let n = 0;
for (;n < i.length;) {
const ret = a(i.slice(n) as any as typeof i);
if (ret instanceof Error) {
if (ret instanceof FatalError) return ret;
if (ret instanceof ParseError) return [ n, outs ]
}
const [ nn, tok ] = ret;
n += nn;
outs = [...outs, tok];
}
return [ n, outs ]
}
}
/*
letter = "A" | "B" | "C" | "D" | "E" | "F" | "G"
| "H" | "I" | "J" | "K" | "L" | "M" | "N"
| "O" | "P" | "Q" | "R" | "S" | "T" | "U"
| "V" | "W" | "X" | "Y" | "Z" | "a" | "b"
| "c" | "d" | "e" | "f" | "g" | "h" | "i"
| "j" | "k" | "l" | "m" | "n" | "o" | "p"
| "q" | "r" | "s" | "t" | "u" | "v" | "w"
| "x" | "y" | "z" ;
*/
function letter(i: readonly string[]) {
return Either(Rune("A"), Either(Rune("B"), Either(Rune("C"), Either(Rune("D"), Either(Rune("E"), Either(Rune("F"), Either(Rune("H"), Either(Rune("I"), Either(Rune("J"), Either(Rune("K"), Either(Rune("L"), Either(Rune("M"), Either(Rune("N"), Either(Rune("O"), Either(Rune("P"), Either(Rune("Q"), Either(Rune("R"), Either(Rune("S"), Either(Rune("T"), Either(Rune("U"), Either(Rune("V"), Either(Rune("W"), Either(Rune("X"), Either(Rune("Z"), Either(Rune("a"), Either(Rune("b"), Either(Rune("c"), Either(Rune("d"), Either(Rune("e"), Either(Rune("f"), Either(Rune("g"), Either(Rune("h"), Either(Rune("i"), Either(Rune("j"), Either(Rune("k"), Either(Rune("l"), Either(Rune("m"), Either(Rune("n"), Either(Rune("o"), Either(Rune("p"), Either(Rune("q"), Either(Rune("r"), Either(Rune("s"), Either(Rune("t"), Either(Rune("u"), Either(Rune("v"), Either(Rune("w"), Either(Rune("x"), Either(Rune("y"), Rune("z"))))))))))))))))))))))))))))))))))))))))))))))))))
(i);
}
/*
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
*/
function digit(i: readonly string[]) {
return Either(Rune("0"), Either(Rune("1"), Either(Rune("2"), Either(Rune("3"), Either(Rune("4"), Either(Rune("5"), Either(Rune("6"), Either(Rune("7"), Either(Rune("8"), Rune("9"))))))))))(i)
}
/*
symbol = "[" | "]" | "{" | "}" | "(" | ")" | "<" | ">"
| "'" | '"' | "=" | "|" | "." | "," | ";" ;
*/
function symbol(i: readonly string[]) {
return Either(Rune("["), Either(Rune("]"), Either(Rune("{"), Either(Rune("}"), Either(Rune("("), Either(Rune(")"), Either(Rune("<"), Either(Rune(">"), Either(Rune("'"), Either(Rune("\""), Either(Rune("="), Either(Rune("|"), Either(Rune("."), Either(Rune(","), Rune(";")))))))))))))))(i);
}
/*
character = letter | digit | symbol | "_" ;
*/
function character(i: readonly string[]){
return Either(letter, Either(digit, Either(symbol, Rune("_")))) (i);
}
/*
identifier = letter , { letter | digit | "_" } ;
*/
function identifier(i: readonly string[]) { return Sequence(
letter,
Repeat(Either(letter, Either(digit, Rune("_"))))
)(i) }
/*
terminal = "'" , character , { character } , "'"
| '"' , character , { character } , '"' ;
*/
function terminal(i: readonly string[]) { return Sequence(
Rune("'"),
Sequence(
character,
Sequence(
Repeat(character),
Rune("'")
)
)
)(i)}
/*
lhs = identifier ;
*/
const lhs = identifier;
function optional(i: readonly string[]) { return Sequence(
Rune("["),
Sequence(
rhs,
Rune("]")
)
)(i) }
function repetition(i: readonly string[]) { return Sequence(
Rune("{"),
Sequence(
rhs,
Rune("}")
)
)(i) }
function grouping(i: readonly string[]) { return Sequence(
Rune("("),
Sequence(
rhs,
Rune(")")
)
)(i) }
function either(i: readonly string[]) { return Sequence(
rhs,
Sequence(
Rune("|"),
rhs
)
)(i) }
function sequence(i: readonly string[]){ return Sequence(
rhs,
Sequence(
Rune(","),
rhs
)
)(i) }
function rhs(i: readonly string[]): rhs {
return Either(
identifier,
Either(
terminal,
Either(
optional,
Either(
repetition,
Either(
grouping,
Either(
either,
sequence
)
)
)
)
)
)(i)
}
/*
rhs = identifier
| terminal
| "[" , rhs , "]"
| "{" , rhs , "}"
| "(" , rhs , ")"
| rhs , "|" , rhs
| rhs , "," , rhs ;
*/
function rule(i: readonly string[]) { return Sequence(lhs, Sequence(Rune("="), Sequence(rhs, Rune(";"))))(i) }
/*
rule = lhs , "=" , rhs , ";" ;
*/
function grammar(i: readonly string[]) { return Repeat(rule)(i) }
/*
grammar = { rule } ;
*/
console.log(grammar([...`OK="1"`]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment