move gf.cabal and all compiler dependent files into src/compiler

This commit is contained in:
Krasimir Angelov
2022-06-18 20:42:31 +02:00
parent 96c8218564
commit a8ad145aeb
264 changed files with 71 additions and 71 deletions
+7
View File
@@ -0,0 +1,7 @@
save: save.hs
ghc --make save.hs
install::
@make save
rsync -avz --exclude .DS_Store P *.html *.css *.js *.cgi *.manifest save www.grammaticalframework.org:/usr/local/www/GF/demos/gfse
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+44
View File
@@ -0,0 +1,44 @@
+ Safety question before deleting a grammar
+ Check identifier syntax
+ Allow lincat for deleted cat to be deleted
+ Allow lin for deleted fun to be deleted
+ Apply category alpha conversion in concrete syntax
+ Remove a concrete syntax
+ Apply function alpha conversion in concrete syntax
+ Change lhs of lins when function type is changed
+ Allow languages other than the ones in the given list to be added
+ Export as plain text
+ Allow definitions to be reordered
+ 1. possibility to compile the grammar set, returning a URL to a translator app
+ 2a. possibility to import modules - resource libraries
- 2b. possibility to import modules - user's own auxiliaries
- 3. possibility to upload own modules
+ 4. access to the created files in an on-line shell (making testing possible)
- 5. rule-to-rule type checking and guidance (e.g. with library oper
suggestions)
+ Try grammars in the Translation Quiz
+ Show lincat and lin before params and opers below
+ Create a new concrete syntax by copying an existing one.
- Easy access to compute_concrete from the editor
- Instead of starting with an empty grammar, start a new grammar by copying
an example.
+ Cloning grammars
- Allow grammars to contain a resoure module. Create the resource module by
factoring out common parts of the concrete syntaxes.
- Integrate example-based concrete syntax construction (using Ramona's tool)
- Open lexicon modules? They are not installed by default!
DictEng, MorphalouFre, DictSwe, DictTur, DictBul, DictFun, DictLav
+ compile only the uploaded grammar even if other grammars are present
+ 'flags startcat' is needed for grammars with only one category (since the
default startcat is S, even if it doesn't exist)
- Bug! After adding a 2nd def of a fun with a different type and then deleting
the old fun, the corresponding lin will have the wrong lhs.
+ Bug! The startcat menu shows the first category by default, but the startcat
flag is actually not set until a selection is made from the menu.
+ Always open a resizable text box when editing concrete syntax.
+309
View File
@@ -0,0 +1,309 @@
<!DOCTYPE HTML>
<html>
<head>
<title>About: GF online editor for simple multilingual grammars</title>
<link rel="stylesheet" type="text/css" href="editor.css" title="Cloud">
<link rel="alternate stylesheet" type="text/css" href="molto.css" title="MOLTO">
<link rel=author href="http://www.cse.chalmers.se/~hallgren/" title="Thomas Hallgren">
<meta name = "viewport" content = "width = device-width">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta charset="UTF-8">
<script type="text/javascript" src="slideshow.js"></script>
</head>
<body>
<h1><a href="../"><img src="../P/gf-cloud.png" alt="" title="GF Cloud Service"></a>GF online editor for simple multilingual grammars</h1>
<div class=right>
<div class=slideshow>
<img onload="start_slideshow(this,{delay:5,fade:0.3})" src="P/w1s.jpg" alt="[GF online editor screen shoot]">
<img class=hidden src="P/w2s.jpg" alt="[GF online editor screen shoot]">
<img class=hidden src="P/w3s.jpg" alt="[GF online editor screen shoot]">
<img class=hidden src="P/w4s.jpg" alt="[GF online editor screen shoot]">
</div>
</div>
<h2>Introduction</h2>
Traditionally, <a href="http://www.grammaticalframework.org/">GF</a>
grammars are created in a text editor and tested in the
GF shell. Text editors know very little (if anything) about the syntax of
GF grammars, and thus provide little guidance for novice GF users. Also, the
grammar author has to download and install the GF software on his/her own
computer.
<p>
In contrast, the
<a href="."><em>GF online editor for simple multilingual grammars</em></a>
is available online, making it easier to get started. All that
is needed is a reasonably modern web browser. Even Android and iOS devices
can be used.
<p>
The editor
also guides the grammar author by showing a skeleton grammar file and
hinting how the parts should be filled in. When a new part is added to the
grammar, it is immediately checked for errors.
<p>
Editing operations are accessed by clicking on editing symbols embedded
in the grammar display:
<span class=more>+</span>=Add an item,
<span class=delete>×</span>=Delete an item,
<span class=edit>%</span>=Edit an item.
These are revealed when hovering over items. On touch devices, hovering is
in some cases simulated by tapping, but there is also a button at the bottom
of the display to "Enable editing on touch devices" that reveals all editing
symbols.
<p>
In spite of its name, the core of the editor runs in the web
browser, so once you have opened the web page, you can
<strong>continue editing</strong> grammars even while you are
<strong>offline</strong>. Grammar compilation &amp; testing and some
error checking is done by the GF server and is not available while offline.
<h3>Current status</h3>
<p>
At the moment, the editor supports only a small subset of the GF grammar
notation.
Proper error checking is done for abstract syntax, but not (yet) for concrete
syntax.
<p>
The grammars created with this editor always consists of one file for the
abstract syntax, and one file for each concrete syntax.
<h4>Abstract syntax</h4>
The supported abstract syntax corresponds to context-free grammars
(no dependent types). The definition of an abstract syntax is limited to
<ul>
<li>a list of inherited abstract syntaxes,
<li>a list of <em>category names</em>,
<var>Cat<sub>1</sub></var> ; ... ; <var>Cat<sub>n</sub></var>,
<li>a list of <em>functions</em> of the form
<var>Fun</var> : <var>Cat<sub>1</sub></var> -> ... ->
<var>Cat<sub>n</sub></var>,
<li>and a <em>start category</em>.
</ul>
Available editing operations:
<ul>
<li>Inherited abstract syntaxes can be added and removed.
<li>Categories can be added, removed and renamed. When renaming a category,
occurences of it in function types will be updated accordingly.
<li>Functions can be added, removed and edited. Concrete syntaxes are updated
to reflect changes.
<li>Functions can be reordered using drag-and-drop.
</ul>
Error checks:
<ul>
<li>Syntactically incorrect function definitions are refused.
<li>Semantic problem such as duplicated definitions or references to
undefined categories, are highlighted.
</ul>
<h4>Concrete syntax</h4>
At the moment, the concrete syntax for a language <var>L</var> is limited to
<ul>
<li>inheriting the concrete syntax <var>G<sub>i</sub>L</var>
for each <var>G<sub>i</sub></var> inherited by the abstract syntax.
<li>opening a selection of the Resource Grammar Library modules
<code>Syntax</code><var>L</var>, <code>Paradigms</code><var>L</var>,
<code>Lexicon</code><var>L</var>, <code>Symbolic</code><var>L</var>
and <code>Extra</code><var>L</var>,
<li><em>linearization types</em> for the categories in the abstract syntax,
<li><em>linearizations</em> for the functions in the abstract syntax,
<li><em>parameter type definitions</em>,
<var>P</var> = <var>C<sub>1</sub></var> | ... |<var>C<sub>n</sub></var>,
<li>and <em>operation definitions</em>, <var>op</var> = <var>expr</var>,
<var>op</var> : <var>type</var> = <var>expr</var>,
</ul>
Available editing operations:
<ul>
<li>Modules can be added and removed from the list of opened Resource Grammar
Library modules.
<li>The LHSs of the linearization types and linearizations are determined by
the abstract syntax and do not need to be entered manually.
The RHSs can
be edited.
<li>Parameter types can be added, removed and edited.
<li>Operation definitons can be added, removed and edited.
<li>Definitions can be reordered (using drag-and-drop).
</ul>
Also,
<ul>
<li>When a new concrete syntax is added to the grammar, a copy of the
currently open concrete syntax is created, since copying and modifying
is usually easier than creating something new from scratch.
(If the abstract syntax is currently open, the new conrete syntax will
start out empty.)
<li>When adding a new concrete syntax, you normally pick one of the supported
languages from a list. The language code and the file name is determined
automatically. But you can also pick <em>Other</em> from the list and change
the language code afterwards to add a concrete syntax for a language
that is not in the list.
</ul>
Error checks:
<ul>
<li>The RHSs in the concrete syntax are checked
for syntactic correctness by the editor as they are entered.
(TODO: the syntax of parameter types is not check at the moment.)
<li>Duplicated definitions are highlighted. Checks for other
semantic errors are delayed until the grammar is compiled.
</ul>
<h3>Grammar views</h3>
The editor supports three ways to view a grammar:
<ul>
<li><strong>Column view</strong>:
this is the traditional view where you see one complete grammar module at a
time. i.e. either the abstract syntax or one of the concrete syntaxes in the
grammar.
<li><strong>Matrix view</strong>:
this presents an overview of the grammar where columns
correspond to the abstract and concrete syntax modules and rows correspond
to the categories and functions in the grammar.
<li><strong>Row view</strong>:
this view shows one function form the abstract syntax and
the corresponding linearization functions from all the concrete syntaxes.
</ul>
<h3>Compiling and testing grammars</h3>
When pressing the <strong>Compile</strong> button, the grammar will be compiled
with GF, and any errors not detected by the editor will be reported.
The grammar will also be compiled when pressing the <strong>Minibar</strong>
and <strong>Quiz</strong> buttons before opening the grammar for testing
in the Minibar or the Translation Quiz, respectively.
<h3><img class=right src="P/1307545089_weather_04.png" alt="">
<img class=right src="P/1306856253_weather_06.png" alt="">Grammars in the
cloud</h3>
While the editor normally stores grammars locally in the browser, it is also
possible to store grammars in the cloud. Grammars can be stored in the cloud
just for backup, or to make them accessible from multiple devices.
<p>
There is no automatic synchronization between local grammars and the cloud.
Instead, the user should press
<img src="P/1306856253_weather_06.png" alt="[Cloud Upload]">
to upload the grammars to the cloud, and press
<img src="P/1307545089_weather_04.png" alt="[Cloud download]">
to download grammars from the cloud. In both cases, complete grammars
are copied and older versions at the destination will be overwritten.
When a grammar is deleted, both the local copy and the copy in the cloud
is deleted.
<p>
Each device is initially assigned to its own unique cloud. Each device can thus
have its own set of grammars that are not available on other devices. It is
also possible to merge clouds and share a common set of grammars between
multiple devices: when uploading grammars to the cloud, a link to this grammar
cloud appears. Accessing this link from another device will cause the clouds of
the two devices to be merged. After this, grammars uploaded from one of the
devices can be downloaded on the other devices. Any number devices can join the
same grammar cloud in this way.
<p>
<strong>Note</strong> that while it is possible to copy grammars between
multiple devices, there is no way to merge concurrent edits from multiple
devices. If the same grammar is uploaded to the
cloud from multiple devices, the last upload wins. Thus the current
implementation is suitable for a single user switching between different
devices, but not recommended for sharing grammars between multiple users.
<p>
Also <strong>note</strong> that each grammar is assigned a unique identity
when it is first created. Renaming a grammar does not change its identity.
This means that name changes are propagated between devices like other changes.
<h4 id=public>Public grammars</h4>
<blockquote>
[October 2012: this is an <strong>experimental feature</strong> that
might be replaced by an incompatible grammar sharing mechanism in the future.]
</blockquote>
<p>
The grammar cloud also includes a list of public grammars.
Grammars can be added to the public list by pressing the
<strong>Publish</strong> button shown next to the grammars in the list of
your grammars.
<p>
The <strong>Publish</strong> button creates <em>copy</em> of your grammar.
If you continue to edit your grammar, the changes will be local only.
You can press the <strong>Publish</strong> button again to update the public
copy.
<p>
You can remove a grammar from the public list by pressing the
<span class=delete>×</span> button next to the grammar in the public list.
You can <em>not</em> remove grammars published by other users.
<p>
When you open a public grammar published by another user, a <em>copy</em> of
the grammar is added to the list of your grammars. Any changes will be made in
your own copy of the grammar. If you publish your copy of the grammar, it will
appear separately in the list of public grammars. You can not
overwrite grammars published by other users, even if they have the same name.
<p>
TODO: Publishing grammars that inherit form other grammars is not recommended.
There is no way to indicate which of several grammars with the same name is
being inherited.
<p>
TODO: There should probably be a way to identify who published a grammar and
when. Maybe the publish button should be restricted to registered users...
<h3>Example-based grammar writing</h3>
We experimented with this in 2011. It is currently not included, but it
might return in a future version...
<h3>Future work</h3>
This prototype gives an idea of how a web based GF grammar editor could work.
While this editor is implemented in JavaScript and runs in the web browser,
we do not expect to create a full implementation of GF that runs in the
web browser, but let the editor communicate with a server running GF.
<p>
By developing a GF server with an appropriate API, it should
be possible to extend the editor to support a larger fragment of GF,
to do proper error checking and make more of the existing GF shell functionality
accessible directly from the editor.
<p>
The current grammar cloud service is very primitive. In particular, it is not
suitable for multiple users developing a grammar in collaboration.
<h3>Related documents</h3>
<ul>
<li><a href="http://www.grammaticalframework.org/~hallgren/Talks/GF/gf-ide.html">GF Grammar Development Tools</a>. Slides from a presentation at the MOLTO meeting in Göteborg, March 2011.
<li><a href="http://www.grammaticalframework.org/grammar-ide/">The GF Grammar IDE</a>. MOLTO deliverable.
<li><a href="http://www.grammaticalframework.org/compiler-api">The GF Grammar
Compiler API</a>. MOLTO deliverable.
</ul>
<hr>
<div class=modtime><small>
<!-- hhmts start -->Last modified: Tue Oct 9 16:52:47 CEST 2012 <!-- hhmts end -->
</small></div>
<address>
<a href="http://www.cse.chalmers.se/~hallgren/">TH</a>
<img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt="">
</address>
</body> </html>
+148
View File
@@ -0,0 +1,148 @@
function with_dir(cont) {
var dir=local.get("dir","");
if(dir) cont(dir);
else ajax_http_get("upload.cgi?dir",
function(dir) {
local.put("dir",dir);
cont(dir);
});
}
function remove_cloud_grammar(g) {
var dir=local.get("dir")
if(dir && g.unique_name) {
var path=dir+"/"+g.unique_name+".json"
ajax_http_get("upload.cgi?rm="+encodeURIComponent(path),debug);
}
}
// Upload the grammar to the server and check it for errors
function upload(g) {
function upload2(dir) {
var form=node("form",{method:"post",action:"upload.cgi"+dir},
[hidden(g.basename+".gf",show_abstract(g))])
for(var i in g.concretes)
form.appendChild(hidden(g.basename+g.concretes[i].langcode+".gf",
show_concrete(g)(g.concretes[i])));
editor.appendChild(form);
form.submit();
form.parentNode.removeChild(form);
}
with_dir(upload2);
}
// Upload the grammar to store it in the cloud
function upload_json(cont) {
function upload3(resptext,status) {
local.put("json_uploaded",Date.now());
//debug("Upload complete")
if(cont) cont();
else {
var sharing=element("sharing");
if(sharing) sharing.innerHTML=resptext;
}
}
function upload2(dir) {
var prefix=dir.substr(10)+"-" // skip "/tmp/gfse."
//debug("New form data");
//var form=new FormData(); // !!! Doesn't work on Android 2.2!
var form="",sep="";
//debug("Preparing form data");
for(var i=0;i<local.count;i++) {
var g=local.get(i,null);
if(g) {
if(!g.unique_name) {
g.unique_name=prefix+i;
save_grammar(g)
}
//form.append(g.unique_name+".json",JSON.stringify(g));
form+=sep+encodeURIComponent(g.unique_name+".json")+"="+
encodeURIComponent(JSON.stringify(g))
sep="&"
}
}
//debug("Upload to "+prefix);
ajax_http_post("upload.cgi"+dir,form,upload3,cont)
}
with_dir(upload2);
}
function download_json() {
var dir=local.get("dir");
var index=grammar_index();
var downloading=0;
function get_list(ok,err) {
ajax_http_get("upload.cgi?ls="+dir,ok,err);
}
function get_file(file,ok,err) {
downloading++;
ajax_http_get("upload.cgi?download="+encodeURIComponent(dir+"/"+file),ok,err);
}
function file_failed(errormsg,status) {
debug(errormsg)
downloading--;
}
function file_downloaded(grammar) {
downloading--;
var newg=JSON.parse(grammar);
debug("Downloaded "+newg.unique_name)
var i=index[newg.unique_name];
if(i!=undefined) merge_grammar(i,newg)
else {
debug("New")
newg.index=null;
save_grammar(newg);
}
if(downloading==0) done()
}
function done() {
setTimeout(function(){location.href="."},2000);
}
function download_files(ls) {
local.put("current",0);
if(ls) {
//debug("Downloading "+ls);
var files=ls.split(" ");
cleanup_deleted(files);
for(var i in files) get_file(files[i],file_downloaded,file_failed);
}
else {
debug("No grammars in the cloud")
done()
}
}
get_list(download_files);
}
function link_directories(newdir,cont) {
with_dir(function(olddir) {
ajax_http_get("upload.cgi?rmdir="+olddir+"&newdir="+newdir,cont)
})
}
/* -------------------------------------------------------------------------- */
// Send a command to the GF shell
function gfshell(cmd,cont) {
alert("gfshell(...) not implmemented!!!")
}
// Check the syntax of an expression
function check_exp(s,cont) {
function check(gf_message) {
//debug("cc "+s+" = "+gf_message);
cont(/(parse|syntax) error/.test(gf_message) ? "syntax error" : null);
}
if(navigator.onLine)
ajax_http_get("upload.cgi?cc="+encodeURIComponent(s),check)
else cont(null)
}
+278
View File
@@ -0,0 +1,278 @@
function with_dir(cont) {
function have_dir(dir) {
var unique_id=local.get("unique_id")
if(!unique_id) {
unique_id=dir.substr(10) // skip "/tmp/gfse."
local.put("unique_id",unique_id)
}
cont(dir,unique_id)
}
var dir=local.get("dir","");
if(/^\/tmp\//.test(dir)) have_dir(dir);
else ajax_http_get("/new",
function(dir) {
local.put("dir",dir);
have_dir(dir);
});
}
function remove_cloud_grammar(g) {
var dir=local.get("dir")
if(dir && g.unique_name) {
var path=g.unique_name+".json"
gfcloud("rm",{file:path},debug);
}
}
// Upload the grammar to the server and check it for errors
function old_upload(g) {
function upload2(dir) {
var form=node("form",{method:"post",action:"/cloud"},
[hidden("dir",dir),hidden("command","make"),
hidden(g.basename+".gf",show_abstract(g))])
//var files = [g.basename+".gf"]
for(var i in g.concretes) {
var cname=g.basename+g.concretes[i].langcode+".gf";
//files.push(cname);
form.appendChild(hidden(cname,
show_concrete(g)(g.concretes[i])));
}
editor.appendChild(form);
form.submit();
form.parentNode.removeChild(form);
}
function upload3(message) { if(message) alert(message); }
with_dir(upload2)
}
// Upload the grammar to the server and check it for errors
function upload_grammars(gs,cont) {
function upload2(dir) {
var pre="dir="+encodeURIComponent(dir)
var form= {command:"make"}
for(var aix in gs) {
var g=gs[aix]
form[encodeURIComponent(g.basename+".gf")]=show_abstract(g)
var cnc=g.concretes
for(var i in cnc) {
var cname=g.basename+cnc[i].langcode+".gf";
form[encodeURIComponent(cname)]=show_concrete(g)(cnc[i]);
}
}
ajax_http_post("/cloud",pre+encodeArgs(form),upload3)
}
function upload3(json) {
var res=JSON.parse(json)
if(cont) cont(res)
else alert(res.errorcode+"\n"+res.command+"\n\n"+res.output);
}
if(navigator.onLine) with_dir(upload2)
else cont({errorcode:"Offline",command:"",output:""})
}
function assign_unique_name(g,unique_id) {
if(!g.unique_name) {
g.unique_name=unique_id+"-"+g.index;
save_grammar(g)
}
return g
}
// Upload all grammars to the cloud
function upload_json(cont) {
function upload2(dir,unique_id) {
function upload3(resptext,status) {
local.put("json_uploaded",Date.now());
//debug("Upload complete")
if(cont) cont();
else {
var sharing=element("sharing");
if(sharing) {
if(status==204) {
var a=empty("a");
a.href="share.html#"+dir.substr(5) // skip "/tmp/"
a.innerHTML=a.href;
sharing.innerHTML="";
sharing.appendChild(text("Use the following link for shared access to your grammars from multiple devices: "))
sharing.appendChild(a)
}
else
sharing.innerHTML=resptext;
}
}
}
//debug("New form data");
//var form=new FormData(); // !!! Doesn't work on Android 2.2!
var form={dir:dir};
//debug("Preparing form data");
for(var i=0;i<local.count;i++) {
var g=local.get(i,null);
if(g) {
g=assign_unique_name(g,unique_id)
//form.append(g.unique_name+".json",JSON.stringify(g));
form[encodeURIComponent(g.unique_name+".json")]=JSON.stringify(g)
}
}
ajax_http_post("/cloud","command=upload"+encodeArgs(form),upload3,cont)
}
with_dir(upload2);
}
function remove_public(name,cont,err) {
gfcloud_public_post("rm",{file:name},cont,err)
}
// Publish a single grammar
function publish_json(g,cont) {
function publish2(dir,unique_id) {
var oldname=g.publishedAs
function publish3(resptext,status) {
console.log("publish3")
if(oldname && oldname!=g.basename) {
console.log("old name="+oldname)
var name=oldname+"-"+g.unique_name+".json"
remove_public(name,cont,cont)
}
else cont()
}
g.publishedAs=g.basename;
save_grammar(g);
g=assign_unique_name(g,unique_id)
var name=g.basename+"-"+g.unique_name
var ix=g.index;
delete g.publishedAs
delete g.unique_name
delete g.index
var form={}
form[encodeURIComponent(name+".json")]=JSON.stringify(g)
g=reget_grammar(ix)
gfcloud_public_post("upload",form,publish3,cont)
}
with_dir(publish2);
}
function download_json() {
var dir=local.get("dir");
var downloading=0;
function get_list(ok,err) { gfcloud("ls",{},ok,err) }
function get_file(file,ok,err) {
downloading++;
gfcloud("download",{file:file},ok,err);
}
function file_failed(errormsg,status) {
debug(errormsg)
downloading--;
}
function file_downloaded(grammar) {
downloading--;
var newg=JSON.parse(grammar);
debug("Downloaded "+newg.unique_name)
var i=my_grammar(newg.unique_name);
if(i!=null) merge_grammar(i,newg)
else {
debug("New")
newg.index=null;
save_grammar(newg);
}
if(downloading==0) done()
}
function done() {
setTimeout(function(){location.href="."},2000);
}
function download_files(ls) {
local.put("current",0);
if(ls) {
//debug("Downloading "+ls);
var files=JSON.parse(ls);
cleanup_deleted(files);
for(var i in files) get_file(files[i],file_downloaded,file_failed);
}
else {
debug("No grammars in the cloud")
done()
}
}
get_list(download_files);
}
function link_directories(newdir,cont) {
gfcloud("link_directories",{newdir:newdir},cont)
}
/* -------------------------------------------------------------------------- */
var public_dir="/tmp/public"
// Request GF cloud service in the public directory (using GET)
function gfcloud_public_json(cmd,args,cont,err) {
var enc=encodeURIComponent;
var url="/cloud?dir="+public_dir+"&command="+enc(cmd)+encodeArgs(args)
http_get_json(url,cont,err)
}
// Request GF cloud service in the public directory (using POST)
function gfcloud_public_post(cmd,args,cont,err) {
var enc=encodeURIComponent;
var req="dir="+public_dir+"&command="+enc(cmd)+encodeArgs(args)
ajax_http_post("/cloud",req,cont,err)
}
// Request GF cloud service (using GET, for idempotent requests)
function gfcloud(cmd,args,cont,err) {
with_dir(function(dir) {
var enc=encodeURIComponent;
var url="/cloud?dir="+enc(dir)+"&command="+enc(cmd)+encodeArgs(args)
ajax_http_get(url,cont,err)
})
}
// Reqest GF cloud service (using POST, for state changing requests)
function gfcloud_post(cmd,args,cont,err) {
with_dir(function(dir) {
var enc=encodeURIComponent;
var req="dir="+enc(dir)+"&command="+enc(cmd)+encodeArgs(args)
ajax_http_post("/cloud",req,cont,err)
})
}
// Send a command to the GF shell
function gfshell(cmd,cont) {
with_dir(function(dir) {
var enc=encodeURIComponent;
ajax_http_get("/gfshell?dir="+enc(dir)+"&command="+enc(cmd),cont)
})
}
// Check the syntax of a source module
function check_module(path,source,cont) {
var enc=encodeURIComponent;
//http_get_json("/parse?"+enc(path)+"="+enc(source),cont)
ajax_http_post_json("/parse",enc(path)+"="+enc(source),cont)
}
// Check the syntax of an expression
function check_exp(s,cont) {
function check(gf_message) {
//debug("cc "+s+" = "+gf_message);
cont(/(parse|syntax) error/.test(gf_message) ? "syntax error" : null);
}
gfshell("cc "+s,check);
}
// Lexing/unlexing text
function lextext(txt,cont) { gfshell('ps -lextext "'+txt+'"',cont) }
function unlextext(txt,cont) { gfshell('ps -bind -unlextext "'+txt+'"',cont) }
+152
View File
@@ -0,0 +1,152 @@
@import url(../cloud.css);
#editor {
/* This allows the div to grow wider than the window if necessary to
accommodate the contents. Otherwise, wide things inside can poke
through the border. */
display: table;
width: 100%;
}
div.home, div.grammar { border: 1px solid black; background: #9df; }
div.home { padding: 5px; }
div.files { margin: 0 8px 8px 8px; position: relative; }
td.public_grammars { padding-left: 2em; }
.no_publish .publish { display: none; }
div#file, table.extension td, table.extension th { border: 2px solid #009; }
div#file { border-top-width: 0; }
pre.plain { border: 2px solid #009; }
div#file, pre.plain, table.matrixview td { background: white; padding: 0.6ex; }
table.extension { border-collapse: collapse; background: white; }
table.extension td, table.extension th { padding: 1ex; }
table.extension th { border-right-width: 0; color: #009; }
table.extension td { border-left-width: 0; min-width: 30em; }
.slideshow .hidden { display: none; }
table.grammar_list { border-collapse: collapse; margin-left: 1.0em; }
table.grammar_list td { padding: 0.4ex 0.25em; }
div.namebar { background: #9df; }
div.namebar table { width: 100%; }
.namebar h3, .sheet h3 { margin: 0; color: #009; }
.home h3 { margin-top: 0; color: #009; }
div.comment:before { content: "-- "; }
div.comment { color: #009; margin-left: 1em; }
td.right { text-align: right; }
td.center { text-align: center; }
.kw { font-weight: bold; font-family: sans-serif; color: #009; }
.sep { font-weight: bold; color: #009; }
div.indent { padding-left: 1em; min-width: 1em; min-height: 1em; }
div.fun:hover, div.param:hover, div.lincat:hover, div.oper:hover, div.lin:hover,
div.template:hover
{ background: #def;}
.exb_linbuttons input[type=button] { float: right; clear: right; margin: 0; }
.exb_output { background: #dfd; float: right; margin: 0 10px; }
.more, .delete { font-weight: bold; font-family: sans-serif; }
.more, .delete, .edit, *[onclick], .onclick { cursor: pointer; }
.onclick:hover, .ident[onclick]:hover { text-decoration: underline; }
.hover .more, .hover .delete, .hover .edit { visibility: hidden }
.hover .hidden, .nohover .ifhover { display: none; }
.editable:hover, .deletable:hover { background: #ff9; }
.extensible:hover .more,.editable:hover > .edit ,.deletable:hover > .delete,
tr.deletable:hover .delete
{ visibility: visible; }
.editable { white-space: pre; }
div.lin span.editable { display: inline-block; vertical-align: top; }
.more { color: green; }
.edit { color: orange; }
.delete { color: red; }
.error_message,.inError { color: red; }
.template, .template .sep, .unimportant { color: #999; }
form { display: inline-block; }
table.tabs {
width: 100%;
border-width: 0; border-spacing: 0; empty-cells: show;
}
table.tabs td { text-align: center; border: 2px solid #009; padding: 2px; white-space: nowrap; }
table.tabs td.active { background: white; border-bottom-width: 0; }
table.tabs td.inactive {
background: #cef;
border-top-color: #66c; border-left-color: #66c; border-right-color: #66c;
}
table.matrixview th { background: #cef; color: #009; }
table.tabs td.gap
{ border-top-width: 0; border-left-width: 0; border-right-width: 0; }
table.tabs input[type=button], table.matrixview th input[type=button] {
border: 0;
background: inherit;
color: #009;
font-size: inherit;
font-weight: bold;
/*text-decoration: underline;*/
}
.string_edit { font-family: inherit; font-size: inherit; }
textarea.string_edit { vertical-align: top; }
ul.languages { -moz-column-width: 10em; }
#sharing h1, #sharing .footer { display: none; }
div.compiler_output .back_to_editor { display: none; }
textarea.text_mode {
/*font-family: inherit; font-size: inherit;*/
width: 99%;
}
div#minibar, div#syntax_editor {
border: 1px solid black;
padding: 5px;
background: #ccc url("../minibar/brushed-metal.png");
}
table.page_overlay {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
}
table.page_overlay>tr>td { text-align: center; vertical-align: middle; }
div.grammar_extension {
display: inline-block;
border: 1px solid black;
background: #9df;
padding: 2ex;
margin: 2ex;
box-shadow: 10px 10px 10px rgba(0,0,0,0.3);
}
div.sheet {
position: relative;
background: white;
padding: 1ex;
margin: 2ex;
box-shadow: 5px 5px 15px rgba(0,0,0,0.5);
transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-webkit-transition: all 0.5s ease-in-out;
}
File diff suppressed because it is too large Load Diff
+190
View File
@@ -0,0 +1,190 @@
var example_based=[];
/*
-- cat lincat fun lin fun cat cat
environ :: ([(CId, CId)],[(CId, Expr)],[((CId, CId), [CId])]) -> Environ
*/
function exb_state(g,ci) {
var conc=g.concretes[ci]
function show_list(show1,xs) {
return "["+map(show1,xs).join(",")+"]";
}
function show_fun(fun) {
var t=fun.type
var res=t[t.length-1]
var args=t.slice(0,length-1);
return "(("+fun.name+","+res+"),["+args.join(",")+"])"
}
function show_lincat(lincat) {
return "("+lincat.cat+","+lincat.type+")"
}
function show_lin(lin) {
return "("+lin.fun+","+(lin.eb_lin||"?")+")"
}
function show_funs(funs) { return show_list(show_fun,funs) }
function show_lincats(lincats) { return show_list(show_lincat,lincats); }
function show_lins(lins) { return show_list(show_lin,lins) }
return "("+show_lincats(conc.lincats)
+","+show_lins(conc.lins)
+","+show_funs(g.abstract.funs)+")"
}
function exb_call(g,ci,command,args,cont) {
var url=window.exb_url || "exb/exb.fcgi";
var q=encodeArgs(args);
var cmd="?command="+command+"&state="+encodeURIComponent(exb_state(g,ci))+q;
http_get_json(url+cmd,cont)
}
function ask_possibilities(g,ci) {
var conc=g.concretes[ci];
function show_poss(poss) {
//debug("possibilities: "+JSON.stringify(poss))
var exready={}
for(var i in poss[0]) exready[poss[0][i]]=true;
var testable={}
for(var i in poss[1]) testable[poss[1][i]]=true;
example_based[ci]={exready:exready,testable:testable}
conc.example_based=true;
if(!conc.example_lang) conc.example_lang=g.concretes[0].langcode;
reload_grammar(g);
}
var exci=conc_index(g,conc.example_lang);
if(!conc.example_lang || !exci)
conc.example_lang=g.concretes[ci==0 ? 1 : 0].langcode;
var exci=conc_index(g,conc.example_lang);
exb_call(g,ci,"possibilities",{example_state:exb_state(g,exci)},show_poss)
}
var parser = { Eng: "ParseEngAbs.pgf",
Swe: "ParseSwe.pgf"
}
function exb_extra(g,ci) {
var conc=g.concretes[ci];
function stop_exb() {
conc.example_based=false;
reload_grammar(g);
}
function exblangmenu() {
function opt(conc) {
return option(concname(conc.langcode),conc.langcode);
}
function skip_target(c) { return c.langcode!=conc.langcode; }
var m =node("select",{},map(opt,filter(skip_target,g.concretes)));
if(conc.example_lang) m.value=conc.example_lang;
m.onchange=function() { conc.example_lang=m.value; save_grammar(g); }
return m
}
function ask_poss() { ask_possibilities(g,ci) }
if(navigator.onLine && g.concretes.length>1 && conc.example_based && !example_based[ci]) ask_poss();
var sb=button("Start",ask_poss)
if(parser[conc.langcode] && g.concretes.length>1)
return indent([wrap("small",text("Example-based editing: ")),
conc.example_based
? node("span",{},
[button("Stop",stop_exb),
wrap("small",text(" Example language: ")),
exblangmenu()
])
: sb])
else {
sb.disabled=true;
var why= g.concretes.length>1
? " ("+concname(conc.langcode)+" is not supported yet)"
: " (Add another language to take examples from first.)"
return indent([unimportant("Example-based editing: "), sb,
unimportant(why)])
}
}
function fun_lincat(g,conc,fun) {
var t=function_type(g,fun);
var abscat=t[t.length-1]
return cat_lincat(conc,abscat)
}
function exb_linbuttons(g,ci,f) {
var conc=g.concretes[ci];
var fun=f.fun;
var eb=example_based[ci];
var exb_output;
function fill_example(maybetree) {
var tree=maybetree.Just
if(tree) {
if(f.template)
conc.lins.push({fun:f.fun,args:f.args,
lin:tree[0],eb_lin:tree[1]});
else {
f.lin=tree[0];
f.eb_lin=tree[1];
}
ask_possibilities(g,ci)
}
else exb_output.innerHTML="Bug: no tree found"
}
function show_example(example){
exb_output.innerHTML="";
var s=prompt(example[1]);
if(s) {
var cat=fun_lincat(g,conc,fun)
exb_output.innerHTML="...";
//server.parse({from:"ParseEng",cat:cat,input:s},fill_example)
exb_call(g,ci,"abstract_example",
{cat:cat,input:s,
parser:parser[conc.langcode],
params:"["+f.args.join(",")+"]",
"abstract":example[0]},
fill_example)
}
}
function by_example() {
var dir=local.get("dir")
if(dir) {
if(exb_output) {
exb_output.innerHTML="...";
exb_call(g,ci,"provide_example",
{lang:g.basename+conc.example_lang,
parser:parser[conc.langcode],
fun:fun,
grammar:dir+"/"+g.basename+".pgf"},
show_example)
}
}
else exb_output.innerHTML="Compile the grammar first!"
}
function show_test(txt) {
exb_output.innerHTML="";
exb_output.appendChild(text(txt))
}
function test_it(b) {
if(exb_output) {
exb_output.innerHTML="...";
exb_call(g,ci,"test_function",
{fun:fun,parser:parser[conc.langcode]},
show_test)
}
}
var buttons=[];
if(conc.example_based && eb) {
if(f.template) {
var byex=button("By example",by_example);
if(!(eb.exready[fun] && fun_lincat(g,conc,fun)))
byex.disabled=true
buttons.push(byex)
}
else {
var b=button("Test it",test_it);
if(!eb.testable[fun] || !f.eb_lin) b.disabled=true;
buttons.push(b)
}
var exb_output=node("span",{"class":"exb_output"},[]);
buttons.push(exb_output)
}
return node("span",{"class":"exb_linbuttons"},buttons)
}
+345
View File
@@ -0,0 +1,345 @@
/* Abstract syntax for a small subset of GF grammars in JavaScript */
/*
type UniqueId = String --persistent unique grammar identifier used by the editor
type Id = String -- all sorts of identifiers in grammars
type ModId = Id -- module name
type Cat = Id -- category name
type FunId = Id -- function name
type Type = [Cat] -- [Cat_1,...,Cat_n] means Cat_1 -> ... -> Cat_n
type Grammar = { basename: ModId,
comment: String,
extends: [ModId], -- in 1-to-1 correspondence with uextends
uextends: [UniqueId], -- added 2012-10-16
abstract: Abstract,
concretes: [Concrete] }
type Abstract = { startcat: Cat, cats: [Cat], funs: [Fun] }
type Fun = { name: FunId, type: Type }
type Concrete = { langcode: Id,
opens: [ModId],
params: [{name: Id, rhs: String}],
lincats : [{ cat: Cat, type: Term}],
opers: [{name: Lhs, rhs: Term}],
lins: [Lin]
}
type Lin = {fun: FunId, args: [Id], lin: Term}
type Lhs = String -- name and type of oper,
-- e.g "regN : Str -> { s:Str,g:Gender} ="
type Term = String -- arbitrary GF term (not parsed by the editor)
type LinType = [Term]
*/
// locally_defined_cats :: Grammar -> {Cat=>ModId} -> {Cat=>ModId} // destr upd
function locally_defined_cats(g,dc) {
with(g.abstract)
for(var i in cats) dc[cats[i]]=g.basename;
return dc;
}
// predefined_cats :: () -> {Cat=>ModId}
function predefined_cats() {
var pd = "Predef"
return { "Int":pd, "Float":pd, "String":pd}
}
// all_defined_cats :: Grammar -> [Grammar] -> {Cat=>ModId}
function all_defined_cats(g,igs) {
return all_inherited_cats(igs,locally_defined_cats(g,predefined_cats()))
}
// all_inherited_cats :: [Grammar] -> {Cat=>ModId} -> {Cat=>ModId} // destr upd
function all_inherited_cats(igs,dc) {
for(var i in igs) dc=locally_defined_cats(igs[i],dc)
return dc;
}
// locally_defined_funs :: [Grammar] -> {FunId=>ModId} -> {Id=>ModId} // destr upd
function locally_defined_funs(g,df) {
with(g.abstract)
for(var i in funs) df[funs[i].name]=g.basename;
return df;
}
// all_defined_funs :: Grammar -> [Grammar] -> {FunId=>ModId}
function all_defined_funs(g,igs) {
return all_inherited_funs(igs,locally_defined_funs(g,{}))
}
// all_inherited_funs :: [Grammar] -> {FunId=>ModId} -> {FunId=>ModId} // destr upd
function all_inherited_funs(igs,df) {
for(var i in igs) df=locally_defined_funs(igs[i],df)
return df;
}
// Return the index of the function the given name in the abstract syntax
// fun_index :: Grammar -> FunId -> (Int|null)
function fun_index(g,fun) {
with(g.abstract)
for(var i in funs) if(funs[i].name==fun) return i
return null;
}
// Return the type of a named function in the abstract syntax
// function_type :: Grammar -> FunId -> (Type|null)
function function_type(g,fun) {
var ix=fun_index(g,fun)
return ix==null ? null : g.abstract.funs[ix].type
}
// Return the lincat defined in a given concrete syntax for an abstract category
// cat_lincat :: Concrete -> Cat -> (Term|null)
function cat_lincat(conc,cat) {
with(conc)
for(var i in lincats) if(lincats[i].cat==cat) return lincats[i].type
return null;
}
// Return the index of the lin in a given concrete syntax for an abstract function
// lin_index :: Concrete -> FunId -> (Int|null)
function lin_index(conc,fun) {
with(conc) for(var i in lins) if(lins[i].fun==fun) return i
return null;
}
// Return the lin defined in a given concrete syntax for an abstract function
// fun_lin :: Concrete -> FunId -> (Lin|null)
function fun_lin(conc,fun) {
var i=lin_index(conc,fun)
if(i!=null) return conc.lins[i]
return null;
}
// Return the index of the concrete syntax with a given langcode
// conc_index :: Grammar -> Id -> (Int|null)
function conc_index(g,langcode) {
var c=g.concretes;
for(var ix=0;ix<c.length;ix++)
if(c[ix].langcode==langcode) return ix
return null;
}
// rename_category :: Grammar -> Cat -> Cat -> Grammar // destructive update
function rename_category(g,oldcat,newcat) {
function rename_cats(cats) {
for(var i in cats) if(cats[i]==oldcat) cats[i]=newcat;
}
function rename_type(t) {
for(var i in t) if(t[i]==oldcat) t[i]=newcat;
}
function rename_funs(funs) {
for(var i in funs) rename_type(funs[i].type)
}
function rename_abstract(a) {
rename_cats(a.cats);
rename_funs(a.funs);
}
function rename_lincat(lc) {
if(lc.cat==oldcat) lc.cat=newcat;
}
function rename_concrete(c) {
for(var i in c.lincats) rename_lincat(c.lincats[i]);
}
function rename_concretes(cs) {
for(var i in cs) rename_concrete(cs[i]);
}
rename_abstract(g.abstract)
rename_concretes(g.concretes);
return g;
}
// rename_function :: Grammar -> FunId -> FunId -> Grammar // destructive update
function rename_function(g,oldfun,newfun) {
function rename_concrete(c) {
var i=lin_index(c,oldfun)
if(i!=null) c.lins[i].fun=newfun;
}
for(var i in g.concretes) rename_concrete(g.concretes[i]);
return g;
}
// change_lin_lhs :: Grammar -> Fun -> Grammar // destructive update
function change_lin_lhs(g,fun) {
function change_concrete(c) {
var i=lin_index(c,fun.name)
if(i!=null) c.lins[i].args=arg_names(fun.type);
}
for(var i in g.concretes) change_concrete(g.concretes[i]);
return g;
}
/* --- Parsing -------------------------------------------------------------- */
// GF idenfifier syntax:
var lex_id=/^[A-Za-z][A-Za-z0-9_']*$/
// See https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions
function check_id(s) { return lex_id.test(s); }
function check_name(s,kind) {
return check_id(s)
? null
: s+"? "+kind+" names must start with a letter and can contain letters, digits, _ and '"
}
// parse_fun :: String -> {error:String} + {ok:Fun}
function parse_fun(s) {
var ws=s.split(/\s+/);
var fun={name:"",type:[]};
/* Use a state machine to parse function definitions */
/* f : T1 -> ... -> Tn */
var state="name";
var ok=true;
for(var i=0;ok && i<ws.length;i++) {
if(ws[i]!="") {
switch(state) {
case "name": fun.name=ws[i]; state=":"; break;
case ":": ok=ws[i]==":"; state="type"; break;
case "type": fun.type.push(ws[i]); state="->"; break;
case "->": ok=ws[i]=="->"; state="type"; break;
}
}
}
var err=check_name(fun.name,"Function");
if(err) return {error: err};
return ok && state=="->"
? {ok:fun}
: { error : "Fun : Cat<sub>1</sub> -> ... -> Cat<sub>n</sub>" }
}
// parse_param :: String -> {error:String} + { ok:{name:Id,rhs:String} }
function parse_param(s) {
var ws=s.split("=");
if(ws.length==2) {
var name=ws[0].trim();
var err=check_name(name,"Parameter type");
return err ? { error:err } : { ok: { name:name,rhs:ws[1].trim() } }
}
else
return { error: "P = C1 | ... | Cn" }
}
// parse_oper :: String -> {error:String} + {ok:{name:Lhs, rhs:Term}}
function parse_oper(s) {
var i=s.indexOf(" ");
var operr = { error: "op = expr" }
if(i>0 && i<s.length-1) {
var name=s.substr(0,i).trim();
var rhs=s.substr(i).trim();
var err=check_name(name,"Operator");
return err
? {error:err}
: rhs!="" ? {ok: {name:name, rhs:rhs}}
: operr
}
else return operr
}
/* --- Print as plain text (normal GF source syntax) ------------------------ */
// show_type :: Type -> String
function show_type(t) {
var s="";
for(var i in t) {
if(i>0) s+=" -> ";
s+=t[i];
}
return s;
}
// show_lintype :: LinType -> String
function show_lintype(t) {
var s="";
for(var i in t) {
if(i>0) s+=" -> ";
s+= check_id(t[i]) ? t[i] : "("+t[i]+")";
}
return s;
}
// show_fun :: Fun -> String
function show_fun(fun) {
return fun.name+" : "+show_type(fun.type);
}
// show_grammar :: Grammar -> String
function show_grammar(g) {
return show_abstract(g)+"\n"+show_concretes(g)
}
function show_abstract(g) {
// var startcat= g.abstract.cats.length==1 ? g.abstract.cats[0] : g.abstract.startcat;
var startcat= g.abstract.startcat || g.abstract.cats[0];
return "abstract "+g.basename+" = "
+show_extends(g.extends)
+"{\n\n"
+"flags coding = utf8 ;\n\n"
+show_startcat(startcat)
+show_cats(g.abstract.cats)
+show_funs(g.abstract.funs)
+"}\n";
}
function show_extends(exts) {
return exts && exts.length>0 ? exts.join(", ")+" ** " : "";
}
function show_startcat(startcat) {
return startcat && startcat!="-"
? "flags startcat = "+startcat+";\n\n"
: "";
}
function show_cats(cats) {
return cats.length>0 ? "cat\n "+cats.join("; ")+";\n\n" : "";
}
function show_funs(funs) { return show_list("fun",show_fun,funs); }
function show_concretes(g) {
return map(show_concrete(g),g.concretes).join("\n\n");
}
function conc_extends(conc) { return function(m) { return m+conc.langcode; }}
function show_concrete(g) {
return function(conc) {
return "" // "--# -path=.:present\n"
+ "concrete "+g.basename+conc.langcode+" of "+g.basename+" = "
+show_extends((g.extends || []).map(conc_extends(conc)))
+show_opens(conc.opens)
+"{\n\nflags coding = utf8 ;\n\n"
+show_lincats(conc.lincats)
+show_lins(conc.lins)
+show_params(conc.params)
+show_opers(conc.opers)
+"}\n"
}
}
function show_list(kw,show1,list) {
return list.length>0
? kw+"\n "+map(show1,list).join(";\n ")+";\n\n"
: ""
}
function show_opens(opens) {
return opens && opens.length>0 ? "\n\nopen "+opens.join(", ")+" in " : ""
}
function show_params(params) { return show_list("param",show_param,params); }
function show_lincats(lincats) { return show_list("lincat",show_lincat,lincats); }
function show_opers(opers) { return show_list("oper",show_oper,opers); }
function show_lins(lins) { return show_list("lin",show_lin,lins); }
function show_param(p) { return p.name + " = " + p.rhs; }
function show_oper(p) { return p.name + " " + p.rhs; }
function show_lincat(p) { return p.cat + " = " + p.type; }
function show_lin(lin) {
return lin.fun + " " + lin.args.join(" ")+ " = " + lin.lin;
}
+4
View File
@@ -0,0 +1,4 @@
CACHE MANIFEST
# 5
NETWORK:
*
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html> <!-- manifest="gfse.manifest" -->
<head>
<title>GF online editor for simple multilingual grammars</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="editor.css" title="Cloud">
<link rel="alternate stylesheet" type="text/css" href="molto.css" title="MOLTO">
<link rel="stylesheet" type="text/css" href="../minibar/minibar.css">
<link rel="stylesheet" type="text/css" href="../syntax-editor/editor.css">
<link rel="stylesheet" type="text/css" href="../wordnet/gf-wordnet.css">
<link rel=author href="http://www.cse.chalmers.se/~hallgren/" title="Thomas Hallgren">
<meta name = "viewport" content = "width = device-width">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body class=hover>
<h2>GF online editor for simple multilingual grammars</h2>
<div id=editor></div>
<small class="hidden">
<span class=more>+</span>=Add an item,
<span class=delete>×</span>=Delete item,
<span class=edit>%</span>=Edit item.
</small>
<small class="ifhover">Hover over items for hints and editing options.</small>
<div id=compiler_output class=compiler_output></div>
<noscript>
This page does not work without JavaScript.
</noscript>
<hr>
<div class=modtime><small>
HTML
<!-- hhmts start -->Last modified: Thu May 21 09:47:39 CEST 2015 <!-- hhmts end -->
</small></div>
<a href="about.html">About</a>
<pre id=debug></pre>
<script type="text/javascript" src="config.js"></script> <!-- optional -->
<script type="text/javascript" src="../js/support.js"></script>
<script type="text/JavaScript" src="../js/pgf_online.js"></script>
<script type="text/javascript" src="../js/localstorage.js"></script>
<script type="text/JavaScript" src="../js/langcode.js"></script>
<script type="text/javascript" src="localstorage.js"></script>
<script type="text/javascript" src="gf_abs.js"></script>
<script type="text/javascript" src="example_based.js"></script>
<script type="text/javascript" src="sort.js"></script>
<script type="text/javascript" src="cloud2.js"></script>
<script type="text/javascript" src="editor.js"></script>
<script type="text/JavaScript" src="../minibar/minibar.js"></script>
<script type="text/JavaScript" src="../minibar/minibar_input.js"></script>
<script type="text/JavaScript" src="../minibar/minibar_translations.js"></script>
<script type="text/JavaScript" src="../minibar/minibar_support.js"></script>
<script type="text/javascript" src="../js/grammar_manager.js"></script>
<script type="text/javascript" src="../syntax-editor/ast.js"></script>
<script type="text/javascript" src="../syntax-editor/editor_menu.js"></script>
<script type="text/javascript" src="../syntax-editor/editor.js"></script>
<script type="text/javascript" src="../wordnet/js/gf-wordnet.js"></script>
<script src="https://unpkg.com/vis-network@9.0.4/standalone/umd/vis-network.min.js"></script>
<script type="text/javascript" src="../wordnet/js/wordcloud2.js"></script>
<div id="search_popup" class="search_popup">
<table id="domains" class="selector">
<thead></thead>
<tbody></tbody>
</table>
<table id="result" class="result">
<thead></thead>
<tbody></tbody>
<tfoot></tfoot>
</table>
</div>
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
//Needs ../js/localstorage.js
var local=appLocalStorage("gf.editor.simple.grammar")
+105
View File
@@ -0,0 +1,105 @@
body { color: #413b36; background: #fffcfa; }
h1 { font-size: 175%; }
h1,h2,h3,h4,small { font-family: sans-serif; }
h1,h2,h3,h4,a { color: #5c1a1a; }
h1:first-child, h2:first-child { margin-top: 0; margin-bottom: 1ex; }
#editor {
/* This allows the div to grow wider than the window if necessary to
accommodate the contents. Otherwise, wide things inside can poke
through the border. */
display: table;
width: 100%;
}
div.grammar { border: 2px solid #b09779; background: #642121; }
div.files { margin: 0 8px 8px 8px; }
div#file { border: 2px solid #b0977d; border-top-width: 0; }
pre.plain { border: 2px solid #b0977d; }
div#file, pre.plain { background: #fffcfa; padding: 0.6ex; }
.slideshow .hidden { display: none; }
img.cloud, img.right, div.right, div.modtime { float: right; }
.modtime { color: #999; white-space: nowrap; }
table.grammar_list { border-collapse: collapse; margin-left: 1.0em; }
table.grammar_list td { padding: 0.4ex 0.25em; }
/*div.namebar { background: #642121; }*/
div.namebar table { width: 100%; }
.namebar h3 { margin: 0; color: white; }
td.right { text-align: right; }
.kw { font-weight: bold; font-family: sans-serif; color: #642121; }
.sep { font-weight: bold; color: #642121; }
div.indent { padding-left: 1em; min-width: 1em; min-height: 1em; }
/*
div.fun, div.param, div.lincat, div.oper, div.lin
{ padding-left: 2em; text-indent: -2em; }
*/
.more, .delete { font-weight: bold; font-family: sans-serif; }
.more, .delete, .edit { cursor: pointer; }
.hover .more, .hover .delete, .hover .edit { visibility: hidden }
.hover .hidden, .nohover .ifhover { display: none; }
.editable:hover, .deletable:hover { background: #ff9; }
.namebar .editable:hover { background: #04b; }
.extensible:hover .more,.editable:hover > .edit ,.deletable:hover > .delete,
tr.deletable:hover .delete
{ visibility: visible; }
.more { color: green; }
.edit { color: orange; }
.delete { color: red; }
.error_message,.inError { color: red; }
.template, .template .sep, .unimportant { color: #999; }
form { display: inline-block; }
table.tabs {
width: 100%;
border-width: 0; border-spacing: 0; empty-cells: show;
}
table.tabs td { text-align: center; border: 2px solid #b09779; padding: 2px; white-space: nowrap; }
table.tabs td.active { background: white; border-bottom-width: 0; }
table.tabs td.inactive {
background: #e1e1e1;
border-top-color: #b09779; border-left-color: #b09779; border-right-color: #b09779;
}
table.tabs td.gap
{ border-top-width: 0; border-left-width: 0; border-right-width: 0; }
table.tabs input[type=button] {
border: 0;
background: inherit;
color: #642121;
font-size: inherit;
font-weight: bold;
/*text-decoration: underline;*/
}
input.string_edit { font-family: inherit; font-size: inherit; }
ul.languages { -moz-column-width: 20em; }
li { margin-top: 0.5ex; margin-bottom: 0.5ex; }
#sharing h1, #sharing .footer { display: none; }
div.compiler_output .back_to_editor { display: none; }
div#minibar {
border: 1px solid black;
padding: 5px;
background: #ccc url("../minibar/brushed-metal.png");
}
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html> <head>
<title>Download from Grammar Cloud</title>
<link rel="stylesheet" type="text/css" href="editor.css" title="Cloud">
<link rel="alternate stylesheet" type="text/css" href="molto.css" title="MOLTO">
</head>
<body>
<h1><img src="P/1307545048_weather_09.png" alt="">Download from Grammar Cloud</h1>
<pre id=debug></pre>
<hr>
<address></address>
<!-- hhmts start -->Last modified: Wed Apr 3 21:53:09 CEST 2013 <!-- hhmts end -->
<script type="text/javascript" src="../js/support.js"></script>
<script type="text/javascript" src="../js/localstorage.js"></script>
<script type="text/javascript" src="localstorage.js"></script>
<script type="text/javascript" src="gf_abs.js"></script>
<script type="text/javascript" src="editor.js"></script>
<script type="text/javascript" src="cloud2.js"></script>
<script type="text/javascript" src="sort.js"></script>
<script type="text/javascript">
download_from_cloud();
</script>
</body>
</html>
+86
View File
@@ -0,0 +1,86 @@
var internet_explorer=navigator.appName=="Microsoft Internet Explorer";
/* How to change opacity in IE:
http://joseph.randomnetworks.com/archives/2006/08/16/css-opacity-in-internet-explorer-ie/
*/
var set_opacity =
internet_explorer
? function(el,o) { el.style.filter="alpha(opacity="+Math.round(o*100)+")";}
: function(el,o) { el.style.opacity=o; };
function start_slideshow(img,options) {
var p=img.parentNode;
if(p.tagName=="A") p=p.parentNode;
var is=p.getElementsByTagName("img");
if(is.length>1) {
var cur=0;
var w=img.width;
var h=img.height;
//p.style.position="relative";
p.style.minWidth=w+"px";
p.style.minHeight=h+"px";
var images=[];
for(var i=0;i<is.length;i++) {
images[i]=is[i];
var c=images[i];
if(internet_explorer) c.style.zoom=1;
c.style.position="absolute";
}
var timeout=1000*(options.delay || 5);
var ft=options.fade==null ? 1 : options.fade;
var tick=function() {
var c=images[cur];
cur= (cur+1) % images.length;
var n=images[cur];
set_opacity(n,0);
//n.style.position="static";
n.style.zIndex=1;
n.className="";
if(n.width>w) { w=n.width; p.style.minWidth=w+"px"; }
if(n.height>h) { h=n.height; p.style.minHeight=h+"px"; }
c.style.position="absolute";
c.style.zIndex=0;
fade(n,0,1,ft,function() {
if(c.width>n.width || c.height>n.height) fade(c,1,0,ft,null);
else set_opacity(c,0); });
//debug.innerHTML=w+"x"+h;
//for(var i=0;i<images.length;i++)
//debug.appendChild(text(" "+images[i].style.position));
}
//var debug=document.createElement("div");
//p.parentNode.insertBefore(debug,p);
//debug.innerHTML=w+"x"+h;
setInterval(tick,timeout);
}
//else alert("No slideshow!");
}
function fade(el,start,stop,t,after) {
// el: which element to fade
// start: starting opacity [0..1]
// stop: ending opacity [0..1]
// t: duration of fade (in seconds), default 1s
// after: function to call when done fading, optional
var dt=40; // Animation granularity, 1/40ms = 25fps
el.step=(stop-start)*dt/(1000*(t==null ? 1 : t));
el.stop=stop;
//alert("fade "+start+" "+stop+" "+el.step);
var done=function() {
clearInterval(el.timer);
el.timer=null;
if(after) after();
}
var f=function() {
var next=el.current+el.step;
if(next>=1) { next=1; done(); }
if(next<=0) { next=0; done(); }
set_opacity(el,next);
el.current=next
}
if(!el.timer) {
el.current=start;
el.timer=setInterval(f,dt);
}
}
+164
View File
@@ -0,0 +1,164 @@
function initialize_sorting(tagList,classList) {
/*
var debugoutput=empty("pre");
document.body.appendChild(debugoutput)
function jsdebug(txt) {
//clear(debugoutput)
debugoutput.appendChild(text(txt+"\n"))
}
*/
function listToSet(list) {
var set={}
for(var i in list) set[list[i]]=true
return set;
}
var sortable_tag=listToSet(tagList)
var sortable_class=listToSet(classList)
function sortable(elem) {
return elem && elem.tagName!="INPUT" && elem.tagName!="BUTTON"
&& (sortable_tag[elem.tagName]
? sortable_class[elem.className]
? elem
: null
: sortable(elem.parentNode))
}
function move_element(elem,x,y) {
elem.style.left=x+"px";
elem.style.top=y+"px";
elem.delta={x:x,y:y};
}
function adjust_refs(elem,dy) {
//jsdebug("dy="+dy);
move_element(elem,elem.delta.x,elem.delta.y-dy);
elem.downAt.y+=dy;
elem.range.lo-=dy;
elem.range.hi-=dy;
}
function move_up(elem) {
var prev=elem.previousElementSibling;
if(prev) {
var top=elem.offsetTop;
var mid=prev.offsetTop+prev.offsetHeight/2;
if(top<mid) {
elem.parentNode.insertBefore(elem,prev);
adjust_refs(elem,elem.offsetTop-top)
}
//else jsdebug("not yet, top="+top+", mid="+mid);
}
//else jsdebug("at top");
}
function move_down(elem) {
var next=elem.nextElementSibling;
if(next) {
var top=elem.offsetTop;
var bot=top+elem.offsetHeight;
var mid=next.offsetTop+next.offsetHeight/2;
if(bot>mid) {
next.parentNode.insertBefore(next,elem);
adjust_refs(elem,elem.offsetTop-top)
}
//else jsdebug("not yet, top="+top+", bot="+bot+", mid="+mid);
}
//else jsdebug("at bottom");
}
function swap(elem,dy) {
if(dy>0) move_down(elem);
else if(dy<0) move_up(elem);
}
function restrictTo(range,y) {
return Math.min(range.hi,Math.max(range.lo,y));
}
// -------------------------------------------------------------------------
// These functions isolate the difference between mouse interfaces and touch
// interfaces
function eventPosition(event) {
var p=event
if(event.touches) p=event.touches[0]
return {x:p.screenX,y:p.screenY}
}
function setStartHandler(ondown) {
if("ontouchstart" in window) document.ontouchstart=ondown
else document.onmousedown=ondown
}
function setDragHandlers(onmove,onend) {
if("ontouchstart" in window) {
document.ontouchmove=onmove;
document.ontouchend=onend;
}
else {
document.onmousemove=onmove;
document.onmouseup=onend;
}
}
// -------------------------------------------------------------------------
function startDrag(event,elem) {
//jsdebug("Start dragging");
elem.style.position="relative";
elem.delta || (elem.delta={x:0,y:0});
var p=eventPosition(event)
elem.downAt={x:p.x-elem.delta.x,y:p.y-elem.delta.y};
var list=elem.parentNode;
// elem and list must have the same offsetParent for this to work!!
var top=list.offsetTop-elem.offsetTop+elem.delta.y;
elem.range={lo:top,hi:top+list.offsetHeight-elem.offsetHeight};
elem.style.zIndex=1;
//console.log("Start dragging",elem.id,list.offsetTop,elem.offsetTop,elem.range.lo,elem.range.hi)
function dragMove(event) {
var p=eventPosition(event)
var dx=0/*p.x-elem.downAt.x*/;
var dy=restrictTo(elem.range,p.y-elem.downAt.y);
//jsdebug("dragging to "+dx+" "+dy+" "+show_props(elem.range,"range"));
//console.log("dragging to ",dy);
move_element(elem,dx,dy);
//jsdebug("dragging to "+elem.offsetLeft+" "+elem.offsetTop);
swap(elem,dy)
return false;
}
function dragEnd() {
//jsdebug("dropped");
elem.style.zIndex=0;
move_element(elem,0,0);
setDragHandlers(null,null)
preventScroll=false;
return false;
}
preventScroll=true;
setDragHandlers(dragMove,dragEnd)
return false;
}
function mousedown(event) {
var elem=sortable(event.target);
if(elem) return startDrag(event,elem);
//else jsdebug("Clicked outside"/*+taglist(event.target)/*+show_props(event,"event")*/);
}
//var jsdebug=debug;
//https://stackoverflow.com/questions/49500339/cant-prevent-touchmove-from-scrolling-window-on-ios
var preventScroll=false;
function pd(e) {if(preventScroll) e.preventDefault()}
function init() {
setStartHandler(mousedown)
document.addEventListener("touchmove",pd,{passive:false})
//var d=element("javascriptdebug");
//if(d) jsdebug=function(msg) { d.innerHTML=msg; }
}
init();
}
//Inspired by http://tool-man.org/examples/sorting.html