From f46c848b7e87e0b7332780dcdc28e85968ba684f Mon Sep 17 00:00:00 2001 From: bringert Date: Wed, 6 Dec 2006 13:52:24 +0000 Subject: [PATCH] Made generated JavaScript more object-oriented. Moved common JS stuff to lib/javascript/gflib.js --- lib/javascript/gflib.js | 113 ++++++++++++++++++++++++++++++++++++++ src/GF/Canon/CanonToJS.hs | 111 +++++++------------------------------ 2 files changed, 132 insertions(+), 92 deletions(-) create mode 100644 lib/javascript/gflib.js diff --git a/lib/javascript/gflib.js b/lib/javascript/gflib.js new file mode 100644 index 000000000..19d6b448e --- /dev/null +++ b/lib/javascript/gflib.js @@ -0,0 +1,113 @@ +/* Abstract syntax trees */ + +function Fun(name) { + this.name = name; + this.children = copy_arguments(arguments, 1); +} +Fun.prototype.toString = function () { return this.show(0); } ; +Fun.prototype.show = function (prec) { + var s = this.name; + for (var i = 0; i < this.children.length; i++) { + s += " " + this.children[i].show(1); + } + if (prec > 0 && this.children.length > 0) { + s = "(" + s + ")" ; + } + return s; +} ; + +function parseTree(str) { + return parseTree_(str.match(new RegExp("[\\w\\']+|\\(|\\)","g")), 0); +} + +function parseTree_(tokens, prec) { + if (tokens.length == 0 || tokens[0] == ")") { return null; } + var t = tokens.shift(); + if (t == "(") { + var tree = parseTree_(tokens, 0); + tokens.shift(); + return tree; + } else { + var tree = new Fun(t); + if (prec == 0) { + while ((c = parseTree_(tokens, 1)) !== null) { + tree.children.push(c); + } + } + return tree; + } +} + + +/* Concrete syntax terms */ + +function Arr() { this.values = copy_arguments(arguments, 0); } +Arr.prototype.print = function() { return this.values[0].print(); }; +Arr.prototype.sel = function(i) { return this.values[i.toIndex()]; }; + +function Seq() { this.values = copy_arguments(arguments, 0); } +Seq.prototype.print = function() { return join_print(this.values, " "); }; + +function Variants() { this.values = copy_arguments(arguments, 0); } +Variants.prototype.print = function() { return /*join_print(this.values, "/");*/ this.values[0].print(); }; + +function Glue() { this.values = copy_arguments(arguments, 0); } +Glue.prototype.print = function() { return join_print(this.values, ""); }; + +function Rp(index,value) { this.index = index; this.value = value; } +Rp.prototype.print = function() { return this.index; }; +Rp.prototype.toIndex = function() { return this.index.toIndex(); }; + +function Suffix(prefix,suffix) { this.prefix = prefix; this.suffix = suffix; }; +Suffix.prototype.print = function() { return this.prefix.print() + this.suffix.print(); }; +Suffix.prototype.sel = function(i) { new Glue(this.prefix, this.suffix.sel(i)); }; + +function Meta() { } +Meta.prototype.print = function() { return "?"; }; +Meta.prototype.toIndex = function() { return 0; }; +Meta.prototype.sel = function(i) { return this; }; + +function Str(value) { this.value = value; } +Str.prototype.print = function() { return this.value; }; + +function Int(value) { this.value = value; } +Int.prototype.print = function() { return this.value; }; +Int.prototype.toIndex = function() { return this.value; }; + +/* Linearization */ + +function Linearizer() { + this.rules = new Array(); +} +Linearizer.prototype.rule = function (name, cs) { return this.rules[name](cs); }; +Linearizer.prototype.addRule = function (name, f) { this.rules[name] = f; }; +Linearizer.prototype.linearize = function (tree) { return this.linearizeToTerm(tree).print(); }; +Linearizer.prototype.linearizeToTerm = function (tree) { + var cs = new Array(); + for (var i = 0; i < tree.children.length; i++) { + cs[i] = this.linearizeToTerm(tree.children[i]); + } + return this.rule(tree.name, cs); +}; + +/* Utilities */ + +function copy_arguments(args, start) { + var arr = new Array(); + for (var i = 0; i < args.length - start; i++) { + arr[i] = args[i + start]; + } + return arr; +} + +function join_print(values, glue) { + var str = ""; + for (var i = 0; i < values.length; i++) { + str += values[i].print(); + if (i < values.length - 1) { + str += glue; + } + } + return str; +} + diff --git a/src/GF/Canon/CanonToJS.hs b/src/GF/Canon/CanonToJS.hs index d029834fc..18071ce80 100644 --- a/src/GF/Canon/CanonToJS.hs +++ b/src/GF/Canon/CanonToJS.hs @@ -8,32 +8,36 @@ import qualified GF.JavaScript.PrintJS as JS prCanon2js :: CanonGrammar -> String -prCanon2js gr = unlines [trees, terms, linearize, utils, (gfcc2js $ mkCanon2gfcc gr)] +prCanon2js gr = gfcc2js $ mkCanon2gfcc gr gfcc2js :: C.Grammar -> String gfcc2js (C.Grm _ _ cs) = JS.printTree (concrete2js (head cs)) -- FIXME concrete2js :: C.Concrete -> JS.Program -concrete2js (C.Cnc c ds) = JS.Program ([JS.ElStmt $ JS.SDeclOrExpr $ JS.Decl [JS.DInit (JS.Ident "lin") (new "Array" [])]] - ++ concatMap cncdef2js ds) +concrete2js (C.Cnc (C.CId c) ds) = + JS.Program ([JS.ElStmt $ JS.SDeclOrExpr $ JS.Decl [JS.DInit l (new "Linearizer" [])]] + ++ concatMap (cncdef2js l) ds) + where l = JS.Ident c -cncdef2js :: C.CncDef -> [JS.Element] -cncdef2js (C.Lin (C.CId f) t) = - [JS.ElStmt $ JS.SDeclOrExpr $ JS.DExpr $ JS.EAssign (lin (JS.EStr f)) (JS.EFun [children] [JS.SReturn (term2js t)])] +cncdef2js :: JS.Ident -> C.CncDef -> [JS.Element] +cncdef2js l (C.Lin (C.CId f) t) = + [JS.ElStmt $ JS.SDeclOrExpr $ JS.DExpr $ JS.ECall (JS.EMember (JS.EVar l) (JS.Ident "addRule")) [JS.EStr f, JS.EFun [children] [JS.SReturn (term2js l t)]]] -term2js :: C.Term -> JS.Expr -term2js t = +term2js :: JS.Ident -> C.Term -> JS.Expr +term2js l t = f t + where + f t = case t of - C.R xs -> new "Arr" (map term2js xs) - C.P x y -> JS.ECall (JS.EMember (term2js x) (JS.Ident "sel")) [term2js y] - C.S xs -> new "Seq" (map term2js xs) + C.R xs -> new "Arr" (map f xs) + C.P x y -> JS.ECall (JS.EMember (f x) (JS.Ident "sel")) [f y] + C.S xs -> new "Seq" (map f xs) C.K t -> tokn2js t C.V i -> JS.EIndex (JS.EVar children) (JS.EInt i) C.C i -> new "Int" [JS.EInt i] - C.F (C.CId f) -> JS.ECall (lin (JS.EStr f)) [JS.EVar children] - C.FV xs -> new "Variants" (map term2js xs) - C.W str x -> new "Suffix" [JS.EStr str, term2js x] - C.RP x y -> new "Rp" [term2js x, term2js y] + C.F (C.CId f) -> JS.ECall (JS.EMember (JS.EVar l) (JS.Ident "rule")) [JS.EStr f, JS.EVar children] + C.FV xs -> new "Variants" (map f xs) + C.W str x -> new "Suffix" [JS.EStr str, f x] + C.RP x y -> new "Rp" [f x, f y] C.TM -> new "Meta" [] argIdent :: Integer -> JS.Ident @@ -46,82 +50,5 @@ tokn2js (C.KP ss vs) = new "Seq" (map JS.EStr ss) -- FIXME children :: JS.Ident children = JS.Ident "cs" -lin :: JS.Expr -> JS.Expr -lin = JS.EIndex (JS.EVar (JS.Ident "lin")) - new :: String -> [JS.Expr] -> JS.Expr new f xs = JS.ENew (JS.Ident f) xs - -trees :: String -trees = unlines - [ - "function Fun(name) {", - " this.name = name;", - " this.children = copy_arguments(arguments, 1);", - "}" - ] - -terms :: String -terms = unlines - [ - "function Arr() { this.values = copy_arguments(arguments, 0); }", - "Arr.prototype.print = function() { return this.values[0].print(); }", - "Arr.prototype.sel = function(i) { return this.values[i.toIndex()]; }", - "function Seq() { this.values = copy_arguments(arguments, 0); }", - "Seq.prototype.print = function() { return join_print(this.values, \" \"); }", - "function Variants() { this.values = copy_arguments(arguments, 0); }", - "Variants.prototype.print = function() { return join_print(this.values, \"/\"); }", - "function Glue() { this.values = copy_arguments(arguments, 0); }", - "Glue.prototype.print = function() { return join_print(this.values, \"\"); }", - "function Rp(index,value) { this.index = index; this.value = value; }", - "Rp.prototype.print = function() { return this.index; }", - "Rp.prototype.toIndex = function() { return this.index.toIndex(); }", - "function Suffix(prefix,suffix) { this.prefix = prefix; this.suffix = suffix; }", - "Suffix.prototype.print = function() { return this.prefix.print() + this.suffix.print(); }", - "Suffix.prototype.sel = function(i) { new Glue(this.prefix, this.suffix.sel(i)); }", - "function Meta() { }", - "Meta.prototype.print = function() { return \"?\"; }", - "Meta.prototype.toIndex = function() { return 0; }", - "Meta.prototype.sel = function(i) { return this; }", - "function Str(value) { this.value = value; }", - "Str.prototype.print = function() { return this.value; }", - "function Int(value) { this.value = value; }", - "Int.prototype.print = function() { return this.value; }", - "Int.prototype.toIndex = function() { return this.value; }" - ] - -linearize :: String -linearize = unlines - [ - "function linearize(tree) { return linearizeToTerm(tree).print(); }", - "function linearizeToTerm(tree) {", - " var cs = new Array();", - " for (var i = 0; i < tree.children.length; i++) {", - " cs[i] = linearizeToTerm(tree.children[i]);", - " }", - " return lin[tree.name](cs);", - "}" - ] - -utils :: String -utils = unlines - [ - "function copy_arguments(args, start) {", - " var arr = new Array();", - " for (var i = 0; i < args.length - start; i++) {", - " arr[i] = args[i + start];", - " }", - " return arr;", - "}", - "", - "function join_print(values, glue) {", - " var str = \"\";", - " for (var i = 0; i < values.length; i++) {", - " str += values[i].print();", - " if (i < values.length - 1) {", - " str += glue;", - " }", - " }", - " return str;", - "}" - ]