I thought about the required work for bootstrapping Photon with OMeta and decided to find the operations needed in the compiler. I did a static analysis to find them and their frequency in the source code.
For those interested, the OMeta code is given at the end.
I apply the analysis to the following files needed for the bootstrap (I still need to make sure I do not need the other stdlib files). To give an idea of the size of each file, I list the number of lines beside it: 135 utility/debug.js 938 utility/num.js 505 utility/misc.js 141 utility/iterators.js 270 utility/arrays.js 624 stdlib/array.js 1146 stdlib/string.js 160 stdlib/function.js 194 stdlib/object.js 1302 backend/asm.js 3352 backend/x86/asm.js 180 ometa-js/lib.js 513 ometa-js/ometa-base.js 46 ometa-js/parser.js 136 ometa-js/photon-compiler.js 405 photon-lib.js 58 photon-test.js 10105 total
I get the following frequencies. I put an 'X' beside supported operations, '/' beside partially supported operations and ' ' beside not supported operations:
get: 9728 / -> need to add support for scope chain lookup string: 9194 X getp: 7179 call: 3693 X this: 3072 X var: 2545 X binop: 1863 '===': 409 X '+': 379 X '<': 204 X '-': 169 X '&&': 126 / -> need to fix semantic to only evaluate second operand when the first is true '>=': 94 '||': 93 / -> ... when the first is false '!==': 69 X '>': 52 '!=': 43 -> I am surprised to see those, I'll need to further investigate where they come from '&': 41 '<<': 32 '>>': 29 '<=': 26 '==': 21 -> idem '*': 20 / -> need to add type test '/': 18 'instanceof': 14 '%': 10 '^': 9 '|': 5 set: 1669 / -> need to add support for assignment in a parent closure/global object or a regular object number: 1548 X return: 1529 X func: 1419 / -> need to add support for closures begin: 1236 X if: 501 X arr: 261 case: 219 binding: 211 X unop: 173 '-': 64 / -> need to add type test and overflow check '!': 60 'typeof': 46 'delete': 3 postop: 148 '++': 119 '--': 29 for: 119 condExpr: 112 X throw: 98 -> need to add support for exceptions preop: 89 '++': 77 '--': 12 switch: 79 break: 73 default: 72 new: 53 json: 52 mset: 48 '+': 39 '-': 5 '>>': 2 '*': 2 while: 44 X forIn: 12 try: 12 -> need to add support for exceptions doWhile: 9 continue: 7
No support for a GC will be done at this time and the bootstrap will be done in memory.
I plan to do the following in order: 1. Add support for binop, unop, preop, postop, mset(partial), arr, for, switch/case/default, json, doWhile, continue, break (except operations requiring Constructors) -> Should be enough to compile C-like code 2. Rewrite the semantic of the object model in extended JS (< 600l of C code) 3. Add support for extension of objects and arrays 4. Add support for the global object 5. Add support for closures and scope chain 6. Add support for exceptions 7. Add support for constructors 8. Add inline cache invalidation mecanism 9. Add reuse of maps 10.Add support for variadic functions and arguments object 11.Port stdlib tachyon-specific operations to photon 12.Try bootstrap, fix bugs, add missing support, rinse, repeat (13.) Optimize get/set property and variable on the scope chain (14.) Optimize string internalization with a dictionary (15.) Optimize lookup of properties on a map with a dictionary (16.) Optimize construction of objects
Help would be appreciated, especially on steps 4-11. Those can mostly be done in parallel once 1-3 have been done. I'll be glad to explain the current system to interested people.
Erick
PS: Here is ASTFrequency Ometa analysis: ometa ASTFrequency <: PhotonASTTraversal { trans = [:t apply(t):ans] -> {self.nodes[t] = (self.nodes[t] === undefined) ? 1 : self.nodes[t] + 1; self;}, binop :op trans:x trans:y -> {if (self.ops.binop[op] === undefined) self.ops.binop[op] = 0; self.ops.binop[op] += 1;}, preop :op trans:x -> {if (self.ops.preop[op] === undefined) self.ops.preop[op] = 0; self.ops.preop[op] += 1;}, unop :op trans:x -> {if (self.ops.unop[op] === undefined) self.ops.unop[op] = 0; self.ops.unop[op] += 1;}, mset trans:lhs :op trans:rhs -> {if (self.ops.mset[op] === undefined) self.ops.mset[op] = 0; self.ops.mset[op] += 1;}, postop :op trans:x -> {if (self.ops.postop[op] === undefined) self.ops.postop[op] = 0; self.ops.postop[op] += 1;} };
ASTFrequency.initialize = function () { this.nodes = {}; this.ops = { binop:{}, preop:{}, mset:{}, unop:{}, postop:{} }; this.freqs = function () { function sorta(a, b) { return b[1] - a[1]; }
var total = 0;
for (var n in this.nodes) { total += this.nodes[n]; }
var numbers = [];
for (var n in this.nodes) { numbers.push([n, this.nodes[n]]); }
numbers.sort(sorta);
for (var i = 0; i < numbers.length; ++i) { print(numbers[i][0] + ": " + numbers[i][1]);
var n = numbers[i][0];
if (this.ops[n] !== undefined) { var op_numbers = [];
for (var op in this.ops[n]) { op_numbers.push([op, this.ops[n][op]]); }
op_numbers.sort(sorta);
for (var j = 0; j < op_numbers.length; ++j) { print(" '" + op_numbers[j][0] + "': " + op_numbers[j][1]); } } } }; };
PPS: Here is the base grammar to traverse the AST:
ometa PhotonASTTraversal { trans = [:t apply(t):ans], curlyTrans = [#begin curlyTrans:r] | [#begin trans*:rs] | trans:r,
this end, break end, continue end, number :n, string :s, arr trans*:xs, unop :op trans:x, getp trans:fd trans:x, get :x, set trans:lhs trans:rhs, mset trans:lhs :op trans:rhs, binop :op trans:x trans:y, preop :op trans:x, postop :op trans:x, return trans:x, with trans:x curlyTrans:s, if trans:cond curlyTrans:t curlyTrans:e, condExpr trans:cond trans:t trans:e, while trans:cond curlyTrans:body, doWhile curlyTrans:body trans:cond, for trans:init trans:cond trans:upd curlyTrans:body, forIn trans:x trans:arr curlyTrans:body, begin trans:x end, begin trans*:xs, func :args :scope curlyTrans:body, call trans:fn trans*:args, send :msg trans:recv trans*:args, new :cls trans*:args, var :name trans:val, throw trans:x, try curlyTrans:x :name curlyTrans:c curlyTrans:f, json trans*:props, binding :name trans:val, switch trans:x trans*:cases, case trans:x trans:y, default trans:y,
global_return trans:x, ref :s, gets trans:fd trans:x, mreturn trans:x trans:y }