import { CompilerError } from "../CompilerError";
import { Effect, ValueKind, ValueReason } from "./HIR";
import {
BuiltInType,
FunctionType,
ObjectType,
PolyType,
PrimitiveType,
} from "./Types";
const PRIMITIVE_TYPE: PrimitiveType = {
kind: "Primitive",
};
let nextAnonId = 0;
function createAnonId(): string {
return `<generated_${nextAnonId++}>`;
}
export function addFunction(
registry: ShapeRegistry,
properties: Iterable<[string, BuiltInType | PolyType]>,
fn: Omit<FunctionSignature, "hookKind">,
id: string | null = null
): FunctionType {
const shapeId = id ?? createAnonId();
addShape(registry, shapeId, properties, {
...fn,
hookKind: null,
});
return {
kind: "Function",
return: fn.returnType,
shapeId,
};
}
export function addHook(
registry: ShapeRegistry,
fn: FunctionSignature & { hookKind: HookKind },
id: string | null = null
): FunctionType {
const shapeId = id ?? createAnonId();
addShape(registry, shapeId, [], fn);
return {
kind: "Function",
return: fn.returnType,
shapeId,
};
}
export function addObject(
registry: ShapeRegistry,
id: string | null,
properties: Iterable<[string, BuiltInType | PolyType]>
): ObjectType {
const shapeId = id ?? createAnonId();
addShape(registry, shapeId, properties, null);
return {
kind: "Object",
shapeId,
};
}
function addShape(
registry: ShapeRegistry,
id: string,
properties: Iterable<[string, BuiltInType | PolyType]>,
functionType: FunctionSignature | null
): ObjectShape {
const shape: ObjectShape = {
properties: new Map(properties),
functionType,
};
CompilerError.invariant(!registry.has(id), {
reason: `[ObjectShape] Could not add shape to registry: name ${id} already exists.`,
description: null,
loc: null,
suggestions: null,
});
registry.set(id, shape);
return shape;
}
export type HookKind =
| "useContext"
| "useState"
| "useReducer"
| "useRef"
| "useEffect"
| "useLayoutEffect"
| "useMemo"
| "useCallback"
| "Custom";
export type FunctionSignature = {
positionalParams: Array<Effect>;
restParam: Effect | null;
returnType: BuiltInType | PolyType;
returnValueKind: ValueKind;
returnValueReason?: ValueReason;
calleeEffect: Effect;
hookKind: HookKind | null;
noAlias?: boolean;
mutableOnlyIfOperandsAreMutable?: boolean;
};
export type ObjectShape = {
properties: Map<string, BuiltInType | PolyType>;
functionType: FunctionSignature | null;
};
export type ShapeRegistry = Map<string, ObjectShape>;
export const BuiltInPropsId = "BuiltInProps";
export const BuiltInArrayId = "BuiltInArray";
export const BuiltInFunctionId = "BuiltInFunction";
export const BuiltInJsxId = "BuiltInJsx";
export const BuiltInObjectId = "BuiltInObject";
export const BuiltInUseStateId = "BuiltInUseState";
export const BuiltInSetStateId = "BuiltInSetState";
export const BuiltInUseRefId = "BuiltInUseRefId";
export const BuiltInRefValueId = "BuiltInRefValue";
export const BuiltInMixedReadonlyId = "BuiltInMixedReadonly";
export const BuiltInUseEffectHookId = "BuiltInUseEffectHook";
export const BuiltInUseLayoutEffectHookId = "BuiltInUseLayoutEffectHook";
export const BuiltInUseInsertionEffectHookId = "BuiltInUseInsertionEffectHook";
export const BuiltInUseOperatorId = "BuiltInUseOperator";
export const BuiltInUseReducerId = "BuiltInUseReducer";
export const BuiltInDispatchId = "BuiltInDispatch";
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
addObject(BUILTIN_SHAPES, BuiltInPropsId, [
["ref", { kind: "Object", shapeId: BuiltInUseRefId }],
]);
addObject(BUILTIN_SHAPES, BuiltInArrayId, [
[
"at",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [Effect.Read],
restParam: null,
returnType: { kind: "Poly" },
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Mutable,
}),
],
[
"concat",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: {
kind: "Object",
shapeId: BuiltInArrayId,
},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Mutable,
}),
],
["length", PRIMITIVE_TYPE],
[
"push",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Primitive,
}),
],
[
"map",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Object", shapeId: BuiltInArrayId },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"filter",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Object", shapeId: BuiltInArrayId },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"every",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Primitive" },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Primitive,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"some",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Primitive" },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Primitive,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"find",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Poly" },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"findIndex",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Primitive" },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Primitive,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
"join",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
]);
addObject(BUILTIN_SHAPES, BuiltInObjectId, [
[
"toString",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
]);
addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
["0", { kind: "Poly" }],
[
"1",
addFunction(
BUILTIN_SHAPES,
[],
{
positionalParams: [],
restParam: Effect.Freeze,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
},
BuiltInSetStateId
),
],
]);
addObject(BUILTIN_SHAPES, BuiltInUseReducerId, [
["0", { kind: "Poly" }],
[
"1",
addFunction(
BUILTIN_SHAPES,
[],
{
positionalParams: [],
restParam: Effect.Freeze,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
},
BuiltInDispatchId
),
],
]);
addObject(BUILTIN_SHAPES, BuiltInUseRefId, [
["current", { kind: "Object", shapeId: BuiltInRefValueId }],
]);
addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
["*", { kind: "Object", shapeId: BuiltInRefValueId }],
]);
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
[
"toString",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
"map",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: { kind: "Object", shapeId: BuiltInArrayId },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
}),
],
[
"filter",
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: { kind: "Object", shapeId: BuiltInArrayId },
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
}),
],
["*", { kind: "Object", shapeId: BuiltInMixedReadonlyId }],
]);
addObject(BUILTIN_SHAPES, BuiltInJsxId, []);
addObject(BUILTIN_SHAPES, BuiltInFunctionId, []);
export const DefaultMutatingHook = addHook(
BUILTIN_SHAPES,
{
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: { kind: "Poly" },
calleeEffect: Effect.Read,
hookKind: "Custom",
returnValueKind: ValueKind.Mutable,
},
"DefaultMutatingHook"
);
export const DefaultNonmutatingHook = addHook(
BUILTIN_SHAPES,
{
positionalParams: [],
restParam: Effect.Freeze,
returnType: { kind: "Poly" },
calleeEffect: Effect.Read,
hookKind: "Custom",
returnValueKind: ValueKind.Frozen,
},
"DefaultNonmutatingHook"
);