mirror of https://github.com/svaarala/duktape.git
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.
204 lines
7.4 KiB
204 lines
7.4 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.
|
|
*/
|
|
|
|
// Minimal console object.
|
|
var DUKWEB_CONSOLE_INIT =
|
|
'Dukweb.console = (function () {\n' +
|
|
' var useProxyWrapper = true;\n' +
|
|
' var c = {};\n' +
|
|
' function console_log(args, errName) {\n' +
|
|
' var msg = Array.prototype.map.call(args, function (v) {\n' +
|
|
' if (typeof v === "object" && v !== null) { return console.format(v); };\n' +
|
|
' return v;\n' +
|
|
' }).join(" ");\n' +
|
|
' if (errName) {\n' +
|
|
' var err = new Error(msg);\n' +
|
|
' err.name = "Trace";\n' +
|
|
' Dukweb.print(err.stack || err);\n' +
|
|
' } else {\n' +
|
|
' Dukweb.print(msg);\n' +
|
|
' }\n' +
|
|
' };\n' +
|
|
' c.format = function format(v) { try { return Duktape.enc("jx", v); } catch (e) { return String(v); } };\n' +
|
|
' c.assert = function assert(v) {\n' +
|
|
' if (arguments[0]) { return; }\n' +
|
|
' console_log(arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [ "false == true" ], "AssertionError");\n' +
|
|
' };\n'+
|
|
' c.log = function log() { console_log(arguments, null); };\n' +
|
|
' c.debug = function debug() { console_log(arguments, null); };\n' +
|
|
' c.trace = function trace() { console_log(arguments, "Trace"); };\n' +
|
|
' c.info = function info() { console_log(arguments, null); };\n' +
|
|
' c.warn = function warn() { console_log(arguments, null); };\n' +
|
|
' c.error = function error() { console_log(arguments, "Error"); };\n' +
|
|
' c.exception = function exception() { console_log(arguments, "Error"); };\n' +
|
|
' c.dir = function dir() { console_log(arguments, null); };\n' +
|
|
' if (typeof Proxy === "function" && useProxyWrapper) {\n' +
|
|
' var orig = c;\n' +
|
|
' var dummy = function () {};\n' +
|
|
' c = new Proxy(orig, {\n' +
|
|
' get: function (targ, key, recv) {\n' +
|
|
' var v = targ[key];\n' +
|
|
' return typeof v === "function" ? v : dummy;\n' +
|
|
' }\n' +
|
|
' });\n' +
|
|
' }\n' +
|
|
' return c;\n' +
|
|
'})();';
|
|
|
|
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(DUKWEB_CONSOLE_INIT);
|
|
Duktape.eval('print = Dukweb.print;');
|
|
Duktape.eval('alert = Dukweb.print;'); // intentionally bound to print()
|
|
Duktape.eval('console = Dukweb.console;');
|
|
|
|
Duktape.initSuccess = !!Duktape.dukweb_is_open();
|
|
//console.log('=== ' + Duktape.eval('Duktape.enc("jx", { env: Duktape.env, version: Duktape.version })') + ' ===');
|
|
|