"use strict";
// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Genie
//
// Copyright 2019-2020 The Board of Trustees of the Leland Stanford Junior University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Giovanni Campagna <gcampagn@cs.stanford.edu>
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.expressionWithCoreferenceKeyFn = exports.argMinMaxKeyFn = exports.expressionStatementKeyFn = exports.errorMessageKeyFn = exports.slotBagKeyFn = exports.invocationKeyFn = exports.expressionKeyFn = exports.functionDefKeyFn = exports.paramArrayKeyFn = exports.paramKeyFn = exports.inputParamKeyFn = exports.filterKeyFn = exports.entityOrNumberValueKeyFn = exports.valueArrayKeyFn = exports.valueKeyFn = exports.placeholderKeyFn = void 0;
const assert_1 = __importDefault(require("assert"));
const thingtalk_1 = require("thingtalk");
const ast_manip_1 = require("./ast_manip");
// Key functions: given the result of a semantic function, compute
// a set of keys to speed-up derivation matching
function placeholderKeyFn(pl) {
    return { type: pl.type, is_numeric: pl.type.isNumeric() };
}
exports.placeholderKeyFn = placeholderKeyFn;
function valueKeyFn(value) {
    const type = value.getType();
    return { type, is_numeric: type.isNumeric(), is_constant: value.isConstant() };
}
exports.valueKeyFn = valueKeyFn;
function valueArrayKeyFn(values) {
    const type = values[0].getType();
    return { type, is_numeric: type.isNumeric() };
}
exports.valueArrayKeyFn = valueArrayKeyFn;
function entityOrNumberValueKeyFn(value) {
    const type = value.getType();
    return { type, is_numeric: type.isNumeric(), value: value.value };
}
exports.entityOrNumberValueKeyFn = entityOrNumberValueKeyFn;
function filterKeyFn(slot) {
    const schema = slot.schema;
    const id = schema === null || schema === void 0 ? void 0 : schema.getArgument('id');
    return {
        functionName: schema ? schema.qualifiedName : null,
        type: slot.ptype,
        is_numeric: slot.ptype ? slot.ptype.isNumeric() : false,
        associatedIdType: id && !id.is_input ? id.type : null
    };
}
exports.filterKeyFn = filterKeyFn;
function inputParamKeyFn(slot) {
    return { functionName: slot.schema.qualifiedName, type: slot.ptype };
}
exports.inputParamKeyFn = inputParamKeyFn;
function paramKeyFn(slot) {
    const id = slot.schema.getArgument('id');
    return {
        functionName: slot.schema.qualifiedName,
        type: slot.type,
        is_numeric: slot.type.isNumeric(),
        elem: slot.type instanceof thingtalk_1.Type.Array ? slot.type.elem : null,
        is_numeric_elem: slot.type instanceof thingtalk_1.Type.Array ? slot.type.elem.isNumeric() : false,
        associatedIdType: id && !id.is_input ? id.type : null,
        filterable: slot.filterable
    };
}
exports.paramKeyFn = paramKeyFn;
function paramArrayKeyFn(slots) {
    if (slots.length === 0)
        return { functionName: null, type: null, associatedIdType: null, filterable: true };
    const id = slots[0].schema.getArgument('id');
    return { functionName: slots[0].schema.qualifiedName, type: slots[0].type,
        associatedIdType: id && !id.is_input ? id.type : null,
        filterable: slots.every((s) => s.filterable) };
}
exports.paramArrayKeyFn = paramArrayKeyFn;
function functionDefKeyFn(fndef) {
    return { functionName: fndef.qualifiedName };
}
exports.functionDefKeyFn = functionDefKeyFn;
function expressionKeyFn(expr) {
    const schema = expr.schema;
    const geo = schema.getArgument('geo');
    const id = schema.getArgument('id');
    let isEventProjection = false;
    let projectionType = null;
    let implicitParamPassingType = null;
    if (expr instanceof thingtalk_1.Ast.MonitorExpression)
        expr = expr.expression;
    if (expr instanceof thingtalk_1.Ast.ProjectionExpression) {
        if (expr.args.length === 1 && expr.computations.length === 0) {
            isEventProjection = expr.args[0] === '$event';
            if (isEventProjection)
                projectionType = thingtalk_1.Type.String;
            else
                projectionType = schema.getArgType(expr.args[0]);
        }
        else if (expr.computations.length === 1 && expr.args.length === 0) {
            projectionType = expr.computations[0].getType();
        }
    }
    else {
        const paramPassing = ast_manip_1.getImplicitParameterPassing(expr.schema);
        if (paramPassing === '$event')
            implicitParamPassingType = thingtalk_1.Type.String;
        else
            implicitParamPassingType = schema.getArgType(paramPassing);
    }
    assert_1.default(projectionType !== undefined);
    return {
        functionName: schema.qualifiedName,
        is_list: schema.is_list,
        is_monitorable: schema.is_monitorable,
        has_geo: !!(geo && geo.type === thingtalk_1.Type.Location),
        projectionType,
        isEventProjection,
        implicitParamPassingType,
        idType: id && !id.is_input ? id.type : null
    };
}
exports.expressionKeyFn = expressionKeyFn;
function invocationKeyFn(expr) {
    const schema = expr.schema;
    const geo = schema.getArgument('geo');
    const id = schema.getArgument('id');
    return {
        functionName: schema.qualifiedName,
        is_list: schema.is_list,
        is_monitorable: schema.is_monitorable,
        has_geo: !!(geo && geo.type === thingtalk_1.Type.Location),
        idType: id && !id.is_input ? id.type : null
    };
}
exports.invocationKeyFn = invocationKeyFn;
function slotBagKeyFn(expr) {
    var _a;
    const id = (_a = expr.schema) === null || _a === void 0 ? void 0 : _a.getArgument('id');
    return {
        functionName: expr.schema ? expr.schema.qualifiedName : null,
        idType: id && !id.is_input ? id.type : null
    };
}
exports.slotBagKeyFn = slotBagKeyFn;
function errorMessageKeyFn(msg) {
    return {
        functionName: msg.bag.schema ? msg.bag.schema.qualifiedName : null,
    };
}
exports.errorMessageKeyFn = errorMessageKeyFn;
function expressionStatementKeyFn(expr) {
    const schema = expr.expression.schema;
    return { functionName: schema.qualifiedName };
}
exports.expressionStatementKeyFn = expressionStatementKeyFn;
function argMinMaxKeyFn(argminmax) {
    return paramKeyFn(argminmax[0]);
}
exports.argMinMaxKeyFn = argMinMaxKeyFn;
function expressionWithCoreferenceKeyFn(coref) {
    const schema = coref.expression.schema;
    const id = schema.getArgument('id');
    return {
        // standard expression keys
        functionName: schema.qualifiedName,
        idType: id && !id.is_input ? id.type : null,
        // coref specific keys
        corefType: coref.type,
        corefFunctionName: coref.slot ? coref.slot.schema.qualifiedName : null,
    };
}
exports.expressionWithCoreferenceKeyFn = expressionWithCoreferenceKeyFn;
//# sourceMappingURL=keyfns.js.map