var obj = {f: undefined};
var f = function() { obj.f(); };
var g = function(fn) { return fn(); };
g(f);
Compiles to something like:
var obj = {f: undefined};
var f = function f(_k2, _address134) {
return _k2(obj.f());
};
var g = function g(_k1, _address135, fn) {
return fn(_k1, _address135.concat('_130')); // source of call to fn: line 3, col 30
};
g(_k0, ''.concat('_131'), f); // source of call to g: line 4, col 0
While extending the address at call expressions, we can build a map from address fragments back to the original location of the call expression we're at:
{
_130: {line: 3, col: 30},
_131: {line: 4, col: 0}
}
When obj.f()
raises an exception, the 'current address' (i.e. the value of _address134
in this case) will be '_131_130'
.
We can look up each fragment in our map, and use the line/col numbers to grab the relevant part of the original source code to give something like:
fn() | line 3, col 30
g(f) | line 4, col 0
This is useful, but it doesn't tell us that the error occurred on line 2 of the original program.