@composita/symbols
Version: 
Composita language symbols.
204 lines • 8.94 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SymbolTable = exports.SearchOptions = void 0;
const type_symbols_1 = require("./type-symbols");
const scope_symbols_1 = require("./scope-symbols");
const generic_symbols_1 = require("./generic-symbols");
class SearchOptions {
    constructor(scope, searchGlobalScope, searchParentScope) {
        this.scope = scope;
        this.searchGlobalScope = searchGlobalScope;
        this.searchParentScope = searchParentScope;
    }
}
exports.SearchOptions = SearchOptions;
class SymbolTable {
    constructor() {
        // varia
        this.globalScope = new scope_symbols_1.GlobalScopeSymbol();
        this.voidType = new type_symbols_1.BuiltInTypeSymbol(this.globalScope, '@@@__VOID__@@@');
        this.anyRequiredInterfaceType = new type_symbols_1.InterfaceSymbol(this.globalScope, '@@@__ANY_REQUIRED_INTERFACE__@@@');
        this.anyGenericComponentType = new generic_symbols_1.GenericSymbol([], []);
        this.anyComponentType = new type_symbols_1.ComponentSymbol(this.globalScope, '@@@__ANY_COMPONENT__@@@', this.anyGenericComponentType, false);
        this.anyMessage = new type_symbols_1.MessageSymbol(this.globalScope, 'ANY', []);
        this.finishMessage = new type_symbols_1.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();
        // types
        this.types = new Array();
        this.builtins = new Array();
        this.components = new Array();
        this.interfaces = new Array();
        this.messages = new Array();
        // lookups
        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 type_symbols_1.ComponentSymbol && paramB instanceof type_symbols_1.ComponentSymbol) {
            return paramA.genericType.canBeSubstitutedBy(paramB.genericType);
        }
        return paramA === paramB;
    }
    findInComponent(data, predicate, options) {
        if (!options.searchGlobalScope && options.scope instanceof scope_symbols_1.GlobalScopeSymbol) {
            return new Array();
        }
        const results = data.filter((element) => predicate(element, options.scope));
        if (results.length > 0) {
            return results;
        }
        if (options.scope instanceof scope_symbols_1.GlobalScopeSymbol) {
            return results;
        }
        if (!options.searchGlobalScope && options.scope.scope instanceof scope_symbols_1.GlobalScopeSymbol) {
            return results;
        }
        if (!options.searchParentScope &&
            (options.scope instanceof type_symbols_1.ComponentSymbol || options.scope instanceof type_symbols_1.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.searchParentScope, 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);
    }
}
exports.SymbolTable = SymbolTable;
//# sourceMappingURL=symboltable.js.map