forked from GitHub/gf-core
Porting of JS runtime to TypeScript (gflib.ts) complete
This commit is contained in:
1
src/runtime/typescript/.gitignore
vendored
Normal file
1
src/runtime/typescript/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.js
|
||||
26
src/runtime/typescript/README.md
Normal file
26
src/runtime/typescript/README.md
Normal file
@@ -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).
|
||||
@@ -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 = []
|
||||
@@ -617,6 +609,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
|
||||
*/
|
||||
@@ -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 + '}'
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "none",
|
||||
"target": "es3",
|
||||
"noImplicitAny": true
|
||||
}
|
||||
},
|
||||
"compileOnSave": true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user