|
function Class(obj) { |
|
var ctor = function () { |
|
if (obj.initialize) { |
|
obj.initialize.apply(this, arguments); |
|
} |
|
}; |
|
ctor.prototype = obj; |
|
|
|
return ctor; |
|
} |
|
|
|
var WhileContext = Class({ |
|
initialize: function(condition, sequence) { |
|
this.condition = condition; |
|
this.sequence = sequence; |
|
}, |
|
|
|
run: function() { |
|
while (true) { |
|
if (!this.sequence.started()) { |
|
if (!this.condition()) { |
|
return false; |
|
} |
|
} |
|
|
|
if (this.sequence.run()) { |
|
this.value = this.sequence.value; |
|
return true; |
|
} |
|
|
|
this.sequence.reset(); |
|
} |
|
} |
|
}); |
|
|
|
var IfContext = Class({ |
|
initialize: function(condition, sequence) { |
|
this.condition = condition; |
|
this.sequence = sequence; |
|
}, |
|
|
|
run: function() { |
|
if (!this.sequence.started() && !this.condition()) |
|
{ |
|
return false; |
|
} |
|
|
|
if (this.sequence.run()) { |
|
this.value = this.sequence.value; |
|
return true; |
|
} |
|
|
|
this.sequence.reset(); |
|
return false; |
|
} |
|
}); |
|
|
|
var StatementsContext = Class({ |
|
initialize: function(proc) { |
|
this.proc = proc; |
|
}, |
|
|
|
run: function() { |
|
this.proc(); |
|
return false; |
|
} |
|
}); |
|
|
|
var YieldContext = Class({ |
|
initialize: function(proc) { |
|
this.proc = proc; |
|
this.should_yield = true; |
|
}, |
|
|
|
run: function() { |
|
if (this.should_yield) { |
|
this.value = this.proc(); |
|
this.should_yield = false; |
|
return true; |
|
} |
|
else { |
|
this.should_yield = true; |
|
} |
|
} |
|
}); |
|
|
|
var SequenceContext = Class({ |
|
initialize: function(proc) { |
|
this.context_list = []; |
|
proc.call(this); |
|
this.pc = -1; |
|
}, |
|
|
|
run: function() { |
|
if (this.pc == -1) { |
|
this.pc = 0; |
|
} |
|
while (this.pc < this.context_list.length) |
|
{ |
|
if (this.context_list[this.pc].run()) { |
|
this.value = this.context_list[this.pc].value; |
|
|
|
return true; |
|
} |
|
++this.pc; |
|
} |
|
return false; |
|
}, |
|
|
|
reset: function() { |
|
this.pc = -1; |
|
}, |
|
|
|
started: function() { |
|
return this.pc >= 0; |
|
}, |
|
|
|
_while: function(condition) { |
|
var context_list = this.context_list; |
|
return function (proc) { |
|
var sequence = new SequenceContext(proc); |
|
context_list.push(new WhileContext(condition, sequence)); |
|
}; |
|
}, |
|
_if: function(condition) { |
|
var context_list = this.context_list; |
|
return function (proc) { |
|
var sequence = new SequenceContext(proc); |
|
context_list.push(new IfContext(condition, sequence)); |
|
}; |
|
}, |
|
_yield: function(proc) { |
|
this.context_list.push(new YieldContext(proc)); |
|
}, |
|
_s: function(proc) { |
|
this.context_list.push(new StatementsContext(proc)); |
|
} |
|
}); |
|
|
|
var Enumerable = Class({ |
|
initialize: function(proc) { |
|
this.sequence = new SequenceContext(proc); |
|
if (this.sequence.run()) { |
|
this.value = this.sequence.value; |
|
return this; |
|
} |
|
|
|
return null; |
|
}, |
|
|
|
next: function() { |
|
if (this.sequence.run()) { |
|
this.value = this.sequence.value; |
|
return this; |
|
} |
|
|
|
return null; |
|
}, |
|
|
|
takeWhile: function(condition) { |
|
var base = this; |
|
return new Enumerable(function() { |
|
this._if(function(){return condition(base.value)})(function (){ |
|
this._yield(function(){return base.value}); |
|
this._while(function(){return base.next() && condition(base.value)})(function (){ |
|
this._yield(function(){return base.value}); |
|
}); |
|
}); |
|
}); |
|
} |
|
}); |
|
|
|
function main() { |
|
|
|
var oneTwoThree = new Enumerable(function(){ |
|
this._yield(function() {return 1}); |
|
this._yield(function() {return 2}); |
|
this._yield(function() {return 3}); |
|
}); |
|
|
|
document.write("<h1>One Two Three</h1><ul>"); |
|
for (; oneTwoThree; oneTwoThree = oneTwoThree.next()) { |
|
document.write("<li>" + oneTwoThree.value + "</li>"); |
|
} |
|
document.write("</ul>\n"); |
|
|
|
function Fib() { |
|
var i = 0; |
|
var j = 1; |
|
return new Enumerable(function(){ |
|
this._while(function(){return true})(function(){ |
|
this._yield(function(){return i}); |
|
this._s(function(){ |
|
var next = i + j; |
|
i = j; |
|
j = next; |
|
}); |
|
}); |
|
}); |
|
}; |
|
|
|
var orig = new Fib(); |
|
document.write("<h1>Fib take while < 100</h1><ul>"); |
|
var fib = orig.takeWhile(function(e){return e < 100;}); |
|
while (fib) { |
|
document.write("<li>" + fib.value + "</li>"); |
|
fib = fib.next(); |
|
} |
|
document.write("</ul>\n"); |
|
} |
|
|
|
main(); |