Use strict mode in TypeScript, catch some more corner cases

This commit is contained in:
John J. Camilleri
2019-06-10 11:14:14 +02:00
parent 6a9c917b29
commit a229507392
3 changed files with 46 additions and 31 deletions

View File

@@ -6,6 +6,11 @@
* A port of the pure JavaScript runtime (/src/runtime/javascript/gflib.js) into TypeScript * A port of the pure JavaScript runtime (/src/runtime/javascript/gflib.js) into TypeScript
*/ */
// We use wrapper type String (instead of primitive string) as we
// extend its prototype with tagging information.
// This linting rule doesn't allow use of String, thus must be disabled:
/* eslint-disable @typescript-eslint/ban-types */
/** /**
* A GF grammar is one abstract and multiple concretes * A GF grammar is one abstract and multiple concretes
*/ */
@@ -22,8 +27,8 @@ class GFGrammar { // eslint-disable-line @typescript-eslint/no-unused-vars
input: string, input: string,
fromLang: string, fromLang: string,
toLang: string toLang: string
): {[key: string]: {[key: string]: string}[]} { ): {[key: string]: {[key: string]: String}[]} {
let outputs: {[key: string]: {[key: string]: string}[]} = {} let outputs: {[key: string]: {[key: string]: String}[]} = {}
let fromConcs = this.concretes let fromConcs = this.concretes
if (fromLang) { if (fromLang) {
fromConcs = {} fromConcs = {}
@@ -214,15 +219,17 @@ class GFAbstract {
return t return t
} }
public parseTree(str: string, type: string): Fun { public parseTree(str: string, type: string): Fun | null {
return this.annotate(this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g), 0), type) let pt = this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g) || [], 0)
return pt ? this.annotate(pt, type) : null
} }
private parseTree_(tokens: string[], prec: number): Fun { private parseTree_(tokens: string[], prec: number): Fun | null {
if (tokens.length == 0 || tokens[0] == ')') { if (tokens.length == 0 || tokens[0] == ')') {
return null return null
} }
let t = tokens.shift() let t = tokens.shift()
if (!t) return null
if (t == '(') { if (t == '(') {
let tree = this.parseTree_(tokens, 0) let tree = this.parseTree_(tokens, 0)
tokens.shift() tokens.shift()
@@ -233,7 +240,7 @@ class GFAbstract {
} else { } else {
let tree = new Fun(t) let tree = new Fun(t)
if (prec == 0) { if (prec == 0) {
let c: Fun let c: Fun | null
let i: number let i: number
for (i = 0; (c = this.parseTree_(tokens, 1)) !== null; i++) { for (i = 0; (c = this.parseTree_(tokens, 1)) !== null; i++) {
tree.setArg(i,c) tree.setArg(i,c)
@@ -356,7 +363,7 @@ class GFConcrete {
res.push({fid: -3, table: [[sym]]}) res.push({fid: -3, table: [[sym]]})
} else if (tree.isMeta()) { } else if (tree.isMeta()) {
// TODO: Use lindef here // TODO: Use lindef here
let cat = this.startCats[tree.type] let cat = this.startCats[tree.type as string]
let sym = new SymKS(tree.name) let sym = new SymKS(tree.name)
sym.tag = tag sym.tag = tag
@@ -413,15 +420,15 @@ class GFConcrete {
return res return res
} }
private syms2toks(syms: Sym[]): string[] { private syms2toks(syms: Sym[]): String[] {
let ts: string[] = [] let ts: String[] = []
for (let i = 0; i < syms.length; i++) { for (let i = 0; i < syms.length; i++) {
let sym0 = syms[i] let sym0 = syms[i]
switch (sym0.id) { switch (sym0.id) {
case 'KS': { case 'KS': {
let sym = sym0 as SymKS let sym = sym0 as SymKS
for (let j in sym.tokens) { for (let j in sym.tokens) {
ts.push(sym.tokens[j].tagWith(sym.tag)) ts.push(sym.tokens[j].tagWith(sym.tag as string))
} }
break break
} }
@@ -437,7 +444,7 @@ class GFConcrete {
if (alt.prefixes.some((p: string): boolean => nextToken.startsWith(p))) { if (alt.prefixes.some((p: string): boolean => nextToken.startsWith(p))) {
alt.tokens.forEach((symks: SymKS): void => { alt.tokens.forEach((symks: SymKS): void => {
symks.tokens.forEach((t: string): void => { symks.tokens.forEach((t: string): void => {
ts.push(t.tagWith(sym.tag)) ts.push(t.tagWith(sym.tag as string))
}) })
}) })
addedAlt = true addedAlt = true
@@ -450,7 +457,7 @@ class GFConcrete {
// Fall through here when no alts (or none apply) // Fall through here when no alts (or none apply)
sym.tokens.forEach((symks: SymKS): void => { sym.tokens.forEach((symks: SymKS): void => {
symks.tokens.forEach((t: string): void => { symks.tokens.forEach((t: string): void => {
ts.push(t.tagWith(sym.tag)) ts.push(t.tagWith(sym.tag as string))
}) })
}) })
break break
@@ -460,23 +467,23 @@ class GFConcrete {
return ts return ts
} }
public linearizeAll(tree: Fun): string[] { public linearizeAll(tree: Fun): String[] {
return this.linearizeSyms(tree,'0').map((r): string => { return this.linearizeSyms(tree,'0').map((r): String => {
return this.unlex(this.syms2toks(r.table[0])) return this.unlex(this.syms2toks(r.table[0]))
}) })
} }
public linearize(tree: Fun): string { public linearize(tree: Fun): String {
let res = this.linearizeSyms(tree,'0') let res = this.linearizeSyms(tree,'0')
return this.unlex(this.syms2toks(res[0].table[0])) return this.unlex(this.syms2toks(res[0].table[0]))
} }
public tagAndLinearize(tree: Fun): string[] { public tagAndLinearize(tree: Fun): String[] {
let res = this.linearizeSyms(tree,'0') let res = this.linearizeSyms(tree,'0')
return this.syms2toks(res[0].table[0]) return this.syms2toks(res[0].table[0])
} }
private unlex(ts: string[]): string { private unlex(ts: String[]): String {
if (ts.length == 0) { if (ts.length == 0) {
return '' return ''
} }
@@ -486,8 +493,8 @@ class GFConcrete {
let s = '' let s = ''
for (let i = 0; i < ts.length; i++) { for (let i = 0; i < ts.length; i++) {
let t: string = ts[i] let t: String = ts[i]
let after: string | null = i < ts.length-1 ? ts[i+1] : null let after: String | null = i < ts.length-1 ? ts[i+1] : null
s += t s += t
if (after != null if (after != null
&& !t.match(noSpaceAfter) && !t.match(noSpaceAfter)
@@ -526,7 +533,8 @@ class GFConcrete {
private tokenize(string: string): string[] { private tokenize(string: string): string[] {
let inToken = false let inToken = false
let start: number, end: number let start = 0
let end: number
let tokens = [] let tokens = []
let i: number let i: number
@@ -619,8 +627,7 @@ class GFConcrete {
let suggs: string[] = [] let suggs: string[] = []
if (acc.value) { if (acc.value) {
acc.value.forEach((a: ActiveItem): void =>{ acc.value.forEach((a: ActiveItem): void =>{
a.seq.forEach((s: SymKS | SymKP): void => { a.seq.forEach((s: Sym): void => {
if (s.tokens == null) return
switch (s.id) { switch (s.id) {
case 'KS': { case 'KS': {
(s as SymKS).tokens.forEach((t: string): void => { (s as SymKS).tokens.forEach((t: string): void => {
@@ -659,9 +666,9 @@ interface Taggable {
*/ */
interface String { interface String {
tag?: string; tag?: string;
tagWith: (tag: string) => string; tagWith: (tag: string) => String;
} }
String.prototype.tagWith = function (tag: string): string { String.prototype.tagWith = function (tag: string): String {
// returns a copy // returns a copy
let s2 = this let s2 = this
s2.tag = tag s2.tag = tag
@@ -741,6 +748,8 @@ class PArg {
this.fid = hypos[hypos.length-1] this.fid = hypos[hypos.length-1]
if (hypos.length > 1) if (hypos.length > 1)
this.hypos = hypos.slice(0, hypos.length-1) this.hypos = hypos.slice(0, hypos.length-1)
else
this.hypos = []
} }
} }
@@ -913,7 +922,7 @@ class SymLit {
* Trie * Trie
*/ */
class Trie<T> { class Trie<T> {
public value: T[] public value: T[] | null
private items: {[key: string]: Trie<T>} private items: {[key: string]: Trie<T>}
public constructor() { public constructor() {
@@ -1193,13 +1202,13 @@ class ParseState {
} }
private process( private process(
agenda: ActiveItem[], agenda: ActiveItem[] | null,
literalCallback: (fid: FId) => Const | null, // this is right literalCallback: (fid: FId) => Const | null, // this is right
tokenCallback: (tokens: string[], item: ActiveItem) => void tokenCallback: (tokens: string[], item: ActiveItem) => void
): void { ): void {
if (agenda != null) { if (agenda != null) {
while (agenda.length > 0) { while (agenda.length > 0) {
let item = agenda.pop() let item = agenda.pop() as ActiveItem
let lin = item.seq let lin = item.seq
if (item.dot < lin.length) { if (item.dot < lin.length) {

View File

@@ -1,3 +1,4 @@
"use strict";
var GFGrammar = (function () { var GFGrammar = (function () {
function GFGrammar(abstract, concretes) { function GFGrammar(abstract, concretes) {
this.abstract = abstract; this.abstract = abstract;
@@ -171,13 +172,16 @@ var GFAbstract = (function () {
return t; return t;
}; };
GFAbstract.prototype.parseTree = function (str, type) { GFAbstract.prototype.parseTree = function (str, type) {
return this.annotate(this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g), 0), type); var pt = this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g) || [], 0);
return pt ? this.annotate(pt, type) : null;
}; };
GFAbstract.prototype.parseTree_ = function (tokens, prec) { GFAbstract.prototype.parseTree_ = function (tokens, prec) {
if (tokens.length == 0 || tokens[0] == ')') { if (tokens.length == 0 || tokens[0] == ')') {
return null; return null;
} }
var t = tokens.shift(); var t = tokens.shift();
if (!t)
return null;
if (t == '(') { if (t == '(') {
var tree = this.parseTree_(tokens, 0); var tree = this.parseTree_(tokens, 0);
tokens.shift(); tokens.shift();
@@ -422,7 +426,8 @@ var GFConcrete = (function () {
}; };
GFConcrete.prototype.tokenize = function (string) { GFConcrete.prototype.tokenize = function (string) {
var inToken = false; var inToken = false;
var start, end; var start = 0;
var end;
var tokens = []; var tokens = [];
var i; var i;
for (i = 0; i < string.length; i++) { for (i = 0; i < string.length; i++) {
@@ -492,8 +497,6 @@ var GFConcrete = (function () {
if (acc.value) { if (acc.value) {
acc.value.forEach(function (a) { acc.value.forEach(function (a) {
a.seq.forEach(function (s) { a.seq.forEach(function (s) {
if (s.tokens == null)
return;
switch (s.id) { switch (s.id) {
case 'KS': { case 'KS': {
s.tokens.forEach(function (t) { s.tokens.forEach(function (t) {
@@ -565,6 +568,8 @@ var PArg = (function () {
this.fid = hypos[hypos.length - 1]; this.fid = hypos[hypos.length - 1];
if (hypos.length > 1) if (hypos.length > 1)
this.hypos = hypos.slice(0, hypos.length - 1); this.hypos = hypos.slice(0, hypos.length - 1);
else
this.hypos = [];
} }
return PArg; return PArg;
}()); }());

View File

@@ -2,6 +2,7 @@
"compilerOptions": { "compilerOptions": {
"module": "none", "module": "none",
"target": "es3", "target": "es3",
"strict": true,
"noImplicitAny": true, "noImplicitAny": true,
"removeComments": true, "removeComments": true,
"outDir": "js" "outDir": "js"