@composita/symbols
Version: 
Composita language symbols.
199 lines • 8.51 kB
JavaScript
import { ComponentSymbol, InterfaceSymbol, BuiltInTypeSymbol, } 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);
        // 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);
    }
    throwCheck(item) {
        if (item === undefined) {
            throw new Error('Item was undefined.');
        }
        return true;
    }
    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);
    }
    findConstant(identifier, options) {
        return this.findVariable(identifier, true, options);
    }
    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;
    }
    findMessage(identifier, options, params) {
        const searchFunction = (symbol, searchScope) => {
            return (symbol.identifier === identifier &&
                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.messages, searchFunction.bind(this), options);
    }
    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) {
            return results;
        }
        if (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.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, mutable, options) {
        return this.findNameInScope(this.variables.filter((variable) => variable.mutable == mutable), identifier, 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