"use strict";
// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Genie
//
// Copyright 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.serializePrediction = exports.serializeNormalized = exports.parseAllPredictions = exports.parsePrediction = exports.parse = void 0;
const assert_1 = __importDefault(require("assert"));
const thingtalk_1 = require("thingtalk");
const entity_retriever_1 = __importDefault(require("./entity-retriever"));
async function parse(code, options) {
    let schemas;
    let loadMetadata;
    if (options instanceof thingtalk_1.SchemaRetriever) {
        schemas = options;
        loadMetadata = false;
    }
    else {
        const tpClient = options.thingpediaClient;
        if (!options.schemaRetriever)
            options.schemaRetriever = new thingtalk_1.SchemaRetriever(tpClient, null, true);
        schemas = options.schemaRetriever;
        loadMetadata = options.loadMetadata || false;
    }
    assert_1.default(code);
    let parsed;
    try {
        // first try parsing using normal syntax
        parsed = thingtalk_1.Syntax.parse(code);
    }
    catch (e1) {
        // if that fails, try with legacy syntax
        if (e1.name !== 'SyntaxError')
            throw e1;
        try {
            parsed = thingtalk_1.Syntax.parse(code, thingtalk_1.Syntax.SyntaxType.Legacy);
        }
        catch (e2) {
            if (e2.name !== 'SyntaxError')
                throw e2;
            throw e1; // use the first error not the second in case both fail
        }
    }
    return parsed.typecheck(schemas, loadMetadata);
}
exports.parse = parse;
async function parsePrediction(code, entities, options, strict = false) {
    const tpClient = options.thingpediaClient;
    if (!options.schemaRetriever)
        options.schemaRetriever = new thingtalk_1.SchemaRetriever(tpClient, null, true);
    const schemas = options.schemaRetriever;
    try {
        let parsed;
        try {
            // first try parsing using normal tokenized syntax
            parsed = thingtalk_1.Syntax.parse(code, thingtalk_1.Syntax.SyntaxType.Tokenized, entities);
        }
        catch (e1) {
            // if that fails, try with legacy NN syntax
            if (e1.name !== 'SyntaxError')
                throw e1;
            try {
                parsed = thingtalk_1.Syntax.parse(code, thingtalk_1.Syntax.SyntaxType.LegacyNN, entities);
            }
            catch (e2) {
                if (e2.name !== 'SyntaxError')
                    throw e2;
                throw e1; // use the first error not the second in case both fail
            }
        }
        await parsed.typecheck(schemas, options.loadMetadata);
        return parsed;
    }
    catch (e) {
        if (strict)
            throw e;
        return null;
    }
}
exports.parsePrediction = parsePrediction;
function notNull(x) {
    return x !== null;
}
async function parseAllPredictions(candidates, entities, options) {
    return (await Promise.all(candidates.map((cand) => {
        return parsePrediction(cand.code, entities, options, false);
    }))).filter(notNull);
}
exports.parseAllPredictions = parseAllPredictions;
/**
 * Convert a program or dialogue state to a normalized sequence of tokens, suitable
 * to input to the neural network as context.
 */
function serializeNormalized(program, entities = {}) {
    if (program === null)
        return [['null'], {}];
    const allocator = new thingtalk_1.Syntax.SequentialEntityAllocator(entities);
    const code = thingtalk_1.Syntax.serialize(program, thingtalk_1.Syntax.SyntaxType.Tokenized, allocator);
    return [code, entities];
}
exports.serializeNormalized = serializeNormalized;
/**
 * Convert a program or dialogue state to a sequence of tokens to predict.
 */
function serializePrediction(program, sentence, entities, options) {
    const entityRetriever = new entity_retriever_1.default(typeof sentence === 'string' ? sentence.split(' ') : sentence, entities, {
        locale: options.locale,
        allowNonConsecutive: true,
        useHeuristics: true,
        alwaysAllowStrings: false,
        ignoreSentence: options.ignoreSentence || false,
    });
    return thingtalk_1.Syntax.serialize(program, thingtalk_1.Syntax.SyntaxType.Tokenized, entityRetriever, {
        compatibility: options.compatibility
    });
}
exports.serializePrediction = serializePrediction;
//# sourceMappingURL=syntax.js.map