Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d37784b
first working version for defining simple custom types
JohannesMeierSE Mar 19, 2025
edd4a32
fixed some other smaller issues
JohannesMeierSE Mar 25, 2025
fa9e3b5
fixed generics, small issues
JohannesMeierSE Apr 4, 2025
9252fe4
no strings for TypeSelectors
JohannesMeierSE Apr 4, 2025
44f5b37
calculate identifiers only from custom properties
JohannesMeierSE Apr 4, 2025
f98b7c7
tests for custom types depending on custom types, no strings for Type…
JohannesMeierSE Apr 4, 2025
bedb16c
test cases for type inference
JohannesMeierSE Apr 6, 2025
f79d0df
fixed bug
JohannesMeierSE Apr 11, 2025
53b3ad3
register as listener and get informed about all existing types, if de…
JohannesMeierSE Apr 11, 2025
8b60ada
conversion and sub-types for custom types
JohannesMeierSE Apr 11, 2025
bdbe76a
test case for validation rules attached to custom type-specific infer…
JohannesMeierSE Apr 11, 2025
796630e
specify names and user representations once for all custom properties…
JohannesMeierSE Apr 11, 2025
0c4659d
test multiple custom types in parallel
JohannesMeierSE Apr 14, 2025
1ced5ca
fixed eslint rule
JohannesMeierSE Apr 15, 2025
74a6f90
support nesting of Properties for custom types
JohannesMeierSE Apr 15, 2025
2571d82
new property to skip type-specific inference rules for types which al…
JohannesMeierSE Apr 16, 2025
7b94761
removed testing stuff, fixed imports
JohannesMeierSE Apr 16, 2025
4e9e31f
more test cases for TypeSelectors with custom types
JohannesMeierSE Apr 16, 2025
d9ea8e1
first improvements according to the review
JohannesMeierSE Jul 4, 2025
98ec8e9
more improvements
JohannesMeierSE Jul 5, 2025
e50d304
improved comments according to the review
JohannesMeierSE Jul 8, 2025
1f63167
properties of custom types are readonly now, default implementation f…
JohannesMeierSE Jul 9, 2025
7003a61
added missing implementation (which will be improved in future PRs)
JohannesMeierSE Jul 9, 2025
7a98ce1
unified initialization design for classes, functions and custom types
JohannesMeierSE Jul 9, 2025
67de361
check typeName for uniqueness
JohannesMeierSE Jul 9, 2025
e551485
wrote some documentation for custom types
JohannesMeierSE Jul 9, 2025
6567a1e
fixes according to the review
JohannesMeierSE Jul 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions documentation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@ This describes the structure and the main content of the documentation for Typir
- [Type inference](./services/inference.md)
- ...


## Predefined types

- ...
The current set of predefined types:

- Top and bottom types
- Primitive types
- Structurally typed classes
- [Custom types](./kinds/custom-types.md)
- Function types
- Operators (are internally mappped to function types)


## Bindings

Expand Down Expand Up @@ -44,6 +53,6 @@ This repository contains the following stand-alone applications. Read their link

- [LOX](./examples/lox/README.md) - static type checking for LOX, implemented with Typir-Langium
- [OX](./examples/ox/README.md) - a reduced version of LOX, implemented with Typir-Langium
- Expressions - TODO
- [Expressions](./examples/expression.README.md) - static type checking for a hand-written reduced expression language, implemented with Typir (core)

Some of the internal test cases developed in [packages/typir/test/](../packages/typir/test/) demonstrate some features of Typir in more detail.
89 changes: 88 additions & 1 deletion documentation/kinds/custom-types.md

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,92 @@
Many languages contain features which cannot be easily described with the predefined types.
This describes how language-specific custom types can be defined and used in Typir.

TODO

## API by example

This section demonstrates the API to define custom types along the example extracted from `custom-example-matrix.test.ts`. Here a new mathematical matrix type is defined with `width` and `height`, which is similar to a two-dimensional array. The content of cells are primitive types.

First of all, you need to specify the properties of matrix types in Typir by creating a TypeScript type (note that `interface` instead of `type` does not work):

```typescript
type MatrixType = {
baseType: PrimitiveType;
width: number;
height: number;
};
```

Then you create a new factory for these matrix types:

```typescript
const matrixFactory = new CustomKind<MatrixType, TestLanguageNode>(typir, {
name: 'Matrix',
calculateTypeName: properties => `My${properties.width}x${properties.height}Matrix`,
// ... here you can specify additional rules for conversion, sub-types, ... for all matrix types ...
});
```

Now you can use this factory to create new matrix types:

```typescript
const matrix2x3 = matrixFactory
.create({ properties: { baseType: integerType, width: 2, height: 3 } })
.finish().getTypeFinal()!;
```

See `custom-example-restricted.test.ts` for another application example.


## Features

This sections describes the features of custom types in more detail.

### Custom properties

Custom types have custom properties ("data") including primitive values, Typir types and nesting/grouping with sets, arrays, and maps, and recursion.
See `custom-nested-properties.test.ts` for some examples.
When the initialization of the custom type is done, all its properties are read-only.

### Support by the TypeScript compiler

The API for custom types uses TypeScript generics to enable TypeScript-safe descriptions for these custom properties.
In the example above, calling `matrix2x3.properties.width` is supported by auto-completion in the IDE and will return the number `2`.

### Uniqueness

Typir ensures uniqueness for custom types.
Two custom types are unique, if their identifiers are the same (this counts for any type, not only for custom types).
Comment thread
JohannesMeierSE marked this conversation as resolved.
Outdated
The default implementation calculates the identifier by concatenating the values of all properties.

### Circular dependencies

Cyclic dependencies of the given types for type properties are handled by Typir.
See some examples in `custom-cycles.test.ts` and `custom-selectors.test.ts`.
Therefore `getTypeFinal()` needs to be called after finishing a new custom type, e.g. `const myCustomType = customKind.create({...}).finish().getTypeFinal();`.
If the custom type is already available, you will get your `CustomType<Properties, LanguageType>`, otherwise `undefined`.
If the type is not yet available, you can register a callback, which is called, when the type is available:

```typescript
customKind.create({...}).finish().addListener(finishedType => {
// here the new custom type is available and can be used as usual
finishedType.getIdentifier();
});
```

### Behaviour

Specify rules for conversion, sub-type, names, identifiers, inference and validation (usually for all custom types OR for single ones).
See `custom-example-restricted.test.ts` for some examples.

### Multiple different custom types

You can use different factories for different custom types in parallel within the same Typir instance.
See `custom-independent.test.ts` for an example.


## Limitations

- You cannot use simple string values for `TypeSelector`s (in order to specify custom properties of type `Type`), since they cannot be distinguished from string values for primitive custom properties.
Therefore, only the restricted `TypeSelectorForCustomTypes` is supported by custom types instead of the usual `TypeSelector`.
- Even if your custom type does not depend on other types or if you know, that the types your custom type depends on are already available,
you need to call `getTypeFinal()`, e.g. `const myCustomType = customKind.create({...}).finish().getTypeFinal()!;`.