Skip to content

Instantly share code, notes, and snippets.

@gvergnaud
Created March 7, 2023 09:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvergnaud/45e7c3d98fe9556a0c49646cd6446bee to your computer and use it in GitHub Desktop.
Save gvergnaud/45e7c3d98fe9556a0c49646cd6446bee to your computer and use it in GitHub Desktop.
import { arg0, Call, Constant, Eval, Fn, Objects, Tuples } from "../src/index";
type Ok<A> = { tag: "Ok"; value: A };
type Err<B> = { tag: "Err"; value: B };
type Result<A, B> = Ok<A> | Err<B>;
type ParseError<expected = unknown, encountered = unknown> = {
expected: expected;
encountered: encountered;
};
type Tag<tag extends string, T> = { tag: tag; value: T };
type ParseResult = [string, Result<unknown, ParseError>];
interface Parser extends Fn {
return: ParseResult;
}
interface Literal<str extends string> extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends `${infer value extends str}${infer rest}`
? [rest, Ok<value>]
: [input, Err<ParseError<str, input>>]
: never;
}
interface Fail<err extends ParseError> extends Parser {
return: [this["arg0"], Err<err>];
}
interface Any extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends `${infer start}${infer rest}`
? [rest, Ok<start>]
: [input, Err<ParseError<"any charater", "then end of the input">>]
: never;
}
interface EndOfInput extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends ""
? [input, Ok<[]>]
: [input, Err<ParseError<"end of line", input>>]
: never;
}
interface Optional<parser extends Parser> extends Parser {
return: Call<parser, this["arg0"]> extends [
infer rest extends string,
Ok<infer A>
]
? [rest, Ok<A>]
: [Extract<this["arg0"], string>, Ok<[]>];
}
type ManyImpl<
input extends string,
parser extends Parser,
output extends any[] = []
> = Call<parser, input> extends [infer rest extends string, Ok<infer value>]
? ManyImpl<rest, parser, [...output, value]>
: [input, Ok<output>];
interface Many<parser extends Parser> extends Parser {
return: ManyImpl<this["arg0"], parser>;
}
type Letter = Literal<
| "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"
>;
type Word = Map<Tuples.Join<"">, Many<Letter>>;
interface AndThen<p extends Parser, getParser extends Fn> extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? Call<p, input> extends infer result
? result extends [infer rest, Ok<infer a>]
? Call<getParser, a> extends infer newParser extends Parser
? Call<newParser, rest>
: never
: result extends [infer rest, Err<infer a>]
? [rest, Err<a>]
: never
: never
: never;
}
type Do<getParsers extends Fn[], output extends Parser = never> = [
output
] extends [never]
? getParsers extends [infer first extends Fn, ...infer rest extends Fn[]]
? Eval<first> extends infer parser extends Parser
? Do<rest, parser>
: Fail<ParseError<"Function didn't return a parser">>
: Fail<ParseError<"No parser in the list">>
: getParsers extends [infer first extends Fn, ...infer rest extends Fn[]]
? Do<rest, AndThen<output, first>>
: output;
interface Map<fn extends Fn, parser extends Parser> extends Parser {
return: Call<parser, this["arg0"]> extends infer res extends ParseResult
? res extends [infer rest extends string, Ok<infer value>]
? [rest, Ok<Call<fn, value>>]
: res
: never;
}
interface ConcatResult<parser extends Parser> extends Fn {
return: Map<Objects.Create<[this["arg0"], arg0]>, parser>;
}
type CommaSep = Do<
[
Constant<Word>,
ConcatResult<Optional<Do<[Constant<Literal<",">>, ConcatResult<CommaSep>]>>>
]
>;
type res1 = Call<CommaSep, `hello,test,abc,hi`>;
// ^?
import {
Pipe,
arg0,
Call,
Apply,
Constant,
Eval,
Fn,
Objects,
Tuples,
Compose,
} from "../src/index";
type Ok<A> = { tag: "Ok"; value: A };
type Err<B> = { tag: "Err"; value: B };
type Result<A, B> = Ok<A> | Err<B>;
type ParseError<expected = unknown, encountered = unknown> = {
expected: expected;
encountered: encountered;
};
type ParseResult = [string, Result<unknown, ParseError>];
interface Parser extends Fn {
return: ParseResult;
}
interface Literal<str extends string> extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends `${infer value extends str}${infer rest}`
? [rest, Ok<value>]
: [input, Err<ParseError<str, input>>]
: never;
}
interface Pure<value> extends Parser {
return: [this["arg0"], Ok<value>];
}
interface Fail<err extends ParseError> extends Parser {
return: [this["arg0"], Err<err>];
}
interface Any extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends `${infer start}${infer rest}`
? [rest, Ok<start>]
: [input, Err<ParseError<"any charater", "the end of the input">>]
: never;
}
interface EndOfInput extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends ""
? [input, Ok<[]>]
: [input, Err<ParseError<"end of line", input>>]
: never;
}
interface Optional<parser extends Parser> extends Parser {
return: Call<parser, this["arg0"]> extends [
infer rest extends string,
Ok<infer A>
]
? [rest, Ok<A>]
: [Extract<this["arg0"], string>, Ok<[]>];
}
type ManyImpl<
input extends string,
parser extends Parser,
output extends any[] = []
> = Call<parser, input> extends [infer rest extends string, Ok<infer value>]
? ManyImpl<rest, parser, [...output, value]>
: [input, Ok<output>];
interface Many<parser extends Parser> extends Parser {
return: ManyImpl<this["arg0"], parser>;
}
type Letter = Literal<
| "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"
>;
type Word = Map<Tuples.Join<"">, Many<Letter>>;
interface Map<fn extends Fn, parser extends Parser> extends Parser {
return: Call<parser, this["arg0"]> extends infer res extends ParseResult
? res extends [infer rest extends string, Ok<infer value>]
? [rest, Ok<Call<fn, value>>]
: res
: never;
}
// type res1 = Call<CommaSep, `hello,test,abc,hi`>;
interface AndThen<p extends Parser, getParser extends Fn> extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? Call<p, input> extends infer result
? result extends [infer rest, Ok<infer a>]
? Call<getParser, a> extends infer newParser extends Parser
? Call<newParser, rest>
: never
: result extends [infer rest, Err<infer a>]
? [rest, Err<a>]
: never
: never
: never;
}
type Do<
getParsers extends Fn[],
output extends Parser = Pure<{}>
> = getParsers extends [infer first extends Fn, ...infer rest extends Fn[]]
? Do<rest, AndThen<output, first>>
: output;
namespace Do {
export interface Let<name extends string, parser extends Parser> extends Fn {
return: this["arg0"] extends infer variables
? Map<
Compose<
[Objects.Assign<variables>, Objects.Create<{ [K in name]: arg0 }>]
>,
parser
>
: Fail<ParseError<"no variables in let">>;
}
type GetByName<names, obj, output extends any[] = []> = names extends [
infer first extends keyof obj,
...infer rest
]
? GetByName<rest, obj, [...output, obj[first]]>
: output;
export interface Ap<fn extends Fn, names> extends Fn {
return: this["arg0"] extends infer variables
? Pure<Apply<fn, GetByName<names, variables>>>
: Fail<ParseError<"no variables in Ap">>;
}
export interface Return<parser extends Parser> extends Fn {
return: parser;
}
}
type CommaSep = Do<
[
Do.Let<"first", Word>,
Do.Let<
"rest",
Optional<Do<[Do.Let<"_", Literal<",">>, Do.Return<CommaSep>]>>
>,
Do.Ap<Tuples.Prepend, ["first", "rest"]>
]
>;
type res1 = Call<CommaSep, `a,b,c,d,e,f,g,h`>;
// ^?
// type res2 = Call<CommaSep, `a,b,c,d,e,f,g,h,i`>;
// ^?
import { Apply, Call, Compose, Constant, Fn } from "../core/Core";
import { Prettify } from "../helpers";
import { Strings } from "../strings/Strings";
import { Tuples } from "../tuples/Tuples";
export namespace Parser {
export type Ok<A> = { tag: "Ok"; value: A };
export type Err<B> = { tag: "Err"; value: B };
type Result<A, B> = Ok<A> | Err<B>;
export type ParseError<expected = unknown, encountered = unknown> = {
expected: expected;
encountered: encountered;
};
export type ParseResult = [string, Result<unknown, ParseError>];
interface Parser extends Fn {
return: ParseResult;
}
type LiteralImpl<str, expected, output extends string = ""> = [
expected
] extends [`${infer eFirst}${infer eRest}`]
? str extends `${infer sFirst}${infer sRest}`
? sFirst extends eFirst
? LiteralImpl<sRest, eRest, `${output}${sFirst}`>
: Err<"Does not math">
: Err<"Does not math">
: Ok<[str, output]>;
export interface Literal<expected extends string> extends Parser {
return: LiteralImpl<this["arg0"], expected> extends infer res
? res extends Ok<[infer rest, infer output]>
? [rest, Ok<output>]
: [this["arg0"], Err<ParseError<expected, this["arg0"]>>]
: never;
}
export interface Pure<value> extends Parser {
return: [this["arg0"], Ok<value>];
}
export interface Fail<err extends ParseError> extends Parser {
return: [this["arg0"], Err<err>];
}
export interface Any extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends `${infer start}${infer rest}`
? [rest, Ok<start>]
: [input, Err<ParseError<"any charater", "the end of the input">>]
: never;
}
export interface EndOfInput extends Parser {
return: this["args"] extends [infer input extends string, ...any]
? input extends ""
? [input, Ok<[]>]
: [input, Err<ParseError<"end of line", input>>]
: never;
}
export interface Optional<parser extends Parser, defaultValue = null>
extends Parser {
return: Call<parser, this["arg0"]> extends [
infer rest extends string,
Ok<infer A>
]
? [rest, Ok<A>]
: [this["arg0"], Ok<defaultValue>];
}
type ManyImpl<
input extends string,
parser extends Parser,
fullInput = input,
output extends any[] = []
> = Call<parser, input> extends [infer rest extends string, Ok<infer value>]
? ManyImpl<rest, parser, fullInput, [...output, value]>
: output extends []
? [fullInput, Err<ParseError<"many", fullInput>>]
: [input, Ok<output>];
export interface Many<parser extends Parser> extends Parser {
return: ManyImpl<this["arg0"], parser>;
}
type LetterUnion =
| "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";
export type Letter = Literal<LetterUnion>;
export type Word = Map<Tuples.Join<"">, Many<Letter>>;
type DigitUnion = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
export type Digit = Literal<DigitUnion>;
export type Number = Map<
Compose<[Strings.ToNumber, Tuples.Join<"">]>,
Many<Digit>
>;
export type WhiteSpace = Literal<" " | "\t" | "\n">;
export type WhiteSpaces = Many<WhiteSpace>;
type OneOfImpl<parsers, input> = parsers extends [
infer parser extends Parser,
...infer rest
]
? Call<parser, input> extends infer res
? res extends [unknown, Ok<unknown>]
? res
: OneOfImpl<rest, input>
: never
: [input, Err<ParseError<"nothing matched", input>>];
export interface OneOf<parsers extends Parser[]> extends Parser {
return: OneOfImpl<parsers, this["arg0"]>;
}
export interface Map<fn extends Fn, parser extends Parser> extends Parser {
return: Call<parser, this["arg0"]> extends infer res extends ParseResult
? res extends [infer rest extends string, Ok<infer value>]
? [rest, Ok<Call<fn, value>>]
: res
: never;
}
type DoImpl<getParsers extends Fn[], output> = output extends [
infer rest,
Ok<infer a>
]
? getParsers extends [
infer first extends Parser,
...infer restParsers extends Fn[]
]
? DoImpl<restParsers, Call<Map<Constant<a>, first>, rest>>
: getParsers extends [
infer first extends Fn,
...infer restParsers extends Fn[]
]
? Call<first, a> extends infer newParser extends Parser
? DoImpl<restParsers, Call<newParser, rest>>
: never
: output
: output;
export interface Do<getParsers extends Fn[]> extends Parser {
return: DoImpl<getParsers, [this["arg0"], Ok<{}>]>;
}
interface LetParser<name extends string, variables, parser extends Parser>
extends Parser {
return: Call<parser, this["arg0"]> extends infer res extends ParseResult
? res extends [infer rest extends string, Ok<infer a>]
? [rest, Ok<Prettify<variables & { [k in name]: a }>>]
: res
: [
this["arg0"],
Err<ParseError<`parser given to Let<${name}, _> is invalid`>>
];
}
export interface Let<name extends string, parser extends Parser> extends Fn {
return: LetParser<name, this["arg0"], parser>;
}
type GetByName<names, obj, output extends any[] = []> = names extends [
infer first extends keyof obj,
...infer rest
]
? GetByName<rest, obj, [...output, obj[first]]>
: output;
export interface Ap<fn extends Fn, names> extends Fn {
return: this["arg0"] extends infer variables
? Pure<Apply<fn, GetByName<names, variables>>>
: Fail<ParseError<"no variables in Ap">>;
}
export interface Return<parser extends Parser> extends Fn {
return: parser;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment