From 7995be6aa05d0c2a2d14da2870a98955196fb1d2 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Fri, 8 Mar 2024 23:30:29 +0000 Subject: [PATCH] fix: Fix tokenizer hitting tail-recursion limit (#125) --- .changeset/eight-yaks-provide.md | 5 ++ src/parser.ts | 96 ++++++++++++++------------------ src/tokenizer.ts | 8 ++- 3 files changed, 54 insertions(+), 55 deletions(-) create mode 100644 .changeset/eight-yaks-provide.md diff --git a/.changeset/eight-yaks-provide.md b/.changeset/eight-yaks-provide.md new file mode 100644 index 00000000..44493187 --- /dev/null +++ b/.changeset/eight-yaks-provide.md @@ -0,0 +1,5 @@ +--- +'gql.tada': patch +--- + +Fix tokenizer hitting tail recursion limit by recursing on each ignored token. diff --git a/src/parser.ts b/src/parser.ts index 1211da54..2e71f648 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -6,6 +6,12 @@ export interface _match { in: In; } +export interface _match2 { + out1: Out1; + out2: Out2; + in: In; +} + type takeOptionalName = In extends [ { kind: Token.Name; name: infer Name }, ...infer In, @@ -112,11 +118,20 @@ export type takeDirectives< ? takeDirectives : _match; -type _takeField = In extends [ - Token.Colon, - { kind: Token.Name; name: infer Name }, +type _takeFieldName = In extends [ + { kind: Token.Name; name: infer MaybeAlias }, ...infer In, ] + ? In extends [Token.Colon, { kind: Token.Name; name: infer Name }, ...infer In] + ? _match2<{ kind: Kind.NAME; value: MaybeAlias }, { kind: Kind.NAME; value: Name }, In> + : _match2 + : void; + +type _takeField = _takeFieldName extends _match2< + infer Alias, + infer Name, + infer In +> ? takeArguments extends _match ? takeDirectives extends _match ? takeSelectionSet extends _match @@ -124,7 +139,7 @@ type _takeField = In extends [ { kind: Kind.FIELD; alias: Alias; - name: { kind: Kind.NAME; value: Name }; + name: Name; arguments: Arguments; directives: Directives; selectionSet: SelectionSet; @@ -135,7 +150,7 @@ type _takeField = In extends [ { kind: Kind.FIELD; alias: Alias; - name: { kind: Kind.NAME; value: Name }; + name: Name; arguments: Arguments; directives: Directives; selectionSet: undefined; @@ -144,33 +159,7 @@ type _takeField = In extends [ > : void : void - : takeArguments extends _match - ? takeDirectives extends _match - ? takeSelectionSet extends _match - ? _match< - { - kind: Kind.FIELD; - alias: undefined; - name: Alias; - arguments: Arguments; - directives: Directives; - selectionSet: SelectionSet; - }, - In - > - : _match< - { - kind: Kind.FIELD; - alias: undefined; - name: Alias; - arguments: Arguments; - directives: Directives; - selectionSet: undefined; - }, - In - > - : void - : void; + : void; export type takeType = In extends [Token.BracketOpen, ...infer In] ? takeType extends _match @@ -193,6 +182,7 @@ export type takeType = In extends [Token.BracketOpen, ...infer : void; type _takeFragmentSpread = In extends [ + Token.Spread, { kind: Token.Name; name: 'on' }, { kind: Token.Name; name: infer Type }, ...infer In, @@ -210,7 +200,7 @@ type _takeFragmentSpread = In extends [ > : void : void - : In extends [{ kind: Token.Name; name: infer Name }, ...infer In] + : In extends [Token.Spread, { kind: Token.Name; name: infer Name }, ...infer In] ? takeDirectives extends _match ? _match< { @@ -221,31 +211,29 @@ type _takeFragmentSpread = In extends [ In > : void - : takeDirectives extends _match - ? takeSelectionSet extends _match - ? _match< - { - kind: Kind.INLINE_FRAGMENT; - typeCondition: undefined; - directives: Directives; - selectionSet: SelectionSet; - }, - In - > + : In extends [Token.Spread, ...infer In] + ? takeDirectives extends _match + ? takeSelectionSet extends _match + ? _match< + { + kind: Kind.INLINE_FRAGMENT; + typeCondition: undefined; + directives: Directives; + selectionSet: SelectionSet; + }, + In + > + : void : void : void; -type _takeSelectionRec = In extends [ - Token.Spread, - ...infer In, -] - ? _takeFragmentSpread extends _match +type _takeSelectionRec = _takeField extends _match< + infer Selection, + infer In +> + ? _takeSelectionRec<[...Selections, Selection], In> + : _takeFragmentSpread extends _match ? _takeSelectionRec<[...Selections, Selection], In> - : void - : In extends [{ kind: Token.Name; name: infer Alias }, ...infer In] - ? _takeField extends _match - ? _takeSelectionRec<[...Selections, Selection], In> - : void : In extends [Token.BraceClose, ...infer In] ? _match<{ kind: Kind.SELECTION_SET; selections: Selections }, In> : void; diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 60094852..bdd30dce 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -34,6 +34,12 @@ type 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'; +type skipIgnored = In extends `#${infer _}\n${infer In}` + ? skipIgnored + : In extends `${ignored}${infer In}` + ? skipIgnored + : In; + type skipDigits = In extends `${digit}${infer In}` ? skipDigits : In; type skipFloat = In extends `${'.'}${infer In}` @@ -96,7 +102,7 @@ type tokenizeRec = : State extends _state ? tokenizeRec< In extends `#${string}\n${infer In}` ? _state - : In extends `${ignored}${infer In}` ? _state + : In extends `${ignored}${infer In}` ? _state, Out> : In extends `...${infer In}` ? _state : In extends `!${infer In}` ? _state : In extends `=${infer In}` ? _state