class PartOfSpeech { constructor(t:string, sn:string, term:Term, p:number) { this.token = t; if (sn[0]=='~') { this.sortName = sn.substring(1); this.negatedSort = true; } else { this.sortName = sn; } this.term = term; this.probability = p; } equals(pos:PartOfSpeech) : boolean { if (this.token != pos.token) return false; if (this.negatedSort != pos.negatedSort) return false; if (this.term == null) { if (pos.term != null) return false; } else { if (pos.term == null) return false; if (this.term.equalsNoBindings(pos.term) != 1) return false; } return true; } toString() : string { return this.term.toString(); } static fromPartOfSpeech(pos:PartOfSpeech) : PartOfSpeech { return new PartOfSpeech(pos.token, (pos.negatedSort?"~":"")+pos.sortName, pos.term, pos.probability); } token:string = null; negatedSort:boolean = false; sortName:string = null; term:Term = null; probability:number = 1.0; } class TokenizationElement { constructor(token:string) { this.token = token; } // throught he first path tokensLeftToParse() : number { if (this.token == null) return 0; if (this.next == null || this.next.length == 0) return 1; return 1 + this.next[0].tokensLeftToParse(); } toStringSimple() : string { let str:string = this.token; if (this.next != null && this.next.length > 0) { return str + " " + this.next[0].toStringSimple(); } else { return str; } } toString() : string { return this.toStringInternal(0); } toStringInternal(tabs:number) : string { let s:string = ""; if (this.token==null) { for(let n of this.next) { s += n.toStringInternal(tabs); } } else { for(let i:number = 0;i= 2) { if (pos.term.attributes[1].sort.name == "uncountable") return false; } } return true; } addTokenPOS(pos:PartOfSpeech) { // o.getSort(pos.sortName); // this is just to check that we have all the sorts! let pos_l:PartOfSpeech[] = this.POS[pos.token]; if (pos_l == null) pos_l = []; pos_l.push(pos); this.POS[pos.token] = pos_l; let pos_ls:PartOfSpeech[] = this.POSbySort[pos.token]; if (pos_ls == null) pos_ls = []; pos_ls.push(pos); this.POSbySort[pos.sortName] = pos_ls; } addStandardNounPOS(noun:string, sortName:string, o:Ontology, multitokens:string[]) { if (noun.indexOf(" ") != -1) { if (multitokens.indexOf(noun) == -1) { multitokens.push(noun); // console.warn("missing multitoken added: " + noun); } if (multitokens.indexOf(noun + "s") == -1) { multitokens.push(noun + "s"); // console.warn("missing multitoken added: " + noun + "s"); } } o.getSort(sortName); // this is just to check that we have all the sorts! this.addTokenPOS(new PartOfSpeech(noun, sortName, Term.fromString("noun('"+sortName+"'["+sortName+"], [singular])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(noun+"s", sortName, Term.fromString("noun('"+sortName+"'["+sortName+"], [plural])", o), 1.0)); } addUncountableNounPOS(noun:string, sortName:string, o:Ontology) { o.getSort(sortName); // this is just to check that we have all the sorts! this.addTokenPOS(new PartOfSpeech(noun, sortName, Term.fromString("noun('"+sortName+"'["+sortName+"], [uncountable])", o), 1.0)); } addStandardVerbPOS(sortStr:string, inf:string, present3:string, past:string, participle:string, gerund:string, modal:boolean, multitokens:string[], o:Ontology) { /* // this messes up the parser when I set up to prefer multitokens, since "to X" prevents parsing "to" as a preposition... if (!modal) { this.addTokenPOS(new PartOfSpeech("to " + inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [infinitive-tense])", o), 1.0)); multitokens.push("to " + inf); } */ this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [infinitive-tense])", o), 1.0)); if (gerund!=null) this.addTokenPOS(new PartOfSpeech(gerund, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [gerund-tense])", o), 1.0)); if (participle!=null) { this.addTokenPOS(new PartOfSpeech(participle, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [participle-tense])", o), 1.0)); if (o.getSortSilent("property."+participle) != null) { this.addTokenPOS(new PartOfSpeech(participle, "property."+participle, Term.fromString("adjective('property."+participle+"'[symbol])", o), 1.0)); } } this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [first-person], [present-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [second-person], [present-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(present3, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [singular], [third-person], [present-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [plural], [third-person], [present-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [first-person], [past-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [second-person], [past-tense])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [third-person], [past-tense])", o), 1.0)); if (inf!=null && inf.indexOf(" ")>=0) multitokens.push(inf); if (present3!=null && present3.indexOf(" ")>=0) multitokens.push(present3); if (past!=null && past.indexOf(" ")>=0) multitokens.push(past); if (participle!=null && participle.indexOf(" ")>=0) multitokens.push(participle); if (gerund!=null && gerund.indexOf(" ")>=0) multitokens.push(gerund); } addPhrasalVerbPOS(sortStr:string, preposition:string, inf:string, present3:string, past:string, participle:string, gerund:string, modal:boolean, multitokens:string[], o:Ontology) { /* // this messes up the parser when I set up to prefer multitokens, since "to X" prevents parsing "to" as a preposition... if (!modal) { this.addTokenPOS(new PartOfSpeech("to " + inf, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [infinitive-tense])", o), 1.0)); multitokens.push("to " + inf); } */ this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [infinitive-tense], '"+preposition+"'[symbol])", o), 1.0)); if (gerund!=null) this.addTokenPOS(new PartOfSpeech(gerund, sortStr, Term.fromString("verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [gerund-tense], '"+preposition+"'[symbol])", o), 1.0)); if (participle!=null) { this.addTokenPOS(new PartOfSpeech(participle, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [no-person], [participle-tense], '"+preposition+"'[symbol])", o), 1.0)); if (o.getSortSilent("property."+participle) != null) { this.addTokenPOS(new PartOfSpeech(participle, "property."+participle, Term.fromString("adjective('property."+participle+"'[symbol], '"+preposition+"'[symbol])", o), 1.0)); } } this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [first-person], [present-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [second-person], [present-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(present3, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [singular], [third-person], [present-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(inf, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [plural], [third-person], [present-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [first-person], [past-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [second-person], [past-tense], '"+preposition+"'[symbol])", o), 1.0)); this.addTokenPOS(new PartOfSpeech(past, sortStr, Term.fromString("phrasal-verb('"+sortStr+"'[symbol], [grammatical-number], [third-person], [past-tense], '"+preposition+"'[symbol])", o), 1.0)); if (inf!=null && inf.indexOf(" ")>=0) multitokens.push(inf); if (present3!=null && present3.indexOf(" ")>=0) multitokens.push(present3); if (past!=null && past.indexOf(" ")>=0) multitokens.push(past); if (participle!=null && participle.indexOf(" ")>=0) multitokens.push(participle); if (gerund!=null && gerund.indexOf(" ")>=0) multitokens.push(gerund); } generateCardinalNumber(token:string, o:Ontology) : PartOfSpeech { return new PartOfSpeech(token, token, Term.fromString("cardinal('"+token+"'[number])", o), 1.0) } tokenize(text:string) : string[] { let tokens:string[] = this.basicTokenization(text); // detect numbers: // - pattern [number, ".", number] for(let i:number = 0;i2 && (tokens[i].substring(tokens[i].length-2)=="pm" || tokens[i].substring(tokens[i].length-2)=="am") && !isNaN(Number(tokens[i].substring(0,tokens[i].length-2)))) { let tmp:string = tokens[i]; tokens[i] = tmp.substring(0,tmp.length-2); tokens.splice(i+1,0,tmp.substring(tmp.length-2, tmp.length)); } } // Remove spaces let finalTokens:string[] = []; for(let t of tokens) { if (t != " ") finalTokens.push(t); } return finalTokens; } basicTokenization(text:string) : string[] { let normal:string="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZ0123456789"; let tokenSeparators:string=".,!-;:'\"?()"; let ignorableSeparators:string=" \t\n\r"; let tokens:string[] = []; let token:string = ""; for(let i:number = 0;i=0) { token += text.charAt(i) } else { if (token != "") tokens.push(token.toLowerCase()); if (tokenSeparators.indexOf(text.charAt(i))>=0) { tokens.push(text.charAt(i)); } else if (ignorableSeparators.indexOf(text.charAt(i))>=0) { tokens.push(" "); } else { console.error("NLPTokenizer: ignoring character '" + text.charAt(i) + "'"); } token = ""; } } if (token != "") tokens.push(token.toLowerCase()); return tokens; } generateMultitokenTable(multitokens_raw:string[]) { this.multitokens_plainlist = multitokens_raw; for(let mt of multitokens_raw) { this.addMultiToken(mt); } } addMultiToken(mt:string) { let tokens_tmp:string[] = mt.split(" "); let tokens:string[] = []; for(let token of tokens_tmp) { if (token[token.length-1] == ".") { tokens.push(token.substring(0,token.length-1)) tokens.push(".") } else { tokens.push(token) } } if (tokens.length == 1) return; // not a multitoken! let key:string = tokens[0]; let value:string[] = tokens.slice(1); let values:string[][] = this.multitokens[key]; if (values==null) values = []; if(values.indexOf(value) == -1) { values.push(value); this.multitokens[key] = values; } } identifyMultiTokenWords(tokens:string[]) : TokenizationElement { if (tokens==null) return null; let tokenization:TokenizationElement = new TokenizationElement(null); let t:TokenizationElement = tokenization; let preferLongerMultiTokens:boolean = true; // preference for multitoken words! remove this line if you want all parses to be returned // let preferLongerMultiTokens:boolean = false; for(let i:number = 0;i longestMultiToken) { longestMultiToken = option.length; bestTokenization = this.identifyMultiTokenWords(tokens.slice(i+option.length+1,tokens.length)); bestTokenization.token = newToken; } } else { let t2:TokenizationElement = this.identifyMultiTokenWords(tokens.slice(i+option.length+1,tokens.length)); t2.token = newToken; t.next.push(t2) } } } if (bestTokenization!=null) { t.next.push(bestTokenization) return tokenization; } } let t2:TokenizationElement = new TokenizationElement(tokens[i]); t.next.push(t2); t = t2; } return tokenization; } tagToken(token:string, o:Ontology) : PartOfSpeech[] { let pos_l:PartOfSpeech[] = this.POS[token]; if (pos_l != null) { // we found it! let pos_l2:PartOfSpeech[] = []; for(let pos of pos_l) { let pos2:PartOfSpeech = PartOfSpeech.fromPartOfSpeech(pos); pos2.token = token; pos_l2.push(pos2); } return pos_l2; } else if (!isNaN(Number(token))) { // numbers: let pos2:PartOfSpeech = this.generateCardinalNumber(token, o); pos2.token = token; return [pos2]; } else { if (token.indexOf("'") == -1) { // not found in the dictionary,assume it's a proper noun (but give a warning): this.unrecognizedTokens.push(token); console.warn("NLPPOSTagging: unknown token: '" + token + "', assuming proper noun"); return [new PartOfSpeech(token, token, Term.fromString("proper-noun('"+token+"'[symbol], [singular])", o), 1.0)]; } else { return null; } } } POSTagging(tokens:TokenizationElement, o:Ontology) { // tag all the tokens in the tokenization: this.POSTaggingInternal(tokens, o); // remove all the paths with a failed tokenization (at least one token not recognized) let failedTokens:string[] = []; if (!this.removeFailedPOSTaggingPaths(tokens, failedTokens)) { console.error(failedTokens); } } POSTaggingInternal(tokens:TokenizationElement, o:Ontology) { if (tokens.token!=null) tokens.POS = this.tagToken(tokens.token, o); for(let t of tokens.next) { this.POSTaggingInternal(t, o); } } POSTaggingArray(tokens:string[], o:Ontology) : PartOfSpeech[][] { let l:PartOfSpeech[][] = []; for(let token of tokens) { let pos_l:PartOfSpeech[] = this.tagToken(token, o); l.push(pos_l); } return l; } removeFailedPOSTaggingPaths(tokens:TokenizationElement, failedTokens:string[]) : boolean { if (tokens.token != null) { if (tokens.POS == null || tokens.POS.length == 0) { if (failedTokens.indexOf(tokens.token)==-1) failedTokens.push(tokens.token); // console.log("failed: " + tokens.token); return false; } if (tokens.next == null || tokens.next.length == 0) { // console.log("end: " + true); return true; } } // console.log("token: " + tokens.token + " next: " + tokens.next.length); let atLeastOneSucceeds:boolean = false; let toDelete:TokenizationElement[] = []; for(let t of tokens.next) { if (this.removeFailedPOSTaggingPaths(t, failedTokens)) { atLeastOneSucceeds = true; } else { toDelete.push(t); } } for(let t of toDelete) { let idx:number = tokens.next.indexOf(t); if (idx>=0) tokens.next.splice(idx,1); } return atLeastOneSucceeds; } static sortIsConsideredForTypes(s:Sort, o:Ontology) { for(let sName of POSParser.sortsToConsiderForTypes) { if (s.is_a(o.getSort(sName))) return true; } return false; } generateTypeSortToEnglishTable(o:Ontology) { for(let token in this.POS) { // prevent synonims to overwrite the core words to be used for NLG: if (token == "person" || token == "persons" || token == "people") { continue; } let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { let sort:Sort = o.getSortSilent(POS.sortName); if (sort != null) { if (POS.term.functor.name == "noun" && POSParser.sortIsConsideredForTypes(sort, o)) { let tmp:string[] = this.typeSortToEnglish[POS.sortName]; if (tmp==null) { tmp = [null,null,null]; this.typeSortToEnglish[POS.sortName] = tmp; } if (POS.term.attributes[1].sort.name == "plural") { tmp[1] = token; } else if (POS.term.attributes[1].sort.name == "uncountable") { tmp[2] = token; tmp[1] = token; // put it also in plural just in case tmp[0] = token; // put it also in singular just in case } else { // singular tmp[0] = token; } //console.log(POS.sortName + "[" + number + "] = " + token); } } } } } generatePropertySortToEnglishTable(o:Ontology) { let propertySort:Sort = o.getSort("property"); //let propertyWVSort:Sort = o.getSort("property-with-value"); for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { let sort:Sort = o.getSortSilent(POS.sortName); if (sort != null) { if ((POS.term.functor.name == "adjective" || POS.term.functor.name == "preposition") && sort.is_a(propertySort)) { this.propertySortToEnglish[POS.sortName] = token; //console.log(POS.sortName + " = " + token); //} else if (POS.term.functor.name == "noun" && // sort.is_a(propertyWVSort)) { // this.propertySortToEnglish[POS.sortName] = token; } } } } } generateRelationSortToEnglishTable(o:Ontology) { let relationSort:Sort = o.getSort("relation"); for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { let sort:Sort = o.getSortSilent(POS.sortName); if (sort != null) { if (POS.term.functor.name == "preposition" && sort.is_a(relationSort)) { this.relationSortToEnglish[POS.sortName] = token; //console.log(POS.sortName + " =(relation)= " + token); } } } } } generateNounSortToEnglishTable() { for(let token in this.POS) { // prevent synonims to overwrite the core words to be used for NLG: if (token == "person" || token == "persons" || token == "people") { continue; } let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { if (POS.term.functor.name == "noun") { let tmp:string[] = this.nounSortToEnglish[POS.sortName]; if (tmp==null) { tmp = [null,null]; this.nounSortToEnglish[POS.sortName] = tmp; } let number:number = 0; if (POS.term.attributes[1].sort.name == "plural") number = 1; tmp[number] = token; //console.log(POS.sortName + "[" + number + "] = " + token); } } } } generateVerbSortToEnglishTable(o:Ontology) { for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { let sort:Sort = o.getSortSilent(POS.sortName); if (sort != null) { if (POS.term.functor.name == "verb" || POS.term.functor.name == "phrasal-verb") { // "verb('verb.be'[symbol], [singular], [first-person], [present-tense]) let number:number = null; let person:number = null; let tense:number = null; if (POS.term.attributes[1].sort.name == "singular") number = 0; if (POS.term.attributes[1].sort.name == "plural") number = 1; if (POS.term.attributes[2].sort.name == "first-person") person = 0; if (POS.term.attributes[2].sort.name == "second-person") person = 1; if (POS.term.attributes[2].sort.name == "third-person") person = 2; if (POS.term.attributes[3].sort.name == "infinitive-tense") tense = 0; if (POS.term.attributes[3].sort.name == "gerund-tense") tense = 1; if (POS.term.attributes[3].sort.name == "participle-tense") tense = 2; if (POS.term.attributes[3].sort.name == "present-tense") tense = 3; if (POS.term.attributes[3].sort.name == "past-tense") tense = 4; if (tense != null) { let idxs:number[] = []; if (tense < 3) { idxs = [tense]; } else { idxs = [3 + (tense-3)*6]; let idxs2:number[] = []; for(let idx of idxs) { if (number == null || number==0) idxs2.push(idx); if (number == null || number==1) idxs2.push(idx+3); } idxs = []; for(let idx of idxs2) { if (person == null || person==0) idxs.push(idx); if (person == null || person==1) idxs.push(idx+1); if (person == null || person==2) idxs.push(idx+2); } } let tmp:string[] = this.verbSortToEnglish[POS.sortName]; if (tmp==null) { tmp = [null,null,null, null,null,null,null,null,null, null,null,null,null,null,null]; this.verbSortToEnglish[POS.sortName] = tmp; } for(let idx of idxs) { // do not add the "to XXX" forms of infinitive if (idx == 0 && token.length>3 && token[0] =='t' && token[1] =='o' && token[2] ==' ') continue; if (POS.term.functor.name == "phrasal-verb") { tmp[idx] = token + " " + (POS.term.attributes[4]).value; } else { tmp[idx] = token; } } //console.log(POS.sortName + " =(verb)= " + token + " [" + idxs + "]"); } else { console.error("No tense specified in " + POS.term); } } } } } } generatePronounSortToEnglishTable(o:Ontology) { for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { if (POS.term.functor.is_a(o.getSort("pronoun"))) { let tmp:string[][] = this.pronounSortToEnglish[POS.sortName]; if (tmp==null) { tmp = [[null,null,null],[null,null,null]]; this.pronounSortToEnglish[POS.sortName] = tmp; } let numbers:number[] = []; let genders:number[] = []; if (POS.term.attributes[1].sort.name == "singular") numbers = [0]; else if (POS.term.attributes[1].sort.name == "plural") numbers = [1]; else numbers = [0,1]; if (POS.term.attributes[2].sort.name == "gender-masculine") genders = [0]; else if (POS.term.attributes[2].sort.name == "gender-femenine") genders = [1]; else if (POS.term.attributes[2].sort.name == "gender-neutral") genders = [2]; else genders = [0,1,2]; for(let gender of genders) { for(let num of numbers) { tmp[num][gender] = token; } } } } } } generateDeterminerSortToEnglishTable(o:Ontology) { for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { if (POS.term.functor.is_a(o.getSort("determiner"))) { let tmp:string[] = this.determinerSortToEnglish[POS.sortName]; if (tmp==null) { tmp = [null,null]; this.determinerSortToEnglish[POS.sortName] = tmp; } if (POS.term.attributes[1].sort.name == "singular") tmp[0] = token; else if (POS.term.attributes[1].sort.name == "plural") tmp[1] = token; else { tmp[0] = token; tmp[1] = token; } } } } } generateAdverbSortToEnglishTable(o:Ontology) { for(let token in this.POS) { let POS_l:PartOfSpeech[] = this.POS[token]; for(let POS of POS_l) { let sort:Sort = o.getSortSilent(POS.sortName); if (sort != null) { if (POS.term.functor.name == "adverb") { this.adverbSortToEnglish[POS.sortName] = token; //console.log(POS.sortName + " = " + token); } } } } } isPhrasalVerb(s:Sort) : PartOfSpeech { let l:PartOfSpeech[] = this.POSbySort[s.name]; for(let pos of l) { if (pos.term.functor.name == "phrasal-verb") return pos; } return null; } sortCanBe(s:Sort, grammaticalFunction:Sort) : boolean { let l:PartOfSpeech[] = this.POSbySort[s.name]; if (l!=null) { for(let pos of l) { if (pos.term.functor.is_a(grammaticalFunction)) return true; } } return false; } // number: 0 = singular, 1 = plural, 2 = uncountable getTypeString(s:Sort, number:number) : string { let tmp:string[] = this.typeSortToEnglish[s.name]; if (tmp == null) return null; return tmp[number]; } // number: 0 = singular, 1 = plural getNounString(s:Sort, number:number, tryAncestors:boolean) : string { let tmp:string[] = this.nounSortToEnglish[s.name]; if (tmp == null) { if (tryAncestors) { let sort_l:Sort[] = s.getAncestors(); for(let ts of sort_l) { let word:string = this.getNounString(ts, 0, false); if (word != null) return word; } } return null; } return tmp[number]; } getPropertyString(s:Sort) : string { let tmp:string = this.propertySortToEnglish[s.name]; return tmp; } getRelationString(s:Sort, consierRelationVerbs:boolean) : string { let tmp:string = this.relationSortToEnglish[s.name]; if (tmp == null && consierRelationVerbs) { if (s.is_a_string("relation-verb")) { return "that " + this.getVerbString(s, 0, 2, 3); } } return tmp; } getVerbString(s:Sort, number:number, person:number, tense:number) : string { let tmp:string[] = this.verbSortToEnglish[s.name]; let idx:number = tense; if (tense>=3) { idx = 3 + (tense-3)*6 + number*3 + person; } if (tmp == null) { console.error("getVerbString: cannot render verb " + s) return null; } // console.log("getVerbString("+s.name+", " + idx + " = (" + number + ", " + person + ", " + tense + ") : " + tmp); return tmp[idx]; } getPronounString(s:Sort, number:number, gender:number) : string { let tmp:string[][] = this.pronounSortToEnglish[s.name]; if (tmp == null) return null; return tmp[number][gender]; } getPronounStringString(s:string, number:number, gender:number) : string { // console.log("s: " + s + ", number: " + number + ", gender: " + gender); let tmp:string[][] = this.pronounSortToEnglish[s]; if (tmp == null) return null; return tmp[number][gender]; } getDeterminerString(s:Sort, number:number) : string { let tmp:string[] = this.determinerSortToEnglish[s.name]; if (tmp == null) return null; return tmp[number]; } getAdverbString(s:Sort) : string { let tmp:string = this.adverbSortToEnglish[s.name]; return tmp; } getPOSString(s:Sort, number:number) : string { let candidates:PartOfSpeech[] = this.POSbySort[s.name]; if (candidates == null || candidates.length == 0) return null; for(let c of candidates) { if (c.term.functor.name == "noun" && c.term.attributes.length == 2) { let numberSort:Sort = c.term.attributes[1].sort; if (number == 0 && numberSort.name == "singular") return c.token; if (number == 1 && numberSort.name == "plural") return c.token; if (number == 2 && numberSort.name == "uncountable") return c.token; } } return candidates[0].token; } multitokens_plainlist:string[] = []; multitokens: { [first: string] : string[][]; } = {}; POS:{[token:string]:PartOfSpeech[];} = {}; POSbySort:{[sort:string]:PartOfSpeech[];} = {}; typeSortToEnglish:{[sort:string] : string[];} = {}; // it maps to two strings: for sigular, plural propertySortToEnglish:{[sort:string] : string;} = {}; relationSortToEnglish:{[sort:string] : string;} = {}; verbSortToEnglish:{[sort:string] : string[];} = {}; nounSortToEnglish:{[sort:string] : string[];} = {}; pronounSortToEnglish:{[sort:string] : string[][];} = {}; determinerSortToEnglish:{[sort:string] : string[];} = {}; adverbSortToEnglish:{[sort:string] : string;} = {}; // for example, "owns" is the reverse relation of "belongs" reverseRelations: { [first: string] : string; } = {}; unrecognizedTokens:string [] = []; static sortsToConsiderForTypes:string[] = ["time.location", "space.location", "physical-entity", "abstract-entity", "role", "event"]; }