diff --git a/src/runtime/c/gu/exn.c b/src/runtime/c/gu/exn.c index c6c7652d6c..951445dd72 100644 --- a/src/runtime/c/gu/exn.c +++ b/src/runtime/c/gu/exn.c @@ -18,12 +18,24 @@ gu_exn_is_raised(GuExn* err) { return err && (err->state == GU_EXN_RAISED); } +GU_API_DECL void +gu_exn_clear(GuExn* err) { + err->caught = NULL; + err->state = GU_EXN_OK; +} + GU_API bool gu_exn_caught_(GuExn* err, const char* type) { return (err->caught && strcmp(err->caught, type) == 0); } +GU_API_DECL void* +gu_exn_caught_data(GuExn* err) +{ + return err->data.data; +} + GU_API void gu_exn_block(GuExn* err) { diff --git a/src/runtime/c/gu/exn.h b/src/runtime/c/gu/exn.h index 6f5d0ff382..968c3f709c 100644 --- a/src/runtime/c/gu/exn.h +++ b/src/runtime/c/gu/exn.h @@ -71,11 +71,13 @@ gu_new_exn(GuPool* pool); GU_API_DECL bool gu_exn_is_raised(GuExn* err); -static inline void -gu_exn_clear(GuExn* err) { - err->caught = NULL; - err->state = GU_EXN_OK; -} +// static inline void +// gu_exn_clear(GuExn* err) { +// err->caught = NULL; +// err->state = GU_EXN_OK; +// } +GU_API_DECL void +gu_exn_clear(GuExn* err); #define gu_exn_caught(err, type) \ (err->caught && strcmp(err->caught, #type) == 0) @@ -83,11 +85,13 @@ gu_exn_clear(GuExn* err) { GU_API_DECL bool gu_exn_caught_(GuExn* err, const char* type); -static inline const void* -gu_exn_caught_data(GuExn* err) -{ - return err->data.data; -} +// static inline const void* +// gu_exn_caught_data(GuExn* err) +// { +// return err->data.data; +// } +GU_API_DECL void* +gu_exn_caught_data(GuExn* err); /// Temporarily block a raised exception. GU_API_DECL void diff --git a/src/runtime/c/pgf/jit.c b/src/runtime/c/pgf/jit.c index 0d5fa9dc6c..9ae788e8e2 100644 --- a/src/runtime/c/pgf/jit.c +++ b/src/runtime/c/pgf/jit.c @@ -26,6 +26,16 @@ PGF_INTERNAL void pgf_jit_predicate(PgfReader* rdr, PgfAbstr* abstr, PgfAbsCat* abscat) { + size_t n_funs = pgf_read_len(rdr); + gu_return_on_exn(rdr->err, ); + + for (size_t i = 0; i < n_funs; i++) { + gu_in_f64be(rdr->in, rdr->err); // ignore + gu_return_on_exn(rdr->err, ); + + PgfCId name = pgf_read_cid(rdr, rdr->tmp_pool); + gu_return_on_exn(rdr->err, ); + } } PGF_INTERNAL void diff --git a/src/runtime/c/pgf/reader.c b/src/runtime/c/pgf/reader.c index 755f14a240..9342d699ee 100644 --- a/src/runtime/c/pgf/reader.c +++ b/src/runtime/c/pgf/reader.c @@ -1326,7 +1326,7 @@ pgf_read_concretes(PgfReader* rdr, PgfAbstr* abstr, bool with_content) PGF_INTERNAL PgfPGF* pgf_read_pgf(PgfReader* rdr) { PgfPGF* pgf = gu_new(PgfPGF, rdr->opool); - + pgf->major_version = gu_in_u16be(rdr->in, rdr->err); gu_return_on_exn(rdr->err, NULL); @@ -1335,7 +1335,7 @@ pgf_read_pgf(PgfReader* rdr) { pgf->gflags = pgf_read_flags(rdr); gu_return_on_exn(rdr->err, NULL); - + pgf_read_abstract(rdr, &pgf->abstract); gu_return_on_exn(rdr->err, NULL); diff --git a/src/runtime/javascript/.gitignore b/src/runtime/javascript/.gitignore new file mode 100644 index 0000000000..425c5e9648 --- /dev/null +++ b/src/runtime/javascript/.gitignore @@ -0,0 +1 @@ +.libs/ diff --git a/src/runtime/javascript/DEPRECATED.md b/src/runtime/javascript/DEPRECATED.md deleted file mode 100644 index 83f4e51d68..0000000000 --- a/src/runtime/javascript/DEPRECATED.md +++ /dev/null @@ -1,4 +0,0 @@ -# Deprecation notice - -As of June 2019, this JavaScript version of the GF runtime is considered deprecated, -in favour of the TypeScript version in . diff --git a/src/runtime/javascript/Dockerfile b/src/runtime/javascript/Dockerfile new file mode 100644 index 0000000000..62378d73d7 --- /dev/null +++ b/src/runtime/javascript/Dockerfile @@ -0,0 +1,48 @@ +FROM emscripten/emsdk:latest + +RUN apt update +RUN apt install -y autoconf automake libtool make + +WORKDIR /tmp/c +COPY gu/*.c gu/*.h /tmp/c/gu/ +COPY pgf/*.c pgf/*.h /tmp/c/pgf/ +COPY pgf/lightning/i386/*.h /tmp/c/pgf/lightning/i386/ +COPY pgf/lightning/*.h /tmp/c/pgf/lightning/ +COPY \ + Makefile.am \ + configure.ac \ + lib*.pc.in \ + /tmp/c/ +RUN autoreconf -i +RUN emconfigure ./configure +RUN emmake make +RUN emcc .libs/libgu.a .libs/libpgf.a -o pgf.js \ + -sALLOW_MEMORY_GROWTH \ + -sEXPORTED_FUNCTIONS="\ + _pgf_read,\ + _pgf_abstract_name,\ + _pgf_read_expr,\ + _pgf_print_expr,\ + _pgf_expr_arity,\ + _gu_new_pool,\ + _gu_new_exn,\ + _gu_data_in,\ + _gu_exn_is_raised,\ + _gu_exn_caught_,\ + _gu_exn_caught_data,\ + _gu_exn_clear,\ + _gu_new_string_buf,\ + _gu_string_buf_out,\ + _gu_string_buf_data,\ + _malloc,\ + _free\ + "\ + -sEXPORTED_RUNTIME_METHODS="\ + ccall,\ + FS,\ + getValue,\ + AsciiToString,\ + stringToUTF8,\ + UTF8ToString,\ + allocateUTF8\ + " diff --git a/src/runtime/javascript/README.md b/src/runtime/javascript/README.md new file mode 100644 index 0000000000..9b7523bf7f --- /dev/null +++ b/src/runtime/javascript/README.md @@ -0,0 +1,11 @@ +# JavaScript runtime using Web Assembly + +This folder contains very early work experimenting with a pure JavaScript runtime, +compiled to Web Assembly (WASM) using [Emscripten](https://emscripten.org/). + +1. Compile the WASM files (inside Docker) using `build-wasm.sh`, placing them in `.libs/` +2. Test in Node.js by running `node test-node.js [path to PGF]` +3. Test in a web browser + 1. Start a server with `npx serve -l 41296` + 2. Browse to `http://localhost:41296/test-web.html` + 3. Check JavaScript console diff --git a/src/runtime/javascript/build-wasm.sh b/src/runtime/javascript/build-wasm.sh new file mode 100755 index 0000000000..5250533189 --- /dev/null +++ b/src/runtime/javascript/build-wasm.sh @@ -0,0 +1,10 @@ +#! /usr/bin/env bash +set -e + +# Build inside Docker image +IMAGE="gf/build-c-runtime-wasm" +docker build ../c --file Dockerfile --tag $IMAGE + +# Copy bulit files from container to host +mkdir -p .libs +docker run --rm --volume "$PWD":/tmp/host $IMAGE bash -c "cp pgf.js pgf.wasm /tmp/host/.libs/" diff --git a/src/runtime/javascript/editor-grammar/Editor.gf b/src/runtime/javascript/editor-grammar/Editor.gf deleted file mode 100644 index 7df69ba5d8..0000000000 --- a/src/runtime/javascript/editor-grammar/Editor.gf +++ /dev/null @@ -1,62 +0,0 @@ -abstract Editor = { - -cat Adjective ; - Noun ; - Verb ; - Determiner ; - Sentence ; - -fun Available : Adjective ; - Next : Adjective ; - Previous : Adjective ; - -fun Bulgarian : Noun ; - Danish : Noun ; - English : Noun ; - Finnish : Noun ; - French : Noun ; - German : Noun ; - Italian : Noun ; - Norwegian : Noun ; - Russian : Noun ; - Spanish : Noun ; - Swedish : Noun ; - -fun Float_N : Noun ; - Integer_N : Noun ; - String_N : Noun ; - - Language : Noun ; - Node : Noun ; - Page : Noun ; - Refinement : Noun ; - Tree : Noun ; - Wrapper : Noun ; - -fun Copy : Verb ; - Cut : Verb ; - Delete : Verb ; - Enter : Verb ; - Parse : Verb ; - Paste : Verb ; - Redo : Verb ; - Refine : Verb ; - Replace : Verb ; - Select : Verb ; - Show : Verb ; - Undo : Verb ; - Wrap : Verb ; - -fun DefPlDet : Determiner ; - DefSgDet : Determiner ; - IndefPlDet : Determiner ; - IndefSgDet : Determiner ; - -fun Command : Verb -> Determiner -> Noun -> Sentence ; - CommandAdj : Verb -> Determiner -> Adjective -> Noun -> Sentence ; - ErrorMessage : Adjective -> Noun -> Sentence ; - Label : Noun -> Sentence ; - RandomlyCommand : Verb -> Determiner -> Noun -> Sentence ; - SingleWordCommand : Verb -> Sentence ; - -} \ No newline at end of file diff --git a/src/runtime/javascript/editor-grammar/EditorEng.gf b/src/runtime/javascript/editor-grammar/EditorEng.gf deleted file mode 100644 index a7161e641c..0000000000 --- a/src/runtime/javascript/editor-grammar/EditorEng.gf +++ /dev/null @@ -1,63 +0,0 @@ ---# -path=alltenses -concrete EditorEng of Editor = open GrammarEng, ParadigmsEng in { - -lincat Adjective = A ; - Noun = N ; - Verb = V ; - Determiner = Det ; - Sentence = Utt ; - -lin Available = mkA "available" ; - Next = mkA "next" ; - Previous = mkA "previous" ; - -lin Bulgarian = mkN "Bulgarian" ; - Danish = mkN "Danish" ; - English = mkN "English" ; - Finnish = mkN "Finnish" ; - French = mkN "French" ; - German = mkN "German" ; - Italian = mkN "Italian" ; - Norwegian = mkN "Norwegian" ; - Russian = mkN "Russian" ; - Spanish = mkN "Spanish" ; - Swedish = mkN "Swedish" ; - -lin Float_N = mkN "float" ; - Integer_N = mkN "integer" ; - String_N = mkN "string" ; - - Language = mkN "language" ; - Node = mkN "node" ; - Page = mkN "page" ; - Refinement = mkN "refinement" ; - Tree = mkN "tree" ; - Wrapper = mkN "wrapper" ; - -lin Copy = mkV "copy" ; - Cut = mkV "cut" ; - Delete = mkV "delete" ; - Enter = mkV "enter" ; - Parse = mkV "parse" ; - Paste = mkV "paste" ; - Redo = mkV "redo" ; - Refine = mkV "refine" ; - Replace = mkV "replace" ; - Select = mkV "select" ; - Show = mkV "show" ; - Undo = mkV "undo" ; - Wrap = mkV "wrap" ; - -lin DefPlDet = DetQuant DefArt NumPl ; - DefSgDet = DetQuant DefArt NumSg ; - IndefPlDet = DetQuant IndefArt NumPl ; - IndefSgDet = DetQuant IndefArt NumSg ; - -lin Command v d n = UttImpSg PPos (ImpVP (ComplSlash (SlashV2a (mkV2 v)) (DetCN d (UseN n)))) ; - CommandAdj v d a n = UttImpSg PPos (ImpVP (ComplSlash (SlashV2a (mkV2 v)) (DetCN d (AdjCN (PositA a) (UseN n))))) ; - ErrorMessage a n = UttNP (DetCN (DetQuant no_Quant NumPl) (AdjCN (PositA a) (UseN n))) ; - Label n = UttNP (MassNP (UseN n)) ; - RandomlyCommand v d n = UttImpSg PPos (ImpVP (AdvVP (ComplSlash (SlashV2a (mkV2 v)) (DetCN d (UseN n))) (PrepNP (mkPrep "at") (MassNP (UseN (mkN "random")))))) ; - SingleWordCommand v = UttImpSg PPos (ImpVP (UseV v)) ; - -} \ No newline at end of file diff --git a/src/runtime/javascript/editor.html b/src/runtime/javascript/editor.html deleted file mode 100644 index ccf23616b9..0000000000 --- a/src/runtime/javascript/editor.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - Web-based Syntax Editor - - -
-
- - diff --git a/src/runtime/javascript/editorGrammar.js b/src/runtime/javascript/editorGrammar.js deleted file mode 100644 index 1fa1fe6394..0000000000 --- a/src/runtime/javascript/editorGrammar.js +++ /dev/null @@ -1 +0,0 @@ -var Editor = new GFGrammar(new GFAbstract("S",{Available: new Type([], "Adjective"), Bulgarian: new Type([], "Noun"), Command: new Type(["Verb", "Determiner", "Noun"], "Sentence"), CommandAdj: new Type(["Verb", "Determiner", "Adjective", "Noun"], "Sentence"), Copy: new Type([], "Verb"), Cut: new Type([], "Verb"), Danish: new Type([], "Noun"), DefPlDet: new Type([], "Determiner"), DefSgDet: new Type([], "Determiner"), Delete: new Type([], "Verb"), English: new Type([], "Noun"), Enter: new Type([], "Verb"), ErrorMessage: new Type(["Adjective", "Noun"], "Sentence"), Finnish: new Type([], "Noun"), Float_N: new Type([], "Noun"), French: new Type([], "Noun"), German: new Type([], "Noun"), IndefPlDet: new Type([], "Determiner"), IndefSgDet: new Type([], "Determiner"), Integer_N: new Type([], "Noun"), Italian: new Type([], "Noun"), Label: new Type(["Noun"], "Sentence"), Language: new Type([], "Noun"), Next: new Type([], "Adjective"), Node: new Type([], "Noun"), Norwegian: new Type([], "Noun"), Page: new Type([], "Noun"), Parse: new Type([], "Verb"), Paste: new Type([], "Verb"), Previous: new Type([], "Adjective"), RandomlyCommand: new Type(["Verb", "Determiner", "Noun"], "Sentence"), Redo: new Type([], "Verb"), Refine: new Type([], "Verb"), Refinement: new Type([], "Noun"), Replace: new Type([], "Verb"), Russian: new Type([], "Noun"), Select: new Type([], "Verb"), Show: new Type([], "Verb"), SingleWordCommand: new Type(["Verb"], "Sentence"), Spanish: new Type([], "Noun"), String_N: new Type([], "Noun"), Swedish: new Type([], "Noun"), Tree: new Type([], "Noun"), Undo: new Type([], "Verb"), Wrap: new Type([], "Verb"), Wrapper: new Type([], "Noun")}),{EditorEng: new GFConcrete({},{0:[new Apply(5,[]), new Apply(34,[]), new Apply(40,[])], 2:[new Apply(19,[]), new Apply(29,[])], 4:[new Apply(18,[]), new Apply(28,[])], 5:[new Apply(6,[]), new Apply(17,[]), new Apply(21,[]), new Apply(24,[]), new Apply(25,[]), new Apply(26,[]), new Apply(27,[]), new Apply(30,[]), new Apply(31,[]), new Apply(33,[]), new Apply(35,[]), new Apply(36,[]), new Apply(37,[]), new Apply(47,[]), new Apply(49,[]), new Apply(54,[]), new Apply(55,[]), new Apply(56,[]), new Apply(57,[]), new Apply(60,[])], 8:[new Apply(7,[new PArg(9), new PArg(12), new PArg(13)]), new Apply(8,[new PArg(10), new PArg(12), new PArg(13)]), new Apply(9,[new PArg(9), new PArg(14), new PArg(13)]), new Apply(10,[new PArg(10), new PArg(14), new PArg(13)]), new Apply(11,[new PArg(9), new PArg(12), new PArg(0), new PArg(13)]), new Apply(12,[new PArg(10), new PArg(12), new PArg(0), new PArg(13)]), new Apply(13,[new PArg(9), new PArg(14), new PArg(0), new PArg(13)]), new Apply(14,[new PArg(10), new PArg(14), new PArg(0), new PArg(13)]), new Apply(23,[new PArg(0), new PArg(13)]), new Apply(32,[new PArg(13)]), new Apply(41,[new PArg(9), new PArg(12), new PArg(13)]), new Apply(42,[new PArg(10), new PArg(12), new PArg(13)]), new Apply(43,[new PArg(9), new PArg(14), new PArg(13)]), new Apply(44,[new PArg(10), new PArg(14), new PArg(13)]), new Apply(52,[new PArg(9)]), new Apply(53,[new PArg(10)])], 10:[new Apply(15,[]), new Apply(16,[]), new Apply(20,[]), new Apply(22,[]), new Apply(38,[]), new Apply(39,[]), new Apply(45,[]), new Apply(46,[]), new Apply(48,[]), new Apply(50,[]), new Apply(51,[]), new Apply(58,[]), new Apply(59,[])], 12:[new Coerce(1), new Coerce(2)], 13:[new Coerce(5), new Coerce(6), new Coerce(7)], 14:[new Coerce(3), new Coerce(4)]},[new CncFun("lindef Adjective",[0, 0, 0, 0, 0, 0, 0]), new CncFun("lindef Determiner",[0, 0, 0, 0]), new CncFun("lindef Noun",[0, 0, 0, 0]), new CncFun("lindef Sentence",[0]), new CncFun("lindef Verb",[0, 0, 0, 0, 0]), new CncFun("Available",[1, 2, 3, 4, 5, 6, 7]), new CncFun("Bulgarian",[8, 9, 10, 11]), new CncFun("Command",[12]), new CncFun("Command",[13]), new CncFun("Command",[14]), new CncFun("Command",[15]), new CncFun("CommandAdj",[16]), new CncFun("CommandAdj",[17]), new CncFun("CommandAdj",[18]), new CncFun("CommandAdj",[19]), new CncFun("Copy",[20, 21, 22, 23, 22]), new CncFun("Cut",[24, 25, 26, 27, 26]), new CncFun("Danish",[28, 29, 30, 31]), new CncFun("DefPlDet",[32, 33, 34, 35]), new CncFun("DefSgDet",[32, 36, 37, 36]), new CncFun("Delete",[38, 39, 40, 41, 40]), new CncFun("English",[42, 43, 44, 45]), new CncFun("Enter",[46, 47, 48, 49, 48]), new CncFun("ErrorMessage",[50]), new CncFun("Finnish",[51, 52, 53, 54]), new CncFun("Float_N",[55, 56, 57, 58]), new CncFun("French",[59, 60, 61, 62]), new CncFun("German",[63, 64, 65, 66]), new CncFun("IndefPlDet",[67, 68, 69, 68]), new CncFun("IndefSgDet",[70, 71, 72, 71]), new CncFun("Integer_N",[73, 74, 75, 76]), new CncFun("Italian",[77, 78, 79, 80]), new CncFun("Label",[81]), new CncFun("Language",[82, 83, 84, 85]), new CncFun("Next",[86, 87, 88, 89, 90, 91, 92]), new CncFun("Node",[93, 94, 95, 96]), new CncFun("Norwegian",[97, 98, 99, 100]), new CncFun("Page",[101, 102, 103, 104]), new CncFun("Parse",[105, 106, 107, 108, 107]), new CncFun("Paste",[109, 110, 111, 112, 111]), new CncFun("Previous",[113, 114, 115, 116, 117, 118, 119]), new CncFun("RandomlyCommand",[120]), new CncFun("RandomlyCommand",[121]), new CncFun("RandomlyCommand",[122]), new CncFun("RandomlyCommand",[123]), new CncFun("Redo",[124, 125, 126, 127, 126]), new CncFun("Refine",[128, 129, 130, 131, 130]), new CncFun("Refinement",[132, 133, 134, 135]), new CncFun("Replace",[136, 137, 138, 139, 138]), new CncFun("Russian",[140, 141, 142, 143]), new CncFun("Select",[144, 145, 146, 147, 146]), new CncFun("Show",[148, 149, 150, 151, 150]), new CncFun("SingleWordCommand",[152]), new CncFun("SingleWordCommand",[81]), new CncFun("Spanish",[153, 154, 155, 156]), new CncFun("String_N",[157, 158, 159, 160]), new CncFun("Swedish",[161, 162, 163, 164]), new CncFun("Tree",[165, 166, 167, 168]), new CncFun("Undo",[169, 170, 171, 172, 171]), new CncFun("Wrap",[173, 174, 175, 176, 175]), new CncFun("Wrapper",[177, 178, 179, 180])],[[new SymLit(0, 0)],[new SymKS("available")],[new SymKS("available's")],[new SymKS("more", "available")],[new SymKS("more", "available's")],[new SymKS("most", "available")],[new SymKS("most", "available's")],[new SymKS("availably")],[new SymKS("Bulgarian")],[new SymKS("Bulgarian's")],[new SymKS("Bulgarians")],[new SymKS("Bulgarians'")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymKS("yourself")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0)],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 2), new SymKS("yourself")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 2)],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymCat(3, 0), new SymKS("yourself")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymCat(3, 0)],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymCat(3, 2), new SymKS("yourself")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymCat(3, 2)],[new SymKS("copy")],[new SymKS("copies")],[new SymKS("copied")],[new SymKS("copying")],[new SymKS("cut")],[new SymKS("cuts")],[new SymKS("cutted")],[new SymKS("cutting")],[new SymKS("Danish")],[new SymKS("Danish's")],[new SymKS("Danishes")],[new SymKS("Danishes'")],[new SymKS("the")],[new SymKS("they")],[new SymKS("theirs")],[new SymKS("them")],[new SymKS("it")],[new SymKS("its")],[new SymKS("delete")],[new SymKS("deletes")],[new SymKS("deleted")],[new SymKS("deleting")],[new SymKS("English")],[new SymKS("English's")],[new SymKS("Englishes")],[new SymKS("Englishes'")],[new SymKS("enter")],[new SymKS("enters")],[new SymKS("enterred")],[new SymKS("enterring")],[new SymKS("no"), new SymCat(0, 0), new SymCat(1, 2)],[new SymKS("Finnish")],[new SymKS("Finnish's")],[new SymKS("Finnishes")],[new SymKS("Finnishes'")],[new SymKS("float")],[new SymKS("float's")],[new SymKS("floats")],[new SymKS("floats'")],[new SymKS("French")],[new SymKS("French's")],[new SymKS("Frenches")],[new SymKS("Frenches'")],[new SymKS("German")],[new SymKS("German's")],[new SymKS("Germans")],[new SymKS("Germans'")],[],[new SymKS("ones")],[new SymKS("ones'")],[new SymKP(["a"],[new Alt(["a"],["eu", "Eu", "uni", "up"]), new Alt(["an"],["un"]), new Alt(["an"],["a", "e", "i", "o", "A", "E", "I", "O"]), new Alt(["an"],["SMS", "sms"])])],[new SymKS("one")],[new SymKS("one's")],[new SymKS("integer")],[new SymKS("integer's")],[new SymKS("integers")],[new SymKS("integers'")],[new SymKS("Italian")],[new SymKS("Italian's")],[new SymKS("Italians")],[new SymKS("Italians'")],[new SymCat(0, 0)],[new SymKS("language")],[new SymKS("language's")],[new SymKS("languages")],[new SymKS("languages'")],[new SymKS("next")],[new SymKS("next's")],[new SymKS("nexter")],[new SymKS("nexter's")],[new SymKS("nextest")],[new SymKS("nextest's")],[new SymKS("nextly")],[new SymKS("node")],[new SymKS("node's")],[new SymKS("nodes")],[new SymKS("nodes'")],[new SymKS("Norwegian")],[new SymKS("Norwegian's")],[new SymKS("Norwegians")],[new SymKS("Norwegians'")],[new SymKS("page")],[new SymKS("page's")],[new SymKS("pages")],[new SymKS("pages'")],[new SymKS("parse")],[new SymKS("parses")],[new SymKS("parsed")],[new SymKS("parsing")],[new SymKS("paste")],[new SymKS("pastes")],[new SymKS("pasted")],[new SymKS("pasting")],[new SymKS("previous")],[new SymKS("previous'")],[new SymKS("more", "previous")],[new SymKS("more", "previous'")],[new SymKS("most", "previous")],[new SymKS("most", "previous'")],[new SymKS("previously")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymKS("yourself", "at", "random")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 0), new SymKS("at", "random")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 2), new SymKS("yourself", "at", "random")],[new SymCat(0, 0), new SymCat(1, 0), new SymCat(2, 2), new SymKS("at", "random")],[new SymKS("redo")],[new SymKS("redoes")],[new SymKS("redoed")],[new SymKS("redoing")],[new SymKS("refine")],[new SymKS("refines")],[new SymKS("refined")],[new SymKS("refining")],[new SymKS("refinement")],[new SymKS("refinement's")],[new SymKS("refinements")],[new SymKS("refinements'")],[new SymKS("replace")],[new SymKS("replaces")],[new SymKS("replaced")],[new SymKS("replacing")],[new SymKS("Russian")],[new SymKS("Russian's")],[new SymKS("Russians")],[new SymKS("Russians'")],[new SymKS("select")],[new SymKS("selects")],[new SymKS("selected")],[new SymKS("selecting")],[new SymKS("show")],[new SymKS("shows")],[new SymKS("showed")],[new SymKS("showing")],[new SymCat(0, 0), new SymKS("yourself")],[new SymKS("Spanish")],[new SymKS("Spanish's")],[new SymKS("Spanishes")],[new SymKS("Spanishes'")],[new SymKS("string")],[new SymKS("string's")],[new SymKS("strings")],[new SymKS("strings'")],[new SymKS("Swedish")],[new SymKS("Swedish's")],[new SymKS("Swedishes")],[new SymKS("Swedishes'")],[new SymKS("tree")],[new SymKS("tree's")],[new SymKS("trees")],[new SymKS("trees'")],[new SymKS("undo")],[new SymKS("undoes")],[new SymKS("undoed")],[new SymKS("undoing")],[new SymKS("wrap")],[new SymKS("wraps")],[new SymKS("wrapped")],[new SymKS("wrapping")],[new SymKS("wrapper")],[new SymKS("wrapper's")],[new SymKS("wrappers")],[new SymKS("wrappers'")]],{Adjective:{s: 0, e: 0}, Determiner:{s: 1, e: 4}, Float:{s: -3, e: -3}, Int:{s: -2, e: -2}, Noun:{s: 5, e: 7}, Sentence:{s: 8, e: 8}, String:{s: -1, e: -1}, Verb:{s: 9, e: 10}, __gfVar:{s: -4, e: -4}}, 15)}); diff --git a/src/runtime/javascript/empty.png b/src/runtime/javascript/empty.png deleted file mode 100644 index 35d9875dfa..0000000000 Binary files a/src/runtime/javascript/empty.png and /dev/null differ diff --git a/src/runtime/javascript/gfjseditor.js b/src/runtime/javascript/gfjseditor.js deleted file mode 100644 index de0ad67fa8..0000000000 --- a/src/runtime/javascript/gfjseditor.js +++ /dev/null @@ -1,1310 +0,0 @@ - -//Variable and Constant definitions - -var expColImg = new Array(2); -expColImg[0] = new Image(12,12); -expColImg[0].src = "minus.png"; -expColImg[1] = new Image(12,12); -expColImg[1].src = "plus.png"; -expColImg[2] = new Image(12,12); -expColImg[2].src = "empty.png"; - -// Grammars -var grammar = undefined; -var editorGrammar = Editor; - -var selectedLanguage = "EditorEng"; -var selectedNode = ""; -var collapseBuffer = new Array(); -var abstractTree = new Fun ("?"); - -var navigationControlString = new Array(); -var undoArray = new Array(); -var redoArray = new Array(); -var clipBoard; -var refPageCounter = 0; - -var stringAbstractTree = undefined; -var myTree = undefined; -var parseTrees = undefined; - -var keys = new Array(); -keys ["Z"] = function() { clickUndo('actUndo'); } -keys ["Y"] = function() { clickRedo('actRedo'); } -keys ["R"] = function() { clickRefine('actRefine'); }; -keys ["V"] = function() { clickPaste('actPaste'); }; -keys ["X"] = function() { clickCut('actCut'); }; -keys ["C"] = function() { clickCopy('actCopy'); }; -keys ["D"] = function() { clickDelete('actDelete'); }; -keys ["E"] = function() { clickReplace('actReplace'); }; -keys ["W"] = function() { clickWrap('actWrap'); }; -keys ["P"] = function() { clickParse('actParse'); }; -keys ["N"] = function() { clickRandomNode('actRandomNode'); }; -keys ["T"] = function() { clickRandomTree('actRandomTree'); }; -keys ["%"] = function() { leftArrowKey(); }; -keys ["&"] = function() { upDownArrowKey(-1); }; -keys ["'"] = function() { rightArrowKey(); }; -keys ["("] = function() { upDownArrowKey( 1); }; -keys ["27"] = function() { clickEsc(); }; - -function state(selectedNode, tree, collapseBuffer) { - this.selectedNode = selectedNode; - this.tree = grammar.abstract.copyTree(tree); - this.collapseBuffer = collapseBuffer; - return this; -} - -function treeNode(name, caption) { - this.name = name; - this.caption = caption; - this.cat = ""; - this.children = new Array(); - this.collapsed = false; - return this; -} - -treeNode.prototype.addChild = function (i, c) { - this.children[i] = c; -} - -treeNode.prototype.hasChildren = function() { - return this.children.length; -} - -/* -------------------------------------------------------------------------- */ -/* ----------------------------- GUI functions ----------------------------- */ -/* -------------------------------------------------------------------------- */ - - -// Creates an instance of the editor and stores it in the given HTML container. -// Previous content is destroyed. -function mkEditor(container, myGrammar) { - grammar = myGrammar; - myTree = treeFromAbstract(grammar.abstract.annotate(abstractTree, grammar.abstract.startcat), "0"); - var holder = document.getElementById(container); - holder.innerHTML = "
"; - nodeClick('0', '?'); -} - -// Generates a tree from the string representation of an abstract tree contained in the element elementToParse -function parseStringTree(elementToParse) { - stringAbstractTree = elementToParse; - abstractTree = grammar.abstract.handleLiterals(grammar.abstract.parseTree(document.getElementById(elementToParse).value, grammar.abstract.startcat)); - myTree = treeFromAbstract(abstractTree, "0"); - nodeClick("0"); -} - -// If a key is pressed and a function assigned to that key, calls the function -function hotKeys(event) { - event = (event) ? event : ((window.event) ? event : null); - if (event) { - var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : event.keyCode); - - if (document.getElementById("actParse").className == "selected" && charCode != 27) - return true; - - if (keys[String.fromCharCode(charCode).toUpperCase()] && - !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) { - keys[String.fromCharCode(charCode).toUpperCase()](); - return false; - } - else if (keys["" + charCode] && - !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) { - keys["" + charCode](); - return false; - } - else if (charCode >= "96" && charCode <= "105" && - !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) { - keys["" + (charCode - 96)](); - return false; - } - } - - return true; -} - -// Clears "numeric" hotkeys -function clearHotKeys() { - for (var key in keys) { - if ((parseInt(key) + 1) && (key != "27")) { keys[key] = function() { }; } - } -} - -// Action to be performed when the up/down arrow key is pressed -function upDownArrowKey(pos) { - var nodePos = getNavPos(selectedNode); - if ((nodePos > 0 && pos < 0) || (nodePos < navigationControlString.length - 1 && pos > 0)) { - nodeClick(navigationControlString[nodePos + pos]); - } -} - -// Gets the position of a given node in the navigationControlString -function getNavPos(nodeName) { - for (var i = 0, j = navigationControlString.length; i < j; i++) { - if (navigationControlString[i] == nodeName) { return i; }; - } - return undefined; -} - -// Given a name and a tree, gets the node in the tree with that name -function getNode(nodeName, node) { - if (nodeName == node.name) { - return node; - } - else { - for (var i = 0, j = node.children.length; i < j; i++) { - var found = getNode(nodeName, node.children[i]); - if (found) { return found; } - } - } -} - -// Action to be performed when the left arrow key is pressed -function leftArrowKey() { - var node = getNode(selectedNode, myTree); - if (!node.collapsed && node.hasChildren()) { - signClick(node.name, node.caption); - } - else { - var parentNode = getParent(node.name, myTree); - if (parentNode) { nodeClick(parentNode.name); } - } -} - -// Gets the parent of the selected node -function getParent(nodeName, node) { - if (node.name == nodeName) { - return undefined; - } - else { - for (var i = 0, j = node.children.length; i < j; i++) { - if (node.children[i].name == nodeName) { return node; } - } - for (var i = 0, j = node.children.length; i < j; i++) { - var found = getParent(nodeName, node.children[i]); - if (found) { return found; } - } - } -} - -// Action to be performed when the right arrow key is pressed -function rightArrowKey() { - var node = getNode(selectedNode, myTree); - if (node.collapsed) { - signClick(node.name, node.caption); - } - else { - var firstDescendant = getfirstDescendant(node); - if (firstDescendant) { - nodeClick(firstDescendant.name); - } - } -} - -// Gets the first descendant child of a node -function getfirstDescendant(node) { - if (node.hasChildren() && !node.collapsed) { return node.children[0]; } - return undefined; -} - -// Produces and displays an HTML representation of the tree -function drawTree() { - var frame = document.getElementById("absFrame"); - navigationControlString = new Array(); - frame.innerHTML = ""; - document.getElementById("link" + selectedNode).scrollIntoView(false); -} - -// Produces an HTML representation of the tree -function getTree(tree, level) { - navigationControlString[navigationControlString.length] = tree.name; - var htmlTree = new Array(); - htmlTree.push("
  • "); - if (tree.hasChildren()) { - htmlTree.push(""); - } - else { - htmlTree.push(""); - } - htmlTree.push(""); - if (tree.cat == "String" || tree.cat == "Int" || tree.cat == "Float") { - htmlTree.push(tree.caption.substring(tree.caption.lastIndexOf("_") + 1)); - } else { - htmlTree.push(tree.caption); - } - htmlTree.push(" : ", tree.cat, "
  • "); - return htmlTree.join(""); -} - -// Linearizes and displays the abstract tree -function drawLinearizedFrame() { - var frame = document.getElementById("conFrame"); - frame.innerHTML = getLinearizedFrame(); -} - -// Linearizes the abstract tree and returns it in HTML form -function getLinearizedFrame() { - var linearizedFrame = new Array(); - for (var i in grammar.concretes) { - linearizedFrame.push("

    ", i, "

    "); - linearizedFrame.push("

    "); - var tokens = grammar.concretes[i].tagAndLinearize(abstractTree); - for (var j = 0, k = tokens.length; j < k; j++) { - linearizedFrame.push(createLinearized(tokens[j])); - } - linearizedFrame.push("

    "); - } - linearizedFrame.push("

    Abstract

    "); - linearizedFrame.push("

    ", createLinearizedFromAbstract(myTree, "0"), "

    "); - return linearizedFrame.join(""); -} - -// Linearizes and displays the abstract tree -function drawEditFrame() { - var frame = document.getElementById("conFrame"); - frame.innerHTML = getEditFrame(); -} - -// Linearizes the abstract tree and returns it in HTML form -function getEditFrame() { - var editFrame = new Array(); - for (var i in grammar.concretes) { - editFrame.push("

    ", i, "

    "); - editFrame.push("

    "); - if (abstractTree.isMeta()) { - editFrame.push(" "); - isLastSelected = true; - } else { - var tokens = grammar.concretes[i].tagAndLinearize(abstractTree); - var isLastSelected = false; - for (var j = 0, k = tokens.length; j < k; j++) { - var token = tokens[j]; - var node = getNode(token.tag, myTree); - - if (node.name.substr(0, selectedNode.length) == selectedNode) { - if (!isLastSelected) { - editFrame.push(""); - isLastSelected = true; - } - - if (token == "&-") - editFrame.push("
    "); - else - editFrame.push(token+" "); - } else { - if (isLastSelected) { - editFrame.push("
    "); - isLastSelected = false; - } - - if (token == "&-") - editFrame.push("
    "); - else - editFrame.push("", token, ""); - } - } - } - - if (isLastSelected) { - editFrame.push("
    "); - isLastSelected = false; - } - - editFrame.push("

    "); - } - editFrame.push("

    Abstract

    "); - editFrame.push("

    ", createLinearizedFromAbstract(myTree, "0"), "

    "); - return editFrame.join(""); -} - -function editFrameKeyDown(me,lang,event) { - event = (event) ? event : ((window.event) ? event : null); - if (event) { - var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : event.keyCode); - - if (charCode == 13) { - refPageCounter = 0; - parseTrees = undefined; - var string = me.innerText; - if (string || string == "") { - var node = getNode(selectedNode, myTree); - switch (node.cat) { - case "String": parseTrees = [new Fun('"'+string+'"')]; break; - case "Int": if (isNaN(string) || (string && string.indexOf(".") != -1)) - parseTrees = new Array(); - else - parseTrees = [new Fun(string)]; - break; - case "Float": if (isNaN(string)) - parseTrees = new Array(); - else - parseTrees = [new Fun(string)]; - break; - default: parseTrees = grammar.concretes[lang].parseString(string, node.cat); break; - } - if (parseTrees.length == 1) { - pushUndoClearRedo(); - abstractTree = insertNode(abstractTree, selectedNode, "0", grammar.abstract.copyTree(grammar.abstract.handleLiterals(parseTrees[0], node.cat))); - document.getElementById("actFrame").innerHTML = showActions(); - document.getElementById("refFrame").innerHTML = ""; - clearHotKeys(); - concludeAction(); - } else if (parseTrees.length > 1) { - document.getElementById("refFrame").innerHTML = showTrees(); - } - } - return false; - } - } - - return true; -} - -// Creates an HTML representation of a linearization of an abstract tree -function createLinearized(token) { - var node = getNode(token.tag, myTree); - var linearized = new Array() - linearized.push(""); } - else { linearized.push(" onclick='nodeClick(\"", node.name, "\");'>", token, ""); } - return linearized.join(""); -} - -// Creates an HTML representation of the abstract tree -function createLinearizedFromAbstract(node, path, prec) { - var linearized = new Array(); - linearized.push(""); - if (node.children.length) { linearized.push(" ("); } - if (node.cat == "String" || node.cat == "Int" || node.cat == "Float") { - linearized.push(" ", node.caption.substring(node.caption.lastIndexOf("_") + 1), " "); - } else { - linearized.push(" ", node.caption, " "); - } - for (var i = 0, j = node.children.length; i < j; i++) { - linearized.push(createLinearizedFromAbstract(node.children[i], path + "-" + i, 1)); - } - if (node.children.length) { linearized.push(") "); } - linearized.push(""); - return linearized.join(""); -} - -// Expands/Collapses node -function signClick(name, caption) { - myTree = expandCollapse(myTree, name); - nodeClick(name); -} - -// Sets the "collapsed" property of a given node -function expandCollapse(node, name) { - if (node.name == name) { - if (wasCollapsed(node.name)) { removeFromCollapseBuffer(node.name); } - else { collapseBuffer[collapseBuffer.length] = node.name; } - node.collapsed ^= true; - } - else { - for (var i = 0, j = node.children.length; i < j; i++) { - expandCollapse(node.children[i], name); - } - } - return node; -} - -// Checks if a node was collapsed on the previous cycle -function wasCollapsed(nodeName) { - for (var i = 0, j = collapseBuffer.length; i < j; i++) { - if (nodeName == collapseBuffer[i]) { - return true; - } - } - return false; -} - -// Removes a node from the collapseBuffer array -function removeFromCollapseBuffer(nodeName) { - var newBuffer = new Array(); - for (var i = 0, j = collapseBuffer.length; i < j; i++) { - if (nodeName != collapseBuffer[i]) { - newBuffer[newBuffer.length] = collapseBuffer[i]; - } - } - collapseBuffer = newBuffer; -} - -// Selects a node -function nodeClick(name) { - if ((document.getElementById("actRefine") && document.getElementById("actRefine").className == "selected") || - (document.getElementById("actReplace") && document.getElementById("actReplace").className == "selected") || - (document.getElementById("actWrap") && document.getElementById("actWrap").className == "selected") || - (document.getElementById("actTree") && document.getElementById("actTree").className == "selected")) { - return; } - selectedNode = name; - if (stringAbstractTree) { - document.getElementById(stringAbstractTree).value = abstractTree.show(); - } - document.getElementById("actFrame").innerHTML = showActions(); - document.getElementById("refFrame").innerHTML = ""; - document.getElementById("messageFrame").innerHTML = showLanguages(); - document.getElementById(selectedLanguage).className = "selected"; - applyLanguage(); - drawTree(); - drawLinearizedFrame(); -} - -// Shows the available languages for the editor -function showLanguages() { - var languages = new Array(); - languages.push("", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "
    BulgarianDanishEnglishFinnishFrenchGermanItalianNorwegianRussianSpanishSwedish
    "); - return languages.join(""); -} - -// Selects the language to use in the editor -function clickLanguage(lang) { - if (lang) { - var tdsToClear = document.getElementById("languagesTable").getElementsByTagName("td"); - for (var i = 0, j = tdsToClear.length; i < j; i++) { - if (tdsToClear[i].className == "selected") { tdsToClear[i].className = "language"; } - } - document.getElementById(lang).className = "selected"; - selectedLanguage = lang; - applyLanguage(); - } -} - -// Applies a language to the editor -function applyLanguage() { - var langsToLinearize = document.getElementById("languagesTable").getElementsByTagName("td"); - for (var i = 0, j = langsToLinearize.length; i < j; i++) { - var absStr = langsToLinearize[i].getAttribute("title"); - var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(absStr, editorGrammar.abstract.startcat)); - lin = lin.substring(0,1).toUpperCase().concat(lin.substring(1)) - if (!langsToLinearize[i].firstChild) { - var txt = document.createTextNode(lin); - langsToLinearize[i].appendChild(txt); - } - else { - langsToLinearize[i].firstChild.nodeValue = lin; - } - } - var actionsToLinearize = document.getElementById("actionsTable").getElementsByTagName("td"); - for (var i = 0, j = actionsToLinearize.length; i < j; i++) { - if (actionsToLinearize[i].className == "action") { - var absStr = actionsToLinearize[i].getAttribute("title"); - var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(absStr, editorGrammar.abstract.startcat)); - lin = lin.substring(0,1).toUpperCase().concat(lin.substring(1)) - if (!actionsToLinearize[i].firstChild) { - var txt = document.createTextNode(lin); - actionsToLinearize[i].appendChild(txt); - } - else { - actionsToLinearize[i].firstChild.nodeValue = lin; - } - } - } - var messageToLinearize = document.getElementById("refgenRefRandom"); - if (messageToLinearize) { - var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("RandomlyCommand Select IndefSgDet Refinement", editorGrammar.abstract.startcat)); - messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1)); - } - var messageToLinearize = document.getElementById("nextRefsNext"); - if (messageToLinearize) { - var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat)); - messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1)); - } - messageToLinearize = document.getElementById("nextRefsPrevious"); - if (messageToLinearize) { - var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat)); - messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1)); - } - var messageToLinearize = document.getElementById("nextWrapsNext"); - if (messageToLinearize) { - var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat)); - messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1)); - } - messageToLinearize = document.getElementById("nextWrapsPrevious"); - if (messageToLinearize) { - var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat)); - messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1)); - } -} - -// Shows the available actions for a node -function showActions(caption) { - var node = getNode(selectedNode, myTree); - var abstractNode = getNodeFromAbstract(abstractTree, node.name, "0"); - var actions = new Array(); - actions.push(""); - if (undoArray.length) { - actions.push(createAction("Undo", "action", "SingleWordCommand Undo", "Z")); } - else { actions.push(createAction("Undo", "unavailable", "SingleWordCommand Undo", "Z")); }; - if (redoArray.length) { - actions.push(createAction("Redo", "action", "SingleWordCommand Redo", "Y")); } - else { actions.push(createAction("Redo", "unavailable", "SingleWordCommand Redo", "Y")); } - if (node.caption == "?") { - actions.push(createAction("Cut", "unavailable", "SingleWordCommand Cut", "X")); - actions.push(createAction("Copy", "unavailable", "SingleWordCommand Copy", "C")); - var AbsNodeType = abstractNode.type; - if (clipBoard && (AbsNodeType == grammar.abstract.getCat(clipBoard.name))) { - actions.push(createAction("Paste", "action", "SingleWordCommand Paste", "V")); - } - else { actions.push(createAction("Paste", "unavailable", "SingleWordCommand Paste", "V")); } - actions.push(createAction("Delete", "unavailable", "SingleWordCommand Delete", "D")); - actions.push(createAction("Refine", "action", "SingleWordCommand Refine", "R")); - actions.push(createAction("Replace", "unavailable", "SingleWordCommand Replace", "E")); - actions.push(createAction("Wrap", "unavailable", "SingleWordCommand Wrap", "W")); - } - else if (node.caption) { - actions.push(createAction("Cut", "action", "SingleWordCommand Cut", "X")); - actions.push(createAction("Copy", "action", "SingleWordCommand Copy", "C")); - actions.push(createAction("Paste", "unavailable", "SingleWordCommand Paste", "V")); - actions.push(createAction("Delete", "action", "SingleWordCommand Delete", "D")); - actions.push(createAction("Refine", "unavailable", "SingleWordCommand Refine", "R")); - actions.push(createAction("Replace", "action", "SingleWordCommand Replace", "E")); - actions.push(createAction("Wrap", "action", "SingleWordCommand Wrap", "W")); - } - - actions.push(createAction("Parse", "action", "Command Parse IndefSgDet String_N", "P")); - - if (node && !abstractNode.isComplete()) { - actions.push(createAction("RandomNode", "action", "RandomlyCommand Refine DefSgDet Node", "N")); - } - else { - actions.push(createAction("RandomNode", "unavailable", "RandomlyCommand Refine DefSgDet Node", "N")); - } - if (!abstractTree.isComplete()) { - actions.push(createAction("RandomTree", "action", "RandomlyCommand Refine DefSgDet Tree", "T")); - } - else { - actions.push(createAction("RandomTree", "unavailable", "RandomlyCommand Refine DefSgDet Tree", "T")); - } - actions.push("
    "); - return actions.join(""); - -} - -// Creates an action -function createAction(actionName, className, caption, hotKey) { - return "" + caption + "(" + hotKey + ")"; -} - -// When the "Refine" action is selected, gets the appropriate refinements for a node -function clickRefine(actName) { - if (document.getElementById(actName).className == "action") { - if (selectedNode) { - refPageCounter = 0; - var node = getNodeFromAbstract(abstractTree, selectedNode, "0"); - if (node.type == "String" || node.type == "Int" || node.type == "Float") { - clickParse("actParse"); - } else { - highlightSelectedAction(actName); - pushUndoClearRedo(); - document.getElementById("refFrame").innerHTML = showRefinements(selectedNode); - } - } - } -} - -// Sets the className of actName to "selected" and grays out the other selections -function highlightSelectedAction(actName) { - graySelections(actName); - document.getElementById(actName).className = "selected"; - drawTree(); -} - -// Grays out all actions except one -function graySelections(except) { - var refs = document.getElementById("actFrame").getElementsByTagName("tr"); - for (var i = 0, j = refs.length; i < j; i++) { - if (refs[i].id != except) { refs[i].className = "closed"; } - } -} - -// Pushes the abstract tree into the undo array and clears the redo array -function pushUndoClearRedo() { - undoArray.push(new state(selectedNode, abstractTree, collapseBuffer)); - redoArray.length = 0; -} - -// Gets the refinements to display -function showRefinements(nodeName) { - var refs = getAvailableRefinements(nodeName, abstractTree, grammar); - var rowsPerPage = 9; - var pages = Math.floor(refs.length / rowsPerPage); - var upperLimit; - if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; } - else { upperLimit = refs.length; } - var refinements = new Array(); - refinements.push(""); - var keyPos = 0; - refinements.push(ref_wrapToHtml("ref", "genRefRandom", "refinement", "", keyPos, "RandomlyCommand Select IndefSgDet Refinement")); - keys["" + keyPos] = mkRefHotKey("genRefRandom"); - keyPos++; - for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) { - refinements.push(ref_wrapToHtml("ref", refs[i], "refinement", "", keyPos, "")); - keys["" + keyPos] = mkRefHotKey(refs[i]); - keyPos++; - } - if (((refs.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) || - ((refs.length % rowsPerPage != 0) && pages > refPageCounter) ) { - refinements.push(ref_wrapNextRefsToHtml("nextRefs", "Next", "refinement", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat)))); - keys["107"] = mkRefNextRefsHotKey("Next"); - } - if (0 < refPageCounter) { - refinements.push(ref_wrapNextRefsToHtml("nextRefs", "Previous", "refinement", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat)))); - keys["109"] = mkRefNextRefsHotKey("Previous"); - } - refinements.push("
    "); - return refinements.join(""); -} - -// Creates an HTML representation of a Refinement/Wrap -function ref_wrapToHtml(funct, name, className, arg, hotKeyPos, caption) { - var ref_wrapHtml = new Array(); - ref_wrapHtml.push(""); - if (caption) { ref_wrapHtml.push(editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(caption, editorGrammar.abstract.startcat))); } - else { ref_wrapHtml.push(name, " : ", refArgsToHtml(name), grammar.abstract.getCat(name)); } - ref_wrapHtml.push("(", hotKeyPos, ")"); - return ref_wrapHtml.join(""); -} - -// Creates the function to be used by a "numeric" hot key -function mkRefHotKey(refName) { - return function() { if (document.getElementById("ref" + refName)) { refClick(refName); } } -} - -// Creates an HTML representation of the Next/Previous Refinement/Wrap page -function ref_wrapNextRefsToHtml(funct, name, className, hotKeyPos, caption) { - var ref_wrapHtml = new Array(); - ref_wrapHtml.push(""); - ref_wrapHtml.push(caption); - ref_wrapHtml.push("(", hotKeyPos, ")"); - return ref_wrapHtml.join(""); -} - -// Creates the function to be used by a "+"/"-" hot key -function mkRefNextRefsHotKey(refName) { - return function() { if (document.getElementById("nextRefs" + refName)) { nextRefsClick(refName); } } -} - -// Creates a string representation of the arguments of a refinement -function refArgsToHtml(fun) { - var args = new Array(); - for (var i = 0, j = grammar.abstract.types[fun].args.length; i < j; i++) { - args.push(grammar.abstract.types[fun].args[i], " -> "); - } - return args.join(""); -} - -// Gets the type of a meta variable -function getMetaType(absNode, route, currRoute) { - if (route == currRoute && absNode.isMeta()) { - return absNode.type; - } - else { - for (var i = 0, j = absNode.args.length; i < j; i++) { - var found = getMetaType(absNode.args[i], route, currRoute + "-" + i); - if (found) { return found }; - } - } -} - -// When the "Undo" action is selected, undoes the last action -function clickUndo(actName) { - if (document.getElementById(actName).className == "action" && undoArray.length) { - highlightSelectedAction(actName); - redoArray.push(new state(selectedNode, abstractTree, collapseBuffer)); - var prevState = undoArray.pop(); - selectedNode = prevState.selectedNode; - abstractTree = grammar.abstract.copyTree(prevState.tree); - collapseBuffer = prevState.collapseBuffer; - if (abstractTree.isComplete()) { selectedNode = "0"; } - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - nodeClick(selectedNode); - } -} - -// When the "Redo" action is selected, redoes the last action -function clickRedo(actName) { - if (document.getElementById(actName).className == "action" && redoArray.length) { - highlightSelectedAction(actName); - undoArray.push(new state(selectedNode, abstractTree, collapseBuffer)); - var nextState = redoArray.pop(); - selectedNode = nextState.selectedNode; - abstractTree = grammar.abstract.copyTree(nextState.tree); - collapseBuffer = nextState.collapseBuffer; - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - nodeClick(selectedNode); - } -} - -// When the "Copy" action is selected, copies the selected node to the clipboard -function clickCopy(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - if (selectedNode) { - clipBoard = grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0")); - document.getElementById("clipboardFrame").innerHTML = clipBoard.name + " : " + grammar.abstract.getCat(clipBoard.name); - nodeClick(selectedNode); - } - } -} - -// When the "Cut" action is selected, deletes the selected node and copies it to the clipboard -function clickCut(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - if (selectedNode) { - clipBoard = grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0")); - document.getElementById("clipboardFrame").innerHTML = clipBoard.name + " : " + grammar.abstract.getCat(clipBoard.name); - abstractTree = deleteNode(abstractTree, selectedNode, "0"); - concludeAction(); - } - } -} - -// Annotates the abstract tree, creates a tree from the abstract tree and selects the next meta variable -function concludeAction() { - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - selectNextMeta(); -} - -// Selects the next meta variable available -function selectNextMeta() { - nodeClick(selectedNode); - if (!abstractTree.isComplete()) { - var pathToNextMeta = ""; - var nodePos = getNavPos(selectedNode); - while (1) { - if (nodePos == navigationControlString.length) { nodePos = 0; } - var node = getNode(navigationControlString[nodePos], myTree); - if (node.caption == "?") { pathToNextMeta = node.name; break; } - nodePos++; - } - expandAscendants(pathToNextMeta); - nodeClick(pathToNextMeta); - } -} - -// Expands the ascendants of a given node -function expandAscendants(nodeName) { - var nodePath = nodeName.split("-"); - var currAscendant = nodePath.shift(); - while (nodePath.length > 0) { - var node = getNode(currAscendant, myTree); - if (node.collapsed) { - myTree = expandCollapse(myTree, currAscendant); - } - currAscendant += "-" + nodePath.shift(); - } -} - -// When the "Paste" action is selected, pastes the contents of the clipboard into the selected node -function clickPaste(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - if (selectedNode) { - abstractTree = insertNode(abstractTree, selectedNode, "0", grammar.abstract.copyTree(clipBoard)); - concludeAction(); - } - } -} - -// When the "Delete" action is selected, deletes the selected node -function clickDelete(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - if (selectedNode) { - abstractTree = deleteNode(abstractTree, selectedNode, "0"); - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - nodeClick(selectedNode); - } - } -} - -// When the "Replace" action is selected, replaces the selected node with another refinement -function clickReplace(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - if (selectedNode) { - refPageCounter = 0; - abstractTree = deleteNode(abstractTree, selectedNode, "0"); - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - drawTree(); - document.getElementById("refFrame").innerHTML = showRefinements(selectedNode); - } - } -} - -// When the "Wrap" action is selected, wraps around the selected node with another refinement -function clickWrap(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - var node = getNode(selectedNode, myTree); - if (selectedNode) { - refPageCounter = 0; - var wrappers = showWrappers(node.caption); - document.getElementById("refFrame").innerHTML = wrappers; - if (wrappers.length <= 31) { - var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("ErrorMessage Available Wrapper", editorGrammar.abstract.startcat)); - alert(lin.substring(0,1).toUpperCase().concat(lin.substring(1))); - document.getElementById("actFrame").innerHTML = showActions(); - nodeClick(selectedNode); - } - } - } -} - -// Gets the wrappers to display -function showWrappers(nodeCaption) { - var nodeType = grammar.abstract.types[nodeCaption].cat; - var rowsPerPage = 10; - var availWrappers = getAvailableWrappers(nodeType, grammar, selectedNode); - var pages = Math.floor(availWrappers.length / rowsPerPage); - var upperLimit; - if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; } - else { upperLimit = availWrappers.length; } - var wrappers = new Array(); - wrappers.push(""); - var keyPos = 0; - for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) { - wrappers.push(ref_wrapToHtml("wrap", availWrappers[i][0], "wrapper", ", " + availWrappers[i][1], keyPos, "")); - keys["" + keyPos] = mkWrapHotKey(availWrappers[i][0], availWrappers[i][1]); - keyPos++; - } - if (((availWrappers.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) || - ((availWrappers.length % rowsPerPage != 0) && pages > refPageCounter) ) { - wrappers.push(ref_wrapNextRefsToHtml("nextWraps", "Next", "wrapper", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat)))); - keys["107"] = mkWrapNextRefsHotKey("Next"); - } - if (0 < refPageCounter) { - wrappers.push(ref_wrapNextRefsToHtml("nextWraps", "Previous", "wrapper", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat)))); - keys["109"] = mkWrapNextRefsHotKey("Previous"); - } - wrappers.push("
    "); - return wrappers.join(""); -} - -// Creates the function to be used by a "numeric" hot key -function mkWrapHotKey(wrapName, argPos) { - return function() { if (document.getElementById("wrap" + wrapName)) { wrapClick(wrapName, argPos); } } -} - -// Creates the function to be used by a "+"/"-" hot key -function mkWrapNextRefsHotKey(wrapName) { - return function() { if (document.getElementById("nextWraps" + wrapName)) { nextWrapsClick(wrapName); } } -} - -// When the "Parse" action is selected, asks the user for a string and parses it -// to generate the subnode -function clickParse(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - var node = getNode(selectedNode, myTree); - if (selectedNode) { - pushUndoClearRedo(); - drawEditFrame(); - } - } -} - -// Displays the parse trees in the refinements panel -function showTrees() { - var rowsPerPage = 10; - var pages = Math.floor(parseTrees.length / rowsPerPage); - var upperLimit; - if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; } - else { upperLimit = parseTrees.length; } - var htmlTrees = new Array(); - htmlTrees.push(""); - var keyPos = 0; - for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) { - htmlTrees.push(treeToHtml(i, keyPos, "")); - keys["" + keyPos] = mkTreeHotKey(i, keyPos); - keyPos++; - } - if (((parseTrees.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) || - ((parseTrees.length % rowsPerPage != 0) && pages > refPageCounter) ) { - htmlTrees.push(ref_wrapNextRefsToHtml("nextTrees", "Next", "tree", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat)))); - keys["107"] = mkTreeNextRefsHotKey("Next"); - } - if (refPageCounter > 0) { - htmlTrees.push(ref_wrapNextRefsToHtml("nextTrees", "Previous", "tree", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat)))); - keys["109"] = mkTreeNextRefsHotKey("Previous"); - } - htmlTrees.push("
    "); - return htmlTrees.join(""); -} - -// Creates an HTML representation of a parse Tree to be shown in the refinements panel -function treeToHtml(i, hotKeyPos, caption) { - var htmlTree = new Array(); - htmlTree.push(""); - if (caption) { htmlTree.push(editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(caption, editorGrammar.abstract.startcat))); } - else { htmlTree.push(parseTrees[i].show()); } - htmlTree.push("(", hotKeyPos, ")"); - return htmlTree.join(""); -} - -// Creates the function to be used by a "numeric" hot key -function mkTreeHotKey(i, keyPos) { - return function() { if (document.getElementById("tree" + keyPos)) { treeClick(i); } } -} - -// Creates the function to be used by a "+"/"-" hot key -function mkTreeNextRefsHotKey(treeName) { - return function() { if (document.getElementById("nextTrees" + treeName)) { nextTreesClick(treeName); } } -} - - -// When the "RandomNode" action is selected, refines the node at random -function clickRandomNode(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - if (selectedNode) { - var tempTree = grammar.abstract.copyTree(abstractTree); - abstractTree = insertNode(tempTree, selectedNode, "0", grammar.abstract.copyTree(fillSubTree(grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0")), grammar))); - concludeAction(); - } - } -} - -// When the "RandomTree" action is selected, refines the tree at random -function clickRandomTree(actName) { - if (document.getElementById(actName).className == "action") { - highlightSelectedAction(actName); - pushUndoClearRedo(); - abstractTree = grammar.abstract.copyTree(fillSubTree(abstractTree, grammar)); - concludeAction(); - } -} - -// If a node is selected and is of type meta, it refines the node with a type refName -function refClick(refName) { - if (selectedNode) { - if (refName == "genRefRandom") { - var refs = getAvailableRefinements(selectedNode, abstractTree, grammar); - refName = refs[Math.floor(refs.length * Math.random())]; - } - abstractTree = refineAbstractTree(abstractTree, selectedNode, "0", refName); - document.getElementById("actFrame").innerHTML = showActions(); - document.getElementById("refFrame").innerHTML = ""; - clearHotKeys(); - concludeAction(); - } -} - -// Creates a tree from an abstract tree -function treeFromAbstract(abstractNode, name) { - var node = new treeNode(name, abstractNode.name); - if (node.caption == "?") { - node.cat = abstractNode.type; } - else { - if (grammar.abstract.types[node.caption]) { - node.cat = grammar.abstract.getCat(node.caption); - } else { - node.cat = node.caption.substring(0, node.caption.indexOf("_")); - grammar.abstract.addType(node.caption, [], node.cat); - var linStr = undefined; - if (node.cat == "String") { - linStr = node.caption.substring(node.caption.indexOf("\"") + 1, node.caption.length - 1); - } else { - linStr = node.caption.substring(node.caption.lastIndexOf("_") + 1) - } - for (var i in grammar.concretes) { - grammar.concretes[i].addRule(node.caption, function(cs){ return new Arr(new Str(linStr));}); - } - } - } - if (wasCollapsed(node.name)) { node.collapsed = true; } - for (var i = 0, j = abstractNode.args.length; i < j; i++) { - node.addChild(i, treeFromAbstract(abstractNode.args[i], name + "-" + i)); - } - return node -} - -// Wraps a refinement around a node -function wrapClick(wrapName, argPos) { - if (selectedNode) { - var tempNode = createRefinement(wrapName); - tempNode.setArg(argPos, grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0"))); - abstractTree = insertNode(abstractTree, selectedNode, "0", tempNode); - var cat = grammar.abstract.getCat(tempNode.name); - if (selectedNode == "0" && cat != grammar.abstract.startcat) { - grammar.abstract.startcat = cat; - } - document.getElementById("actFrame").innerHTML = showActions(); - document.getElementById("refFrame").innerHTML = ""; - clearHotKeys(); - concludeAction(); - } -} - -// Wraps a refinement around a node -function treeClick(i) { - if (selectedNode) { - pushUndoClearRedo(); - var node = getNode(selectedNode, myTree); - var tempNode = grammar.abstract.copyTree(grammar.abstract.handleLiterals(parseTrees[i], node.cat)); - abstractTree = insertNode(abstractTree, selectedNode, "0", tempNode); - document.getElementById("actFrame").innerHTML = showActions(); - document.getElementById("refFrame").innerHTML = ""; - clearHotKeys(); - concludeAction(); - } -} - -// Handler for the escape key -function clickEsc() { - if ((document.getElementById("actRefine").className == "selected" || - document.getElementById("actReplace").className == "selected" || - document.getElementById("actWrap").className == "selected" || - document.getElementById("actParse").className == "selected") && undoArray.length) { - var prevState = undoArray.pop(); - selectedNode = prevState.selectedNode; - abstractTree = grammar.abstract.copyTree(prevState.tree); - collapseBuffer = prevState.collapseBuffer; - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - myTree = treeFromAbstract(abstractTree, "0"); - document.getElementById("actFrame").innerHTML = showActions(); - if (selectedNode) { nodeClick(selectedNode) } - } -} - -// If there are over ten refinements available shows only the selected nine -function nextRefsClick(refName) { - if (refName == "Next") { refPageCounter++; } else { refPageCounter--; } - clearHotKeys(); - document.getElementById("refFrame").innerHTML = showRefinements(selectedNode); -} - -// If there are over ten wrappers available shows only the selected nine -function nextWrapsClick(wrapName) { - if (wrapName == "Next") { refPageCounter++; } else { refPageCounter--; } - clearHotKeys(); - var node = getNode(selectedNode, myTree); - document.getElementById("refFrame").innerHTML = showWrappers(node.caption); -} - -// If there are over ten parse trees available shows only the selected nine -function nextTreesClick(treeName) { - if (treeName == "Next") { refPageCounter++; } else { refPageCounter--; } - clearHotKeys(); - document.getElementById("refFrame").innerHTML = showTrees(); -} - -/* -------------------------------------------------------------------------- */ -/* ---------- GUI independent functions to handle syntax editing ---------- */ -/* -------------------------------------------------------------------------- */ - -// Gets the node rooted at the indicated path (route) in the tree absNode -function getNodeFromAbstract(absNode, route, currRoute) { - if (route == currRoute) { - return absNode; - } - else { - for (var i = 0, j = absNode.args.length; i < j; i++) { - var found = getNodeFromAbstract(absNode.args[i], route, currRoute + "-" + i); - if (found) { return found; } - } - } -} - -// Gets the first metavariable from the abstract tree rooted at the path route -function getNextMetaFromAbstract(node, route) { - if (node.isMeta()) { return route; } - for (var i = 0, j = node.args.length; i < j; i++) { - var found = getNextMetaFromAbstract(node.args[i], route + "-" + i); - if (found) { return found; } - } -} - -// Inserts the node into the abstract tree absNode at the path route -function insertNode(absNode, route, currRoute, node) { - if (route == currRoute) { - return node; - } - else { - for (var i = 0, j = absNode.args.length; i < j; i++) { - absNode.setArg(i, insertNode(absNode.args[i], route, currRoute + "-" + i, node)); - } - return absNode; - } -} - -// Deletes the node rooted at the path route from the abstract tree absNode -function deleteNode(absNode, route, currRoute) { - if (route == currRoute) { - return new Fun("?"); - } - else { - for (var i = 0, j = absNode.args.length; i < j; i++) { - absNode.setArg(i, deleteNode(absNode.args[i], route, currRoute + "-" + i)); - } - return absNode; - } -} - -// Gets the available refinements for the node nodeName, which is in the tree -// abstractTree, from those found in the grammar. -function getAvailableRefinements(nodeName, abstractTree, grammar) { - var node = getNodeFromAbstract(abstractTree, nodeName, "0"); - var metaType = node.type; - var refinements = new Array(); - for (var fun in grammar.abstract.types) { - if (grammar.abstract.types[fun].cat == metaType) { - refinements[refinements.length] = fun; - } - } - return refinements; -} - -// It refines the node rooted at the path route in the abstract tree absNode -// with the refinement refName. Returns the refined abstract tree. -function refineAbstractTree(absNode, route, currRoute, refName) { - if (route == currRoute && absNode.isMeta()) { - return createRefinement(refName); - } - else { - for (var i = 0, j = absNode.args.length; i < j; i++) { - absNode.setArg(i, refineAbstractTree(absNode.args[i], route, currRoute + "-" + i, refName)); - } - return absNode; - } -} - -// Creates a node of type refName object with the appropriate number of arguments -function createRefinement(refName) { - var newRef = new Fun(refName); - for (var i = 0, j = grammar.abstract.types[refName].args.length; i < j; i++) { - newRef.setArg(i, new Fun("?")); - } - return newRef; -} - -// Gets the available wrappers for a node of type nodeType found in the grammar -function getAvailableWrappers(nodeType, grammar, top) { - var wrappers = new Array(); - for (var fun in grammar.abstract.types) { - for (var i = 0, j = grammar.abstract.types[fun].args.length; i < j; i++) { - if (top != "0") { - if (grammar.abstract.types[fun].args[i] == nodeType && grammar.abstract.types[fun].cat == nodeType) { - wrappers[wrappers.length] = new Array(fun, i); - break; - } - } else { - if (grammar.abstract.types[fun].args[i] == nodeType) { - wrappers[wrappers.length] = new Array(fun, i); - break; - } - } - } - } - return wrappers; -} - -// Instantiates metavariables found in the tree abstractTree with refinements -// selected at random from those found in the grammar -function fillSubTree(abstractTree, grammar) { - while (!abstractTree.isComplete()) { - var nodeToRefine = getNextMetaFromAbstract(abstractTree, "0"); - if (nodeToRefine) { - var refs = getAvailableRefinements(nodeToRefine, abstractTree, grammar); - if (refs.length == 0) { - var node = getNodeFromAbstract(abstractTree, nodeToRefine, "0"); - if (node.type == "String" || node.type == "Int" || node.type == "Float") { - var newType = undefined; - var newTypeCat = node.type + "_Literal_"; - switch(node.type) - { - case "String": - newType = "AutoString"; - break; - case "Int": - newType = "8"; - break; - case "Float": - newType = "8.0"; - break; - } - if (node.type == "String") { - newTypeCat += "\"" + newType + "\""; - } else { - newTypeCat += newType; - } - if (!grammar.abstract.types[newTypeCat]) { - grammar.abstract.addType(newTypeCat, [], node.type); - for (var i in grammar.concretes) { - grammar.concretes[i].addRule(newTypeCat, function(cs){ return new Arr(new Str(newType));}); - } - } - node.name = newTypeCat; - abstractTree = insertNode(abstractTree, nodeToRefine, "0", node); - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - } - } - else { - var selectedRef = refs[Math.floor(refs.length * Math.random())]; - abstractTree = refineAbstractTree(abstractTree, nodeToRefine, "0", selectedRef); - abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat); - } - } - } - return abstractTree; -} diff --git a/src/runtime/javascript/gflib-xhtml-voice.js b/src/runtime/javascript/gflib-xhtml-voice.js deleted file mode 100644 index fd86601007..0000000000 --- a/src/runtime/javascript/gflib-xhtml-voice.js +++ /dev/null @@ -1,54 +0,0 @@ -/* Output */ - -function sayText(text) { - document.voice_output_text = text; - activateForm("voice_output"); -} - -/* XHTML+Voice Utilities */ - -function activateForm(formid) { - var form = document.getElementById(formid); - var e = document.createEvent("UIEvents"); - e.initEvent("DOMActivate","true","true"); - form.dispatchEvent(e); -} - - -/* DOM utilities */ - -/* Gets the head element of the document. */ -function getHeadElement() { - var hs = document.getElementsByTagName("head"); - if (hs.length == 0) { - var head = document.createElement("head"); - document.documentElement.insertBefore(head, document.documentElement.firstChild); - return head; - } else { - return hs[0]; - } -} - -/* Gets the body element of the document. */ -function getBodyElement() { - var bs = document.getElementsByTagName("body"); - if (bs.length == 0) { - var body = document.createElement("body"); - document.documentElement.appendChild(body); - return body; - } else { - return bs[0]; - } -} - -/* Removes all the children of a node */ -function removeChildren(node) { - while (node.hasChildNodes()) { - node.removeChild(node.firstChild); - } -} - -function setText(node, text) { - removeChildren(node); - node.appendChild(document.createTextNode(text)); -} diff --git a/src/runtime/javascript/gflib.js b/src/runtime/javascript/gflib.js deleted file mode 100644 index 0dc5a2ff3d..0000000000 --- a/src/runtime/javascript/gflib.js +++ /dev/null @@ -1,1148 +0,0 @@ - -function GFGrammar(abstract, concretes) { - this.abstract = abstract; - this.concretes = concretes; -} - -/* Translates a string from any concrete syntax to all concrete syntaxes. - Uses the start category of the grammar. -*/ -GFGrammar.prototype.translate = function (input, fromLang, toLang) { - var outputs = new Object(); - var fromConcs = this.concretes; - if (fromLang) { - fromConcs = new Object(); - fromConcs[fromLang] = this.concretes[fromLang]; - } - var toConcs = this.concretes; - if (toLang) { - toConcs = new Object(); - toConcs[toLang] = this.concretes[toLang]; - } - for (var c1 in fromConcs) { - var concrete = this.concretes[c1]; - var trees = concrete.parseString(input, this.abstract.startcat); - if (trees.length > 0) { - outputs[c1] = new Array(); - for (var i in trees) { - outputs[c1][i] = new Object(); - for (var c2 in toConcs) { - outputs[c1][i][c2] = this.concretes[c2].linearize(trees[i]); - } - } - } - } - return outputs; -} - - -/* ------------------------------------------------------------------------- */ -/* ----------------------------- LINEARIZATION ----------------------------- */ -/* ------------------------------------------------------------------------- */ - -/* Extension to the String object */ - -String.prototype.tag = ""; -String.prototype.setTag = function (tag) { this.tag = tag; }; - -/* Abstract syntax trees */ -function Fun(name) { - this.name = name; - this.args = new Array(); - for (var i = 1; i < arguments.length; i++) { - this.args[i-1] = arguments[i]; - } -} -Fun.prototype.print = function () { return this.show(0); } ; -Fun.prototype.show = function (prec) { - if (this.isMeta()) { - if (isUndefined(this.type)) { - return '?'; - } else { - var s = '?:' + this.type; - if (prec > 0) { - s = "(" + s + ")" ; - } - return s; - } - } else { - var s = this.name; - var cs = this.args; - for (var i in cs) { - s += " " + (isUndefined(cs[i]) ? "undefined" : cs[i].show(1)); - } - if (prec > 0 && cs.length > 0) { - s = "(" + s + ")" ; - } - return s; - } -}; -Fun.prototype.getArg = function (i) { - return this.args[i]; -}; -Fun.prototype.setArg = function (i,c) { - this.args[i] = c; -}; -Fun.prototype.isMeta = function() { - return this.name == '?'; -} ; -Fun.prototype.isComplete = function() { - if (this.isMeta()) { - return false; - } else { - for (var i in this.args) { - if (!this.args[i].isComplete()) { - return false; - } - } - return true; - } -} ; -Fun.prototype.isLiteral = function() { - return (/^[\"\-\d]/).test(this.name); -} ; -Fun.prototype.isString = function() { - return (/^\".*\"$/).test(this.name); -} ; -Fun.prototype.isInt = function() { - return (/^\-?\d+$/).test(this.name); -} ; -Fun.prototype.isFloat = function() { - return (/^\-?\d*(\.\d*)?$/).test(this.name) && - this.name != "." && - this.name != "-."; -} ; -Fun.prototype.isEqual = function(obj) { - if (this.name != obj.name) - return false; - - for (var i in this.args) { - if (!this.args[i].isEqual(obj.args[i])) - return false; - } - - return true; -} - -/* Type annotation */ - -function GFAbstract(startcat, types) { - this.startcat = startcat; - this.types = types; -} -GFAbstract.prototype.addType = function(fun, args, cat) { - this.types[fun] = new Type(args, cat); -} ; -GFAbstract.prototype.getArgs = function(fun) { - return this.types[fun].args; -} -GFAbstract.prototype.getCat = function(fun) { - return this.types[fun].cat; -}; -GFAbstract.prototype.annotate = function(tree, type) { - if (tree.name == '?') { - tree.type = type; - } else { - var typ = this.types[tree.name]; - for (var i in tree.args) { - this.annotate(tree.args[i], typ.args[i]); - } - } - return tree; -} ; -GFAbstract.prototype.handleLiterals = function(tree, type) { - if (tree.name != '?') { - if (type == "String" || type == "Int" || type == "Float") { - tree.name = type + "_Literal_" + tree.name; - } else { - var typ = this.types[tree.name]; - for (var i in tree.args) { - this.handleLiterals(tree.args[i], typ.args[i]); - } - } - } - return tree; -} ; -/* Hack to get around the fact that our SISR doesn't build real Fun objects. */ -GFAbstract.prototype.copyTree = function(x) { - var t = new Fun(x.name); - if (!isUndefined(x.type)) { - t.type = x.type; - } - var cs = x.args; - if (!isUndefined(cs)) { - for (var i in cs) { - t.setArg(i, this.copyTree(cs[i])); - } - } - return t; -} ; -GFAbstract.prototype.parseTree = function(str, type) { - return this.annotate(this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g), 0), type); -} ; -GFAbstract.prototype.parseTree_ = function(tokens, prec) { - if (tokens.length == 0 || tokens[0] == ")") { return null; } - var t = tokens.shift(); - if (t == "(") { - var tree = this.parseTree_(tokens, 0); - tokens.shift(); - return tree; - } else if (t == '?') { - var tree = this.parseTree_(tokens, 0); - return new Fun('?'); - } else { - var tree = new Fun(t); - if (prec == 0) { - var c, i; - for (i = 0; (c = this.parseTree_(tokens, 1)) !== null; i++) { - tree.setArg(i,c); - } - } - return tree; - } -} ; - -function Type(args, cat) { - this.args = args; - this.cat = cat; -} - -/* Linearization */ - -function GFConcrete(flags, productions, functions, sequences, startCats, totalFIds) { - this.flags = flags; - this.productions = productions; - this.functions = functions; - this.sequences = sequences; - this.startCats = startCats; - this.totalFIds = totalFIds; - - this.pproductions = productions; - this.lproductions = new Object(); - - for (var fid in productions) { - for (var i in productions[fid]) { - var rule = productions[fid][i]; - - if (rule.id == "Apply") { - var fun = this.functions[rule.fun]; - var lproductions = this.lproductions; - - rule.fun = fun; - - var register = function (args, key, i) { - if (i < args.length) { - var c = 0; - var arg = args[i].fid; - - for (var k in productions[arg]) { - var rule = productions[arg][k]; - if (rule.id == "Coerce") { - register(args,key + "_" + rule.arg,i+1); - c++; - } - } - - if (c == 0) - register(args,key + "_" + arg,i+1); - } else { - var set = lproductions[key]; - if (set == null) { - set = new Array(); - lproductions[key] = set; - } - set.push({fun: fun, fid: fid}); - } - } - - register(rule.args,rule.fun.name,0); - } - } - } - - for (var i in functions) { - var fun = functions[i]; - for (var j in fun.lins) { - fun.lins[j] = sequences[fun.lins[j]]; - } - } -} -GFConcrete.prototype.linearizeSyms = function (tree, tag) { - var res = new Array(); - - if (tree.isString()) { - var sym = new SymKS(tree.name); - sym.tag = tag; - res.push({fid: -1, table: [[sym]]}); - } else if (tree.isInt()) { - var sym = new SymKS(tree.name); - sym.tag = tag; - res.push({fid: -2, table: [[sym]]}); - } else if (tree.isFloat()) { - var sym = new SymKS(tree.name); - sym.tag = tag; - res.push({fid: -3, table: [[sym]]}); - } else if (tree.isMeta()) { - // TODO: Use lindef here - var cat = this.startCats[tree.type]; - - var sym = new SymKS(tree.name); - sym.tag = tag; - - for (var fid = cat.s; fid <= cat.e; fid++) { - res.push({fid: fid, table: [[sym]]}); - } - } else { - var cs = new Array(); - for (var i in tree.args) { - // TODO: we should handle the case for nondeterministic linearization - cs.push(this.linearizeSyms(tree.args[i],tag + "-" + i)[0]); - } - var key = tree.name; - for (var i in cs) { - key = key + "_" + cs[i].fid - } - - for (var i in this.lproductions[key]) { - var rule = this.lproductions[key][i]; - var row = {fid: rule.fid, table: new Array()}; - for (var j in rule.fun.lins) { - var lin = rule.fun.lins[j]; - var toks = new Array(); - row.table[j] = toks; - - for (var k in lin) { - var sym = lin[k]; - switch (sym.id) { - case "Arg": - case "Lit": - var ts = cs[sym.i].table[sym.label]; - for (var l in ts) { - toks.push(ts[l]); - } - break; - case "KS": - case "KP": - toks.push(this.tagIt(sym,tag)); - break; - } - } - } - res.push(row); - } - } - - return res; -}; -GFConcrete.prototype.syms2toks = function (syms) { - var ts = new Array(); - for (var i in syms) { - var sym = syms[i]; - switch (sym.id) { - case "KS": - for (var j in sym.tokens) { - ts.push(this.tagIt(sym.tokens[j],sym.tag)); - } - break; - case "KP": - for (var j in sym.tokens) { - ts.push(this.tagIt(sym.tokens[j],sym.tag)); - } - break; - } - } - return ts; -}; -GFConcrete.prototype.linearizeAll = function (tree) { - var res = this.linearizeSyms(tree,"0"); - for (var l in res) { - res[l] = this.unlex(this.syms2toks(res[l].table[0])); - } - - return res; -}; -GFConcrete.prototype.linearize = function (tree) { - var res = this.linearizeSyms(tree,"0"); - return this.unlex(this.syms2toks(res[0].table[0])); -} -GFConcrete.prototype.tagAndLinearize = function (tree) { - var res = this.linearizeSyms(tree,"0"); - return this.syms2toks(res[0].table[0]); -} -GFConcrete.prototype.unlex = function (ts) { - if (ts.length == 0) { - return ""; - } - - var noSpaceAfter = /^[\(\-\[]/; - var noSpaceBefore = /^[\.\,\?\!\)\:\;\-\]]/; - - var s = ""; - for (var i = 0; i < ts.length; i++) { - var t = ts[i]; - var after = i < ts.length-1 ? ts[i+1] : null; - s += t; - if (after != null && !t.match(noSpaceAfter) - && !after.match(noSpaceBefore)) { - s += " "; - } - } - return s; -}; -GFConcrete.prototype.tagIt = function (obj, tag) { - if (isString(obj)) { - var o = new String(obj); - o.setTag(tag); - return o; - } else { - var me = arguments.callee; - if (arguments.length == 2) { - me.prototype = obj; - var o = new me(); - o.tag = tag; - return o; - } - } -}; - -/* Utilities */ - -/* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */ -function isString(a) { return typeof a == 'string'; } -function isArray(a) { return a && typeof a == 'object' && a.constructor == Array; } -function isUndefined(a) { return typeof a == 'undefined'; } -function isBoolean(a) { return typeof a == 'boolean'; } -function isNumber(a) { return typeof a == 'number' && isFinite(a); } -function isFunction(a) { return typeof a == 'function'; } - -function dumpObject (obj) { - 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)) { - var x = "["; - for (var i in obj) { - x += dumpObject(obj[i]); - if (i < obj.length-1) { - x += ","; - } - } - return x + "]"; - } else { - var x = "{"; - for (var y in obj) { - x += y + "=" + dumpObject(obj[y]) + ";" ; - } - return x + "}"; - } -} - -/* ------------------------------------------------------------------------- */ -/* -------------------------------- PARSING -------------------------------- */ -/* ------------------------------------------------------------------------- */ - - -GFConcrete.prototype.showRules = function () { - var ruleStr = new Array(); - ruleStr.push(""); - for (var i = 0, j = this.rules.length; i < j; i++) { - ruleStr.push(this.rules[i].show()); - } - return ruleStr.join(""); -}; -GFConcrete.prototype.tokenize = function (string) { - var inToken = false; - var start, end; - var tokens = new Array(); - - for (var i = 0; i < string.length; i++) { - if ( string.charAt(i) == ' ' // space - || string.charAt(i) == '\f' // form feed - || string.charAt(i) == '\n' // newline - || string.charAt(i) == '\r' // return - || string.charAt(i) == '\t' // horizontal tab - || string.charAt(i) == '\v' // vertical tab - || string.charAt(i) == String.fromCharCode(160) //   - ) { - if (inToken) { - end = i-1; - inToken = false; - - tokens.push(string.substr(start,end-start+1)); - } - } else { - if (!inToken) { - start = i; - inToken = true; - } - } - } - - if (inToken) { - end = i-1; - inToken = false; - - tokens.push(string.substr(start,end-start+1)); - } - return tokens; -}; -GFConcrete.prototype.parseString = function (string, cat) { - var tokens = this.tokenize(string); - - var ps = new ParseState(this, cat); - for (var i in tokens) { - if (!ps.next(tokens[i])) - return new Array(); - } - return ps.extractTrees(); -}; -/** - * Generate list of suggestions given an input string - */ -GFConcrete.prototype.complete = function (input, cat) { - - // Parameter defaults - if (input == null) input = ""; - if (cat == null) cat = grammar.abstract.startcat; - - // Tokenise input string & remove empty tokens - tokens = input.trim().split(' '); - for (var i = tokens.length - 1; i >= 0; i--) { - if (tokens[i] == "") { tokens.splice(i, 1); } - } - - // Capture last token as it may be partial - current = tokens.pop(); - if (current == null) current = ""; - - // Init parse state objects. - // ps2 is used for testing whether the final token is parsable or not. - var ps = new ParseState(this, cat); - var ps2 = new ParseState(this, cat); - - // Iterate over tokens, feed one by one to parser - for (var i = 0; i < tokens.length ; i++) { - if (!ps.next(tokens[i])) { - return new Array(); // Incorrect parse, nothing to suggest - } - ps2.next(tokens[i]); // also consume token in ps2 - } - - // Attempt to also parse current, knowing it may be incomplete - if (ps2.next(current)) { - ps.next(current); - tokens.push(current); - current = ""; - } - delete(ps2); // don't need this anymore - - // Parse is successful so far, now get suggestions - var acc = ps.complete(current); - - // Format into just a list of strings & return - // (I know the multiple nesting looks horrible) - var suggs = new Array(); - if (acc.value) { - // Iterate over all acc.value[] - for (var v = 0; v < acc.value.length; v++) { - // Iterate over all acc.value[].seq[] - for (var s = 0; s < acc.value[v].seq.length; s++) { - if (acc.value[v].seq[s].tokens == null) continue; - // Iterate over all acc.value[].seq[].tokens - for (var t = 0; t < acc.value[v].seq[s].tokens.length; t++) { - suggs.push( acc.value[v].seq[s].tokens[t] ); - } - } - } - } - - // Note: return used tokens too - return { 'consumed' : tokens, 'suggestions' : suggs }; -} - -// Apply Object Definition - -function Apply(fun, args) { - this.id = "Apply"; - this.fun = fun; - this.args = args; -} -Apply.prototype.show = function (cat) { - var recStr = new Array(); - recStr.push(cat, " -> ", fun.name, " [", this.args, "]"); - return recStr.join(""); -}; -Apply.prototype.isEqual = function (obj) { - if (this.id != obj.id || this.fun != obj.fun || this.args.length != obj.args.length) - return false; - - for (var i in this.args) { - if (this.args[i] != obj.args[i]) - return false; - } - - return true; -}; - -function PArg() { - this.fid = arguments[arguments.length-1]; - if (arguments.length > 1) - this.hypos = arguments.slice(0,arguments.length-1); -} - -// Coerce Object Definition - -function Coerce(arg) { - this.id = "Coerce"; - this.arg = arg; -} -Coerce.prototype.show = function (cat) { - var recStr = new Array(); - recStr.push(cat, " -> _ [", this.args, "]"); - return recStr.join(""); -}; - -// Const Object Definition - -function Const(lit, toks) { - this.id = "Const"; - this.lit = lit; - this.toks = toks; -} -Const.prototype.show = function (cat) { - var recStr = new Array(); - recStr.push(cat, " -> ", lit.print()); - return recStr.join(""); -}; -Const.prototype.isEqual = function (obj) { - if (this.id != obj.id || this.lit.isEqual(obj.lit) || this.toks.length != obj.toks.length) - return false; - - for (var i in this.toks) { - if (this.toks[i] != obj.toks[i]) - return false; - } - - return true; -}; - -function CncFun(name,lins) { - this.name = name; - this.lins = lins; -} - -// Definition of symbols present in linearization records - -// Object to represent argument projections in grammar rules -function SymCat(i, label) { - this.id = "Arg"; - this.i = i; - this.label = label; -} -SymCat.prototype.getId = function () { return this.id; }; -SymCat.prototype.getArgNum = function () { return this.i }; -SymCat.prototype.show = function () { - var argStr = new Array(); - argStr.push(this.i, this.label); - return argStr.join("."); -}; - -// Object to represent terminals in grammar rules -function SymKS() { - this.id = "KS"; - this.tokens = arguments; -} -SymKS.prototype.getId = function () { return this.id; }; -SymKS.prototype.show = function () { - var terminalStr = new Array(); - terminalStr.push('"', this.tokens, '"'); - return terminalStr.join(""); -}; - -// Object to represent pre in grammar rules -function SymKP(tokens,alts) { - this.id = "KP"; - this.tokens = tokens; - this.alts = alts; -} -SymKP.prototype.getId = function () { return this.id; }; -SymKP.prototype.show = function () { - var terminalStr = new Array(); - terminalStr.push('"', this.tokens, '"'); - return terminalStr.join(""); -}; - -function Alt(tokens, prefixes) { - this.tokens = tokens; - this.prefixes = prefixes; -} - -// Object to represent pre in grammar rules -function SymLit(i,label) { - this.id = "Lit"; - this.i = i; - this.label = label; -} -SymLit.prototype.getId = function () { return this.id; }; -SymLit.prototype.show = function () { - var argStr = new Array(); - argStr.push(this.i, this.label); - return argStr.join("."); -}; - -// Parsing - -function Trie() { - this.value = null; - this.items = new Object(); -} -Trie.prototype.insertChain = function(keys,obj) { - var node = this; - for (var i in keys) { - var nnode = node.items[keys[i]]; - if (nnode == null) { - nnode = new Trie(); - node.items[keys[i]] = nnode; - } - node = nnode; - } - node.value = obj; -} -Trie.prototype.insertChain1 = function(keys,obj) { - var node = this; - for (var i in keys) { - var nnode = node.items[keys[i]]; - if (nnode == null) { - nnode = new Trie(); - node.items[keys[i]] = nnode; - } - node = nnode; - } - if (node.value == null) - node.value = [obj]; - else - node.value.push(obj); -} -Trie.prototype.lookup = function(key,obj) { - return this.items[key]; -} -Trie.prototype.isEmpty = function() { - if (this.value != null) - return false; - - for (var i in this.items) { - return false; - } - - return true; -} - -function ParseState(concrete, startCat) { - this.concrete = concrete; - this.startCat = startCat; - this.items = new Trie(); - this.chart = new Chart(concrete); - - var items = new Array(); - - var fids = concrete.startCats[startCat]; - if (fids != null) { - var fid; - for (fid = fids.s; fid <= fids.e; fid++) { - var exProds = this.chart.expandForest(fid); - for (var j in exProds) { - var rule = exProds[j]; - var fun = rule.fun; - for (var lbl in fun.lins) { - items.push(new ActiveItem(0,0,rule.fun,fun.lins[lbl],rule.args,fid,lbl)); - } - } - } - } - - this.items.insertChain(new Array(), items); -} -ParseState.prototype.next = function (token) { - var acc = this.items.lookup(token); - if (acc == null) - acc = new Trie(); - - this.process( this.items.value - , function (fid) { - switch (fid) { - case -1: return new Const(new Fun('"'+token+'"'), [token]); // String - case -2: var x = parseInt(token,10); - if (token == "0" || (x != 0 && !isNaN(x))) // Integer - return new Const(new Fun(token), [token]); - else - return null; - case -3: var x = parseFloat(token); - if (token == "0" || token == "0.0" || (x != 0 && !isNaN(x))) // Float - return new Const(new Fun(token), [token]); - else - return null; - } - - return null; - } - , function (tokens, item) { - if (tokens[0] == token) { - var tokens1 = new Array(); - var i; - for (i = 1; i < tokens.length; i++) { - tokens1[i-1] = tokens[i]; - } - acc.insertChain1(tokens1, item); - } - } - ); - - this.items = acc; - this.chart.shift(); - - return !this.items.isEmpty(); -} -/** - * For a ParseState and a partial input, return all possible completions - * Based closely on ParseState.next() - * currentToken could be empty or a partial string - */ -ParseState.prototype.complete = function (currentToken) { - - // Initialise accumulator for suggestions - var acc = this.items.lookup(currentToken); - if (acc == null) - acc = new Trie(); - - this.process( - // Items - this.items.value, - - // Deal with literal categories - function (fid) { - // Always return null, as suggested by Krasimir - return null; - }, - - // Takes an array of tokens and populates the accumulator - function (tokens, item) { - if (currentToken == "" || tokens[0].indexOf(currentToken) == 0) { //if begins with... - var tokens1 = new Array(); - for (var i = 1; i < tokens.length; i++) { - tokens1[i-1] = tokens[i]; - } - acc.insertChain1(tokens1, item); - } - } - ); - - // Return matches - return acc; -} -ParseState.prototype.extractTrees = function() { - this.process( this.items.value - , function (fid) { - return null; - } - , function (tokens, item) { - } - ); - - - var totalFIds = this.concrete.totalFIds; - var forest = this.chart.forest; - - function go(fid) { - if (fid < totalFIds) { - return [new Fun("?")]; - } else { - var trees = new Array(); - - var rules = forest[fid]; - for (var j in rules) { - var rule = rules[j]; - - if (rule.id == "Const") { - trees.push(rule.lit); - } else { - var arg_ix = new Array(); - var arg_ts = new Array(); - for (var k in rule.args) { - arg_ix[k] = 0; - arg_ts[k] = go(rule.args[k].fid); - } - - while (true) { - var t = new Fun(rule.fun.name); - for (var k in arg_ts) { - t.setArg(k,arg_ts[k][arg_ix[k]]); - } - trees.push(t); - - var i = 0; - while (i < arg_ts.length) { - arg_ix[i]++; - if (arg_ix[i] < arg_ts[i].length) - break; - - arg_ix[i] = 0; - i++; - } - - if (i >= arg_ts.length) - break; - } - } - } - - return trees; - } - } - - - var trees = new Array(); - var fids = this.concrete.startCats[this.startCat]; - if (fids != null) { - var fid0; - for (fid0 = fids.s; fid0 <= fids.e; fid0++) { - - var labels = new Object(); - var rules = this.chart.expandForest(fid0); - for (var i in rules) { - for (var lbl in rules[i].fun.lins) { - labels[lbl] = true; - } - } - - for (var lbl in labels) { - var fid = this.chart.lookupPC(fid0,lbl,0); - var arg_ts = go(fid); - for (var i in arg_ts) { - var isMember = false; - for (var j in trees) { - if (arg_ts[i].isEqual(trees[j])) { - isMember = true; - break; - } - } - - if (!isMember) - trees.push(arg_ts[i]); - } - } - } - } - - return trees; -} -ParseState.prototype.process = function (agenda,literalCallback,tokenCallback) { - if (agenda != null) { - while (agenda.length > 0) { - var item = agenda.pop(); - var lin = item.seq; - - if (item.dot < lin.length) { - var sym = lin[item.dot]; - switch (sym.id) { - case "Arg": var fid = item.args[sym.i].fid; - var label = sym.label; - - var items = this.chart.lookupAC(fid,label); - if (items == null) { - var rules = this.chart.expandForest(fid); - for (var j in rules) { - var rule = rules[j]; - agenda.push(new ActiveItem(this.chart.offset,0,rule.fun,rule.fun.lins[label],rule.args,fid,label)); - } - this.chart.insertAC(fid,label,[item]); - } else { - var isMember = false; - for (var j in items) { - if (items[j].isEqual(item)) { - isMember = true; - break; - } - } - - if (!isMember) { - items.push(item); - - var fid2 = this.chart.lookupPC(fid,label,this.chart.offset); - if (fid2 != null) { - agenda.push(item.shiftOverArg(sym.i,fid2)); - } - } - } - break; - case "KS": tokenCallback(sym.tokens, item.shiftOverTokn()); - break; - case "KP": var pitem = item.shiftOverTokn(); - tokenCallback(sym.tokens, pitem); - for (var i in sym.alts) { - var alt = sym.alts[i]; - tokenCallback(alt.tokens, pitem); - } - break; - case "Lit": var fid = item.args[sym.i].fid; - var rules = this.chart.forest[fid]; - if (rules != null) { - tokenCallback(rules[0].toks, item.shiftOverTokn()); - } else { - var rule = literalCallback(fid); - if (rule != null) { - fid = this.chart.nextId++; - this.chart.forest[fid] = [rule]; - tokenCallback(rule.toks,item.shiftOverArg(sym.i,fid)); - } - } - break; - } - } else { - var fid = this.chart.lookupPC(item.fid,item.lbl,item.offset); - if (fid == null) { - fid = this.chart.nextId++; - - var items = this.chart.lookupACo(item.offset,item.fid,item.lbl); - if (items != null) { - for (var j in items) { - var pitem = items[j]; - var i = pitem.seq[pitem.dot].i; - agenda.push(pitem.shiftOverArg(i,fid)); - } - } - - this.chart.insertPC(item.fid,item.lbl,item.offset,fid); - this.chart.forest[fid] = [new Apply(item.fun,item.args)]; - } else { - var labels = this.chart.labelsAC(fid); - if (labels != null) { - for (var lbl in labels) { - agenda.push(new ActiveItem(this.chart.offset,0,item.fun,item.fun.lins[lbl],item.args,fid,lbl)); - } - } - - var rules = this.chart.forest[fid]; - var rule = new Apply(item.fun,item.args); - - var isMember = false; - for (var j in rules) { - if (rules[j].isEqual(rule)) - isMember = true; - } - - if (!isMember) - rules.push(rule); - } - } - } - } -} - -function Chart(concrete) { - this.active = new Object(); - this.actives = new Array(); - this.passive = new Object(); - this.forest = new Object(); - this.nextId = concrete.totalFIds; - this.offset = 0; - - for (var fid in concrete.pproductions) { - this.forest[fid] = concrete.pproductions[fid]; - } -} -Chart.prototype.lookupAC = function (fid,label) { - var tmp = this.active[fid]; - if (tmp == null) - return null; - return tmp[label]; -} -Chart.prototype.lookupACo = function (offset,fid,label) { - var tmp; - - if (offset == this.offset) - tmp = this.active[fid]; - else - tmp = this.actives[offset][fid]; - - if (tmp == null) - return null; - - return tmp[label]; -} -Chart.prototype.labelsAC = function (fid) { - return this.active[fid]; -} -Chart.prototype.insertAC = function (fid,label,items) { - var tmp = this.active[fid]; - if (tmp == null) { - tmp = new Object(); - this.active[fid] = tmp; - } - tmp[label] = items; -} -Chart.prototype.lookupPC = function (fid,label,offset) { - var key = fid+"."+label+"-"+offset; - return this.passive[key]; -} -Chart.prototype.insertPC = function (fid1,label,offset,fid2) { - var key = fid1+"."+label+"-"+offset; - this.passive[key] = fid2; -} -Chart.prototype.shift = function () { - this.actives.push(this.active); - this.active = new Object(); - - this.passive = new Object(); - - this.offset++; -} -Chart.prototype.expandForest = function (fid) { - var rules = new Array(); - var forest = this.forest; - - var go = function (rules0) { - for (var i in rules0) { - var rule = rules0[i]; - switch (rule.id) { - case "Apply": rules.push(rule); break; - case "Coerce": go(forest[rule.arg]); break; - } - } - } - - go(this.forest[fid]); - return rules; -} - -function ActiveItem(offset, dot, fun, seq, args, fid, lbl) { - this.offset= offset; - this.dot = dot; - this.fun = fun; - this.seq = seq; - this.args = args; - this.fid = fid; - this.lbl = lbl; -} -ActiveItem.prototype.isEqual = function (obj) { - return (this.offset== obj.offset && - this.dot == obj.dot && - this.fun == obj.fun && - this.seq == obj.seq && - this.args == obj.args && - this.fid == obj.fid && - this.lbl == obj.lbl); -} -ActiveItem.prototype.shiftOverArg = function (i,fid) { - var nargs = new Array(); - for (var k in this.args) { - nargs[k] = this.args[k]; - } - nargs[i] = new PArg(fid); - return new ActiveItem(this.offset,this.dot+1,this.fun,this.seq,nargs,this.fid,this.lbl); -} -ActiveItem.prototype.shiftOverTokn = function () { - return new ActiveItem(this.offset,this.dot+1,this.fun,this.seq,this.args,this.fid,this.lbl); -} diff --git a/src/runtime/javascript/grammar.js b/src/runtime/javascript/grammar.js deleted file mode 100644 index c6b2bb9891..0000000000 --- a/src/runtime/javascript/grammar.js +++ /dev/null @@ -1 +0,0 @@ -var Foods = new GFGrammar(new GFAbstract("Phrase",{Boring: new Type([], "Quality"), Cheese: new Type([], "Kind"), Delicious: new Type([], "Quality"), Expensive: new Type([], "Quality"), Fish: new Type([], "Kind"), Fresh: new Type([], "Quality"), Is: new Type(["Item", "Quality"], "Phrase"), Italian: new Type([], "Quality"), Pizza: new Type([], "Kind"), QKind: new Type(["Quality", "Kind"], "Kind"), That: new Type(["Kind"], "Item"), These: new Type(["Kind"], "Item"), This: new Type(["Kind"], "Item"), Those: new Type(["Kind"], "Item"), Very: new Type(["Quality"], "Quality"), Warm: new Type([], "Quality"), Wine: new Type([], "Kind")}),{FoodsEng: new GFConcrete({},{0:[new Apply(19,[new PArg(2)]), new Apply(21,[new PArg(2)])], 1:[new Apply(20,[new PArg(2)]), new Apply(22,[new PArg(2)])], 2:[new Apply(9,[]), new Apply(12,[]), new Apply(17,[]), new Apply(18,[new PArg(4), new PArg(2)]), new Apply(25,[])], 3:[new Apply(14,[new PArg(0), new PArg(4)]), new Apply(15,[new PArg(1), new PArg(4)])], 4:[new Apply(8,[]), new Apply(10,[]), new Apply(11,[]), new Apply(13,[]), new Apply(16,[]), new Apply(23,[new PArg(4)]), new Apply(24,[])]},[new CncFun("'lindef Item'",[5]), new CncFun("'lindef Item'",[0]), new CncFun("'lindef Kind'",[5, 5]), new CncFun("'lindef Kind'",[0]), new CncFun("'lindef Phrase'",[5]), new CncFun("'lindef Phrase'",[0]), new CncFun("'lindef Quality'",[5]), new CncFun("'lindef Quality'",[0]), new CncFun("Boring",[7]), new CncFun("Cheese",[8, 9]), new CncFun("Delicious",[10]), new CncFun("Expensive",[11]), new CncFun("Fish",[12, 12]), new CncFun("Fresh",[13]), new CncFun("Is",[4]), new CncFun("Is",[3]), new CncFun("Italian",[6]), new CncFun("Pizza",[14, 15]), new CncFun("QKind",[1, 2]), new CncFun("That",[16]), new CncFun("These",[17]), new CncFun("This",[18]), new CncFun("Those",[19]), new CncFun("Very",[20]), new CncFun("Warm",[21]), new CncFun("Wine",[22, 23])],[[new SymCat(0, 0)],[new SymCat(0, 0), new SymCat(1, 0)],[new SymCat(0, 0), new SymCat(1, 1)],[new SymCat(0, 0), new SymKS("are"), new SymCat(1, 0)],[new SymCat(0, 0), new SymKS("is"), new SymCat(1, 0)],[new SymLit(0, 0)],[new SymKS("Italian")],[new SymKS("boring")],[new SymKS("cheese")],[new SymKS("cheeses")],[new SymKS("delicious")],[new SymKS("expensive")],[new SymKS("fish")],[new SymKS("fresh")],[new SymKS("pizza")],[new SymKS("pizzas")],[new SymKS("that"), new SymCat(0, 0)],[new SymKS("these"), new SymCat(0, 1)],[new SymKS("this"), new SymCat(0, 0)],[new SymKS("those"), new SymCat(0, 1)],[new SymKS("very"), new SymCat(0, 0)],[new SymKS("warm")],[new SymKS("wine")],[new SymKS("wines")]],{Float:{s: -3, e: -3}, Int:{s: -2, e: -2}, Item:{s: 0, e: 1}, Kind:{s: 2, e: 2}, Phrase:{s: 3, e: 3}, Quality:{s: 4, e: 4}, String:{s: -1, e: -1}}, 5), FoodsIta: new GFConcrete({},{0:[new Apply(22,[new PArg(4)]), new Apply(26,[new PArg(4)])], 1:[new Apply(23,[new PArg(5)]), new Apply(27,[new PArg(5)])], 2:[new Apply(24,[new PArg(4)]), new Apply(28,[new PArg(4)])], 3:[new Apply(25,[new PArg(5)]), new Apply(29,[new PArg(5)])], 4:[new Apply(9,[]), new Apply(12,[]), new Apply(20,[new PArg(7), new PArg(4)]), new Apply(32,[])], 5:[new Apply(19,[]), new Apply(21,[new PArg(7), new PArg(5)])], 6:[new Apply(14,[new PArg(0), new PArg(7)]), new Apply(15,[new PArg(1), new PArg(7)]), new Apply(16,[new PArg(2), new PArg(7)]), new Apply(17,[new PArg(3), new PArg(7)])], 7:[new Apply(8,[]), new Apply(10,[]), new Apply(11,[]), new Apply(13,[]), new Apply(18,[]), new Apply(30,[new PArg(7)]), new Apply(31,[])]},[new CncFun("'lindef Item'",[9]), new CncFun("'lindef Item'",[0]), new CncFun("'lindef Kind'",[9, 9]), new CncFun("'lindef Kind'",[0]), new CncFun("'lindef Phrase'",[9]), new CncFun("'lindef Phrase'",[0]), new CncFun("'lindef Quality'",[9, 9, 9, 9]), new CncFun("'lindef Quality'",[0]), new CncFun("Boring",[39, 38, 36, 37]), new CncFun("Cheese",[23, 22]), new CncFun("Delicious",[21, 20, 18, 19]), new CncFun("Expensive",[17, 16, 14, 15]), new CncFun("Fish",[40, 41]), new CncFun("Fresh",[27, 26, 24, 25]), new CncFun("Is",[3]), new CncFun("Is",[4]), new CncFun("Is",[1]), new CncFun("Is",[2]), new CncFun("Italian",[31, 30, 28, 29]), new CncFun("Pizza",[42, 43]), new CncFun("QKind",[5, 7]), new CncFun("QKind",[6, 8]), new CncFun("That",[45]), new CncFun("That",[46]), new CncFun("These",[50]), new CncFun("These",[49]), new CncFun("This",[51]), new CncFun("This",[48]), new CncFun("Those",[44]), new CncFun("Those",[47]), new CncFun("Very",[32, 33, 34, 35]), new CncFun("Warm",[13, 12, 10, 11]), new CncFun("Wine",[53, 52])],[[new SymCat(0, 0)],[new SymCat(0, 0), new SymKS("sono"), new SymCat(1, 1)],[new SymCat(0, 0), new SymKS("sono"), new SymCat(1, 3)],[new SymCat(0, 0), new SymKS("è"), new SymCat(1, 0)],[new SymCat(0, 0), new SymKS("è"), new SymCat(1, 2)],[new SymCat(1, 0), new SymCat(0, 0)],[new SymCat(1, 0), new SymCat(0, 2)],[new SymCat(1, 1), new SymCat(0, 1)],[new SymCat(1, 1), new SymCat(0, 3)],[new SymLit(0, 0)],[new SymKS("calda")],[new SymKS("calde")],[new SymKS("caldi")],[new SymKS("caldo")],[new SymKS("cara")],[new SymKS("care")],[new SymKS("cari")],[new SymKS("caro")],[new SymKS("deliziosa")],[new SymKS("deliziose")],[new SymKS("deliziosi")],[new SymKS("delizioso")],[new SymKS("formaggi")],[new SymKS("formaggio")],[new SymKS("fresca")],[new SymKS("fresche")],[new SymKS("freschi")],[new SymKS("fresco")],[new SymKS("italiana")],[new SymKS("italiane")],[new SymKS("italiani")],[new SymKS("italiano")],[new SymKS("molto"), new SymCat(0, 0)],[new SymKS("molto"), new SymCat(0, 1)],[new SymKS("molto"), new SymCat(0, 2)],[new SymKS("molto"), new SymCat(0, 3)],[new SymKS("noiosa")],[new SymKS("noiose")],[new SymKS("noiosi")],[new SymKS("noioso")],[new SymKS("pesce")],[new SymKS("pesci")],[new SymKS("pizza")],[new SymKS("pizze")],[new SymKS("quei"), new SymCat(0, 1)],[new SymKS("quel"), new SymCat(0, 0)],[new SymKS("quella"), new SymCat(0, 0)],[new SymKS("quelle"), new SymCat(0, 1)],[new SymKS("questa"), new SymCat(0, 0)],[new SymKS("queste"), new SymCat(0, 1)],[new SymKS("questi"), new SymCat(0, 1)],[new SymKS("questo"), new SymCat(0, 0)],[new SymKS("vini")],[new SymKS("vino")]],{Float:{s: -3, e: -3}, Int:{s: -2, e: -2}, Item:{s: 0, e: 3}, Kind:{s: 4, e: 5}, Phrase:{s: 6, e: 6}, Quality:{s: 7, e: 7}, String:{s: -1, e: -1}}, 8)}); diff --git a/src/runtime/javascript/jspgf.js b/src/runtime/javascript/jspgf.js new file mode 100644 index 0000000000..5136b2398a --- /dev/null +++ b/src/runtime/javascript/jspgf.js @@ -0,0 +1,543 @@ +/** + * This module is the high-level JavaScript wrapper around the WASM-compiled version. + */ + +async function mkAPI() { + + const sizeof_GuMapItor = 4; + const offsetof_GuMapItor_fn = 0; + + var asm = null; + var wasmTable = null; + var freeTableIndexes = []; + + function setErrNo(value) { + HEAP32[asm.__errno_location() >> 2] = value; + return value; + } + + function abortOnCannotGrowMemory(requestedSize) { + abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value ' + HEAP8.length + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 '); + } + + function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + abortOnCannotGrowMemory(requestedSize); + } + + var tempRet0 = 0; + var urlData = {}; + var fdData = {}; + var fdMax = 0; + var asmLibraryArg = { + "__syscall_fcntl64": + function (fd, cmd, varargs) { + setErrNo(134); + return -1; + }, + + "__syscall_ioctl": + function (fd, op, varargs) { + setErrNo(134); + return -1; + }, + + "__syscall_open": + function (pathPtr, flags, varargs) { + const path = UTF8ToString(pathPtr); + const data = urlData[path]; + if (data == null) { + setErrNo(129); + return -1; + } + fdMax++; + fdData[fdMax] = {data: data, pos: 0}; + delete urlData[path]; + return fdMax; + }, + + "_munmap_js": + function (addr, len, prot, flags, fd, offset) { + setErrNo(134); + return -1; + }, + + "abort": + function () { + console.log('native code called abort()'); + }, + + "emscripten_memcpy_big": + function (dest, src, num) { + HEAPU8.copyWithin(dest, src, src + num); + }, + + "emscripten_resize_heap": + function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + abortOnCannotGrowMemory(requestedSize); + }, + + "fd_close": + function (fd) { + delete fdData[fd]; + return 0; + }, + + "fd_read": + function (fd, iov, iovcnt, pnum) { + const info = fdData[fd]; + if (info == null) { + setErrNo(121); + return -1; + } + + let num = 0; + for (let i = 0; i < iovcnt; i++) { + const ptr = HEAP32[(((iov)+(i*8))>>2)]; + const len = HEAP32[(((iov)+(i*8 + 4))>>2)]; + + let cnt = 0; + while (cnt < len && info.pos < info.data.length) { + HEAP8[ptr+cnt] = info.data[info.pos]; + info.pos++ + cnt++; + } + + num += cnt; + if (cnt < len) break; // nothing more to read + } + + HEAP32[((pnum)>>2)] = num; + return 0; + }, + + "fd_seek": + function (fd, offset_low, offset_high, whence, newOffset) { + setErrNo(134); + return -1; + }, + + "fd_write": + function _fd_write(fd, iov, iovcnt, pnum) { + setErrNo(134); + return -1; + }, + + "setTempRet0": + function (value) { + tempRet0 = value; + }, + + "__assert_fail": + function (condition, filename, line, func) { + abort('Assertion failed: ' + UTF8ToString(condition) + ', at: ' + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); + } + }; + + // Wraps a JS function as a wasm function with a given signature. + function convertJsFunctionToWasm(func, sig) { + + // If the type reflection proposal is available, use the new + // "WebAssembly.Function" constructor. + // Otherwise, construct a minimal wasm module importing the JS function and + // re-exporting it. + if (typeof WebAssembly.Function == "function") { + var typeNames = { + 'i': 'i32', + 'j': 'i64', + 'f': 'f32', + 'd': 'f64' + }; + var type = { + parameters: [], + results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] + }; + for (var i = 1; i < sig.length; ++i) { + type.parameters.push(typeNames[sig[i]]); + } + return new WebAssembly.Function(type, func); + } + + // The module is static, with the exception of the type section, which is + // generated based on the signature passed in. + var typeSection = [ + 0x01, // id: section, + 0x00, // length: 0 (placeholder) + 0x01, // count: 1 + 0x60, // form: func + ]; + var sigRet = sig.slice(0, 1); + var sigParam = sig.slice(1); + var typeCodes = { + 'i': 0x7f, // i32 + 'j': 0x7e, // i64 + 'f': 0x7d, // f32 + 'd': 0x7c, // f64 + }; + + // Parameters, length + signatures + typeSection.push(sigParam.length); + for (var i = 0; i < sigParam.length; ++i) { + typeSection.push(typeCodes[sigParam[i]]); + } + + // Return values, length + signatures + // With no multi-return in MVP, either 0 (void) or 1 (anything else) + if (sigRet == 'v') { + typeSection.push(0x00); + } else { + typeSection = typeSection.concat([0x01, typeCodes[sigRet]]); + } + + // Write the overall length of the type section back into the section header + // (excepting the 2 bytes for the section id and length) + typeSection[1] = typeSection.length - 2; + + // Rest of the module is static + var bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") + 0x01, 0x00, 0x00, 0x00, // version: 1 + ].concat(typeSection, [ + 0x02, 0x07, // import section + // (import "e" "f" (func 0 (type 0))) + 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, + 0x07, 0x05, // export section + // (export "f" (func 0 (type 0))) + 0x01, 0x01, 0x66, 0x00, 0x00, + ])); + + // We can compile this wasm module synchronously because it is very small. + // This accepts an import (at "e.f"), that it reroutes to an export (at "f") + var module = new WebAssembly.Module(bytes); + var instance = new WebAssembly.Instance(module, { + 'e': {'f': func} + }); + var wrappedFunc = instance.exports['f']; + return wrappedFunc; + } + + function addFunction(func, sig) { + func = convertJsFunctionToWasm(func, sig); + + let index; + + // Reuse a free index if there is one, otherwise grow. + if (freeTableIndexes.length) { + index = freeTableIndexes.pop(); + } else { + // Grow the table + try { + wasmTable.grow(1); + } catch (err) { + if (!(err instanceof RangeError)) { + throw err; + } + throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; + } + index = wasmTable.length - 1; + } + + wasmTable.set(index, func); + return index; + } + + function removeFunction(index) { + freeTableIndexes.push(index); + } + + const response = await fetch("pgf.wasm", { credentials: 'same-origin' }); + + const info = { + 'env': asmLibraryArg, + 'wasi_snapshot_preview1': asmLibraryArg, + }; + + // Suppress closure warning here since the upstream definition for + // instantiateStreaming only allows Promise rather than + // an actual Response. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed. + /** @suppress {checkTypes} */ + const result = await WebAssembly.instantiateStreaming(response, info); + + asm = result["instance"].exports; + wasmTable = asm['__indirect_function_table']; + const buf = asm['memory'].buffer; + const HEAP8 = new Int8Array(buf); + const HEAP16 = new Int16Array(buf); + const HEAP32 = new Int32Array(buf); + const HEAPU8 = new Uint8Array(buf); + const HEAPU16 = new Uint16Array(buf); + const HEAPU32 = new Uint32Array(buf); + const HEAPF32 = new Float32Array(buf); + const HEAPF64 = new Float64Array(buf); + + // Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte. + function lengthBytesUTF8(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); + if (u <= 0x7F) ++len; + else if (u <= 0x7FF) len += 2; + else if (u <= 0xFFFF) len += 3; + else len += 4; + } + return len; + } + + function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) { + var u1 = str.charCodeAt(++i); + u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); + } + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + if (u > 0x10FFFF) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } + } + + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; + } + + function allocateUTF8(pool,str) { + var size = lengthBytesUTF8(str) + 1; + var ptr = asm.gu_malloc(pool,size); + if (ptr) stringToUTF8Array(str, HEAP8, ptr, size); + return ptr; + } + + const UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; + + /** + * @param {number} idx + * @param {number=} maxBytesToRead + * @return {string} + */ + function UTF8ArrayToString(heap, idx, maxBytesToRead) { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. + // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. + // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity) + while (heap[endPtr] && !(endPtr >= endIdx)) ++endPtr; + + if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) { + return UTF8Decoder.decode(heap.subarray(idx, endPtr)); + } else { + var str = ''; + // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that + while (idx < endPtr) { + // For UTF8 byte structure, see: + // http://en.wikipedia.org/wiki/UTF-8#Description + // https://www.ietf.org/rfc/rfc2279.txt + // https://tools.ietf.org/html/rfc3629 + var u0 = heap[idx++]; + if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } + var u1 = heap[idx++] & 63; + if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } + var u2 = heap[idx++] & 63; + if ((u0 & 0xF0) == 0xE0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!'); + u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63); + } + + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } + } + } + return str; + } + + function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; + } + + const GuErrnoStrPtr = asm.malloc(8); + stringToUTF8Array("GuErrno", HEAP8, GuErrnoStrPtr, 8); + + const PgfExnStrPtr = asm.malloc(8); + stringToUTF8Array("PgfExn", HEAP8, PgfExnStrPtr, 8); + + function pgfError(err) { + if (asm.gu_exn_caught_(err, GuErrnoStrPtr)) { + errDataPtr = asm.gu_exn_caught_data(err); + return new Error("errno="+HEAP32[errDataPtr >> 2]); + } else if (asm.gu_exn_caught_(err, PgfExnStrPtr)) { + msgPtr = asm.gu_exn_caught_data(err); + return new Error(UTF8ToString(msgPtr)); + } + return new Error(); + } + + const registry = new FinalizationRegistry((pool) => { + asm.gu_pool_free(pool); + }); + + function PGF(pgfPtr,name,pool) { + this.pgfPtr = pgfPtr; + this.abstractName = name; + this.pool = pool; + this.languages = {}; + registry.register(this,pool); + } + + function Concr(pgf,concrPtr,name) { + this.pgf = pgf; + this.name = name; + this.concrPtr = concrPtr; + } + Concr.prototype.linearize = function(expr) { + const tmp_pool = asm.gu_new_pool(); + const err = asm.gu_new_exn(tmp_pool); + const sb = asm.gu_new_string_buf(tmp_pool); + const out = asm.gu_string_buf_out(sb); + + asm.pgf_linearize(this.concrPtr, expr.exprPtr, out, err); + if (asm.gu_exn_is_raised(err)) { + const e = pgfError(err); + asm.gu_pool_free(tmp_pool); + throw e; + } + + const strPtr = asm.gu_string_buf_data(sb); + const len = asm.gu_string_buf_length(sb); + const str = UTF8ToString(strPtr,len); + asm.gu_pool_free(tmp_pool); + + return str + } + + async function readPGF(pgfURL) { + const response = await fetch(pgfURL); + urlData[pgfURL] = new Int8Array(await response.arrayBuffer()); + + const pool = asm.gu_new_pool(); + + const tmp_pool = asm.gu_new_pool(); + const err = asm.gu_new_exn(tmp_pool); + const strPtr = allocateUTF8(tmp_pool,pgfURL); + const pgfPtr = asm.pgf_read(strPtr,pool,err); + if (asm.gu_exn_is_raised(err)) { + const e = pgfError(err); + asm.gu_pool_free(tmp_pool); + throw e; + } + + const namePtr = asm.pgf_abstract_name(pgfPtr); + const abstractName = UTF8ToString(namePtr); + + const pgf = new PGF(pgfPtr,abstractName,pool); + + const itor = asm.gu_malloc(tmp_pool,sizeof_GuMapItor); + const fn = + addFunction( + (itor,namePtr,concrPtrPtr,err) => { + const name = UTF8ToString(namePtr); + const concrPtr = HEAP32[concrPtrPtr >> 2]; + pgf.languages[name] = new Concr(pgf,concrPtr,name); + }, + "viiii" + ); + HEAP32[(itor+offsetof_GuMapItor_fn) >> 2] = fn; + asm.pgf_iter_languages(pgfPtr,itor,err); + removeFunction(fn); + + asm.gu_pool_free(tmp_pool); + return pgf; + } + + function Expr(exprPtr,pool) { + this.exprPtr = exprPtr; + this.pool = pool; + registry.register(this,pool); + } + Expr.prototype.toString = function() { + const tmp_pool = asm.gu_new_pool(); + + const sb = asm.gu_new_string_buf(tmp_pool); + const out = asm.gu_string_buf_out(sb); + const err = asm.gu_new_exn(tmp_pool); + asm.pgf_print_expr(this.exprPtr, 0, 0, out, err); + if (asm.gu_exn_is_raised(err)) { + const e = pgfError(err); + asm.gu_pool_free(tmp_pool); + throw e; + } + + const strPtr = asm.gu_string_buf_data(sb); + const len = asm.gu_string_buf_length(sb); + const str = UTF8ToString(strPtr,len); + asm.gu_pool_free(tmp_pool); + + return str; + }; + Expr.prototype.arity = function(expr) { + return asm.pgf_expr_arity(this.expr); + } + + function readExpr(exprStr) { + const tmp_pool = asm.gu_new_pool(); + + const strPtr = allocateUTF8(tmp_pool,exprStr); + const in_ = asm.gu_data_in(strPtr, exprStr.length, tmp_pool); + const err = asm.gu_new_exn(tmp_pool); + const pool = asm.gu_new_pool(); + const expr = asm.pgf_read_expr(in_, pool, tmp_pool, err); + asm.gu_pool_free(tmp_pool); + + if (asm.gu_exn_is_raised(err)) { + throw pgfError(err); + } + if (expr == 0) { + throw new Error('Expression cannot be parsed'); + } + + return new Expr(expr,pool); + } + + return { readPGF, readExpr }; +} + +// This allows us to use both from Node and in browser +if (typeof module != 'undefined') { + module.exports = mkAPI; +} diff --git a/src/runtime/javascript/minus.png b/src/runtime/javascript/minus.png deleted file mode 100644 index 84cc2a9ba9..0000000000 Binary files a/src/runtime/javascript/minus.png and /dev/null differ diff --git a/src/runtime/javascript/plus.png b/src/runtime/javascript/plus.png deleted file mode 100644 index 4d2e8ee830..0000000000 Binary files a/src/runtime/javascript/plus.png and /dev/null differ diff --git a/src/runtime/javascript/style.css b/src/runtime/javascript/style.css deleted file mode 100644 index 312983e5ee..0000000000 --- a/src/runtime/javascript/style.css +++ /dev/null @@ -1,252 +0,0 @@ -body { - font-family:arial,helvetica,sans-serif; - font-size:12px; - background-color: white; -} - -#wrapper { - width:740px; - height:520px; - margin:auto 50px; - border:1px solid gray; - padding:10px; - -} - -#absFrame { - width:250px; - height:250px; - padding:10px; - border:1px solid gray; - float:left; - white-space: nowrap; -} - -#conFrame { - width:436px; - height:250px; - margin-left:10px; - padding:10px; - border:1px solid gray; - float:left; - white-space: normal; - overflow:auto; -} - -#actFrame { - width:250px; - height:170px; - margin-top:10px; - padding:10px; - border:1px solid gray; - float:left; - overflow:auto; -} - -#refFrame { - width:436px; - height:170px; - margin-left:10px; - margin-top:10px; - padding:10px; - border:1px solid gray; - float:left; - overflow:auto; -} - -#messageFrame { - width:506px; - height:15px; - margin-top:10px; - margin-right:10px; - padding:10px; - border:1px solid gray; - float:left; - overflow:hidden; -} - -#clipboardFrame { - width:180px; - height:15px; - margin-top:10px; - padding:10px; - border:1px solid gray; - float:left; - overflow:auto; -} - -#tree { - left: -10px; - top: -10px; - margin: 0px; - padding: 10px; - overflow: auto; -} - -ul { - position: relative; - list-style: none; - margin-left: 20px; - padding: 0px; -} - -li { - position: relative; -} - -img.tree-menu { - margin-right: 5px; -} - -a.tree:link, a.tree:visited, a.tree:active { - color: black; - background-color: white; - text-decoration: none; - margin-right:10px; -} - -a.tree:hover { - color: blue; - background-color: white; - text-decoration: underline; - margin-right:10px; -} - -a.treeSelected:link, a.treeSelected:visited, a.treeSelected:active { - color: white; - background-color: #3366CC; - text-decoration: none; - margin-right:10px; -} - -a.treeSelected:hover { - color: white; - background-color: #3366CC; - text-decoration: underline; - margin-right:10px; -} - -a.treeGray:link, a.treeGray:visited, a.treeGray:active { - color: silver; - background-color: white; - text-decoration: none; - margin-right:10px; -} - -a.treeGray:hover { - color: silver; - background-color: white; - text-decoration: none; - margin-right:10px; -} - -table.action, table.refinement, table.wrapper, table.tree, table.language { - margin: 0px; - padding: 0px; - border-style: none; - border-collapse: collapse; - border-spacing: 0px; -} - -tr.selected { - color: white; - background-color: #3366CC; -} - -tr.unavailable, tr.closed { - color: silver; - background-color: white; -} - -tr.unavailable:hover { - color: silver; - background-color: #3366CC; -} - -tr.action, tr.refinement, tr.wrapper, tr.tree { - color: black; - background-color: white; -} - -tr.action:hover, tr.refinement:hover, tr.wrapper:hover, tr.tree:hover { - color: white; - background-color: #3366CC; -} - -td.action { - width: 220px; - margin: 0px; - padding: 0px; -} - -td.refinement, td.wrapper, td.tree { - width: 515px; - margin: 0px; - padding: 0px; -} - -td.hotKey { - width: 30px; - margin: 0px; - padding: 0px; - text-align: right; -} - -td.language { - color: black; - background-color: white; - margin: 1px; - padding: 1px; -} - -td.language:hover { - color: blue; - background-color: white; - text-decoration: underline; - margin: 1px; - padding: 1px; -} - -td.selected { - color: white; - background-color: #3366CC; - margin: 1px; - padding: 1px; -} - -td.selected:hover { - color: white; - background-color: #3366CC; - text-decoration: underline; - margin: 1px; - padding: 1px; -} - -p { - margin-bottom: 40px; -} - -span.normal { - color: black; - background-color: white; - text-decoration: none; - padding-left: 2px; - padding-right: 2px; -} - -span.edit { - color: black; - background-color: white; - text-decoration: none; - border:2px inset; - padding-left: 2px; - padding-right: 2px; -} - -span.selected { - color: white; - background-color: #3366CC; - text-decoration: none; - padding-left: 2px; - padding-right: 2px; -} diff --git a/src/runtime/javascript/test-node.js b/src/runtime/javascript/test-node.js new file mode 100644 index 0000000000..92fc82b3fd --- /dev/null +++ b/src/runtime/javascript/test-node.js @@ -0,0 +1,33 @@ +const Module = require('./.libs/pgf.js'); +const JSPGF = require('./jspgf.js')(Module); +const fs = require('fs'); +const path = require('path'); + +Module.onRuntimeInitialized = () => { + + // Read PGF path from args + if (process.argv.length > 2) { + const pgfPathHost = process.argv[2]; + + // Copy file into filesystem + const pgfPathFS = '/tmp/' + path.basename(pgfPathHost); + const rawPgf = fs.readFileSync(pgfPathHost); + Module.FS.writeFile(pgfPathFS, rawPgf); + + // Read PGF + const pgf = JSPGF.readPGF(pgfPathFS); + + // Print its name + console.log(JSPGF.abstractName(pgf)); + } + + // Parse expression + const expr = JSPGF.readExpr("Pred (Another (x f))"); + + // Show it + console.log(JSPGF.showExpr(expr)); + + // Print its arity + console.log('arity', JSPGF.arity(expr)); +} + diff --git a/src/runtime/javascript/test-web.html b/src/runtime/javascript/test-web.html new file mode 100644 index 0000000000..ff65294c4d --- /dev/null +++ b/src/runtime/javascript/test-web.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/runtime/javascript/test-web.js b/src/runtime/javascript/test-web.js new file mode 100644 index 0000000000..6f881f7ef5 --- /dev/null +++ b/src/runtime/javascript/test-web.js @@ -0,0 +1,21 @@ +mkAPI().then((pgf) => { + // Parse expression + const expr = pgf.readExpr("Pred (This Fish) Fresh"); + + // Show it + console.log(expr.toString()); + + // Print its arity + console.log('arity', expr.arity()); + + pgf.readPGF("Foods.pgf").then((gr) => { + // Print the grammar name + console.log(gr.abstractName); + + // Access a language and print the concrete name + console.log(gr.languages["FoodsEng"].name); + + // Linearize an expression + console.log(gr.languages["FoodsEng"].linearize(expr)); + }); +}); diff --git a/src/runtime/javascript/translator.css b/src/runtime/javascript/translator.css deleted file mode 100644 index f7f7719277..0000000000 --- a/src/runtime/javascript/translator.css +++ /dev/null @@ -1,54 +0,0 @@ -body { - color: black; - background-color: white; -} - -dl { - -} - -dt { - margin: 0; - padding: 0; -} - -dl dd { - margin: 0; - padding: 0; -} - -dl.fromLang dt { - display: none; -} - -dl.toLang { - border-width: 1px 0 0 0; - border-style: solid; - border-color: #c0c0c0; -} - -dl.toLang dt { - color: #c0c0c0; - display: block; - float: left; - width: 5em; -} - - -dl.toLang dd { - border-width: 0 0 1px 0; - border-style: solid; - border-color: #c0c0c0; -} - - -ul { - margin: 0; - padding: 0; -} - -li { - list-style-type: none; - margin: 0; - padding: 0; -} \ No newline at end of file diff --git a/src/runtime/javascript/translator.html b/src/runtime/javascript/translator.html deleted file mode 100644 index b2c926550c..0000000000 --- a/src/runtime/javascript/translator.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - Web-based GF Translator - - -
    -

    - -

    -

    - From: - To: - -

    -
    -
    - - diff --git a/src/runtime/javascript/translator.js b/src/runtime/javascript/translator.js deleted file mode 100644 index 31da042904..0000000000 --- a/src/runtime/javascript/translator.js +++ /dev/null @@ -1,51 +0,0 @@ -function formatTranslation (outputs) { - var dl1 = document.createElement("dl"); - dl1.className = "fromLang"; - for (var fromLang in outputs) { - var ul = document.createElement("ul"); - addDefinition(dl1, document.createTextNode(fromLang), ul); - for (var i in outputs[fromLang]) { - var dl2 = document.createElement("dl"); - dl2.className = "toLang"; - for (var toLang in outputs[fromLang][i]) { - addDefinition(dl2, document.createTextNode(toLang), document.createTextNode(outputs[fromLang][i][toLang])); - } - addItem(ul, dl2); - } - } - - return dl1; -} - -/* DOM utilities for specific tags */ - -function addDefinition (dl, t, d) { - var dt = document.createElement("dt"); - dt.appendChild(t); - dl.appendChild(dt); - var dd = document.createElement("dd"); - dd.appendChild(d); - dl.appendChild(dd); -} - -function addItem (ul, i) { - var li = document.createElement("li"); - li.appendChild(i); - ul.appendChild(li); -} - -function addOption (select, value, content) { - var option = document.createElement("option"); - option.value = value; - option.appendChild(document.createTextNode(content)); - select.appendChild(option); -} - -/* General DOM utilities */ - -/* Removes all the children of a node */ -function removeChildren(node) { - while (node.hasChildNodes()) { - node.removeChild(node.firstChild); - } -} diff --git a/src/runtime/typescript/MOVED.md b/src/runtime/typescript/MOVED.md deleted file mode 100644 index 3648aa2260..0000000000 --- a/src/runtime/typescript/MOVED.md +++ /dev/null @@ -1,7 +0,0 @@ -# Project moved - -The GF TypeScript runtime has been moved to the repository: - - -If you are looking for an updated version of the JavaScript runtime, -you should also look there.