constructor(config, isTest = false) {
        this.logs = [];
        this.isTest = isTest;
        this.utils = new Utils(this);
        config = Object.assign({
            functions: {},
            functionsNeedContext: {},
            onVariable: () => null,
            onCell: () => 0,
            onRange: () => [[0]],
        }, config);

        this.onVariable = config.onVariable;
        this.functions = Object.assign({}, DateFunctions, StatisticalFunctions, InformationFunctions, ReferenceFunctions,
            EngFunctions, LogicalFunctions, TextFunctions, MathFunctions, TrigFunctions, WebFunctions,
            config.functions, config.functionsNeedContext);
        this.onRange = config.onRange;
        this.onCell = config.onCell;

        // functions treat null as 0, other functions treats null as ""
        this.funsNullAs0 = Object.keys(MathFunctions)
            .concat(Object.keys(TrigFunctions))
            .concat(Object.keys(LogicalFunctions))
            .concat(Object.keys(EngFunctions))
            .concat(Object.keys(ReferenceFunctions))
            .concat(Object.keys(StatisticalFunctions))
            .concat(Object.keys(DateFunctions));

        // functions need context and don't need to retrieve references
        this.funsNeedContextAndNoDataRetrieve = ['ROW', 'ROWS', 'COLUMN', 'COLUMNS', 'SUMIF', 'INDEX', 'AVERAGEIF', 'IF'];

        // functions need parser context
        this.funsNeedContext = [...Object.keys(config.functionsNeedContext), ...this.funsNeedContextAndNoDataRetrieve,
            'INDEX', 'OFFSET', 'INDIRECT', 'IF', 'CHOOSE', 'WEBSERVICE'];

        // functions preserve reference in arguments
        this.funsPreserveRef = Object.keys(InformationFunctions);

        this.parser = new Parser(this, this.utils);
    }
@param {{functions: {}, functionsNeedContext: {}, onVariable: function, onCell: function, onRange: function}} [config]
@param isTest - is in testing environment