Published 2007-07-31 23:08:00

Add one feature, and create a few bugs.. seems like it's always the way..

The two features added over the weekend where class syntax support and include support. My initial effort proved to be a little off the mark.

Read on if you want to know the nitty gritty details about writing an interperted language runtime... Along with a list of the Gtk binding improvements..


Class support
This is implemented by re-writing the code a little before it's turned into the AST. effectively changing

class A.X extend B.Y {
var a;
function A() {}
function C() {}
}

Into

A.X = function () {}
(function() {
foreach(i in B.Y.prototype)
{ A.prototype[i] = B.prototype[i];
}
).call())
A.X.prototype.a = false;
A.X.prototype.C = function() {}

While testing this with a real application I kept throwing up an message like "error getting Object on Undefined". - Which was not very helpfull. The reality was that often I mistyped the class name B.Y or A.X. But given the line numbering was not accurate (see later) and the message was not helpful, tracking down the problem proved quite difficult.

One cure to this problem lay in introducing Warnings - when a variable is looked up and not found, in Javascript it's type is "undefined" - So I added warnings in the interpreter to Flag up when that happened and show the line and the variable name that was missing.

Now the only snag was that sometimes variables are supposed to be undefined (like when you call a function with fewer arguments than are defined in the definition). Then try to check if they had been given
eg.
function A(v1, v2, v3) {
v3 = typeof(v3) == "undefined" ? false : v3;
....

So basically typeof() needed to silence those errors. The solution to this was to add an extra opcode. IRwarningHide(int). This was set to 1 before an typeof() call fetched the variables in the argument, and set to 0 after completion. I guess this could be used to set other runtime flags - and renamed to something more general.

Include support

Originally I'm sure I read in the Javascript 2 specification that the include would load and execute the code when it encountered an include statement. After reading the ecma4 spec, it is clear that include basically imports the code in the external file exactly into the location where the import statement is. - and executes during the execution phase of the script.

Note, this means that if you have to be careful about where you include files as Class definitions which are built ontop of other Classes (eg. a.b.c.d etc.) have to be created after they are defined.
eg.
class MyClass {
....
}

include "MyClassSubs.js";
>>>
>>> class MyClass.test { ..... }
>>>

If the include statement goes before 'class MyClass', then MyClass will not exist when the interperter tries to create MyClass.test.

Without getting alot cleverer with the FunctionDefintion process, this probably will not be solved soon. (it's not a big problem...)


There turned out to be a number of other issues with include process - First off was the fact that I had to work out how the code should deal with filenames. When compiling the AST into IRcodes, dmdscript combines the opcode with the line number into 4 bytes (a uint). The actual opcode only uses 1 byte (actually there are really only about 90 opcodes) there is 1 byte of padding and 2 bytes that store the line number.

Normally dmdscript had assumed that you just combined all the code together into one big file, and linenumbers where just offset's of the last line. (or in the case of my initial include implementation) started at 1 for each file.

So when an error got reported at runtime, the opcode executer just spat out the line number of the code that failed but had no idea in which file it came from. To fix this, involved keeping a small file registry and using the high bytes of the linenumber to store the file ID during compilation. and using the padding byte to store the file number in the IR opcodes.

Obviously this has a slight snag in the fact you can only have 255 files included. and each file can have at most 65535 lines. (It' would probably not take too much to fix this.. - just modify the
'combine' method in irstate.d and fix the struct in opcodes)

The other change that had to be made was passing the instance of the program being compiled to the Parser and lexer, so that they could register the classes when the come across include statements. As dmdscript is designed to be thread safe, And the program is only registered after it has succesfully compiled.

Scoping fixes

I spent quite a while trying to solve a simple scoping bug with nested functions. And I'm still not sure how reliable the fix is.

This is the problem:

function A() {
var c = "fred";
function d() {
println("c is " + c);
}
d();
}
A();

Should just print "c is fred", however, since a normal function definiton hides the outside scope (except globals). This was failing. I ended up flagging this type of locally defined functions. Then when scope is created during the Call() method, copying all of the inherited scope, rather than just the root scope. - I still think this needs more looking at, but the kludge works for the time being with simple nested functions.

Killer debugging

Even with all the improvements with error reporting on includes, there where still times when I was testing when the program would just segfault. (and before I sorted the line numbers out, I needed a way to work out what was going on - so I could understand the flow). The fun thing I found was print() method in the opcodes.d file. Which dumps an opcode and arugments to a readable string. By adding a conditional call in the opcode run loop to call this I can now do opcode level logging. Just run any of the cli versions of the code with the "-d" option. You can see the file, line number of the all the executed opcodes. making it simple to spot where things go wrong.

At present it also dumps the all tokens, top level Statements as the AST sees them, and opcode runtime. (probably needs a bit of fine tuning..)

Gtk Updates
On the gtk bindings I've been fine tuning some of the method calls,
  • TreeStore constructor now accepts array of types as an argument, as well as the previous varargs style. along with that it accepts an object (to do casting from DataStores).
  • Gobject.setProperty() works and autoconverts your types into G.Types (although I should check if you actually do try and send it a G.Type..)
  • Combobox constructor has a optional constructor flag (it should documented in the manual as a note)
  • menuItem with Mnemonic now works correctly.
  • Toolbarbuttons with stock icons work nicely.
  • G.Types integers are now exported into Javascript.
  • all the stock icons are parsed from the documentation and exported Gtk.Stock.*
  • Gdk.Pixbuf.getType() works.
  • Gdk.Color() constructor works with single 0xFFFFCCCCFFFF and 0xFFFF, 0xCCCC , 0xFFFF values.



Mentioned By:
google.com : april (92 referals)
google.com : december (53 referals)
www.planet-php.net : Planet PHP (14 referals)
google.com : before statement in php with xul (13 referals)
google.com : gtkds (10 referals)
planet.dprogramming.com : Planet D (5 referals)
www.debian.org.hk : Planet DebianHK | Debian HK (3 referals)
www.loadaveragezero.com : dnews: Web Developer RSS News Feeds [Headlines from Planet PHP: Daily News] - loadaverageZero (2 referals)
google.com : php include external class (2 referals)
google.com : php opcode execute function (2 referals)
google.com : test compatibilité php4 vers php5 (2 referals)
www.hanrss.com : 한RSS (1 referals)
www.att.net : AT&T - Web Search (1 referals)
planet-php.org : Planet PHP (1 referals)
google.com : .net opcode call "setproperty" (1 referals)
google.com : aciphex (1 referals)
google.com : ativan (1 referals)
google.com : ax prototype (1 referals)
google.com : before missing statement in php with xul (1 referals)
google.com : before statement in php with xul (1 referals)

Add Your Comment