Skip to content

Commit

Permalink
designed new API and simple example, joint work with Insa, still WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JohannesMeierSE committed Dec 10, 2024
1 parent 32aacf8 commit b3e269b
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 42 deletions.
1 change: 1 addition & 0 deletions packages/typir/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export * from './services/equality.js';
export * from './services/inference.js';
export * from './services/kind-registry.js';
export * from './services/operator.js';
export * from './services/factory.js';
export * from './services/printing.js';
export * from './services/subtype.js';
export * from './services/validation.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/typir/src/kinds/class/class-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class ClassType extends Type {

// resolve methods
this.methods = typeDetails.methods.map(method => <MethodDetails>{
type: new TypeReference(kind.getMethodKind().createFunctionType(method), kind.services),
type: new TypeReference(kind.getMethodKind().create(method), kind.services),
});
const refMethods = this.methods.map(m => m.type);
// the uniqueness of methods can be checked with the predefined UniqueMethodValidation below
Expand Down
5 changes: 3 additions & 2 deletions packages/typir/src/kinds/function/function-kind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { TypeCheckStrategy, checkTypes, checkValueForConflict, createTypeCheckSt
import { Kind, isKind } from '../kind.js';
import { FunctionTypeInitializer } from './function-initializer.js';
import { FunctionType, isFunctionType } from './function-type.js';
import { FunctionPredefinedService } from '../../services/factory.js';


export interface FunctionKindOptions {
Expand Down Expand Up @@ -112,7 +113,7 @@ export type InferFunctionCall<T = unknown> = {
* - optional parameters
* - parameters which are used for output AND input
*/
export class FunctionKind implements Kind, TypeGraphListener {
export class FunctionKind implements Kind, TypeGraphListener, FunctionPredefinedService {
readonly $name: 'FunctionKind';
readonly services: TypirServices;
readonly options: Readonly<FunctionKindOptions>;
Expand Down Expand Up @@ -238,7 +239,7 @@ export class FunctionKind implements Kind, TypeGraphListener {
return new TypeReference(() => this.calculateIdentifier(typeDetails), this.services);
}

createFunctionType<T>(typeDetails: CreateFunctionTypeDetails<T>): TypeInitializer<FunctionType> {
create<T>(typeDetails: CreateFunctionTypeDetails<T>): TypeInitializer<FunctionType> {
return new FunctionTypeInitializer(this.services, this, typeDetails);
}

Expand Down
18 changes: 5 additions & 13 deletions packages/typir/src/kinds/primitive/primitive-kind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { PrimitiveFactoryService } from '../../services/factory.js';
import { InferenceRuleNotApplicable } from '../../services/inference.js';
import { TypirServices } from '../../typir.js';
import { assertTrue, toArray } from '../../utils/utils.js';
Expand All @@ -20,7 +21,7 @@ export type InferPrimitiveType = (domainElement: unknown) => boolean;

export const PrimitiveKindName = 'PrimitiveKind';

export class PrimitiveKind implements Kind {
export class PrimitiveKind implements Kind, PrimitiveFactoryService {
readonly $name: 'PrimitiveKind';
readonly services: TypirServices;

Expand All @@ -30,22 +31,13 @@ export class PrimitiveKind implements Kind {
this.services.kinds.register(this);
}

getPrimitiveType(typeDetails: PrimitiveTypeDetails): PrimitiveType | undefined {
get(typeDetails: PrimitiveTypeDetails): PrimitiveType | undefined {
const key = this.calculateIdentifier(typeDetails);
return this.services.graph.getType(key) as PrimitiveType;
}

getOrCreatePrimitiveType(typeDetails: PrimitiveTypeDetails): PrimitiveType {
const primitiveType = this.getPrimitiveType(typeDetails);
if (primitiveType) {
this.registerInferenceRules(typeDetails, primitiveType);
return primitiveType;
}
return this.createPrimitiveType(typeDetails);
}

createPrimitiveType(typeDetails: PrimitiveTypeDetails): PrimitiveType {
assertTrue(this.getPrimitiveType(typeDetails) === undefined);
create(typeDetails: PrimitiveTypeDetails): PrimitiveType {
assertTrue(this.get(typeDetails) === undefined);

// create the primitive type
const primitiveType = new PrimitiveType(this, this.calculateIdentifier(typeDetails));
Expand Down
78 changes: 78 additions & 0 deletions packages/typir/src/services/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/******************************************************************************
* Copyright 2024 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { TypeInitializer } from '../initialization/type-initializer.js';
import { CreateFunctionTypeDetails, FunctionKind } from '../kinds/function/function-kind.js';
import { FunctionType } from '../kinds/function/function-type.js';
import { PrimitiveKind, PrimitiveTypeDetails } from '../kinds/primitive/primitive-kind.js';
import { PrimitiveType } from '../kinds/primitive/primitive-type.js';
import { TypirServices } from '../typir.js';
import { OperatorManager } from './operator.js';

export interface FactoryService {
primitives: PrimitiveFactoryService;
functions: FunctionPredefinedService;
operators: OperatorManager;
}

export interface PrimitiveFactoryService {
create(typeDetails: PrimitiveTypeDetails): PrimitiveType;
get(typeDetails: PrimitiveTypeDetails): PrimitiveType | undefined;
// getKind(): PrimitiveKind; // erstmal nicht rausreichen
}

export class DefaultPrimitivePredefinedService implements PrimitiveFactoryService {
protected primitiveKind: PrimitiveKind;

constructor(services: TypirServices) {
this.initializePrimitives(services);
}

protected initializePrimitives(services: TypirServices): void {
this.primitiveKind = new PrimitiveKind(services);
}

create(typeDetails: PrimitiveTypeDetails): PrimitiveType {
return this.primitiveKind.create(typeDetails);
}

get(typeDetails: PrimitiveTypeDetails): PrimitiveType | undefined {
return this.primitiveKind.get(typeDetails);
}
}

export interface FunctionPredefinedService {
create(typeDetails: CreateFunctionTypeDetails<unknown>): TypeInitializer<FunctionType>;
}


export class DefaultPredefinedService implements FactoryService {
protected readonly services: TypirServices;

primitives: PrimitiveFactoryService;
functions: FunctionPredefinedService;
operators: OperatorManager;

constructor(services: TypirServices) {
this.services = services;

// primitives
this.initializePrimitives();

// functions
const functionKind = new FunctionKind(this.services);
this.functions = {
create: (typeDetails: CreateFunctionTypeDetails<unknown>) => functionKind.create(typeDetails),
};

this.operators = services.operators;

Check failure on line 71 in packages/typir/src/services/factory.ts

View workflow job for this annotation

GitHub Actions / typir-build

Property 'operators' does not exist on type 'TypirServices'.

Check failure on line 71 in packages/typir/src/services/factory.ts

View workflow job for this annotation

GitHub Actions / typir-build

Property 'operators' does not exist on type 'TypirServices'.
}

protected initializePrimitives(): void {
this.primitives = new DefaultPrimitivePredefinedService(this.services);
}

}
24 changes: 12 additions & 12 deletions packages/typir/src/services/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ export interface GenericOperatorDetails<T> {

// TODO rename it to "OperatorFactory", when there are no more responsibilities!
export interface OperatorManager {
createUnaryOperator<T>(typeDetails: UnaryOperatorDetails<T>): TypeInitializers<Type>
createBinaryOperator<T>(typeDetails: BinaryOperatorDetails<T>): TypeInitializers<Type>
createTernaryOperator<T>(typeDetails: TernaryOperatorDetails<T>): TypeInitializers<Type>
createUnary<T>(typeDetails: UnaryOperatorDetails<T>): TypeInitializers<Type>
createBinary<T>(typeDetails: BinaryOperatorDetails<T>): TypeInitializers<Type>
createTernary<T>(typeDetails: TernaryOperatorDetails<T>): TypeInitializers<Type>

/** This function allows to create a single operator with arbitrary input operands. */
createGenericOperator<T>(typeDetails: GenericOperatorDetails<T>): TypeInitializer<Type>;
createGeneric<T>(typeDetails: GenericOperatorDetails<T>): TypeInitializer<Type>;
}

/**
Expand Down Expand Up @@ -99,11 +99,11 @@ export class DefaultOperatorManager implements OperatorManager {
this.services = services;
}

createUnaryOperator<T>(typeDetails: UnaryOperatorDetails<T>): TypeInitializers<Type> {
createUnary<T>(typeDetails: UnaryOperatorDetails<T>): TypeInitializers<Type> {
const signatures = toArray(typeDetails.signature);
const result: Array<TypeInitializer<Type>> = [];
for (const signature of signatures) {
result.push(this.createGenericOperator({
result.push(this.createGeneric({
name: typeDetails.name,
outputType: signature.return,
inferenceRule: typeDetails.inferenceRule, // the same inference rule is used (and required) for all overloads, since multiple FunctionTypes are created!
Expand All @@ -115,11 +115,11 @@ export class DefaultOperatorManager implements OperatorManager {
return result.length === 1 ? result[0] : result;
}

createBinaryOperator<T>(typeDetails: BinaryOperatorDetails<T>): TypeInitializers<Type> {
createBinary<T>(typeDetails: BinaryOperatorDetails<T>): TypeInitializers<Type> {
const signatures = toArray(typeDetails.signature);
const result: Array<TypeInitializer<Type>> = [];
for (const signature of signatures) {
result.push(this.createGenericOperator({
result.push(this.createGeneric({
name: typeDetails.name,
outputType: signature.return,
inferenceRule: typeDetails.inferenceRule, // the same inference rule is used (and required) for all overloads, since multiple FunctionTypes are created!
Expand All @@ -132,11 +132,11 @@ export class DefaultOperatorManager implements OperatorManager {
return result.length === 1 ? result[0] : result;
}

createTernaryOperator<T>(typeDetails: TernaryOperatorDetails<T>): TypeInitializers<Type> {
createTernary<T>(typeDetails: TernaryOperatorDetails<T>): TypeInitializers<Type> {
const signatures = toArray(typeDetails.signature);
const result: Array<TypeInitializer<Type>> = [];
for (const signature of signatures) {
result.push(this.createGenericOperator({
result.push(this.createGeneric({
name: typeDetails.name,
outputType: signature.return,
inferenceRule: typeDetails.inferenceRule, // the same inference rule is used (and required) for all overloads, since multiple FunctionTypes are created!
Expand All @@ -150,12 +150,12 @@ export class DefaultOperatorManager implements OperatorManager {
return result.length === 1 ? result[0] : result;
}

createGenericOperator<T>(typeDetails: GenericOperatorDetails<T>): TypeInitializer<Type> {
createGeneric<T>(typeDetails: GenericOperatorDetails<T>): TypeInitializer<Type> {
// define/register the wanted operator as "special" function
const functionKind = this.getFunctionKind();

// create the operator as type of kind 'function'
const newOperatorType = functionKind.createFunctionType({
const newOperatorType = functionKind.create({
functionName: typeDetails.name,
outputParameter: { name: NO_PARAMETER_NAME, type: typeDetails.outputType },
inputParameters: typeDetails.inputParameter,
Expand Down
24 changes: 20 additions & 4 deletions packages/typir/src/typir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { TypeGraph } from './graph/type-graph.js';
import { FunctionKind } from './kinds/function/function-kind.js';
import { PrimitiveKind } from './kinds/primitive/primitive-kind.js';
import { DefaultTypeAssignability, TypeAssignability } from './services/assignability.js';
import { DefaultDomainElementInferenceCaching, DefaultTypeRelationshipCaching, DomainElementInferenceCaching, TypeRelationshipCaching } from './services/caching.js';
import { DefaultTypeConversion, TypeConversion } from './services/conversion.js';
import { DefaultTypeEquality, TypeEquality } from './services/equality.js';
import { FunctionPredefinedService, PrimitiveFactoryService } from './services/factory.js';
import { DefaultTypeInferenceCollector, TypeInferenceCollector } from './services/inference.js';
import { DefaultKindRegistry, KindRegistry } from './services/kind-registry.js';
import { DefaultOperatorManager, OperatorManager } from './services/operator.js';
import { DefaultTypeConflictPrinter, ProblemPrinter } from './services/printing.js';
import { DefaultSubType, SubType } from './services/subtype.js';
import { DefaultValidationCollector, DefaultValidationConstraints, ValidationCollector, ValidationConstraints } from './services/validation.js';
import { TypeGraph } from './graph/type-graph.js';
import { DefaultKindRegistry, KindRegistry } from './services/kind-registry.js';
import { inject, Module } from './utils/dependency-injection.js';

/**
Expand Down Expand Up @@ -48,12 +51,18 @@ export type TypirServices = {
};
readonly graph: TypeGraph;
readonly kinds: KindRegistry;
readonly operators: OperatorManager;
// readonly operators: OperatorManager;
readonly printer: ProblemPrinter;
readonly validation: {
readonly collector: ValidationCollector;
readonly constraints: ValidationConstraints;
};
// readonly factory: PredefinedService; // alternative names: predefined, library, types
readonly factory: {
primitives: PrimitiveFactoryService;
functions: FunctionPredefinedService;
operators: OperatorManager;
};
};

export const DefaultTypirServiceModule: Module<TypirServices> = {
Expand All @@ -67,13 +76,20 @@ export const DefaultTypirServiceModule: Module<TypirServices> = {
typeRelationships: (services) => new DefaultTypeRelationshipCaching(services),
domainElementInference: () => new DefaultDomainElementInferenceCaching()
},
operators: (services) => new DefaultOperatorManager(services),
// operators: (services) => new DefaultOperatorManager(services),
kinds: () => new DefaultKindRegistry(),
printer: () => new DefaultTypeConflictPrinter(),
validation: {
collector: (services) => new DefaultValidationCollector(services),
constraints: (services) => new DefaultValidationConstraints(services),
},
// factory: (services) => new DefaultPredefinedService(services),
factory: {
// primitives: (services) => new DefaultPrimitivePredefinedService(services),
primitives: (services) => new PrimitiveKind(services),
functions: (services) => new FunctionKind(services, { subtypeParameterChecking: 'ASSIGNABLE_TYPE' }),
operators: (services) => new DefaultOperatorManager(services),
},
};

/**
Expand Down
Loading

0 comments on commit b3e269b

Please sign in to comment.