1
0
forked from GitHub/gf-core

Porting of JS runtime to TypeScript (gflib.ts) complete

This commit is contained in:
John J. Camilleri
2019-06-07 13:58:23 +02:00
parent f2e03bfc51
commit ffcdaa921f
4 changed files with 121 additions and 73 deletions

1
src/runtime/typescript/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.js

View 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).

View File

@@ -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 + '}'
// }
// }

View File

@@ -1,5 +1,8 @@
{
"compilerOptions": {
"module": "none",
"target": "es3",
"noImplicitAny": true
}
},
"compileOnSave": true
}