UNPKG

@composita/compiler

Version:

Composita language compiler.

173 lines 8 kB
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