summaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorJohn J. Camilleri <john@digitalgrammars.com>2019-06-07 13:58:23 +0200
committerJohn J. Camilleri <john@digitalgrammars.com>2019-06-07 13:58:23 +0200
commitffcdaa921f21aca97da90936e0a57eec93a1f53b (patch)
tree6c8eb04d343f92dd62cbfd4a3bbb78fa2fa97d85 /src/runtime
parentf2e03bfc5116d426617b335d0fc90cc9ca9ccd24 (diff)
Porting of JS runtime to TypeScript (`gflib.ts`) complete
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/typescript/.gitignore1
-rw-r--r--src/runtime/typescript/README.md26
-rw-r--r--src/runtime/typescript/gflib.ts162
-rw-r--r--src/runtime/typescript/tsconfig.json5
4 files changed, 121 insertions, 73 deletions
diff --git a/src/runtime/typescript/.gitignore b/src/runtime/typescript/.gitignore
new file mode 100644
index 000000000..a6c7c2852
--- /dev/null
+++ b/src/runtime/typescript/.gitignore
@@ -0,0 +1 @@
+*.js
diff --git a/src/runtime/typescript/README.md b/src/runtime/typescript/README.md
new file mode 100644
index 000000000..7f796a63b
--- /dev/null
+++ b/src/runtime/typescript/README.md
@@ -0,0 +1,26 @@
+# GF TypeScript Runtime
+
+`gflib.ts` is a TypeScript implementation of the GF runtime.
+It is ported from an older JavaScript implementation [`gflib.js`](../javascript/gflib.js),
+with some small improvements.
+
+Importantly, all **future** updates will only be made to this TypeScript version.
+
+## Applicability
+
+This runtime allows you use GF in pure JavaScript, and thus have GF-powered apps without the need for a server backend.
+However, it has not been actively maintained as the other runtimes have been.
+So its features are limited and it is not efficient, making it really only useful for smaller grammars.
+
+## Using
+
+`gflib.ts` can be transpiled to JavaScript by running `tsc` in this folder (of course you need TypeScript installed).
+It has no module depenedencies.
+You can then include the generated `gflib.js` file in your application as usual.
+
+Your GF grammar should be compiled with: `gf --make --output-format=js`
+
+## What happened to `gflib.d.ts`?
+
+There was once a file here called `gflib.d.ts`, which contained TypeScript type definitions for the **old** `gflib.js`.
+Since the runtime is now ported to TypeScript, those type definitions are no longer necessary (plus they contained many errors).
diff --git a/src/runtime/typescript/gflib.ts b/src/runtime/typescript/gflib.ts
index 274b46b33..75a0bd385 100644
--- a/src/runtime/typescript/gflib.ts
+++ b/src/runtime/typescript/gflib.ts
@@ -6,18 +6,10 @@
* A port of the pure JavaScript runtime (/src/runtime/javascript/gflib.js) into TypeScript
*/
-// Note: the String prototype is extended with:
-// String.prototype.tag = "";
-// String.prototype.setTag = function (tag) { this.tag = tag; };
-
-interface Taggable {
- tag?: string;
-}
-
/**
* A GF grammar is one abstract and multiple concretes
*/
-export class GFGrammar {
+class GFGrammar { // eslint-disable-line @typescript-eslint/no-unused-vars
public abstract: GFAbstract
public concretes: {[key: string]: GFConcrete}
@@ -62,7 +54,7 @@ export class GFGrammar {
/**
* Abstract Syntax Tree
*/
-export class Fun {
+class Fun {
public name: string
public args: Fun[]
public type?: string
@@ -408,7 +400,7 @@ class GFConcrete {
case 'KS':
case 'KP': {
let sym = sym0 as SymKS | SymKP
- toks.push(this.tagIt(sym,tag))
+ toks.push(sym.tagWith(tag))
break
}
}
@@ -428,14 +420,14 @@ class GFConcrete {
case 'KS': {
let sym = sym0 as SymKS
for (let j in sym.tokens) {
- ts.push(this.tagIt(sym.tokens[j],sym.tag))
+ ts.push(sym.tokens[j].tagWith(sym.tag))
}
break
}
case 'KP': {
let sym = sym0 as SymKP
for (let j in sym.tokens) {
- ts.push(this.tagIt(sym.tokens[j],sym.tag))
+ ts.push(sym.tokens[j].tagWith(sym.tag))
}
break
}
@@ -482,21 +474,21 @@ class GFConcrete {
return s
}
- private tagIt(obj: Taggable, tag: string): Taggable {
- if (isString(obj)) {
- let o = new String(obj)
- o.setTag(tag)
- return o
- } else {
- let me = arguments.callee
- if (arguments.length == 2) {
- me.prototype = obj
- let o = new me()
- o.tag = tag
- return o
- }
- }
- }
+ // private tagIt(obj: Taggable, tag: string): Taggable {
+ // if (isString(obj)) {
+ // let o = new String(obj)
+ // o.setTag(tag)
+ // return o
+ // } else {
+ // let me = arguments.callee
+ // if (arguments.length == 2) {
+ // me.prototype = obj
+ // let o = new me()
+ // o.tag = tag
+ // return o
+ // }
+ // }
+ // }
// public showRules(): string {
// let ruleStr = []
@@ -618,6 +610,26 @@ class GFConcrete {
}
/**
+ * A type which can be tagged
+ */
+interface Taggable {
+ tag?: string;
+ tagWith: (tag: string) => Taggable;
+}
+
+/**
+ * Strings can also be tagged in the same way
+ */
+interface String {
+ tag?: string;
+ tagWith: (tag: string) => string;
+}
+String.prototype.tagWith = function (tag: string): string {
+ this.tag = tag
+ return this
+}
+
+/**
* Function ID
*/
type FId = number
@@ -783,6 +795,11 @@ class SymKS implements Taggable {
terminalStr.push('"', this.tokens, '"')
return terminalStr.join('')
}
+
+ public tagWith(tag: string): SymKS {
+ this.tag = tag
+ return this
+ }
}
/**
@@ -805,6 +822,11 @@ class SymKP implements Taggable {
terminalStr.push('"', this.tokens, '"')
return terminalStr.join('')
}
+
+ public tagWith(tag: string): SymKS {
+ this.tag = tag
+ return this
+ }
}
/**
@@ -1423,52 +1445,48 @@ class ActiveItem {
* Utilities
*/
-/*
-eslint-disable
- @typescript-eslint/no-explicit-any,
- @typescript-eslint/no-unused-vars
-*/
+/* eslint-disable @typescript-eslint/no-explicit-any */
/* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */
-function isString(a: any): boolean {
- return typeof a == 'string'
-}
-function isArray(a: any): boolean {
- return a && typeof a == 'object' && a.constructor == Array
-}
+// function isString(a: any): boolean {
+// return typeof a == 'string'
+// }
+// function isArray(a: any): boolean {
+// return a && typeof a == 'object' && a.constructor == Array
+// }
function isUndefined(a: any): boolean {
return typeof a == 'undefined'
}
-function isBoolean(a: any): boolean {
- return typeof a == 'boolean'
-}
-function isNumber(a: any): boolean {
- return typeof a == 'number' && isFinite(a)
-}
-function isFunction(a: any): boolean {
- return typeof a == 'function'
-}
-function dumpObject (obj: any): string {
- if (isUndefined(obj)) {
- return 'undefined'
- } else if (isString(obj)) {
- return '"' + obj.toString() + '"' // FIXME: escape
- } else if (isBoolean(obj) || isNumber(obj)) {
- return obj.toString()
- } else if (isArray(obj)) {
- let x = '['
- for (let i = 0; i < obj.length; i++) {
- x += dumpObject(obj[i])
- if (i < obj.length-1) {
- x += ','
- }
- }
- return x + ']'
- } else {
- let x = '{'
- for (let y in obj) {
- x += y + '=' + dumpObject(obj[y]) + ';'
- }
- return x + '}'
- }
-}
+// function isBoolean(a: any): boolean {
+// return typeof a == 'boolean'
+// }
+// function isNumber(a: any): boolean {
+// return typeof a == 'number' && isFinite(a)
+// }
+// function isFunction(a: any): boolean {
+// return typeof a == 'function'
+// }
+// function dumpObject (obj: any): string {
+// if (isUndefined(obj)) {
+// return 'undefined'
+// } else if (isString(obj)) {
+// return '"' + obj.toString() + '"' // FIXME: escape
+// } else if (isBoolean(obj) || isNumber(obj)) {
+// return obj.toString()
+// } else if (isArray(obj)) {
+// let x = '['
+// for (let i = 0; i < obj.length; i++) {
+// x += dumpObject(obj[i])
+// if (i < obj.length-1) {
+// x += ','
+// }
+// }
+// return x + ']'
+// } else {
+// let x = '{'
+// for (let y in obj) {
+// x += y + '=' + dumpObject(obj[y]) + ';'
+// }
+// return x + '}'
+// }
+// }
diff --git a/src/runtime/typescript/tsconfig.json b/src/runtime/typescript/tsconfig.json
index dc8bbb8e1..9a6cb7ac6 100644
--- a/src/runtime/typescript/tsconfig.json
+++ b/src/runtime/typescript/tsconfig.json
@@ -1,5 +1,8 @@
{
"compilerOptions": {
+ "module": "none",
+ "target": "es3",
"noImplicitAny": true
- }
+ },
+ "compileOnSave": true
}