@composita/compiler
Version:
Composita language compiler.
173 lines • 8 kB
JavaScript
import { ComponentSymbol, InterfaceSymbol, ImplementationSymbol, ProcedureSymbol, NamedScopeSymbol, SearchOptions, GlobalScopeSymbol, } from '../symbols/symbols';
import { FixExpressionNodeVisitor } from './fix-expression-node';
import { FixTypeNodeVisitor } from './fix-type-node';
export class CheckerHelper {
static checkNotConstantSymbol(name, symbolTable) {
const value = symbolTable.constants.filter((constant) => constant.identifier === name);
if (value.length !== 0) {
throw new Error(`${name} is a constant variable!`);
}
}
static getComponent(symbolTable, name, options) {
this.checkNotConstantSymbol(name, symbolTable);
const components = symbolTable.findComponent(name, options);
if (components.length > 1) {
throw new Error(`Component ${name} defined ${components.length} times in the same scope.`);
}
if (components.length < 1) {
throw new Error(`No component ${name} found.`);
}
return components[0];
}
static getInterface(symbolTable, name, options) {
this.checkNotConstantSymbol(name, symbolTable);
const interfaces = symbolTable.findInterface(name, options);
if (interfaces.length > 1) {
throw new Error(`Interface ${name} defined ${interfaces.length} times in the same scope.`);
}
if (interfaces.length < 1) {
throw new Error(`No interface ${name} found.`);
}
return interfaces[0];
}
static getImplementation(symbolTable, name, options) {
this.checkNotConstantSymbol(name, symbolTable);
if (!(options.scope instanceof ComponentSymbol)) {
throw new Error(`Failed to locate ${name}, must be inside a component.`);
}
const implementations = symbolTable.findImplementation(name, options);
if (implementations.length > 1) {
throw new Error(`Implementaiton ${name} defined ${implementations.length} times in the same scope.`);
}
if (implementations.length < 1) {
throw new Error(`No implementation ${name} found.`);
}
return implementations[0];
}
static getConstant(symbolTable, name) {
const constant = symbolTable.constants.filter((constant) => constant.identifier === name);
if (constant.length > 1) {
throw new Error(`Found ${name} multiple times.`);
}
if (constant.length < 1) {
throw new Error(`Failed to find ${name}.`);
}
return constant[0];
}
static getVariable(symbolTable, name, options) {
const symbol = symbolTable.findVariable(name, options);
if (symbol.length > 1) {
throw new Error(`Found ${name} multiple times.`);
}
if (symbol.length < 1) {
throw new Error(`Failed to find ${name}.`);
}
return symbol[0];
}
static getProcedureParam(symbolTable, scope, name) {
while (!(scope instanceof ProcedureSymbol) && scope instanceof NamedScopeSymbol) {
// go up to procedure.
scope = scope.scope;
}
if (!(scope instanceof ProcedureSymbol)) {
throw new Error(`${name} is not a procedure parameter.`);
}
const symbol = this.getVariable(symbolTable, name, new SearchOptions(scope, false, false));
if (!(symbol.scope instanceof ProcedureSymbol)) {
throw new Error(`Found ${name} outside procedure param.`);
}
return symbol;
}
static getProcedure(name, symbolTable, params, returnType, options) {
this.checkNotConstantSymbol(name, symbolTable);
const procedures = symbolTable.findProcedure(name, params, returnType, options);
if (procedures.length > 1) {
throw new Error(`Procedure ${name} defined ${procedures.length} times in the same scope.`);
}
if (procedures.length < 1) {
throw new Error(`No procedure ${name} found.`);
}
return procedures[0];
}
static getProcedureFromNode(node, symbolTable, options) {
const name = node.getName().getName();
this.checkNotConstantSymbol(name, symbolTable);
let returnType = symbolTable.voidType;
const returnTypeNode = node.getType();
if (returnTypeNode !== undefined) {
returnTypeNode.accept(new FixTypeNodeVisitor(symbolTable, options.scope));
const foundType = symbolTable.typeToSymbol.get(returnTypeNode);
if (foundType === undefined) {
throw new Error(`Failed to find procedure ${name} return type.`);
}
returnType = foundType;
}
const paramTypes = CheckerHelper.convertParamTypes(symbolTable, options.scope, node.getParams().map((param) => param.getParameter()));
return this.getProcedure(name, symbolTable, paramTypes, returnType, options);
}
static getTypeType(symbolTable, node) {
const type = symbolTable.typeToSymbol.get(node);
if (type === undefined) {
throw new Error(`Type node type lookup failed.`);
}
return type;
}
static convertParamTypes(symbolTable, scope, params) {
return params.flatMap((param) => {
param.getType().accept(new FixTypeNodeVisitor(symbolTable, scope));
const type = this.getTypeType(symbolTable, param.getType());
return param.getNames().map(() => type);
});
}
static getMessageInImplentation(symbolTable, scope, name, ignoreArgs, args) {
while (!(scope instanceof ImplementationSymbol)) {
if (scope instanceof GlobalScopeSymbol) {
throw new Error(`Failed message lookup for ${name}.`);
}
scope = scope.scope;
}
const messages = symbolTable.findMessage(name, ignoreArgs, args, new SearchOptions(scope.interfaceSymbol, false, false));
if (messages.length > 1) {
throw new Error(`Ambiguous message lookup for ${name}.`);
}
if (messages.length < 1) {
throw new Error(`Message lookup failed for ${name}.`);
}
return messages[0];
}
static getMessage(symbolTable, scope, interfaceTarget, name, ignoreArgs, args) {
const argTypes = args.map((argument) => {
argument.accept(new FixExpressionNodeVisitor(symbolTable, scope));
const type = symbolTable.expressionToSymbol.get(argument);
if (type === undefined) {
throw new Error('Failed argument type lookup.');
}
return type;
});
interfaceTarget?.accept(new FixExpressionNodeVisitor(symbolTable, scope));
if (interfaceTarget !== undefined) {
const type = symbolTable.expressionToSymbol.get(interfaceTarget);
const messages = new Array();
if (type instanceof ComponentSymbol) {
messages.push(...type.genericType.offered
.map((offer) => offer.interfaceSymbol)
.flatMap((potentialInterface) => symbolTable.findMessage(name, ignoreArgs, argTypes, new SearchOptions(potentialInterface, false, false))));
}
else if (type instanceof InterfaceSymbol) {
messages.push(...symbolTable.findMessage(name, ignoreArgs, argTypes, new SearchOptions(type, false, false)));
}
else {
throw new Error(`Failed interface lookup for ${name}.`);
}
if (messages.length > 1) {
throw new Error(`Ambigious message lookup for ${name}.`);
}
if (messages.length < 1) {
throw new Error(`Message lookup failed for ${name}.`);
}
return messages[0];
}
return this.getMessageInImplentation(symbolTable, scope, name, ignoreArgs, argTypes);
}
}
//# sourceMappingURL=static-helpers.js.map