/// import * as events from 'events'; import * as I18n from '../i18n'; import { Replaceable, ReplacedResult } from '../utils/template-string'; import { Derivation, NonTerminal } from './runtime'; import { SemanticAction, KeyFunction, RuleAttributes, ContextPhrase, ContextTable, GrammarOptions } from './types'; import ThingpediaLoader from '../templates/load-thingpedia'; interface GenericSentenceGeneratorOptions extends GrammarOptions { locale: string; templateFiles?: string[]; rootSymbol?: string; targetPruningSize: number; maxDepth: number; maxConstants: number; rng: () => number; logPrefix?: string; } interface BasicSentenceGeneratorOptions { contextual: false; } interface ContextualSentenceGeneratorOptions { contextual: true; rootSymbol?: string; } export declare type SentenceGeneratorOptions = GenericSentenceGeneratorOptions & (BasicSentenceGeneratorOptions | ContextualSentenceGeneratorOptions); interface Constant { token: ReplacedResult; value: unknown; } /** * Low-level class that generates sentences and associated logical forms, * given a grammar expressed as Genie template files. */ export default class SentenceGenerator extends events.EventEmitter { private _templateFiles; private _langPack; private _entityAllocator; private _tpLoader; private _logPrefix; private _options; private _contextual; private _nonTermTable; private _nonTermList; private _rules; private _contextTable; private _constantMap; private _finalized; private _nonTermHasContext; private _charts; private _progress; private _stackDepth; constructor(options: SentenceGeneratorOptions); get tpLoader(): ThingpediaLoader; get langPack(): I18n.LanguagePack; /** * Log a debug message. * * This is a wrapper over `console.log` that includes a logging prefix * to disambiguate recursive calls and parallel generation. * * @param message the message to log * @param args additional arguments to `console.log` */ log(message: string, ...args: []): void; initialize(): Promise; get progress(): number; hasSymbol(symbol: string): boolean; hasContext(symbol: string): boolean; get contextTable(): ContextTable; private _internalDeclareSymbol; declareContext(context: string): void; declareSymbol(symbol: string): void; private _lookupNonTerminal; private _addRuleInternal; addConstants(symbol: string, token: string, type: any, keyFunction: KeyFunction, attributes?: RuleAttributes): void; addRule(symbol: string, expansion: NonTerminal[], sentenceTemplate: string | Replaceable, semanticAction: SemanticAction, keyFunction: KeyFunction | undefined, attributes?: RuleAttributes): void; private _typecheck; private _computeHasContext; private _addAutomaticRepeat; finalize(): void; addConstantsFromContext(constants: { [key: string]: Constant[]; }): void; private _enableAllRules; private _removeTemporaryRules; private _disableRulesForConstants; /** * Generate a single derivation for a particular symbol in the grammar, given the single context. * * This method will expand the grammar then sample exactly one derivation out of the given non-terminal. * * This method is optimized for individual generation, and prune the set of enabled rules * based on the context. It cannot be called for non-contextual grammars. No `progress` events will * be emitted during this method. * * @param context - the current context * @param nonTerm - the symbol to generate * @return {Derivation} - the sampled derivation */ generateOne(contexts: Iterable, nonTerm: string): Derivation | undefined; private _getRuleTarget; /** * Convert the context inputs into something suitable to pass to the semantic functions. * * `contextInputs` is an array of arbitrary objects, each corresponding to one possible * context to use. Each object will be passed to the `contextInitializer` function that * was passed when constructing the grammar. * * The contextInitializer returns a tuple with the "context tags" (a list of grammar * non-terminals declared in a "context" statement) and the "context info", which is actually * passed to the semantic function. * The input to the context initializer and the info are stored in a Context object, * which is then set as the .context property of the derivation. * * When generating agent sentences, contextInputs is an array of PartialDialogues, * each having .context which is the C: state of the dialogue. * We call the "context" function to compute the tags and the info. * * When generating user sentences, contextInputs is an array of agent turns. The turns * already contain the tags and the context info (computed by the semantic function * of the agent derivation). * * This fairly convoluted design allows two things: * - "Grammar" (this class) has no notion of user or agent, all it knows is to put the right * stuff in the right non-terminals and generate. * - The templates can define arbitrary tags for the context, and can define arbitrary functions * to tag the C: state context (the result of simulation). * - The templates can pass arbitrary information from the agent turns to the user turns, * including information that is not representable in a ThingTalk dialogue state. */ private _initializeContexts; /** * Reset this generator, and prepare for the next turn of generation. * * This will clear all intermediate derivations that depend on the current set of contexts. * * If hard is true, it will also clear all other derivations and reset the chart table. * Otheriwse, it will not clear other intermediate derivations. * * @param hard - whether to reset all derivations or only those that depend on the context */ reset(hard?: boolean): void; private _initializeCharts; /** * Ensure that the rule is ready to generate at the given depth. * * This will ensure that all non-terminals referenced by the rule have been generated * at lower depths. * * @param rule * @param atDepth the depth at which rule will be expanded * @returns whether the rule should be expanded at all */ private _ensureRuleReadyToGenerate; /** * Ensure that the given non-terminal is fully generated at the given depth. * * This will recursively generate the non-terminals that feed into the given one * at lower depths, then apply all the rules for this non-terminal. * * This method has no effect if the non-terminal was already generated at the given * depth since the last call to {@link reset}. It also has no effect if depth is * negative. * * @param nonTermIndex the index of the non-terminal to generate * @param depth the depth at which to generate * @param mode whether to generate and sample randomly, or whether to choose only * the derivations with the highest priority * @returns the size of the non terminal at this depth */ private _ensureGenerated; private _getAllDerivations; /** * Generate a batch of derivations for the given symbol, given the batch of contexts. * */ generate(contextPhrases: Iterable, symbol: string): Iterable>; } export {};