UNPKG

@composita/symbols

Version:

Composita language symbols.

199 lines 8.66 kB
import { ComponentSymbol, InterfaceSymbol, BuiltInTypeSymbol, MessageSymbol, } from './type-symbols'; import { GlobalScopeSymbol } from './scope-symbols'; import { GenericSymbol } from './generic-symbols'; export class SearchOptions { constructor(scope, searchGlobalScope, searchParentScope) { this.scope = scope; this.searchGlobalScope = searchGlobalScope; this.searchParentScope = searchParentScope; } } export class SymbolTable { constructor() { // varia this.globalScope = new GlobalScopeSymbol(); this.voidType = new BuiltInTypeSymbol(this.globalScope, '@@@__VOID__@@@'); this.anyRequiredInterfaceType = new InterfaceSymbol(this.globalScope, '@@@__ANY_REQUIRED_INTERFACE__@@@'); this.anyGenericComponentType = new GenericSymbol([], []); this.anyComponentType = new ComponentSymbol(this.globalScope, '@@@__ANY_COMPONENT__@@@', this.anyGenericComponentType, false); this.anyMessage = new MessageSymbol(this.globalScope, 'ANY', []); this.finishMessage = new MessageSymbol(this.globalScope, 'FINISH', []); // mappings symbol -> node this.symbolToDeclaration = new Map(); this.symbolToImplementation = new Map(); this.symbolToComponent = new Map(); this.symbolToInterface = new Map(); // mappings node -> symbol this.expressionToSymbol = new Map(); this.typeToSymbol = new Map(); this.designatorToSymbol = new Map(); this.variableToSymbol = new Map(); this.callToSymbol = new Map(); this.sendReceiveToSymbol = new Map(); this.patternToSymbol = new Map(); this.implementationToSymbol = new Map(); this.procedureToSymbol = new Map(); // types this.types = new Array(); this.builtins = new Array(); this.components = new Array(); this.interfaces = new Array(); this.messages = new Array(); // lookups this.constants = new Array(); this.procedures = new Array(); this.impplementations = new Array(); this.variables = new Array(); this.collectionVariables = new Array(); } getMessages(scope) { return this.messages.filter((message) => message.scope === scope); } getSystemProcedures() { return this.procedures.filter((procedure) => procedure.scope === this.globalScope); } getProcedures(scope) { return this.procedures.filter((procedure) => procedure.scope === scope); } getImplementations(scope) { return this.impplementations.filter((implementation) => implementation.scope === scope); } getVariables(scope) { return this.variables.filter((variable) => variable.scope === scope); } getCollectionVariables(scope) { return this.collectionVariables.filter((variable) => variable.scope === scope); } registerBuiltIns(builtin) { this.builtins.push(builtin); this.types.push(builtin); } registerComponent(component) { this.components.push(component); this.types.push(component); } registerInterface(interfaceSymbol) { this.interfaces.push(interfaceSymbol); this.types.push(interfaceSymbol); } registerMessage(message) { this.messages.push(message); this.types.push(message); } registerProcedure(procedure) { this.procedures.push(procedure); } registerImplementation(implementation) { this.impplementations.push(implementation); } registerVariable(variable) { this.variables.push(variable); } registerCollectionVariable(variable) { this.collectionVariables.push(variable); } getOrThrow(item) { if (item === undefined) { throw new Error('Item was undefined.'); } return item; } getFirstOrThrow(data) { if (data.length < 1) { throw Error('Data containted no element.'); } if (data.length > 1) { throw Error('Data contained more than one element.'); } return data[0]; } static componentSatisfiesGeneric(component, generic) { if (generic.offered.length === 0 && generic.required.length === 0) { return true; } return generic.canBeSubstitutedBy(component.genericType); } findBuiltIn(name) { return this.builtins.filter((builtin) => builtin.identifier === name); } findProcedure(identifier, params, returnType, options) { const searchFunction = (procedure, searchScope) => { return (procedure.identifier === identifier && procedure.parameters.length === params.length && procedure.parameters.filter((p, i) => this.isAssignable(p, params[i])).length === params.length && (returnType === undefined || procedure.returnType === returnType) && procedure.scope === searchScope); }; return this.findInComponent(this.procedures, searchFunction.bind(this), options); } isAssignable(paramA, paramB) { if (paramA instanceof ComponentSymbol && paramB instanceof ComponentSymbol) { return paramA.genericType.canBeSubstitutedBy(paramB.genericType); } return paramA === paramB; } findInComponent(data, predicate, options) { if (!options.searchGlobalScope && options.scope instanceof GlobalScopeSymbol) { return new Array(); } const results = data.filter((element) => predicate(element, options.scope)); if (results.length > 0 || options.scope instanceof GlobalScopeSymbol) { return results; } if (!options.searchGlobalScope && options.scope.scope instanceof GlobalScopeSymbol) { return results; } if (!options.searchParentScope && (options.scope instanceof ComponentSymbol || options.scope instanceof InterfaceSymbol)) { if (options.searchGlobalScope) { return this.findInComponent(data, predicate, new SearchOptions(this.globalScope, options.searchGlobalScope, options.searchParentScope)); } return results; } return this.findInComponent(data, predicate, new SearchOptions(options.scope.scope, options.searchGlobalScope, options.searchParentScope)); } findNameInScope(data, identifier, options) { const searchFunction = (element, searchScope) => element.identifier === identifier && element.scope === searchScope; return this.findInComponent(data, searchFunction.bind(this), options); } findVariable(identifier, options) { return this.findNameInScope(this.variables, identifier, options); } findMessage(identifier, ignoreParams, params, options) { const searchFunction = (symbol, searchScope) => { return (symbol.identifier === identifier && symbol.scope === searchScope && (ignoreParams || (symbol.parameters.length === params.length && symbol.parameters.filter((p, i) => this.isAssignable(p, params[i])).length === params.length))); }; return this.findInComponent(this.messages, searchFunction.bind(this), options); } findCollectionVariable(identifier, ignoreParams, params, options) { const searchFunction = (symbol, searchScope) => { return (symbol.identifier === identifier && (ignoreParams || (symbol.parameters.length === params.length && symbol.parameters.filter((p, i) => this.isAssignable(p, params[i])).length === params.length)) && symbol.scope === searchScope); }; return this.findInComponent(this.collectionVariables, searchFunction.bind(this), options); } findComponent(identifier, options) { return this.findNameInScope(this.components, identifier, options); } findInterface(identifier, options) { return this.findNameInScope(this.interfaces, identifier, options); } findType(identifier, options) { return this.findNameInScope(this.types, identifier, options); } findImplementation(identifier, options) { const searchFunction = (symbol, searchScope) => { return symbol.interfaceSymbol.identifier === identifier && symbol.scope === searchScope; }; return this.findInComponent(this.impplementations, searchFunction.bind(this), options); } } //# sourceMappingURL=symboltable.js.map