Created
March 7, 2023 09:20
-
-
Save gvergnaud/45e7c3d98fe9556a0c49646cd6446bee to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`>; | |
// ^? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`>; | |
// ^? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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