mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-05-23 09:52:55 -06:00
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
|
* 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
|
* 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 abstract: GFAbstract
|
||||||
public concretes: {[key: string]: GFConcrete}
|
public concretes: {[key: string]: GFConcrete}
|
||||||
|
|
||||||
@@ -62,7 +54,7 @@ export class GFGrammar {
|
|||||||
/**
|
/**
|
||||||
* Abstract Syntax Tree
|
* Abstract Syntax Tree
|
||||||
*/
|
*/
|
||||||
export class Fun {
|
class Fun {
|
||||||
public name: string
|
public name: string
|
||||||
public args: Fun[]
|
public args: Fun[]
|
||||||
public type?: string
|
public type?: string
|
||||||
@@ -408,7 +400,7 @@ class GFConcrete {
|
|||||||
case 'KS':
|
case 'KS':
|
||||||
case 'KP': {
|
case 'KP': {
|
||||||
let sym = sym0 as SymKS | SymKP
|
let sym = sym0 as SymKS | SymKP
|
||||||
toks.push(this.tagIt(sym,tag))
|
toks.push(sym.tagWith(tag))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,14 +420,14 @@ class GFConcrete {
|
|||||||
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(this.tagIt(sym.tokens[j],sym.tag))
|
ts.push(sym.tokens[j].tagWith(sym.tag))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'KP': {
|
case 'KP': {
|
||||||
let sym = sym0 as SymKP
|
let sym = sym0 as SymKP
|
||||||
for (let j in sym.tokens) {
|
for (let j in sym.tokens) {
|
||||||
ts.push(this.tagIt(sym.tokens[j],sym.tag))
|
ts.push(sym.tokens[j].tagWith(sym.tag))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -482,21 +474,21 @@ class GFConcrete {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
private tagIt(obj: Taggable, tag: string): Taggable {
|
// private tagIt(obj: Taggable, tag: string): Taggable {
|
||||||
if (isString(obj)) {
|
// if (isString(obj)) {
|
||||||
let o = new String(obj)
|
// let o = new String(obj)
|
||||||
o.setTag(tag)
|
// o.setTag(tag)
|
||||||
return o
|
// return o
|
||||||
} else {
|
// } else {
|
||||||
let me = arguments.callee
|
// let me = arguments.callee
|
||||||
if (arguments.length == 2) {
|
// if (arguments.length == 2) {
|
||||||
me.prototype = obj
|
// me.prototype = obj
|
||||||
let o = new me()
|
// let o = new me()
|
||||||
o.tag = tag
|
// o.tag = tag
|
||||||
return o
|
// return o
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// public showRules(): string {
|
// public showRules(): string {
|
||||||
// let ruleStr = []
|
// 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
|
* Function ID
|
||||||
*/
|
*/
|
||||||
@@ -783,6 +795,11 @@ class SymKS implements Taggable {
|
|||||||
terminalStr.push('"', this.tokens, '"')
|
terminalStr.push('"', this.tokens, '"')
|
||||||
return terminalStr.join('')
|
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, '"')
|
terminalStr.push('"', this.tokens, '"')
|
||||||
return terminalStr.join('')
|
return terminalStr.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public tagWith(tag: string): SymKS {
|
||||||
|
this.tag = tag
|
||||||
|
return this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1423,52 +1445,48 @@ class ActiveItem {
|
|||||||
* Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
eslint-disable
|
|
||||||
@typescript-eslint/no-explicit-any,
|
|
||||||
@typescript-eslint/no-unused-vars
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */
|
/* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */
|
||||||
function isString(a: any): boolean {
|
// function isString(a: any): boolean {
|
||||||
return typeof a == 'string'
|
// return typeof a == 'string'
|
||||||
}
|
// }
|
||||||
function isArray(a: any): boolean {
|
// function isArray(a: any): boolean {
|
||||||
return a && typeof a == 'object' && a.constructor == Array
|
// return a && typeof a == 'object' && a.constructor == Array
|
||||||
}
|
// }
|
||||||
function isUndefined(a: any): boolean {
|
function isUndefined(a: any): boolean {
|
||||||
return typeof a == 'undefined'
|
return typeof a == 'undefined'
|
||||||
}
|
}
|
||||||
function isBoolean(a: any): boolean {
|
// function isBoolean(a: any): boolean {
|
||||||
return typeof a == 'boolean'
|
// return typeof a == 'boolean'
|
||||||
}
|
// }
|
||||||
function isNumber(a: any): boolean {
|
// function isNumber(a: any): boolean {
|
||||||
return typeof a == 'number' && isFinite(a)
|
// return typeof a == 'number' && isFinite(a)
|
||||||
}
|
// }
|
||||||
function isFunction(a: any): boolean {
|
// function isFunction(a: any): boolean {
|
||||||
return typeof a == 'function'
|
// return typeof a == 'function'
|
||||||
}
|
// }
|
||||||
function dumpObject (obj: any): string {
|
// function dumpObject (obj: any): string {
|
||||||
if (isUndefined(obj)) {
|
// if (isUndefined(obj)) {
|
||||||
return 'undefined'
|
// return 'undefined'
|
||||||
} else if (isString(obj)) {
|
// } else if (isString(obj)) {
|
||||||
return '"' + obj.toString() + '"' // FIXME: escape
|
// return '"' + obj.toString() + '"' // FIXME: escape
|
||||||
} else if (isBoolean(obj) || isNumber(obj)) {
|
// } else if (isBoolean(obj) || isNumber(obj)) {
|
||||||
return obj.toString()
|
// return obj.toString()
|
||||||
} else if (isArray(obj)) {
|
// } else if (isArray(obj)) {
|
||||||
let x = '['
|
// let x = '['
|
||||||
for (let i = 0; i < obj.length; i++) {
|
// for (let i = 0; i < obj.length; i++) {
|
||||||
x += dumpObject(obj[i])
|
// x += dumpObject(obj[i])
|
||||||
if (i < obj.length-1) {
|
// if (i < obj.length-1) {
|
||||||
x += ','
|
// x += ','
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return x + ']'
|
// return x + ']'
|
||||||
} else {
|
// } else {
|
||||||
let x = '{'
|
// let x = '{'
|
||||||
for (let y in obj) {
|
// for (let y in obj) {
|
||||||
x += y + '=' + dumpObject(obj[y]) + ';'
|
// x += y + '=' + dumpObject(obj[y]) + ';'
|
||||||
}
|
// }
|
||||||
return x + '}'
|
// return x + '}'
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"module": "none",
|
||||||
|
"target": "es3",
|
||||||
"noImplicitAny": true
|
"noImplicitAny": true
|
||||||
}
|
},
|
||||||
|
"compileOnSave": true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user