1var noun = require('./noun.js'),
2 NounMap = require('./hamt.js').NounMap,
3 list = require('./list.js'),
7 MEMO = noun.dwim("memo"),
8 SLOG = noun.dwim("slog"),
9 FAST = noun.dwim("fast"),
10 SPOT = noun.dwim("spot"),
11 MEAN = noun.dwim("mean"),
12 HUNK = noun.dwim("hunk"),
13 LOSE = noun.dwim("lose");
22Block.prototype = Object.create(Statement.prototype);
23Block.prototype.constructor = Block;
25Block.prototype.append = function(st) {
26 this.statements.push(st);
29Block.prototype.toJs = function() {
30 var sts = this.statements;
31 var parts = new Array(sts.length);
32 for ( var i = 0; i < sts.length; ++i) {
33 parts[i] = sts[i].toJs();
35 return parts.join('');
38function Assignment(name, expr) {
43Assignment.prototype = Object.create(Statement.prototype);
44Assignment.prototype.constructor = Assignment;
46Assignment.prototype.toJs = function() {
47 return "var " + this.name + " = " + this.expr.toJs() + ";";
50function Expression() {
53function Cons(head, tail) {
54 Expression.call(this);
58Cons.prototype = Object.create(Expression.prototype);
59Cons.prototype.constructor = Cons;
61Cons.prototype.toJs = function() {
62 return "context.cons(" + this.head + ", " + this.tail + ")";
65function Frag(axis, name) {
66 Expression.call(this);
70Frag.prototype = Object.create(Expression.prototype);
71Frag.prototype.constructor = Frag;
73Frag.prototype.toJs = function() {
74 var parts = [this.name];
75 for ( var ax = this.axis; ax > 1; ax = ax.mas() ) {
76 parts.push( ( 2 === ax.cap().valueOf() ) ? "head" : "tail" );
78 return parts.join(".");
84Bail.prototype = Object.create(Statement.prototype);
85Bail.prototype.constructor = Bail;
87Bail.prototype.toJs = function() {
88 return "throw new Error(\"Bail\")";
91function Identity(name) {
92 Expression.call(this);
95Identity.prototype = Object.create(Expression.prototype);
96Identity.prototype.constructor = Identity;
98Identity.prototype.toJs = function() {
102function Constant(index) {
103 Expression.call(this);
106Constant.prototype = Object.create(Expression.prototype);
107Constant.prototype.constructor = Constant;
109Constant.prototype.toJs = function() {
110 return "constants[" + this.index + "]";
113function Nock(subject, formula, tail) {
114 Expression.call(this);
115 this.subject = subject;
116 this.formula = formula;
119Nock.prototype = Object.create(Expression.prototype);
120Nock.prototype.constructor = Nock;
122Nock.prototype.toJs = function() {
123 var f = this.formula;
124 var targetCode = "(" + f + ".hasOwnProperty('target') ? " + f +
125 ".target : (" + f + ".target = context.compile(" + this.formula + ")))";
127 "context.trampoline(" + targetCode + ", " + this.subject + ")" :
128 targetCode + "(" + this.subject + ")";
132 Expression.call(this);
135Deep.prototype = Object.create(Expression.prototype);
136Deep.prototype.constructor = Deep;
138Deep.prototype.toJs = function() {
139 return this.name +".deep ? context.yes : context.no";
143 Expression.call(this);
146Bump.prototype = Object.create(Expression.prototype);
147Bump.prototype.constructor = Bump;
149Bump.prototype.toJs = function() {
150 return this.name + ".bump()";
153function Same(one, two) {
154 Expression.call(this);
158Same.prototype = Object.create(Expression.prototype);
159Same.prototype.constructor = Same;
161Same.prototype.toJs = function() {
162 return "(" + this.one + ".equals(" + this.two + ")" + " ? context.yes : context.no)";
165function If(test, yes, no) {
166 Statement.call(this);
171If.prototype = Object.create(Statement.prototype);
172If.prototype.constructor = If;
174If.prototype.toJs = function() {
175 return "if(" + this.test + ".loob()){" +
176 this.yes.toJs() + "}else{" + this.no.toJs() + "}";
179function Kick(axis, core, tail) {
180 Expression.call(this)
185Kick.prototype = Object.create(Expression.prototype);
186Kick.prototype.constructor = Kick;
188Kick.prototype.toJs = function() {
189 var axis = this.axis.shortCode();
191 return "(function (cor) {" +
192 "var pro, tgt, bus, arms, bat = cor.head, has = false;" +
193 "if ( bat.hasOwnProperty('loc') && (tgt = bat.loc.jets[" + axis + "]) && bat.loc.fine(cor) ) {" +
196 "if ( bat.hasOwnProperty('arms') ) {" +
198 "has = arms.hasOwnProperty('" + axis + "');" +
200 "else arms = bat.arms = {};" +
201 "tgt = (has ? arms['" + axis + "'] : (arms['" + axis + "'] = context.compile(" +
202 new Frag(this.axis, "bat").toJs() + ")));" +
204 (this.tail ? "pro = context.trampoline(tgt, bus);" :
207 "if ( context.isTrampoline(pro) ) {" +
208 "tgt = pro.target;" +
209 "bus = pro.subject;" +
214 "})(" + this.core + ")";
217function GetMemo(name) {
218 Expression.call(this);
221GetMemo.prototype = Object.create(Expression.prototype);
222GetMemo.prototype.constructor = GetMemo;
224GetMemo.prototype.toJs = function() {
225 return "context.getMemo(" + this.name + ")";
228function PutMemo(key, val) {
229 Statement.call(this);
233PutMemo.prototype = Object.create(Statement.prototype);
234PutMemo.prototype.constructor = PutMemo;
237 Statement.call(this);
240Push.prototype = Object.create(Statement.prototype);
241Push.prototype.constructor = Push;
243Push.prototype.toJs = function() {
244 return "context.stackPush(" + this.name + ");";
248 Statement.call(this);
250Pop.prototype = Object.create(Statement.prototype);
251Pop.prototype.constructor = Pop;
253Pop.prototype.toJs = function() {
254 return "context.stackPop()";
257function Fast(clue, core) {
258 Statement.call(this);
263Fast.prototype.toJs = function() {
264 return "context.register(" + this.core + ", " + this.clue + ");";
268 Statement.call(this);
272Slog.prototype.toJs = function() {
273 return "context.slog(" + this.name + ")";
276function compile(formula, subject, product, fresh, constants, block, tail) {
277 var op, arg, one, two, odd;
278 if ( !(formula instanceof Cell )) {
279 throw new Error("invalid formula");
283 if ( op instanceof Cell ) {
286 compile(op, subject, one, fresh, constants, block, false);
287 compile(arg, subject, two, fresh, constants, block, false);
288 block.append(new Assignment(product, new Cons(one, two)));
290 else switch ( op.valueOf() ) {
293 block.append(new Bail());
295 else if ( 1 === arg ) {
296 block.append(new Identity(subject));
299 block.append(new Assignment(product, new Frag(arg, subject)));
304 block.append(new Assignment(product, new Constant(constants.length - 1)));
309 compile(arg.head, subject, one, fresh, constants, block, false);
310 compile(arg.tail, subject, two, fresh, constants, block, false);
311 block.append(new Assignment(product, new Nock(one, two, tail)));
315 compile(arg, subject, one, fresh, constants, block, false);
316 block.append(new Assignment(product, new Deep(one)));
320 compile(arg, subject, one, fresh, constants, block, false);
321 block.append(new Assignment(product, new Bump(one)));
326 compile(arg.head, subject, one, fresh, constants, block, false);
327 compile(arg.tail, subject, two, fresh, constants, block, false);
328 block.append(new Assignment(product, new Same(one, two)));
334 compile(arg.head, subject, odd, fresh, constants, block, false);
335 compile(arg.tail.head, subject, product, fresh, constants, one, tail);
336 compile(arg.tail.tail, subject, product, fresh, constants, two, tail);
337 block.append(new If(odd, one, two));
341 compile(arg.head, subject, one, fresh, constants, block, false);
342 compile(arg.tail, one, product, fresh, constants, block, tail);
347 compile(arg.head, subject, one, fresh, constants, block, false);
348 block.append(new Assignment(two, new Cons(one, subject)));
349 compile(arg.tail, two, product, fresh, constants, block, tail);
353 if ( 2 === odd.cap().valueOf() ) {
356 compile(arg.tail, subject, one, fresh, constants, block, false);
357 block.append(new Assignment(product, new Kick(two, one, tail)));
360 compile(noun.dwim([7, arg.tail, 2, [0, 1], 0, odd]),
361 subject, product, fresh, constants, block, tail);
366 if ( !(arg.head instanceof Cell) ) {
367 // no recognized static hints
368 compile(arg.tail, subject, product, fresh, constants, block, tail);
373 compile(hint.tail, subject, clu, fresh, constants, block, false);
374 if ( zep.equals(MEMO) ) {
381 block.append(new Assignment(konst, new Constant(hint.tail)));
382 block.append(new Assignment(key, new Cons(subject, konst)));
383 block.append(new Assignment(got, new GetMemo(two)));
384 block.append(new Assignment(odd, new Deep(got)));
385 one.append(new Assignment(product, new Frag(noun.dwim(3), got)));
386 compile(arg.tail, subject, product, fresh, two, false);
387 two.append(new PutMemo(key, product));
388 block.append(new If(odd, one, two));
390 else if ( zep.equals(SLOG) ) {
391 block.append(new Slog(clu));
392 compile(arg.tail, subject, product, fresh, constants, block, tail);
394 else if ( zep.equals(FAST) ) {
395 compile(arg.tail, subject, product, fresh, constants, block, false);
396 block.append(new Fast(clu, product));
398 else if ( zep.equals(SPOT) ||
404 block.append(new Assignment(one, new Constant(zep)));
405 block.append(new Assignment(two, new Cons(one, clu)));
406 block.append(new Push(two));
407 compile(arg.tail, subject, product, fresh, constants, block, false);
408 block.append(new Pop());
412 compile(arg.tail, subject, product, fresh, constants, block, tail);
419 compile(arg.head, subject, one, fresh, constants, block, false);
420 compile(arg.tail, subject, two, fresh, constants, block, false);
421 block.append(new Assignment(product, new Esc(one, two)));
424 throw new Error("invalid opcode");
428function Trampoline(target, subject) {
429 this.target = target;
430 this.subject = subject;
433function genFine(loc) {
434 var constants = [], out = [], i;
435 for ( i = 0; !loc.isStatic; ++i ) {
436 out.push("if(!constants[" + i + "].equals(a.head)){return false;}");
437 constants.push(loc.noun);
438 out.push("a=" + new Frag(loc.axisToParent, "a").toJs() + ";");
441 out.push("return constants[" + i + "].equals(a);");
442 constants.push(loc.noun);
443 var body = 'return function(a){' + out.join('') + 'return true;};';
444 var builder = new Function('constants', body);
445 return builder(constants);
448var three = noun.dwim(3);
449function Location(context, name, label, axisToParent, hooks, noun, parentLoc) {
452 this.parentLoc = parentLoc;
453 this.axisToParent = axisToParent;
454 this.fragToParent = Noun.fragmenter(axisToParent);
455 this.nameToAxis = hooks;
456 this.axisToName = {};
457 this.isStatic = ( null === parentLoc || (three.equals(axisToParent) && parentLoc.isStatic) );
458 if ( this.isStatic ) {
462 this.noun = noun.head;
465 for ( var k in hooks ) {
466 if ( hooks.hasOwnProperty(k) ) {
467 this.axisToName[hooks[k].shortCode()] = k;
471 var drivers = context.drivers[label];
472 if ( drivers && drivers.length > 0 ) {
473 for ( var i = 0; i < drivers.length; ++i ) {
475 if ( d instanceof AxisArm ) {
476 this.jets[d.axis.mas().shortCode()] = d.fn;
479 this.jets[nameToAxis[d.name].mas().shortCode()] = d.fn;
483 this.fine = genFine(this);
486function Clue(name, parentAxis, hooks) {
488 this.parentAxis = parentAxis;
492function JetDriver(label, fn) {
497function AxisArm(label, axis, fn) {
498 JetDriver.call(this, label, fn);
501AxisArm.prototype = Object.create(JetDriver.prototype);
502AxisArm.prototype.constructor = AxisArm;
504function NamedArm(label, name, fn) {
505 JetDriver.call(this, label, fn);
508NamedArm.prototype = Object.create(JetDriver.prototype);
509NamedArm.prototype.constructor = NamedArm;
511var two = noun.dwim(2);
512function collectFromCore(prefix, spec, out) {
513 var name = spec[0], arms = spec[1], children = spec[2],
514 labl = prefix + "/" + name;
515 if ( arms instanceof Function ) {
516 out[labl] = [new AxisArm(labl, two, arms)];
520 for ( var k in arms ) {
521 if ( arms.hasOwnProperty(k) ) {
522 all.push(( 'number' === typeof(k) ) ?
523 new AxisArm(labl, noun.dwim(k), arms[k]) :
524 new NamedArm(labl, k, arms[k]));
530 for ( var i = 0; i < children.length; ++i ) {
531 collectFromCore(labl, children[i], out);
536function Context(drivers) {
537 this.memo = new NounMap();
538 this.clues = new NounMap();
539 this.dash = new NounMap();
540 this.tax = noun.Atom.yes;
543 collectFromCore('', drivers, this.drivers);
547Context.prototype.yes = noun.Atom.yes;
548Context.prototype.no = noun.Atom.no;
549Context.prototype.cons = function (h, t) {
550 return new Cell(h, t);
553Context.prototype.trampoline = function(tgt, bus) {
554 return new Trampoline(tgt, bus);
557Context.prototype.isTrampoline = function(a) {
558 return (a instanceof Trampoline);
561Context.prototype.compile = function(cell) {
563 var fresh = function() {
566 var body = new Block();
568 compile(cell, "subject", "product", fresh, constants, body, true);
569 var text = "return function(subject){" + body.toJs() + "return product;}";
570 var builder = new Function("context", "constants", text);
571 return cell.target = builder(this, constants);
574Context.prototype.nock = function(subject, formula) {
576 if ( !formula.hasOwnProperty("target") ) {
577 this.compile(formula);
579 target = formula.target;
581 product = target(subject);
582 if ( product instanceof Trampoline ) {
583 subject = product.subject;
584 target = product.target;
592Context.prototype.getMemo = function(key) {
593 return this.memo.get(key);
596Context.prototype.putMemo = function(key, val) {
597 this.memo.insert(key, val);
600Context.prototype.stackPush = function(item) {
601 this.tax = new Cell(item, this.tax);
604Context.prototype.stackPop = function() {
605 this.tax = this.tax.tail;
608Context.prototype.slog = function(item) {
609 // TODO: don't rewrite ++wash again, just call the kernel
615 return Atom.cordToString(n.head) + n.tail.number.shortValue().toString(10);
618 return Atom.cordToString(n);
622var ten = noun.dwim(10);
623function skipHints(formula) {
625 if ( formula.deep ) {
626 if ( ten.equals(formula.head) ) {
627 formula = formula.tail.tail;
635var zero = noun.dwim(0), constant_zero = noun.dwim(1,0);
636function parseParentAxis(noun) {
637 var f = skipHints(noun);
638 if ( constant_zero.equals(f) ) {
641 else if ( !zero.equals(f.head) ) {
642 throw new Error("weird formula head");
644 else if ( 3 != f.tail.cap().valueOf() ) {
645 throw new Error("weird parent axis");
650var nine = noun.dwim(9), constant_frag = noun.dwim(0,1);
651function parseHookAxis(nock) {
652 var f = skipHints(nock),
655 if ( zero.equals(op) ) {
656 if ( !f.tail.deep ) {
660 else if ( nine.equals(op) ) {
662 if ( !rest.head.deep && constant_frag.equals(rest.tail) ) {
670function parseHooks(noun) {
672 list.forEach(noun, function(c) {
673 var term = Atom.cordToString(c.head),
674 axis = parseHookAxis(c.tail);
675 if ( null != axis ) {
682Context.prototype.parseClue = function(raw) {
683 var clue = this.clues.get(raw);
684 if ( clue === undefined ) {
685 var name = chum(raw.head),
686 parentAxis = parseParentAxis(raw.tail.head),
687 hooks = parseHooks(raw.tail.tail);
688 clue = new Clue(name, parentAxis, hooks);
689 this.clues.insert(raw, clue);
694Context.prototype.register = function(core, raw) {
696 var loc = this.dash.get(bat);
697 if ( undefined === loc ) {
699 var clue = this.parseClue(raw);
700 if ( zero.equals(clue.parentAxis) ) {
701 loc = new Location(this, clue.name, '/' + clue.name, zero, clue.hooks, core, null);
704 var parentCore = core.at(clue.parentAxis),
705 parentBattery = parentCore.head,
706 parentLoc = this.dash.get(parentBattery);
707 if ( undefined === parentLoc ) {
708 console.log('register: invalid parent for ' + clue.name);
711 var label = parentLoc.label + "/" + clue.name;
712 loc = new Location(this, clue.name, label, clue.parentAxis, clue.hooks, core, parentLoc);
716 this.dash.insert(bat, loc);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list