import type { BigintLiteral, error, List, NumberLiteral, writeMalformedNumericLiteralMessage } from "../../../dev/utils/src/main.js" import type { Comparator } from "../../nodes/primitive/range.js" import type { resolve, Scope, UnparsedScope } from "../../scope.js" import type { GenericProps } from "../../type.js" import type { CastTo, inferDefinition } from "../definition.js" import type { writeInvalidGenericArgsMessage } from "../generic.js" import type { StringLiteral } from "../string/shift/operand/enclosed.js" import type { writeMissingSubscopeAccessMessage } from "../string/shift/operand/unenclosed.js" import type { parseString } from "../string/string.js" import type { validateBound } from "./bound.js" import type { validateDivisor } from "./divisor.js" import type { inferIntersection } from "./intersections.js" import type { astToString } from "./utils.js" export type inferAst = ast extends List ? inferExpression : inferTerminal export type GenericInstantiationAst< g extends GenericProps = GenericProps, argAsts extends unknown[] = unknown[] > = [g, "<>", argAsts] export type inferExpression< ast extends List, $, args > = ast extends GenericInstantiationAst ? inferDefinition< ast[0]["definition"], ast[0]["$"] extends UnparsedScope ? // If the generic was defined in the current scope, its definition can be // resolved using the same scope as that of the input args. $ : // Otherwise, use the scope that was explicitly associated with it. ast[0]["$"], { // Using keyof g["parameters"] & number here results in the element types // being mixed- another reason TS should not have separate `${number}` and number keys! [i in keyof ast[0]["parameters"] & `${number}` as ast[0]["parameters"][i]]: inferAst< ast[2][i & keyof ast[2]], $, args > } > : ast[1] extends "[]" ? inferAst[] : ast[1] extends "|" ? inferAst | inferAst : ast[1] extends "&" ? inferIntersection, inferAst> : ast[1] extends Comparator ? ast[0] extends NumberLiteral ? inferAst : inferAst : ast[1] extends "%" ? inferAst : ast[0] extends "keyof" ? keyof inferAst : never export type validateAst = ast extends string ? validateStringAst : ast extends PostfixExpression ? operator extends "[]" ? validateAst : never : ast extends InfixExpression ? operator extends "&" | "|" ? validateInfix : operator extends Comparator ? validateBound : operator extends "%" ? validateDivisor : undefined : ast extends readonly ["keyof", infer operand] ? [keyof inferAst] extends [never] ? error>> : validateAst : ast extends GenericInstantiationAst ? validateGenericArgs : error>> type writeUnexpectedExpressionMessage = `Unexpectedly failed to parse the expression resulting from ${expression}` type validateGenericArgs = argAsts extends [ infer head, ...infer tail ] ? validateAst extends error ? error : validateGenericArgs : undefined export const writeUnsatisfiableExpressionError = ( expression: expression ): writeUnsatisfiableExpressionError => `${expression} results in an unsatisfiable type` export type writeUnsatisfiableExpressionError = `${expression} results in an unsatisfiable type` type validateStringAst = def extends NumberLiteral< infer value > ? number extends value ? error> : undefined : def extends BigintLiteral ? bigint extends value ? error> : undefined : def extends keyof $ ? // these problems would've been caught during a fullStringParse, but it's most // efficient to check for them here in case the string was naively parsed $[def] extends GenericProps ? error> : $[def] extends Scope ? error> : undefined : undefined export type validateString = parseString< def, $, args > extends infer ast ? ast extends error ? error : validateAst extends error ? error : def : never export type PrefixOperator = "keyof" | "instanceof" | "===" | "node" export type PrefixExpression< operator extends PrefixOperator = PrefixOperator, operand = unknown > = [operator, operand] export type PostfixOperator = "[]" export type PostfixExpression< operator extends PostfixOperator = PostfixOperator, operand = unknown > = [operand, operator] export type InfixOperator = "|" | "&" | Comparator | "%" | ":" | "=>" export type InfixExpression< operator extends InfixOperator = InfixOperator, l = unknown, r = unknown > = [l, operator, r] type validateInfix = validateAst< ast[0], $, args > extends error ? error : validateAst extends error ? error : undefined export type RegexLiteral = `/${source}/` export type inferTerminal = token extends keyof args | keyof $ ? resolve : token extends CastTo ? t : token extends StringLiteral ? Text : token extends RegexLiteral ? string : token extends NumberLiteral ? value : token extends BigintLiteral ? value : never