@composita/symbols
Version:
Composita language symbols.
199 lines • 8.66 kB
JavaScript
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