mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-05-24 02:12:50 -06:00
Avoid modifying String prototype in TypeScript runtime
Adds new class TaggedString
This commit is contained in:
@@ -6,11 +6,6 @@
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
@@ -27,8 +22,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 = {}
|
||||||
@@ -420,15 +415,15 @@ class GFConcrete {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
private syms2toks(syms: Sym[]): String[] {
|
private syms2toks(syms: Sym[]): TaggedString[] {
|
||||||
let ts: String[] = []
|
let ts: TaggedString[] = []
|
||||||
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 as string))
|
ts.push(new TaggedString(sym.tokens[j], sym.tag as string))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -444,7 +439,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 as string))
|
ts.push(new TaggedString(t, sym.tag as string))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
addedAlt = true
|
addedAlt = true
|
||||||
@@ -457,7 +452,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 as string))
|
ts.push(new TaggedString(t, sym.tag as string))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
@@ -467,23 +462,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): TaggedString[] {
|
||||||
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: TaggedString[]): string {
|
||||||
if (ts.length == 0) {
|
if (ts.length == 0) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@@ -493,8 +488,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].s
|
||||||
let after: String | null = i < ts.length-1 ? ts[i+1] : null
|
let after: string | null = i < ts.length-1 ? ts[i+1].s : null
|
||||||
s += t
|
s += t
|
||||||
if (after != null
|
if (after != null
|
||||||
&& !t.match(noSpaceAfter)
|
&& !t.match(noSpaceAfter)
|
||||||
@@ -654,25 +649,17 @@ class GFConcrete {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A type which can be tagged
|
* A string with a tag
|
||||||
|
* This avoids modifying the String prototype, which was messy
|
||||||
*/
|
*/
|
||||||
interface Taggable {
|
class TaggedString {
|
||||||
tag?: string;
|
public s: string
|
||||||
tagWith: (tag: string) => Taggable;
|
public tag: string
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public constructor(s: string, tag: string) {
|
||||||
* Strings can also be tagged in the same way
|
this.s = s
|
||||||
*/
|
this.tag = tag
|
||||||
interface String {
|
}
|
||||||
tag?: string;
|
|
||||||
tagWith: (tag: string) => String;
|
|
||||||
}
|
|
||||||
String.prototype.tagWith = function (tag: string): String {
|
|
||||||
// returns a copy
|
|
||||||
let s2 = this
|
|
||||||
s2.tag = tag
|
|
||||||
return s2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -828,7 +815,7 @@ class SymCat {
|
|||||||
/**
|
/**
|
||||||
* SymKS: Object to represent terminals in grammar rules
|
* SymKS: Object to represent terminals in grammar rules
|
||||||
*/
|
*/
|
||||||
class SymKS implements Taggable {
|
class SymKS {
|
||||||
public id: string
|
public id: string
|
||||||
public tokens: string[]
|
public tokens: string[]
|
||||||
public tag?: string
|
public tag?: string
|
||||||
@@ -855,7 +842,7 @@ class SymKS implements Taggable {
|
|||||||
/**
|
/**
|
||||||
* SymKP: Object to represent pre in grammar rules
|
* SymKP: Object to represent pre in grammar rules
|
||||||
*/
|
*/
|
||||||
class SymKP implements Taggable {
|
class SymKP {
|
||||||
public id: string
|
public id: string
|
||||||
public tokens: SymKS[]
|
public tokens: SymKS[]
|
||||||
public alts: Alt[]
|
public alts: Alt[]
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ var GFConcrete = (function () {
|
|||||||
case 'KS': {
|
case 'KS': {
|
||||||
var sym = sym0;
|
var sym = sym0;
|
||||||
for (var j in sym.tokens) {
|
for (var j in sym.tokens) {
|
||||||
ts.push(sym.tokens[j].tagWith(sym.tag));
|
ts.push(new TaggedString(sym.tokens[j], sym.tag));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -366,7 +366,7 @@ var GFConcrete = (function () {
|
|||||||
if (alt.prefixes.some(function (p) { return nextToken_1.startsWith(p); })) {
|
if (alt.prefixes.some(function (p) { return nextToken_1.startsWith(p); })) {
|
||||||
alt.tokens.forEach(function (symks) {
|
alt.tokens.forEach(function (symks) {
|
||||||
symks.tokens.forEach(function (t) {
|
symks.tokens.forEach(function (t) {
|
||||||
ts.push(t.tagWith(sym_1.tag));
|
ts.push(new TaggedString(t, sym_1.tag));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
addedAlt_1 = true;
|
addedAlt_1 = true;
|
||||||
@@ -379,7 +379,7 @@ var GFConcrete = (function () {
|
|||||||
break;
|
break;
|
||||||
sym_1.tokens.forEach(function (symks) {
|
sym_1.tokens.forEach(function (symks) {
|
||||||
symks.tokens.forEach(function (t) {
|
symks.tokens.forEach(function (t) {
|
||||||
ts.push(t.tagWith(sym_1.tag));
|
ts.push(new TaggedString(t, sym_1.tag));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -413,8 +413,8 @@ var GFConcrete = (function () {
|
|||||||
var noSpaceBefore = /^[\.\,\?\!\)\:\;\-\]]/;
|
var noSpaceBefore = /^[\.\,\?\!\)\:\;\-\]]/;
|
||||||
var s = '';
|
var s = '';
|
||||||
for (var i = 0; i < ts.length; i++) {
|
for (var i = 0; i < ts.length; i++) {
|
||||||
var t = ts[i];
|
var t = ts[i].s;
|
||||||
var after = i < ts.length - 1 ? ts[i + 1] : null;
|
var after = i < ts.length - 1 ? ts[i + 1].s : null;
|
||||||
s += t;
|
s += t;
|
||||||
if (after != null
|
if (after != null
|
||||||
&& !t.match(noSpaceAfter)
|
&& !t.match(noSpaceAfter)
|
||||||
@@ -520,11 +520,13 @@ var GFConcrete = (function () {
|
|||||||
};
|
};
|
||||||
return GFConcrete;
|
return GFConcrete;
|
||||||
}());
|
}());
|
||||||
String.prototype.tagWith = function (tag) {
|
var TaggedString = (function () {
|
||||||
var s2 = this;
|
function TaggedString(s, tag) {
|
||||||
s2.tag = tag;
|
this.s = s;
|
||||||
return s2;
|
this.tag = tag;
|
||||||
};
|
}
|
||||||
|
return TaggedString;
|
||||||
|
}());
|
||||||
var Apply = (function () {
|
var Apply = (function () {
|
||||||
function Apply(fun, args) {
|
function Apply(fun, args) {
|
||||||
this.id = 'Apply';
|
this.id = 'Apply';
|
||||||
|
|||||||
Reference in New Issue
Block a user