added type system
This commit is contained in:
@@ -1,29 +1,10 @@
|
||||
import { Impl, Module, TraitTypeDeclaration, TypeUsage } from "../parse/ast";
|
||||
import { compareTypes } from "./type_system";
|
||||
|
||||
interface Context {
|
||||
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 {
|
||||
withModule = (module: Module) => {
|
||||
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