Interfacing EWB with Tricky JavaScript
by Erick Engelke
September 29, 204
I had an epiphany when I was thinking about how to solve my Nice Re-compiler challenges. That lead to this simplifed method described in this article.
I know of four ways to interface EWB with JavaScript.
Methods to Interface With JavaScript
Method | Upside | Downside |
---|---|---|
TScript / external fns/variables in JavaScript files |
Easiest to understand, well documented by Elevate |
Run into limitations including having to wait for libraries to load. |
call JavaScript through CreateObject() |
inline, doesn’t need to load external libraries |
often awkward, also local vars not accessible, compressed EWB files add challenges with renaming of variables and functions |
Nice recompiler |
can nicely mix EWB + JavaScript |
There is a bug in EWB’s compiler with Variants that makes it awkward. Also, Compressed functions can make more complicated. |
Dynamic Functions (the topic of this blog article) |
solves most of above problems |
interface code must be written in pure JavaScript. |
What do I mean by Dynamic Functions?
JavaScript allows you to replace a function in real-time while a program is running.
I will give the example of a JavaScript debugger where you can set a breakpoint in your code. Note, for this to work you must be using an HTML5 compatible browser (Edge, Chrome, Firefox, Safari, etc.) and have the JavaScript debug window open for the breakpoint to show.
You take the following steps.
Steps to Create Dynamic Functions
Name | Example |
---|---|
Define Type of your new function or procedure |
Type |
Declare variable to hold that new function or procedure. |
var |
Implement code to "compile" your new JavaScript function. It can process local-to-it varibles and can also access global EXTERNAL variables (since externals will not be renamted during compressed compiles). |
procedure InstallQuickDebugger; |
Call the installation function first |
InstallQuickDebugger(); |
Call the new function/procedure when needed |
quickdebugger('some title'); |
Example In Code
Here’s the same code laid out in a program:
type
TQuickDebugger = procedure( title : string );
var
quickdebugger : TQuickDebugger;
procedure InstallQuickDebugger;
begin
if not assigned( quickdebugger ) then
quickdebugger := TQuickDebugger( variant(CreateObject('function(title) { window.alert("Debug: " + title ); debugger; }')) );
end;
procedure TForm1.Form1Show(Sender: TObject);
var
v : variant;
tproc3 : TTestProc3 ;
tfn3 : TTestfn3;
begin
InstallQuickDebugger;
quickdebugger( 'startup code' );
...
When using this function, the browser will pop up the message: Debug: startup code
and if you have JavaScript debugger enabled, will show something like
Press single step twice, and you will sit nicely after the code point your placed your breakpoint.
:
Creating Stubs
Pascal has many benefits for most of your program, such as its strong type checking that finds errors before run-time, and the namespaces which allow cleaner separation of variable names.
Where this method shines is calling library or browser functions that cannot be done easily in EWB.
I recommend doing as little in pure JavaScript as possible. Intead, create short stubs that just pop into JavaScript for the bare minumum, and do all the real workload in Object Pascal.
Using Overloaded Functions
If you know the variable types of the parameters you are passing, by all means, delcare your function declaration with those types.
But many Javascript functions take naked variables (could be Pascal string, integer, double, function, etc.).
If it will take multiple types, you have two choices. You can:
Solution | Advantage | Disadvantage |
---|---|---|
declare overloaded functions for each supported type |
EWB will enforce the types correctly |
|
use variant |
Faster to write |
will allow you to call with unsupported types |
See the notes below on variant issues…
Obscure
Note: at present there are some very obscure bugs (in my opinion) in EWB’s Object Pascal compiler relating to variants;
If you declare: var external fn : TProcedure; variant v;
v := fn;
the generated code is: v = fn();
whereas it should be v = fn;
Also, you cannot assign functions or procedures without first declaring and using a pointer to that function, whereas you should be able to do so.
Post Analysis and Actual Solution….
After doing all that work, I had a second epiphany, all this work was started when I wanted to create a function which called JavaScript:
debugger;
After it was all done and published, I suddenly realized had been thinking too hard. I could accomplish this with a variable declaration and a simple statement;
var
external debugger ; integer;
procedure test;
begin
debugger ;
// code to debug
....
And it works.
Erick