// -*- 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>

import { Ast, } from 'thingtalk';

// import the combinator library
import * as C from './ast_manip';
import ThingpediaLoader from './load-thingpedia';

import './common-constants.genie';

// Declare key functions for non-contextual stuff
keyfn = {
    C.Placeholder : C.placeholderKeyFn,
    Ast.Value : C.valueKeyFn,
    Ast.LocationValue : C.valueKeyFn,
    Ast.NumberValue : C.entityOrNumberValueKeyFn,
    Ast.EntityValue : C.entityOrNumberValueKeyFn,
    Ast.EntityValue|Ast.NumberValue : C.entityOrNumberValueKeyFn,
    Ast.ContextRefValue : C.valueKeyFn,
    [Ast.Value, Ast.Value] : C.valueArrayKeyFn,
    Ast.Value[] : C.valueArrayKeyFn,
    Ast.Expression : C.expressionKeyFn,
    Ast.InvocationExpression : C.expressionKeyFn,
    Ast.ChainExpression : C.expressionKeyFn,
    Ast.Invocation : C.invocationKeyFn,
    Ast.ExpressionStatement : C.expressionStatementKeyFn,
    Ast.FunctionDef : C.functionDefKeyFn,
    C.InputParamSlot : C.inputParamKeyFn,
    C.FilterSlot : C.filterKeyFn,
    C.FilterSlot|C.DomainIndependentFilterSlot : C.filterKeyFn,
    C.ParamSlot : C.paramKeyFn,
    C.ParamSlot[] : C.paramArrayKeyFn,
    C.ArgMinMax : C.argMinMaxKeyFn,
    SlotBag : C.slotBagKeyFn,
    C.ErrorMessage : C.errorMessageKeyFn,
    C.ExpressionWithCoreference : C.expressionWithCoreferenceKeyFn,
}

// Thingpedia Grammar Rules

// the following are a all autogenerated by load-thingpedia.js

thingpedia_complete_query : Ast.Expression = {}
thingpedia_complete_get_command : Ast.Expression = {}
thingpedia_complete_stream : Ast.Expression = {}
thingpedia_complete_action : Ast.Expression = {}
thingpedia_complete_action_past : Ast.Expression = {}
thingpedia_complete_join_action_past : Ast.Expression = {}
thingpedia_complete_program : Ast.Expression = {}

thingpedia_who_question : Ast.Expression = {}
thingpedia_search_question : C.ParamSlot = {}
thingpedia_slot_fill_question : C.ParamSlot = {}
thingpedia_user_question : C.ParamSlot[] = {}

same_sentence_coref = {}
context_coref = {}
list_context_coref = {}
coref_constant : Ast.Value = {}
placeholder : C.Placeholder = {}
constant_or_undefined : Ast.Value = {
    pl:placeholder => {
        const v = new Ast.Value.Undefined(true);
        // override getType() so we can do type-checks
        v.getType = () => pl.type;
        return v;
    };
}

// joins can be produced directly by replacing into primitive templates,
// hence we declare the associated non-terminals here
table_join_replace_placeholder : Ast.ChainExpression = {}
action_replace_param_with_table : Ast.ChainExpression = {}
action_replace_param_with_stream : Ast.ChainExpression = {}
with_filtered_table : Ast.Expression = {}
with_arg_min_max_table : Ast.Expression = {}
projection_Any : Ast.Expression = {}
stream_projection_Any : Ast.Expression = {}

// coreference expressions
stream_coref_same_sentence : C.ExpressionWithCoreference = {}
stream_coref_context : C.ExpressionWithCoreference = {}
stream_coref_list_context : C.ExpressionWithCoreference = {}
action_coref_same_sentence : C.ExpressionWithCoreference = {}
action_coref_context : C.ExpressionWithCoreference = {}
action_coref_list_context : C.ExpressionWithCoreference = {}
query_coref_same_sentence : C.ExpressionWithCoreference = {}
query_coref_context : C.ExpressionWithCoreference = {}
query_coref_list_context : C.ExpressionWithCoreference = {}
get_command_coref_same_sentence : C.ExpressionWithCoreference = {}
get_command_coref_context : C.ExpressionWithCoreference = {}
get_command_coref_list_context : C.ExpressionWithCoreference = {}

// references to parameter by name
out_param_Any : C.ParamSlot = {}
out_param_Any_hidden: C.ParamSlot = {}
the_out_param_Any : C.ParamSlot = {}
out_param_Array__Any : C.ParamSlot = {}
out_param_Array__Compound : C.ParamSlot = {}
out_param_ArrayCount : C.ParamSlot = {}
out_param_npp : C.ParamSlot = {}
out_param_npi : C.ParamSlot = {}
out_param_avp : C.ParamSlot = {}
out_param_pvp : C.ParamSlot = {}
out_param_npv : C.ParamSlot = {}
out_param_apv : C.ParamSlot = {}

input_param : C.ParamSlot = {}

// helper prefix for "and" filters
// English overrides this to add "both" as well
both_prefix : string = {
    '';
}

// pronouns used to refer to the first/second part of 
// an expression with left-hand side and right-hand side
// like join
pronoun_the_first : string = {}
pronoun_the_second : string = {}

// terminal for symmetric properties
each_other : string = {}

// filters & input parameters on npp parameters
// nnp: Noun-Phrase parameter for Property of the subject
// e.g.: "name", "date of birth"

npp_filter : C.FilterSlot = {}
npp_join_condition : C.FilterSlot = {}
npp_symmetric_join_condition : C.FilterSlot = {}
npp_input_param : C.InputParamSlot = {}
npp_argminmax : C.ArgMinMax = {}
coref_npp_filter : C.FilterSlot = {}
coref_npp_input_param : C.InputParamSlot = {}
npp_boolean_projection : C.ParamSlot = {}

// filters & input parameters on npi parameters
// npi: Noun-phrase parameter for Identity of the subejct
// e.g.: "owner of <company>", "student in <university>"
npi_filter : C.FilterSlot = {}
npi_join_condition : C.FilterSlot = {}
npi_symmetric_join_condition : C.FilterSlot = {}
npi_input_param : C.InputParamSlot = {}
npi_argminmax : C.ArgMinMax = {}
coref_npi_filter : C.FilterSlot = {}
coref_npi_input_param : C.InputParamSlot = {}
npi_boolean_projection : C.ParamSlot = {}

// filters & input parameters on pvp parameters
// pvp: Passive-Verb Phrase parameter
// e.g.: "called <nickname>", "born on <date>"
pvp_filter : C.FilterSlot = {}
pvp_join_condition : C.FilterSlot = {}
pvp_symmetric_join_condition : C.FilterSlot = {}
pvp_input_param : C.InputParamSlot = {}
pvp_argminmax : C.ArgMinMax = {}
coref_pvp_filter : C.FilterSlot = {}
coref_pvp_input_param : C.InputParamSlot = {}
pvp_boolean_projection : C.ParamSlot = {}

// filters & input parameters on prep parameters
// prep: preposition parameter
// e.g.: "at <time>", "in <area>"
preposition_filter : C.FilterSlot = {}
preposition_join_condition : C.FilterSlot = {}
preposition_symmetric_join_condition : C.FilterSlot = {}
preposition_input_param : C.InputParamSlot = {}
preposition_argminmax : C.ArgMinMax = {}
coref_preposition_filter : C.FilterSlot = {}
coref_preposition_input_param : C.InputParamSlot = {}
preposition_boolean_projection : C.ParamSlot = {}

// filters & input parameters on avp parameters
// avp: Active-Verb Phrase parameter
// e.g.: "owns <company>", "studied in <university>"
avp_filter : C.FilterSlot = {}
avp_join_condition : C.FilterSlot = {}
avp_symmetric_join_condition : C.FilterSlot = {}
avp_input_param : C.InputParamSlot = {}
avp_argminmax : C.ArgMinMax = {}
coref_avp_filter : C.FilterSlot = {}
coref_avp_input_param : C.InputParamSlot = {}
avp_boolean_projection : C.ParamSlot = {}

// filters & input parameters on npv parameters
// npv: implicit parameter with Noun-Phrase Value, i.e., the parameter itself will not appear in the sentence
// e.g.: "Bob is a PhD", the parameter `academic_degree` is implicit, and should be inferred by the value "PhD"
npv_filter : C.FilterSlot = {}
npv_join_condition : C.FilterSlot = {}
npv_symmetric_join_condition : C.FilterSlot = {}
npv_input_pconstant_namearam : C.InputParamSlot = {}
npv_argminmax : C.ArgMinMax = {}
coref_npv_filter : C.FilterSlot = {}
coref_npv_input_param : C.InputParamSlot = {}
npv_boolean_projection : C.ParamSlot = {}

// filters & input parameters on apv parameter
// apv: implicit parameter with Adjective-Phrase Value (similar to npv, but in adjective form)
// e.g.: "Bob is left-handed"
apv_filter : C.FilterSlot = {}
apv_join_condition : C.FilterSlot = {}
apv_symmetric_join_condition : C.FilterSlot = {}
apv_input_param : C.InputParamSlot = {}
apv_argminmax : C.ArgMinMax = {}
coref_apv_filter : C.FilterSlot = {}
coref_apv_input_param : C.InputParamSlot = {}
apv_boolean_projection : C.ParamSlot = {}

// filters & input parameters on reverese_verb parameter
// reverse verb: verb-phrase parameter where value is the subject of the verb phrase
// e.g., "movies that Bob directed"
reverse_verb_filter : C.FilterSlot = {}
reverse_verb_join_condition : C.FilterSlot = {}
reverse_verb_symmetric_join_condition : C.FilterSlot = {}
reverse_verb_input_param : C.InputParamSlot = {}
coref_reverse_verb_filter : C.FilterSlot = {}
coref_reverse_verb_input_param : C.InputParamSlot = {}

// projections
question_projection_table = {}
command_projection_table = {}


constant_name : Ast.EntityValue|Ast.NumberValue = {
    // numbers are always allowed as "names" (id values)
    // other ID values should be entities
    constant_Number;
}

the_base_table : Ast.InvocationExpression = {}
base_table : Ast.InvocationExpression = {}
base_table_hidden : Ast.InvocationExpression = {}
base_noun_phrase : Ast.FunctionDef = {}
generic_anything_noun_phrase : Ast.InvocationExpression = {}
generic_base_noun_phrase : Ast.InvocationExpression = {}
