[Tech Note] Toll-free bridges between JavaScript and RPL

General Discussions about the API

[Tech Note] Toll-free bridges between JavaScript and RPL

Postby oliver » Sat Jan 01, 2011 5:22 pm

In MorphEngine-based calculators, JavaScript and RPL are bridged toll-free: they can call each other with no declarative syntax required, even though this is one language talking to another.

JavaScript can call on RPL programs as if they were JavaScript functions. Likewise, RPL programs can use JavaScript functions as if they were RPL commands.
This is true both for user functions and programs (written and defined in a "folder") and "built-in" functions and programs (both those shipping with MorphEngine, and those injected by an extension).

For example:
Code: Select all
<< 1.0 myFunction >>

will invoke myFunction, and there's no telling if myFunction is a built-in or user JavaScript function or RPL program.
The same goes for
Code: Select all
function() { return myFunction(1.0); }


This tech note examines how this is accomplished "under the hood".

The execution environment of MorphEngine is JavaScript. There is a stack implemented as a native JavaScript array.

RPL programs are interpreted by a byte-code compiler and runner written in JavaScript.
Every RPL program has a JavaScript wrapper function which makes it accessible to JavaScript. The wrapper does two things: it places any given arguments on the stack, and then invokes the interpreter on the associated RPL program.
JavaScript's special "arguments" function variable enables the var-arg aspect of this functionality.
Something like "myFunction(1, 2, 3);" becomes equivalent to evaluating << 1 2 3 myFunction >>, if myFunction is an RPL program. (If myFunction is a JavaScript function, this same syntax is a normal function call.)
The interpreter has a very low start-up latency. You can start it several thousand times per second. That is, calling RPL code from JavaScript is viable, even in an inner loop.

In the opposite direction, the RPL interpreter indirectly calls on JavaScript functions through the stack-oriented calculator.push() function, which accepts data and commands. If the push function is given a function name, it uses quick object hash look-ups (via "in" operator) on its function collection objects (one per type, one for each blended-in folder) to identify the function, followed by JavaScript function introspection to determine the number of args the function takes. It then pulls that many arguments from the stack and calls the function with them.
Hence, something like << 1 2 3 myFunction >> becomes a function call "myFunction(1, 2, 3)", if myFunction is a JavaScript function. The interpreter itself is thereby unconcerned what type of command or function a given name is. The intelligence resides in the same function, push, that is also used in the normal RPN operation of the calculator.

Conclusion: toll-free bridges enable cross-language calls without declarative overhead. The implementation is efficient and enabled through special JavaScript language features.


Traditional RPL note: an upshot of the described mechanism is that MorphEngine can relax the restrictions traditionally placed around RPL programs vs. "RPL user functions". Only latter were traditionally suitable sources for operations that expected a knowable number of arguments as input or output. For example, you could not graph any RPL program or use it in an expression, only the subset of RPL programs known as "user functions", which start with a declaration of local variables (per \-> operator) to be pulled from the stack. In MorphEngine, any RPL program will work in these situations. An over- or under-supply of arguments will be appropriately reflected by the stack.
oliver
Site Admin
 
Posts: 433
Joined: Sat May 01, 2010 2:11 pm

Return to General

Who is online

Users browsing this forum: No registered users and 1 guest

cron