Commit 27908962 authored by Alexander Shabarshin's avatar Alexander Shabarshin

Rgrid = Webitable + Weberta

parent e57c78c1
/* http://webitable.sourceforge.net (E-mail: shaos@users.sourceforge.net)
/*
Rgrid.js = AJAX engine + ROBBY interpreter ( see http://rgrid.net )
Weberta - Roberta bytecode interpreter for Webitable System
Copyright (C) 2012 Alexander Shabarshin (ashabarshin@gmail.com)
Copyright (C) 2012,2018 Alexander Shabarshin <me@shaos.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -20,13 +19,18 @@
*/
var $R = {
lib_name: "Weberta",
lib_name: "Rgrid", /* before 2018 it was called "Webitable" */
ver_major: 0,
ver_minor: 1,
copyright: "(c) 2012 Alexander Shabarshin",
table: "rtab",
prefix: "",
ver_minor: 3,
copyright: "(c) 2012,2018 Alexander Shabarshin",
// ex-webitable:
cache: {},
threads: [],
started: 0,
// ex-weberta:
table_prefix: "rtab",
prefix: "",
opcache: {},
robots: [null],
queue: [],
qindex: [null],
......@@ -49,23 +53,263 @@ $R.clear = function() {
this.cache = {};
};
// $R.init - initialize WebertaVM and create screen for it
function $(s) {
return document.getElementById(s);
}
function $_(s) {
var e = $(s);
var v = arguments[1];
if(e!=null)
{
if(v==null) {
if(e.value==null) {
return e.innerHTML;
} else {
return e.value;
}
} else {
if(e.value==null) {
e.innerHTML = v;
} else {
e.value = v;
}
return v;
}
}
}
function $__(s,u) {
var r = null;
var p = arguments[2];
try {
r = new XMLHttpRequest();
} catch(e) {
r = null;
}
if(r!=null)
{
r.onreadystatechange = function() {
if(r.readyState==4 && r.status==200) {
if(typeof s == 'string') {
$_(s,r.responseText);
}
if(typeof s == 'function') {
s(r.responseText);
}
}
}
if(p==null) {
r.open("GET",u,true);
r.send(null);
} else {
r.open("POST",u,true);
r.send(p);
}
}
}
function $$(s) {
return $R.select(s);
}
function $$_(s) {
return $map($$(s),function(e){return e.id;});
}
function $time() {
return Math.floor(+new Date/1000);
}
function $random(r) {
return Math.floor(r*Math.random());
}
function $map(a,f) {
var r = [];
for(var i in a) {
r.push(f(a[i]));
}
return r;
}
function $reduce(a,b,f) {
for(var i in a) {
b = f(b,a[i]);
}
return b;
}
function $filter(a,f) {
var r = [];
for(var i in a) {
if(f(a[i])) {
r.push(a[i]);
}
}
return r;
}
function $hex(i,j) {
var k,l,m=1,s="",r=i,g=1;
var h=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
if(r<0) {
g = -1;
r = -i;
}
for(k=1;k<j;k++) {
m = m*16;
}
if(r >= m*16) {
g = 0;
r = r&(m*16-1);
}
for(k=0;k<j;k++) {
l = Math.floor(r/m);
r = r-l*m;
m = m/16;
s += h[l];
}
if(g<0) {
return "-" + s;
}
if(g==0) {
return "~" + s;
}
return s;
}
$R.iterate = function(node) {
var base = this.cache["*"];
$map(node.childNodes,
function(e) {
if(e.id!=null && e.id!="") {
base.push(e);
}
$R.iterate(e);
return null;
}
);
}
$R.select = function(s) {
if(this.cache["*"]==null) {
this.cache["*"] = [];
$R.iterate(document.body);
}
if(this.cache[s]==null) {
var regexp = s.replace(/\./g,"\\.").replace(/\*/g,".*");
this.cache[s] = $filter(this.cache["*"],
function(e) {
return e.id.search(regexp)==0;
}
);
}
return this.cache[s];
};
$R.create = function(p,t,s) {
if($(s)!=null) return 0;
var e = $(p);
if(e==null) return 0;
var n = document.createElement(t);
if(n==null) return 0;
n.id = s;
e.appendChild(n);
this.clear();
return 1;
}
$R.remove = function(s) {
var e = $(s);
if(e==null) return 0;
var p = e.parentNode;
p.removeChild(e);
this.clear();
return 1;
}
$R.table = function(p,h,w,s) {
var d = arguments[4];
var ts = s+"~";
if($(p)==null) return 0;
if($(s)!=null) return 0;
if($(ts)!=null) return 0;
if($$(s+'.*').lendth > 0) return 0;
$(p).innerHTML = "";
var r = this.create(p,"table",ts);
var t = $(ts);
t.setAttribute("cellPadding","0");
t.setAttribute("cellSpacing","0");
t.setAttribute("border","0");
r += this.create(ts,"tbody",s);
var i,j;
for(j=0;j<h;j++) {
var tr = s+"."+j;
r += this.create(s,"tr",tr);
for(i=0;i<w;i++) {
var td = tr+"."+i;
r += this.create(tr,"td",td);
if(d!=null) $_(td,d);
else $_(td,"&nbsp;");
}
}
return r;
}
$R.thread = function(obj) {
var m = this.threads.length;
this.threads[m] = {o:obj,c:[],a:0,p:1};
return m;
}
$R.stop = function() {
if(this.started!=0) {
clearInterval(this.started);
this.started = 0;
}
}
$R.start = function() {
// optional percentage
var p = arguments[0];
if(p==null) p=16; // 0.8 duty
else p=p/5; // for 20 ms
this.stop();
var sf = "";
for(var t in this.threads) {
sf += "var t"+t+"=$R.threads["+t+"];if(t"+t+".f) t"+t+".a=t"+t+".f(t"+t+".o);";
}
sf += "var t=+new Date;while(+ new Date-t<"+p+"){";
var i,j=0;
while(j<100) {
for(var t in this.threads) {
for(i=0;i<this.threads[t].p;i++) {
sf += "t"+t+".a=t"+t+".c[t"+t+".a](t"+t+".o);";
j++;
}
}
}
sf += "}";
this.started = setInterval(new Function(sf),20);
}
// $R.grid - initialize RobbyVM and create screen for it
// s - id of the element where we will add a table
// w - width of the table (number of columns)
// h - height of the table (number of rows)
// f - handler for mouse clicks
// fs (opt) - handler for selected areas
$R.init = function(s,w,h,f) {
$R.grid = function(s,w,h,f) {
var fs = arguments[4];
if(fs) {
this.areaf = fs;
}
// 0x00 - NOP
this.cache["x00"] = function(r) {
this.opcache["x00"] = function(r) {
return ++r.regs[13];
};
// 0x33 - RET
this.cache["x33"] = function(r) {
this.opcache["x33"] = function(r) {
if(r.regs[15]<=0) {
r.regs[13] = r.code.length-1;
} else {
......@@ -73,28 +317,23 @@ $R.init = function(s,w,h,f) {
}
return r.regs[13];
};
// 0x34 - STEP
this.cache["x34"] = function(r) {
this.opcache["x34"] = function(r) {
alert("STEP is not supported!");
return ++r.regs[13];
};
// 0x35 - LEFT
this.cache["x35"] = function(r) {
this.opcache["x35"] = function(r) {
alert("LEFT is not supported!");
return ++r.regs[13];
};
// 0x36 - RIGHT
this.cache["x36"] = function(r) {
this.opcache["x36"] = function(r) {
alert("RIGHT is not supported!");
return ++r.regs[13];
};
// 0x3B - SPY
this.cache["x3B"] = function(r) {
this.opcache["x3B"] = function(r) {
alert("SPY is not supported!");
return ++r.regs[13];
};
// 0x63 - POP
this.cache["x63"] = function(r) {
this.opcache["x63"] = function(r) {
var v = 0;
if(r.regs[15]>0) {
v = r.regs[256-(r.regs[15]--)];
......@@ -102,20 +341,17 @@ $R.init = function(s,w,h,f) {
regs[14] = v;
return ++r.regs[13];
};
// 0x73 - PUSH
this.cache["x73"] = function(r) {
this.opcache["x73"] = function(r) {
r.regs[256-(++r.regs[15])] = r.regs[14];
return ++r.regs[13];
}
// 0xFF - END
this.cache["xFF"] = function(r) {
this.opcache["xFF"] = function(r) {
r.regs[15] = -1;
return r.regs[13];
};
// create table
var r = $W.table(s,h,w,this.table,"<img src=" + this.prefix + "0000.gif>");
var r = $R.table(s,h,w,this.table_prefix,"<img src=" + this.prefix + "0000.gif>");
if(r > 0) {
$map($$($R.table+'.*.*'),function(e){
$map($$(this.table_prefix+'.*.*'),function(e){
var a = e.id.split('.');
e.onclick = function(){f(parseInt(a[2]),parseInt(a[1]))};
e.setAttribute("param0","0");
......@@ -127,6 +363,7 @@ $R.init = function(s,w,h,f) {
// $R.add - add robot to the list of robots
// o - robot object or JSON-string of the robot
$R.add = function(o) {
var ro = o;
if(typeof o == 'string') {
......@@ -136,15 +373,15 @@ $R.add = function(o) {
var i,j,j2,k,k2,l,n,v,h,t1,t2;
this.qindex[m] = this.queue.length;
ro.regs[9] = m;
var t = $W.thread(o);
var t = $R.thread(o);
var f = function(r) {
alert("Unexpected jump to 0x"+r.regs[13].toString(16));
return r.code.length-1;
}
for(i=0;i<ro.code.length;i++) {
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
}
$W.threads[t].f = function(r) {
this.threads[t].f = function(r) {
if(r.regs[9]==1) {
$R.gtime++;
}
......@@ -178,23 +415,21 @@ $R.add = function(o) {
i = 0;
while(1) {
switch(ro.code[i]) {
// DEF arr[n] - just skip (no check)
case 0x01:
h = hh(ro.code,i,5);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
f = new Function("r","r.regs[13]+=5;return r.regs[13];");
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i += 4;
break;
// DEF arr[n] = {...} - store values
case 0x02:
j = ro.code[i+5]+(ro.code[i+6]<<8);
k = j + j + 7;
h = hh(ro.code,i,k);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "r.regs[13]+="+k+";";
n = ro.code[i+1]+(ro.code[i+2]<<8);
......@@ -208,12 +443,11 @@ $R.add = function(o) {
}
sss += "return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i += k-1;
break;
// M1=M2
case 0x20:
n = i + 1;
t1 = ro.code[n++];
......@@ -238,7 +472,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "$R.write(r";
if(t1==0 || t1==1) {
......@@ -255,12 +489,11 @@ $R.add = function(o) {
}
sss += "r.regs[13]+="+l+";return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// SAY "..."
case 0x37:
n = i + 1;
l = 2;
......@@ -270,15 +503,14 @@ $R.add = function(o) {
l++;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
f = new Function("r","alert(\""+sss+"\");r.regs[13]+="+l+";return r.regs[13];");
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// PRINT m
case 0x38:
n = i + 1;
t1 = ro.code[n++];
......@@ -293,7 +525,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "var t";
if(t1==0) {
......@@ -307,115 +539,113 @@ $R.add = function(o) {
sss += "alert(\"[#\"+$hex(r.regs[13],4)+\"] #\"+$hex(h,4)+\" (\"+t+\")\");";
sss += "r.regs[13]+="+l+";return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// DUMP b1 b2
case 0x3F:
t1 = ro.code[i+1];
t2 = ro.code[i+2];
h = hh(ro.code,i,3);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "var i,s=\"\";for(i="+t1+";i<"+r.varm+";i++){s+=\" \"+$hex(r.vars[i],4);if(((i-"+t1+")%"+t2+")=="+t2+"-1){ss+=\"\\n\";}}";
sss += "alert(s);r.regs[13]+=3;return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
i += 2;
break;
// var=expression
case 0x40:
l = ro.code[i+1] + 2;
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "var t,s=256-r.regs[15];";
n = i + 2;
go = 1;
while(go) {
switch(ro.code[n]) {
case 0x80: // AND
case 0x80:
sss += "r.regs[s+1]=(r.regs[s+1]&&r.regs[s])?1:0;s++;";
break;
case 0x81: // OR
case 0x81:
sss += "r.regs[s+1]=(r.regs[s+1]||r.regs[s])?1:0;s++;";
break;
case 0x90: // EQ
case 0x90:
sss += "r.regs[s+1]=(r.regs[s+1]==r.regs[s])?1:0;s++;";
break;
case 0x91: // NEQ
case 0x91:
sss += "r.regs[s+1]=(r.regs[s+1]!=r.regs[s])?1:0;s++;";
break;
case 0x92: // GT
case 0x92:
sss += "r.regs[s+1]=(r.regs[s+1]>r.regs[s])?1:0;s++;";
break;
case 0x93: // LT
case 0x93:
sss += "r.regs[s+1]=(r.regs[s+1]<r.regs[s])?1:0;s++;";
break;
case 0x94: // GTEQ
case 0x94:
sss += "r.regs[s+1]=(r.regs[s+1]>=r.regs[s])?1:0;s++;";
break;
case 0x95: // LTEQ
case 0x95:
sss += "r.regs[s+1]=(r.regs[s+1]<=r.regs[s])?1:0;s++;";
break;
case 0xA0: // ADD
case 0xA0:
sss += "r.regs[s+1]=r.regs[s+1]+r.regs[s];s++;";
break;
case 0xA1: // SUB
case 0xA1:
sss += "r.regs[s+1]=r.regs[s+1]-r.regs[s];s++;";
break;
case 0xB0: // MUL
case 0xB0:
sss += "r.regs[s+1]=r.regs[s+1]*r.regs[s];s++;";
break;
case 0xB1: // DIV
case 0xB1:
sss += "r.regs[s+1]=Math.floor(r.regs[s+1]/r.regs[s]);s++;";
break;
case 0xB2: // MOD
case 0xB2:
sss += "r.regs[s+1]=r.regs[s+1]%r.regs[s];s++;";
break;
case 0xC0: // BAND
case 0xC0:
sss += "r.regs[s+1]=r.regs[s+1]&r.regs[s];s++;";
break
case 0xC1: // BOR
case 0xC1:
sss += "r.regs[s+1]=r.regs[s+1]|r.regs[s];s++;";
break;
case 0xC2: // XOR
case 0xC2:
sss += "r.regs[s+1]=r.regs[s+1]^r.regs[s];s++;";
break;
case 0xD0: // SHR
case 0xD0:
sss += "r.regs[s+1]=r.regs[s+1]>>r.regs[s];s++;";
break;
case 0xD1: // SHL
case 0xD1:
sss += "r.regs[s+1]=r.regs[s+1]<<r.regs[s];s++;";
break;
case 0xE0: // NEG
case 0xE0:
sss += "r.regs[s]=-r.regs[s];";
break;
case 0xE1: // INV
case 0xE1:
sss += "r.regs[s]=~r.regs[s];";
break;
case 0xE2: // NOT
case 0xE2:
sss += "r.regs[s]=r.regs[s]?0:1;";
break;
case 0xF0: // IFE
case 0xF0:
sss += "if(r.regs[s+2]){r.regs[s+2]=r.regs[s+1];}else{r.regs[s+2]=r.regs[s];}s+=2;";
break;
case 0xF1: // DUP
case 0xF1:
sss += "s--;r.regs[s]=r.regs[s+1];";
break;
case 0xF2: // ROL
case 0xF2:
sss += "t=r.regs[s];r.regs[s]=r.regs[s+1];r.regs[s+1]=t;";
break;
case 0xF3: // LOAD
case 0xF3:
sss += "r.regs[s]=$R.read(r,r.regs[s]);"
break;
case 0xF4: // SAVE
case 0xF4:
sss += "t=r.regs[s];$R.write(r,r.regs[s+1],t);s+=2;$R.write(r,0xFF0E,t);$R.write(r,0xFF1E,t>>16);";
break;
case 0xF5: // PUSH w
case 0xF5:
k = ro.code[n+1]+(ro.code[n+2]<<8);
if(k>=0x8000) {
k -= 0x10000;
......@@ -423,24 +653,22 @@ $R.add = function(o) {
sss += "r.regs[--s]="+k+";";
n+=2;
break;
case 0xF6: // INDEX
case 0xF6:
sss += "r.regs[s+1]=$R.index(r,r.regs[s+1],r.regs[s],1);s++;";
break;
default:
alert("Invalid long expression at 0x"+i.toString(16));
go = 0;
}
// alert("n="+n+" l="+l);
if(++n-i>=l) break;
}
sss += "r.regs[13]+="+l+";return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i += l - 1;
break;
// IFY M1 M2
case 0x41:
n = i + 1;
t1 = ro.code[n++];
......@@ -465,7 +693,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "r.regs[13]+="+l+";if";
if(t1==0) {
......@@ -485,12 +713,11 @@ $R.add = function(o) {
}
sss += "return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// IFN M1 M2
case 0x42:
n = i + 1;
t1 = ro.code[n++];
......@@ -515,7 +742,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "r.regs[13]+="+l+";if";
if(t1==0) {
......@@ -535,12 +762,11 @@ $R.add = function(o) {
}
sss += "return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// GOTO m
case 0x43:
n = i + 1;
t1 = ro.code[n++];
......@@ -555,7 +781,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "r.regs[13]";
if(t1==0) {
......@@ -567,12 +793,11 @@ $R.add = function(o) {
}
sss += "return r.regs[13];";
f = new Function("r",sss);
this.cache[h] = f;
this.opcache[h] = f;
}
$W.threads[t].c[i] = f;
this.threads[t].c[i] = f;
i = n - 1;
break;
// CALL m
case 0x44:
n = i + 1;
t1 = ro.code[n++];
......@@ -587,7 +812,7 @@ $R.add = function(o) {
l+=2;
}
h = hh(ro.code,i,l);
f = this.cache[h];
f = this.opcache[h];
if(f==null) {
sss = "r.regs[256-(++r.regs[15])]=r.regs[13]+"+l+";r.regs[13]";