"use strict";
// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Genie
//
// Copyright 2021 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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.replacePlaceholderWithCoreference = exports.replacePlaceholderWithTableOrStream = exports.replacePlaceholdersWithConstants = exports.replaceErrorMessagePlaceholders = exports.replaceSlotBagPlaceholders = void 0;
const assert_1 = __importDefault(require("assert"));
const thingtalk_1 = require("thingtalk");
const C = __importStar(require("./ast_manip"));
// Semantic functions for primitive templates
function replaceSlotBagPlaceholders(bag, names, args) {
    const clone = bag.clone();
    assert_1.default(names.length === args.length);
    for (let i = 0; i < names.length; i++) {
        const name = names[i];
        const value = args[i];
        if (name === null)
            continue;
        assert_1.default(value.isConstant());
        clone.set(name, value);
    }
    return clone;
}
exports.replaceSlotBagPlaceholders = replaceSlotBagPlaceholders;
function replaceErrorMessagePlaceholders(msg, names, args) {
    const newBag = replaceSlotBagPlaceholders(msg.bag, names, args);
    if (!newBag)
        return null;
    return { code: msg.code, bag: newBag };
}
exports.replaceErrorMessagePlaceholders = replaceErrorMessagePlaceholders;
function replacePlaceholdersWithConstants(ex, names, args) {
    const replacements = {};
    assert_1.default(names.length === args.length);
    for (let i = 0; i < names.length; i++) {
        const name = names[i];
        const value = args[i];
        if (name === null)
            continue;
        assert_1.default(value.getType().equals(ex.args[name]));
        replacements[name] = value;
    }
    return C.betaReduceMany(ex.value, replacements);
}
exports.replacePlaceholdersWithConstants = replacePlaceholdersWithConstants;
function replacePlaceholderWithTableOrStream(ex, names, tableParamIdx, args, tpLoader) {
    // first check the table, then replace the parameters, and then finally construct the chain expression
    const table = args[tableParamIdx];
    assert_1.default(table instanceof thingtalk_1.Ast.Expression);
    const intoname = names[tableParamIdx];
    assert_1.default(typeof intoname === 'string');
    const intoType = ex.args[intoname];
    assert_1.default(intoType);
    let projection;
    if (!(table instanceof thingtalk_1.Ast.ProjectionExpression)) {
        const maybeProjection = C.makeTypeBasedTableProjection(tpLoader, table, intoType);
        if (maybeProjection === null)
            return null;
        projection = maybeProjection;
    }
    else {
        projection = table;
        // FIXME we should make up a projection based on what parameter is actually passed
        if (projection.args.length !== 1)
            return null;
        if (projection.args[0] === 'id')
            return null;
    }
    assert_1.default(projection.args.length === 1);
    const joinArg = projection.args[0];
    if (joinArg === '$event' && ['p_body', 'p_message', 'p_caption', 'p_status'].indexOf(intoname) < 0)
        return null;
    const joinType = joinArg === '$event' ? thingtalk_1.Type.String : projection.schema.getArgType(joinArg);
    // note: we need to use isAssignable here to get entity inheritance right
    if (!thingtalk_1.Type.isAssignable(joinType, intoType, {}, tpLoader.entitySubTypeMap))
        return null;
    const replacements = {};
    assert_1.default(names.length === args.length);
    for (let i = 0; i < names.length; i++) {
        const name = names[i];
        if (name === null)
            continue;
        if (i === tableParamIdx) {
            const value = joinArg === '$event' ? new thingtalk_1.Ast.Value.Event(null) : new thingtalk_1.Ast.Value.VarRef(joinArg);
            replacements[name] = value;
        }
        else {
            const value = args[i];
            assert_1.default(value.getType().equals(ex.args[name]));
            replacements[name] = value;
        }
    }
    const reduced = C.betaReduceMany(ex.value, replacements);
    if (!reduced)
        return null;
    return C.makeChainExpression(projection.expression, reduced);
}
exports.replacePlaceholderWithTableOrStream = replacePlaceholderWithTableOrStream;
function replacePlaceholderWithCoreference(ex, names, corefParamIdx, args) {
    // first perform some checks, then replace the parameters, and then finally construct
    // the expression with coreference
    // what kind of coreference are we performing
    const pname = names[corefParamIdx];
    assert_1.default(pname);
    const corefArg = args[corefParamIdx];
    let corefReplacement = null;
    let corefSlot = null;
    if (corefArg === undefined || typeof corefArg === 'string') {
        // generic coreference ("it", "this", etc.)
    }
    else if (corefArg instanceof thingtalk_1.Ast.Expression) {
        // table based coreference ("book the restaurant")
        const idArg = corefArg.schema.getArgument('id');
        if (!idArg || !idArg.type.equals(ex.args[pname]))
            return null;
    }
    else {
        // param based coreference ("post the caption")
        const slot = corefArg;
        if (!slot.type.equals(ex.args[pname]))
            return null;
        if (slot.name === 'id') // do not make a reference to "the name"
            return null;
        corefReplacement = new thingtalk_1.Ast.Value.VarRef(slot.name);
        corefSlot = slot;
    }
    const replacements = {};
    assert_1.default(names.length === args.length);
    for (let i = 0; i < names.length; i++) {
        const name = names[i];
        if (name === null)
            continue;
        if (i === corefParamIdx) {
            if (corefReplacement !== null)
                replacements[name] = corefReplacement;
        }
        else {
            const value = args[i];
            assert_1.default(value.getType().equals(ex.args[name]));
            replacements[name] = value;
        }
    }
    const reduced = C.betaReduceMany(ex.value, replacements);
    if (!reduced)
        return null;
    return {
        expression: reduced,
        type: ex.args[pname],
        slot: corefSlot,
        pname: corefSlot ? null : pname
    };
}
exports.replacePlaceholderWithCoreference = replacePlaceholderWithCoreference;
//# sourceMappingURL=primitive_templates.js.map