diff options
| -rw-r--r-- | src/lang/builtin/index.ts | 34 | ||||
| -rw-r--r-- | src/lang/core/common.ts (renamed from src/lib/core/common.ts) | 0 | ||||
| -rw-r--r-- | src/lang/core/eval.ts | 42 | ||||
| -rw-r--r-- | src/lang/core/index.ts (renamed from src/lib/core/index.ts) | 0 | ||||
| -rw-r--r-- | src/lang/core/lexer.ts (renamed from src/lib/core/lexer.ts) | 0 | ||||
| -rw-r--r-- | src/lang/core/parser.ts (renamed from src/lib/core/parser.ts) | 0 | ||||
| -rw-r--r-- | src/lang/index.ts (renamed from src/lib/index.ts) | 0 | ||||
| -rw-r--r-- | src/lang/util/index.ts | 3 | ||||
| -rw-r--r-- | src/lang/util/number.ts | 34 | ||||
| -rw-r--r-- | src/lang/util/string.ts | 17 | ||||
| -rw-r--r-- | src/lang/util/utils.ts | 8 | ||||
| -rw-r--r-- | src/lib/core/eval.ts | 126 |
12 files changed, 138 insertions, 126 deletions
diff --git a/src/lang/builtin/index.ts b/src/lang/builtin/index.ts new file mode 100644 index 0000000..373f54a --- /dev/null +++ b/src/lang/builtin/index.ts @@ -0,0 +1,34 @@ +import { + AddNumbers, + AddStrings, + Multiply, + ToString, + UnarrayIfOnlyHead, +} from "../util"; + +export type FnError<T extends string> = `Function execution error: ${T}`; + +export type BUILTIN_Arr<Args extends readonly any[]> = Args; + +export type BUILTIN_ToString<Args extends readonly any[]> = ToString< + UnarrayIfOnlyHead<{ + [Idx in keyof Args]: ToString<Args[Idx]>; + }> +>; + +export type BUILTIN_Add<Args extends readonly any[]> = + Args extends readonly string[] + ? AddStrings<Args> + : Args extends readonly number[] + ? AddNumbers<Args> + : FnError<`Cannot add operands ${ToString<Args>}`>; + +export type BUILTIN_Mul<Args extends readonly any[]> = Args extends [ + infer A, + infer B, + infer C +] + ? FnError<`Can only multiply [number, number], but got ${ToString<Args>}`> + : Args extends [infer M extends number, infer N extends number] + ? Multiply<M, N> + : FnError<`Can only multiply [number, number], but got ${ToString<Args>}`>; diff --git a/src/lib/core/common.ts b/src/lang/core/common.ts index c1a1dc3..c1a1dc3 100644 --- a/src/lib/core/common.ts +++ b/src/lang/core/common.ts diff --git a/src/lang/core/eval.ts b/src/lang/core/eval.ts new file mode 100644 index 0000000..6a25a6c --- /dev/null +++ b/src/lang/core/eval.ts @@ -0,0 +1,42 @@ +import { + BUILTIN_Add, + BUILTIN_Arr, + BUILTIN_Mul, + BUILTIN_ToString, +} from "../builtin"; +import { ASTNode, NodeType } from "./common"; +import { Lex } from "./lexer"; +import { Parse } from "./parser"; + +export type SENTINEL_NO_BUILTIN = "__NO_BUILTIN__"; +export type MapBuiltins<Node extends ASTNode> = + Node["children"] extends infer Children extends readonly ASTNode[] + ? { + [Idx in keyof Children]: Children[Idx] extends ASTNode + ? Evaluate<Children[Idx]> + : never; + } extends infer Args extends readonly any[] + ? Node["name"] extends "tostring" + ? BUILTIN_ToString<Args> + : Node["name"] extends "arr" + ? BUILTIN_Arr<Args> + : Node["name"] extends "add" + ? BUILTIN_Add<Args> + : Node["name"] extends "mul" + ? BUILTIN_Mul<Args> + : SENTINEL_NO_BUILTIN + : never + : never; + +export type EvalError<T extends string> = `Eval error: ${T}`; + +export type Evaluate<Node extends ASTNode> = Node["type"] extends NodeType.INT + ? Node["value"] + : Node["type"] extends NodeType.EXT + ? MapBuiltins<Node> + : EvalError<`Unhandled node type ${Node["type"]}`>; + +const input = `` as const; +const lex_result = null as unknown as Lex<typeof input>; +const parse_result = null as unknown as Parse<typeof lex_result>; +const eval_result = null as unknown as Evaluate<typeof parse_result>; diff --git a/src/lib/core/index.ts b/src/lang/core/index.ts index e69de29..e69de29 100644 --- a/src/lib/core/index.ts +++ b/src/lang/core/index.ts diff --git a/src/lib/core/lexer.ts b/src/lang/core/lexer.ts index 33a408a..33a408a 100644 --- a/src/lib/core/lexer.ts +++ b/src/lang/core/lexer.ts diff --git a/src/lib/core/parser.ts b/src/lang/core/parser.ts index 79218e9..79218e9 100644 --- a/src/lib/core/parser.ts +++ b/src/lang/core/parser.ts diff --git a/src/lib/index.ts b/src/lang/index.ts index 8d119de..8d119de 100644 --- a/src/lib/index.ts +++ b/src/lang/index.ts diff --git a/src/lang/util/index.ts b/src/lang/util/index.ts new file mode 100644 index 0000000..00a3e54 --- /dev/null +++ b/src/lang/util/index.ts @@ -0,0 +1,3 @@ +export * from "./number"; +export * from "./utils"; +export * from "./string"; diff --git a/src/lang/util/number.ts b/src/lang/util/number.ts new file mode 100644 index 0000000..132994b --- /dev/null +++ b/src/lang/util/number.ts @@ -0,0 +1,34 @@ +export type NumberToArray< + Number extends number, + Carry extends readonly any[] = [] +> = Number extends Carry["length"] + ? Carry + : NumberToArray<Number, [...Carry, any]>; + +export type NumbersToArray< + Numbers extends readonly number[], + Carry extends readonly any[] = [] +> = Numbers extends [ + infer Head extends number, + ...infer Tail extends readonly number[] +] + ? NumbersToArray<Tail, [...Carry, ...NumberToArray<Head>]> + : Carry; + +export type AddNumbers<Numbers extends readonly number[]> = + NumbersToArray<Numbers> extends infer T extends readonly any[] + ? T["length"] + : never; + +export type MultiplyInner< + N extends number, + MS extends readonly any[], + Carry extends number = 0 +> = MS extends [infer Head extends number, ...infer Tail extends readonly any[]] + ? MultiplyInner<N, Tail, AddNumbers<[Carry, N]>> + : Carry; + +export type Multiply<M extends number, N extends number> = MultiplyInner< + M, + NumberToArray<N> +>; diff --git a/src/lang/util/string.ts b/src/lang/util/string.ts new file mode 100644 index 0000000..5772f40 --- /dev/null +++ b/src/lang/util/string.ts @@ -0,0 +1,17 @@ +export type AddStrings< + Strings extends readonly string[], + Carry extends string = "" +> = Strings extends [infer Head extends string, ...infer Tail extends string[]] + ? AddStrings<Tail, `${Carry}${Head}`> + : Carry; + +export type ToString<T, Carry extends string = ""> = T extends string | number + ? `${T}` + : T extends readonly any[] + ? T extends readonly [infer Head, ...infer Tail] + ? `${ToString< + Tail, + `${Carry extends "" ? "" : `${Carry}, `}${ToString<Head>}` + >}` + : `[${Carry}]` + : never; diff --git a/src/lang/util/utils.ts b/src/lang/util/utils.ts new file mode 100644 index 0000000..ac36ca1 --- /dev/null +++ b/src/lang/util/utils.ts @@ -0,0 +1,8 @@ +export type UnarrayIfOnlyHead<T extends readonly any[]> = T extends [ + infer Head, + infer Next +] + ? T + : T extends [infer Head] + ? Head + : T; diff --git a/src/lib/core/eval.ts b/src/lib/core/eval.ts deleted file mode 100644 index 59cda1d..0000000 --- a/src/lib/core/eval.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { ASTNode, NodeType } from "./common"; -import { Lex } from "./lexer"; -import { Parse } from "./parser"; - -export type FnError<T extends string> = `Function execution error: ${T}`; - -export type ToStringInner<T, Carry extends string = ""> = T extends - | string - | number - ? `${T}` - : T extends readonly any[] - ? T extends readonly [infer Head, ...infer Tail] - ? `${ToStringInner< - Tail, - `${Carry extends "" ? "" : `${Carry}, `}${ToStringInner<Head>}` - >}` - : `[${Carry}]` - : FnError<`Can't stringify`>; - -export type UnarrayIfOnlyHead<T extends readonly any[]> = T extends [ - infer Head, - infer Next -] - ? T - : T extends [infer Head] - ? Head - : T; - -export type NumberToArray< - Number extends number, - Carry extends readonly any[] = [] -> = Number extends Carry["length"] - ? Carry - : NumberToArray<Number, [...Carry, any]>; - -export type NumbersToArray< - Numbers extends readonly number[], - Carry extends readonly any[] = [] -> = Numbers extends [ - infer Head extends number, - ...infer Tail extends readonly number[] -] - ? NumbersToArray<Tail, [...Carry, ...NumberToArray<Head>]> - : Carry; - -export type AddNumbers<Numbers extends readonly number[]> = - NumbersToArray<Numbers> extends infer T extends readonly any[] - ? T["length"] - : never; - -export type AddStrings< - Strings extends readonly string[], - Carry extends string = "" -> = Strings extends [infer Head extends string, ...infer Tail extends string[]] - ? AddStrings<Tail, `${Carry}${Head}`> - : Carry; - -export type MultiplyInner< - N extends number, - MS extends readonly any[], - Carry extends number = 0 -> = MS extends [infer Head extends number, ...infer Tail extends readonly any[]] - ? MultiplyInner<N, Tail, AddNumbers<[Carry, N]>> - : Carry; -export type Multiply<M extends number, N extends number> = MultiplyInner< - M, - NumberToArray<N> ->; - -export type BUILTIN_Arr<Args extends readonly any[]> = Args; - -export type BUILTIN_ToString<Args extends readonly any[]> = ToStringInner< - UnarrayIfOnlyHead<{ - [Idx in keyof Args]: ToStringInner<Args[Idx]>; - }> ->; - -export type BUILTIN_Add<Args extends readonly any[]> = - Args extends readonly string[] - ? AddStrings<Args> - : Args extends readonly number[] - ? AddNumbers<Args> - : FnError<`Cannot add operands ${ToStringInner<Args>}`>; - -export type BUILTIN_Mul<Args extends readonly any[]> = Args extends [ - infer A, - infer B, - infer C -] - ? FnError<`Can only multiply [number, number], but got ${ToStringInner<Args>}`> - : Args extends [infer M extends number, infer N extends number] - ? Multiply<M, N> - : FnError<`Can only multiply [number, number], but got ${ToStringInner<Args>}`>; - -export type SENTINEL_NO_BUILTIN = "__NO_BUILTIN__"; -export type MapBuiltins<Node extends ASTNode> = - Node["children"] extends infer Children extends readonly ASTNode[] - ? { - [Idx in keyof Children]: Children[Idx] extends ASTNode - ? Evaluate<Children[Idx]> - : never; - } extends infer Args extends readonly any[] - ? Node["name"] extends "tostring" - ? BUILTIN_ToString<Args> - : Node["name"] extends "arr" - ? BUILTIN_Arr<Args> - : Node["name"] extends "add" - ? BUILTIN_Add<Args> - : Node["name"] extends "mul" - ? BUILTIN_Mul<Args> - : SENTINEL_NO_BUILTIN - : never - : never; - -export type EvalError<T extends string> = `Eval error: ${T}`; - -export type Evaluate<Node extends ASTNode> = Node["type"] extends NodeType.INT - ? Node["value"] - : Node["type"] extends NodeType.EXT - ? MapBuiltins<Node> - : EvalError<`Unhandled node type ${Node["type"]}`>; - -const input = `` as const; -const lex_result = null as unknown as Lex<typeof input>; -const parse_result = null as unknown as Parse<typeof lex_result>; -const eval_result = null as unknown as Evaluate<typeof parse_result>; |
