added type system
This commit is contained in:
@@ -1,29 +1,10 @@
|
|||||||
import { Impl, Module, TraitTypeDeclaration, TypeUsage } from "../parse/ast";
|
import { Impl, Module, TraitTypeDeclaration, TypeUsage } from "../parse/ast";
|
||||||
|
import { compareTypes } from "./type_system";
|
||||||
|
|
||||||
interface Context {
|
interface Context {
|
||||||
environment: Record<string, TraitTypeDeclaration>;
|
environment: Record<string, TraitTypeDeclaration>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compareTypes = (typeA: TypeUsage, typeB: TypeUsage) => {
|
|
||||||
if (typeA.typeUsage !== typeB.typeUsage) {
|
|
||||||
throw Error(`Mismatched types: ${typeA.typeUsage} ${typeB.typeUsage}`);
|
|
||||||
}
|
|
||||||
if (typeA.typeUsage == "NamedTypeUsage" && typeB.typeUsage == "NamedTypeUsage") {
|
|
||||||
if (typeA.name.name !== typeB.name.name) {
|
|
||||||
throw Error(`Mismatched types: ${typeA.name.name} ${typeB.name.name}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeA.typeUsage == "FunctionTypeUsage" && typeB.typeUsage == "FunctionTypeUsage") {
|
|
||||||
if (typeA.arguments.length !== typeB.arguments.length) {
|
|
||||||
throw Error(`Mismatched arg lengths: ${typeA.arguments.length} ${typeB.arguments.length}`);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < typeA.arguments.length; i++) {
|
|
||||||
compareTypes(typeA.arguments[i], typeB.arguments[i]);
|
|
||||||
}
|
|
||||||
compareTypes(typeA.returnType, typeB.returnType);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class TraitChecker {
|
export default class TraitChecker {
|
||||||
withModule = (module: Module) => {
|
withModule = (module: Module) => {
|
||||||
let ctx: Context = { environment: {} };
|
let ctx: Context = { environment: {} };
|
||||||
|
|||||||
0
packages/boringlang/src/types/type_checker.ts
Normal file
0
packages/boringlang/src/types/type_checker.ts
Normal file
165
packages/boringlang/src/types/type_system.ts
Normal file
165
packages/boringlang/src/types/type_system.ts
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
import { TypeUsage } from "../parse/ast";
|
||||||
|
|
||||||
|
export const compareTypes = (typeA: TypeUsage, typeB: TypeUsage) => {
|
||||||
|
if (typeA.typeUsage !== typeB.typeUsage) {
|
||||||
|
throw Error(`Mismatched types: ${typeA.typeUsage} ${typeB.typeUsage}`);
|
||||||
|
}
|
||||||
|
if (typeA.typeUsage == "NamedTypeUsage" && typeB.typeUsage == "NamedTypeUsage") {
|
||||||
|
if (typeA.name.name !== typeB.name.name) {
|
||||||
|
throw Error(`Mismatched types: ${typeA.name.name} ${typeB.name.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeA.typeUsage == "FunctionTypeUsage" && typeB.typeUsage == "FunctionTypeUsage") {
|
||||||
|
if (typeA.arguments.length !== typeB.arguments.length) {
|
||||||
|
throw Error(`Mismatched arg lengths: ${typeA.arguments.length} ${typeB.arguments.length}`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < typeA.arguments.length; i++) {
|
||||||
|
compareTypes(typeA.arguments[i], typeB.arguments[i]);
|
||||||
|
}
|
||||||
|
compareTypes(typeA.returnType, typeB.returnType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Equals {
|
||||||
|
operation: "equals";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Argument {
|
||||||
|
operation: "argument";
|
||||||
|
argNum: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReturnValue {
|
||||||
|
operation: "return";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Comparison {
|
||||||
|
left: TypeUsage;
|
||||||
|
operation: Equals | Argument | ReturnValue;
|
||||||
|
right: TypeUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeSystem {
|
||||||
|
comparisons: Comparison[];
|
||||||
|
result: Record<string, TypeUsage>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.comparisons = [];
|
||||||
|
this.result = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
compare = (comparison: Comparison) => {
|
||||||
|
this.comparisons.push(comparison);
|
||||||
|
};
|
||||||
|
|
||||||
|
solve = () => {
|
||||||
|
let foundUpdate = false;
|
||||||
|
let containsUnknown = false;
|
||||||
|
while (true) {
|
||||||
|
for (const comparison of this.comparisons) {
|
||||||
|
// if already found, just update
|
||||||
|
if (comparison.left.typeUsage === "UnknownTypeUsage" && this.result[comparison.left.name]) {
|
||||||
|
foundUpdate = true;
|
||||||
|
comparison.left = this.result[comparison.left.name];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
comparison.right.typeUsage === "UnknownTypeUsage" &&
|
||||||
|
this.result[comparison.right.name]
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
comparison.right = this.result[comparison.right.name];
|
||||||
|
}
|
||||||
|
// equals
|
||||||
|
if (comparison.operation.operation === "equals") {
|
||||||
|
// solve left
|
||||||
|
if (
|
||||||
|
comparison.left.typeUsage === "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage !== "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[comparison.left.name] = comparison.right;
|
||||||
|
comparison.left = comparison.right;
|
||||||
|
}
|
||||||
|
// solve right
|
||||||
|
if (
|
||||||
|
comparison.left.typeUsage !== "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage === "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[comparison.right.name] = comparison.left;
|
||||||
|
comparison.right = comparison.left;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
comparison.left.typeUsage !== "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage !== "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
compareTypes(comparison.left, comparison.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// argument
|
||||||
|
if (comparison.operation.operation === "argument") {
|
||||||
|
if (comparison.left.typeUsage !== "FunctionTypeUsage") {
|
||||||
|
throw Error("Argument for something that isn't a function");
|
||||||
|
}
|
||||||
|
// solve left
|
||||||
|
const argument = comparison.left.arguments[comparison.operation.argNum];
|
||||||
|
if (
|
||||||
|
argument.typeUsage === "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage !== "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[argument.name] = comparison.right;
|
||||||
|
comparison.left.arguments[comparison.operation.argNum] = comparison.right;
|
||||||
|
}
|
||||||
|
// solve right
|
||||||
|
if (
|
||||||
|
argument.typeUsage !== "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage === "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[comparison.right.name] =
|
||||||
|
comparison.left.arguments[comparison.operation.argNum];
|
||||||
|
comparison.right = comparison.left.arguments[comparison.operation.argNum];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return type
|
||||||
|
if (comparison.operation.operation === "return") {
|
||||||
|
if (comparison.left.typeUsage !== "FunctionTypeUsage") {
|
||||||
|
throw Error("return type for something that isn't a function");
|
||||||
|
}
|
||||||
|
// solve left
|
||||||
|
if (
|
||||||
|
comparison.left.returnType.typeUsage === "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage !== "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[comparison.left.returnType.name] = comparison.right;
|
||||||
|
comparison.left.returnType = comparison.right;
|
||||||
|
}
|
||||||
|
// solve right
|
||||||
|
if (
|
||||||
|
comparison.left.returnType.typeUsage !== "UnknownTypeUsage" &&
|
||||||
|
comparison.right.typeUsage === "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
foundUpdate = true;
|
||||||
|
this.result[comparison.right.name] = comparison.left.returnType;
|
||||||
|
comparison.right = comparison.left.returnType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
comparison.left.typeUsage === "UnknownTypeUsage" ||
|
||||||
|
comparison.right.typeUsage === "UnknownTypeUsage"
|
||||||
|
) {
|
||||||
|
containsUnknown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundUpdate && containsUnknown) {
|
||||||
|
throw Error("Type system failed to resolve all unknowns");
|
||||||
|
}
|
||||||
|
if (!foundUpdate) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.result;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user