You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

158 lines
5.2 KiB

/*
* Dukweb glue appended to Emscripten-generated dukweb.js code.
*
* Sets up a 'Duktape' object accessible from web page Javascript. 'Duktape'
* provides various glue functions, the most important being Duktape.eval()
* which evaluates a string inside Duktape and returns the result. Currently
* Duktape.eval() is limited to JSON compatible results (other values are
* coerced in whichever way).
*
* https://github.com/kripken/emscripten/wiki/Interacting-with-code
*/
var Duktape = {};
/*
* Utilities
*/
Duktape.log = function() {};
if (typeof console === 'object' && typeof console.log === 'function') {
Duktape.log = function() {
console.log.apply(console, arguments);
}
} else if (typeof print === 'function') {
Duktape.log = function() {
print.apply(this, arguments);
}
}
Duktape.log('Duktape (dukweb) initializing');
Duktape.logOwnProperties = function() {
Duktape.log('Own properties of Duktape:');
Object.getOwnPropertyNames(Duktape).forEach(function (k) {
var v = Duktape[k];
if (typeof v === 'function') { v = '[omitted]'; }
Duktape.log(' ' + k + ' = (' + typeof Duktape[k] + ') ' + String(v));
});
}
Duktape.hexVal = function(x, ndigits) {
var nybbles = '0123456789abcdef';
var i;
var res = ''
for (i = 0; i < ndigits; i++) {
res += nybbles[x & 0x0f];
x >>>= 4;
}
return res;
};
Duktape.escapeTable = (function() {
var i, n;
var res = {};
for (i = 0; i < 256; i++) {
if (i < 0x20 || i > 0x7e || i == 0x27 /*apos*/ || i == 0x22 /*quot*/ ||
i == 0x5c /*backslash*/) {
res[String.fromCharCode(i)] = '\\u' + Duktape.hexVal(i, 4);
} else {
res[String.fromCharCode(i)] = String.fromCharCode(i);
}
}
return res;
})();
// Probably unnecessary, JSON.stringify() escapes strings nicely.
Duktape.escapeString = function(x) {
var res = [];
var i, n = x.length;
var c;
var esc = Duktape.escapeTable;
for (i = 0; i < n; i++) {
c = x.charAt(i);
res.push(esc[c] || '\\u' + Duktape.hexVal(String.charCodeAt(i)));
}
return res.join('');
}
/*
* Raw C function bindings.
*
* The dukweb_eval() binding is a very raw binding which provides an
* interface to eval one string, and to get one string output (ToString
* coerced result or error).
*/
// FIXME: not sure about the memory use here (leaks?), check
Duktape.dukweb_is_open = Module.cwrap('dukweb_is_open', 'number', [ ]);
Duktape.dukweb_open = Module.cwrap('dukweb_open', 'void', [ ]);
Duktape.dukweb_close = Module.cwrap('dukweb_close', 'void', [ ]);
Duktape.dukweb_eval = Module.cwrap('dukweb_eval', 'string', [ 'string' ]);
Duktape.logOwnProperties();
/*
* Duktape.eval: run code inside Duktape, encode output value using JSON.
*/
// FIXME: errors should probably be promoted to work better
Duktape.eval = function(code) {
// Code escape into a Javascript string
var escapedString = JSON.stringify(String(code));
//var escapedString = '"' + Duktape.escapeString(code) + '"';
// The raw eval result is first JSON encoded to make it a string.
// For unsupported types JSON.stringify() might return e.g. 'undefined'.
var res = Duktape.dukweb_eval(
'(function() { var t; try { ' +
't = eval(' + escapedString + ');' +
'return JSON.stringify(t) || "\\"undefined\\"";' +
'} catch (e) { ' +
'return "ERROR: " + String(e); ' +
'} })();'
);
Duktape.log('raw eval result: ' + typeof(res) + ': ' + String(res));
return JSON.parse(res);
};
/*
* Handlers for Duktape's print() and alert() replacements.
*/
// Expect web page to override this, e.g. to append to some buffer.
Duktape.printHandler = function(msg) {
log(msg);
}
// Expect web page to override this, e.g. to use browser alert().
Duktape.alertHandler = function(msg) {
log(msg);
}
/*
* Initialize Duktape heap automatically (not closed for now), and use
* Duktape.eval() to pull in some convenience properties like Duktape
* version.
*/
Duktape.dukweb_open();
Duktape.version = Duktape.eval('Duktape.version');
Duktape.env = Duktape.eval('Duktape.env');
Duktape.logOwnProperties();
/*
* Initialize a 'Dukweb' instance inside Duktape for interfacing with the
* browser side.
*/
Duktape.eval('Dukweb = {};');
Duktape.eval('Dukweb.userAgent = ' + (JSON.stringify(navigator.userAgent.toString()) || '"unknown"') + ';');
Duktape.eval('Dukweb.emscripten_run_script = this.emscripten_run_script; delete this.emscripten_run_script;');
Duktape.eval('Dukweb.eval = Dukweb.emscripten_run_script;') // FIXME: better binding
Duktape.eval('Dukweb.print = function() { Dukweb.eval("Duktape.printHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };');
Duktape.eval('Dukweb.alert = function() { Dukweb.eval("Duktape.alertHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };');
Duktape.eval('print = Dukweb.print;');
Duktape.eval('alert = Dukweb.print;'); // intentionally bound to print()
Duktape.initSuccess = !!Duktape.dukweb_is_open();
//console.log('=== ' + Duktape.eval('Duktape.enc("jx", { env: Duktape.env, version: Duktape.version })') + ' ===');