diff options
author | alon@honor <none@none> | 2010-08-26 22:52:02 -0700 |
---|---|---|
committer | alon@honor <none@none> | 2010-08-26 22:52:02 -0700 |
commit | c96ca4ad280e3d9704b8f127311e5b48b707e3bd (patch) | |
tree | b63e654f7df8a9c18f4477edfdec4b26a428424c | |
parent | a9256705ada4ae335870cdb60ae7f9c8373038e3 (diff) |
cleanup + prep for enzymatic2
-rw-r--r-- | src/enzymatic2.js | 163 | ||||
-rw-r--r-- | src/parser.js | 14 | ||||
-rw-r--r-- | src/utility.js | 33 |
3 files changed, 200 insertions, 10 deletions
diff --git a/src/enzymatic2.js b/src/enzymatic2.js new file mode 100644 index 00000000..bdab72bd --- /dev/null +++ b/src/enzymatic2.js @@ -0,0 +1,163 @@ +/** + * A 2nd implementation of an 'enzymatic programming' paradigm. + */ + +Zyme2 = function(reqs) { + //! List of items that we want. Each element in this list is + //! a list of features, we want elements that have them all. + //! We will only call this Zyme if we find *all* of the elements + //! it wants. + this.reqs = reqs; +}; + +Substrate2 = function(name_) { + this.name_ = name_; + this.elems = {}; + this.currUid = 1; +}; + +Substrate2.prototype = { + _addElement: function(elem) { + if (!elem.__uid__) { + elem.__uid__ = this.currUid; + this.currUid ++; + } else { + assertTrue(!this.elems[elem.__uid__]); + } + this.elems[elem.__uid__] = elem; + }, + + _removeElement: function(elem) { + this.elems[elem.__uid__] = null; + delete elem.__uid__; + }, + + _getElement: function(uid) { return this.elems[uid]; }, + + getItems: function() { + return values(this.elems).filter(function(elem) { return elem.isItem }); + }, + + getZymes: function() { + return values(this.elems).filter(function(elem) { return elem.isZyme }); + }, + + addItem: function(item) { + this._addElement(item); + item.isItem = true; + + this.getZymes().forEach(function(zyme) { this.noticeItem(zyme, item) }); + }, + + addZyme: function(zyme) { + this._addElement(zyme); + zyme.isZyme = true; + zyme.potentials = zyme.reqs.map(function() { return [] }); + + this.getItems().forEach(function(item) { this.noticeItem(zyme, item); }); + }, + + removeItem: function(item) { + this._removeElement(item); + delete item.__result__; + delete item.__finalResult__; + + this.getZymes().forEach(function(zyme) { this.forgetItem(zyme, item) }); + }, + + removeZyme: function(zyme) { + this._removeElement(zyme); + }, + + _getFits: function(zyme, item) { + return fits = zyme.reqs.map(function(req) { + return req.filter(function(feat) { return !item[feat] }).length == 0; + }); + }, + + noticeItem: function(zyme, item) { + loopOn(this._getFits(zyme, item), function(i, fit) { + if (fit) { + zyme.potentials[i].push(item); + } + }); + }, + + forgetItem: function(zyme, item) { + loopOn(this._getFits(zyme, item), function(i, fit) { + if (fit) { + zyme.potentials = zyme.potentials.filter(function(item2) { return item2 !== item }); + } + }); + }, + + processItem: function(zyme, items) { + items.forEach(this.removeItem, this); + var splat = splitter(zyme.process(items), function(item) { + return item.__result__ || item.__finalResult__; + }); + splat.leftIn.forEach(this.addItem, this); + return splat.splitOut; + }, + +// if (sumTruthy(combo) == zyme.reqs.length) { // good to go + +// XXX + + solve: function() { + var startTime = Date.now(); + var midTime = startTime; + var that = this; + function midComment() { + var curr = Date.now(); + if (curr - midTime > 1000) { + print('// Working on ' + that.name_ + ', so far ' + ((curr-startTime)/1000).toString().substr(0,10) + ' seconds. Have ' + that.items.length + ' items.'); + midTime = curr; + } + } + function finalComment() { + print('// Completed ' + that.name_ + ' in ' + ((Date.now() - startTime)/1000).toString().substr(0,10) + ' seconds.'); + } + + var results = []; + var done = false; + while (!done) { + var hadProcessing = false; + this.getZymes().forEach(function(zyme) { + while (!done) { + var selected = zyme.potentials.map(function(potential) { return potential[0] }); + if (sumTruthy(selected) == zyme.reqs.length) { + var outputs = this.processItem(zyme, selected); + hadProcessing = true; + if (outputs.length === 1 && outputs[0].__finalResult__) { + results = outputs; + done = true; + } else { + results = results.concat(outputs); + } + } else { + break; + } + } + }, this); + if (this.items.length === 0) { + finalComment(); + done = true; + } + if (!hadProcessing) { + print("Reached a dead end."); + this.getItems().forEach(function(item) { + print("remaining item:" + dump(item)); + }); + throw "failure"; + } + midComment(); + } + if (results[0].__finalResult__) { + return results[0]; + } else { + return results; + } + }, +}; + diff --git a/src/parser.js b/src/parser.js index ba0a36e4..390daf9b 100644 --- a/src/parser.js +++ b/src/parser.js @@ -24,6 +24,7 @@ if (!this['read']) { load('utility.js'); load('enzymatic.js'); +load('enzymatic2.js'); // Tools @@ -89,13 +90,6 @@ function addIdent(token) { return token; } -// Splits out items that pass filter. Returns also the original sans the filtered -function splitter(array, filter) { - var splitOut = array.filter(filter); - var original = array.filter(function(x) { return !filter(x) }); - return { original: original, splitOut: splitOut }; -} - function combineTokens(tokens) { var ret = { lineNum: tokens[0].lineNum, @@ -822,7 +816,7 @@ function analyzer(data) { ['globalConstant', 'globalVariable', 'functionStub', 'type'].forEach(function(intertype) { var temp = splitter(item.items, function(item) { return item.intertype == intertype }); item[intertype + 's'] = temp.splitOut; - item.items = temp.original; + item.items = temp.leftIn; }); // Functions & labels item.functions = [] @@ -1307,7 +1301,7 @@ print("\n\n// XXX MAKEBLOCK " + entry + ' : ' + labels.length + ' : ' + getLabel print("//no first line"); return; } - var others = split.original; + var others = split.leftIn; var lastLine = first.lines.slice(-1)[0]; print("// makeBlock " + entry + ' : ' + getLabelIds(labels) + ' IN: ' + first.inLabels + ' OUT: ' + first.outLabels); // If we have one outgoing, and none incoming - make this a block of 1, @@ -1332,7 +1326,7 @@ print('// loop ? b'); // outside the loop. Insiders are those that can get back to the entry var split2 = splitter(others, function(label) { return label.allOutLabels.indexOf(entry) == -1 }); var outsiders = split2.splitOut; - var insiders = split2.original; + var insiders = split2.leftIn; print('// potential loop : in/out : ' + getLabelIds(insiders) + ' to ' + getLabelIds(outsiders)); // Hopefully exactly one of the outsiders is a 'pivot' - a label to which all those leaving // the loop must go. Then even some |if (falala) { ... break; }| will get ... diff --git a/src/utility.js b/src/utility.js index 447c52a6..f95e81f1 100644 --- a/src/utility.js +++ b/src/utility.js @@ -80,3 +80,36 @@ function walkJSON(item, func) { } } +function keys(x) { + var ret = []; + for (a in x) ret.push(a); + return ret; +} + +function values(x) { + var ret = []; + for (a in x) ret.push(x[a]); + return ret; +} + +function sum(x) { + return x.reduce(function(a,b) { return a+b }, 0); +} + +function sumTruthy(x) { + return x.reduce(function(a,b) { return (!!a)+(!!b) }, 0); +} + +function loopOn(array, func) { + for (var i = 0; i < array.length; i++) { + func(i, array[i]); + } +} + +// Splits out items that pass filter. Returns also the original sans the filtered +function splitter(array, filter) { + var splitOut = array.filter(filter); + var leftIn = array.filter(function(x) { return !filter(x) }); + return { leftIn: leftIn, splitOut: splitOut }; +} + |