Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

more lexer work

  • Loading branch information...
commit 854c36c647d543937a2590b21926c3c5353381a0 1 parent abf67c9
@doug-martin authored
Showing with 3,072 additions and 3,593 deletions.
  1. +23 −23 benchmark/manners/manners.flow.js
  2. +1 −2  benchmark/{mannersJson → mannersDsl}/benchmark.js
  3. +145 −0 benchmark/mannersDsl/data.js
  4. +36 −32 benchmark/{mannersJson → mannersDsl}/manners.nools
  5. +0 −145 benchmark/mannersJson/data.js
  6. +34 −0 examples/fibonacci.dsl.js
  7. +0 −46 examples/fibonacci.json
  8. +44 −0 examples/fibonacci.nools
  9. +0 −31 examples/fibonacciFromJson.js
  10. +28 −25 examples/helloWorld-strings.js
  11. +29 −26 examples/helloWorld.js
  12. +157 −0 lib/compile.js
  13. +9 −5 lib/index.js
  14. +37 −32 lib/matchResult.js
  15. +740 −719 lib/nodes.js
  16. +0 −20 lib/nodes/alphaNode.js
  17. +0 −42 lib/nodes/bridgeNode.js
  18. +0 −20 lib/nodes/equalityNode.js
  19. +0 −199 lib/nodes/index.js
  20. +0 −132 lib/nodes/joinNode.js
  21. +0 −28 lib/nodes/leftAdapterNode.js
  22. +0 −99 lib/nodes/node.js
  23. +0 −73 lib/nodes/notNode.js
  24. +0 −21 lib/nodes/propertyNode.js
  25. +0 −50 lib/nodes/referenceNode.js
  26. +0 −32 lib/nodes/rightAdapterNode.js
  27. +0 −59 lib/nodes/terminalNode.js
  28. +0 −42 lib/nodes/typeNode.js
  29. +14 −17 lib/parser/index.js
  30. +30 −5 lib/parser/nools/tokens.js
  31. +65 −61 lib/pattern.js
  32. +161 −240 lib/rule.js
  33. +0 −117 lib/util.js
  34. +51 −47 lib/workingMemory.js
  35. +301 −298 test/constraintMatcher.test.js
  36. +359 −273 test/flow.test.js
  37. +37 −2 test/noolsParser.test.js
  38. +633 −630 test/parser.test.js
  39. +93 −0 test/rules/diagnosis.nools
  40. +45 −0 test/rules/fibonacci.nools
View
46 benchmark/manners/manners.flow.js
@@ -47,16 +47,15 @@ module.exports = exports = nools.flow("Manners", function (flow) {
lgn = facts.leftGuestName,
rightSeat = s.rightSeat,
seatId = facts.sid, countValue = count.value;
- var seating = new Seating(countValue, seatId, false, rightSeat, facts.seatingRightGuestName, rightSeat + 1, lgn);
- this.assert(seating);
- var path = new Path(countValue, rightSeat + 1, lgn);
- this.assert(path);
- var chosen = new Chosen(seatId, lgn, facts.rightGuestHobby);
- this.assert(chosen);
- ++count.value;
- this.modify(count);
- context.state = Context.MAKE_PATH;
- this.modify(context);
+ this.assert(new Seating(countValue, seatId, false, rightSeat, facts.seatingRightGuestName, rightSeat + 1, lgn));
+ this.assert(new Path(countValue, rightSeat + 1, lgn));
+ this.assert(new Chosen(seatId, lgn, facts.rightGuestHobby));
+ this.modify(count, function(){
+ this.value++;
+ });
+ this.modify(context, function(){
+ this.state = Context.MAKE_PATH
+ });
});
flow.rule("makePath", [
@@ -65,19 +64,20 @@ module.exports = exports = nools.flow("Manners", function (flow) {
[Path, "p", "p.id == seatingPid", {guestName:"pathGuestName", seat:"pathSeat"}],
["not", Path, "p2", "p2.id == seatingId && p2.guestName == pathGuestName"]
], function (facts) {
- var path = new Path(facts.seatingId, facts.pathSeat, facts.pathGuestName);
- this.assert(path);
+ this.assert(new Path(facts.seatingId, facts.pathSeat, facts.pathGuestName));
});
flow.rule("pathDone", [
[Context, "c", "c.state == " + Context.MAKE_PATH],
[Seating, "s", "s.path == false"]
], function (facts) {
- var c = facts.c, s = facts.s;
- s.path = true;
- this.modify(s);
- c.state = Context.CHECK_DONE;
- this.modify(c);
+ var s = facts.s;
+ this.modify(s, function(){
+ this.path = true;
+ });
+ this.modify(facts.c, function(){
+ this.state = Context.CHECK_DONE;
+ });
console.log("path Done : %s", s);
});
@@ -87,17 +87,17 @@ module.exports = exports = nools.flow("Manners", function (flow) {
[LastSeat, "ls", "true", {seat:"lastSeat"}],
[Seating, "s", "s.rightSeat == lastSeat"]
], function (facts) {
- var c = facts.c;
- c.state = Context.PRINT_RESULTS;
- this.modify(c);
+ this.modify(facts.c, function () {
+ this.state = Context.PRINT_RESULTS;
+ });
});
flow.rule("continue", [Context, "c", "c.state == " + Context.CHECK_DONE],
function (facts) {
- var c = facts.c;
- c.state = Context.ASSIGN_SEATS;
- this.modify(c);
+ this.modify(facts.c, function () {
+ this.state = Context.ASSIGN_SEATS;
+ });
});
flow.rule("allDone", [Context, "c", "c.state == " + Context.PRINT_RESULTS], function () {
View
3  benchmark/mannersJson/benchmark.js → benchmark/mannersDsl/benchmark.js
@@ -1,10 +1,9 @@
var data = require("./data"),
nools = require("../../index");
-var flow = nools.parse(__dirname + "/manners.withDefined.json");
+var flow = nools.compile(__dirname + "/manners.nools");
var guests = data.load(flow.getDefined("guest"), flow.getDefined("lastSeat")).guests16;
var session = flow.getSession.apply(flow, guests);
-session.print();
session.assert(new (flow.getDefined("context"))({state:"start"}));
session.assert(new (flow.getDefined("count"))({value:1}));
var start = new Date();
View
145 benchmark/mannersDsl/data.js
@@ -0,0 +1,145 @@
+exports.load = function (Guest, LastSeat) {
+ return {
+ guests5:[
+ new Guest({name:"n1", sex:"m", hobby:"h1"}),
+ new Guest({name:"n2", sex:"f", hobby:"h1"}),
+ new Guest({name:"n2", sex:"f", hobby:"h3"}),
+ new Guest({name:"n3", sex:"m", hobby:"h3"}),
+ new Guest({name:"n4", sex:"m", hobby:"h1"}),
+ new Guest({name:"n4", sex:"f", hobby:"h2"}),
+ new Guest({name:"n4", sex:"f", hobby:"h3"}),
+ new Guest({name:"n5", sex:"f", hobby:"h2"}),
+ new Guest({name:"n5", sex:"f", hobby:"h1"}),
+ new LastSeat({seat:5})
+ ],
+
+ guests16:[
+ new Guest({name:"n1", sex:"f", hobby:"h3"}),
+ new Guest({name:"n1", sex:"f", hobby:"h1"}),
+ new Guest({name:"n1", sex:"f", hobby:"h2"}),
+ new Guest({name:"n2", sex:"f", hobby:"h3"}),
+ new Guest({name:"n2", sex:"f", hobby:"h2"}),
+ new Guest({name:"n3", sex:"m", hobby:"h1"}),
+ new Guest({name:"n3", sex:"m", hobby:"h3"}),
+ new Guest({name:"n4", sex:"m", hobby:"h2"}),
+ new Guest({name:"n4", sex:"m", hobby:"h1"}),
+ new Guest({name:"n5", sex:"m", hobby:"h2"}),
+ new Guest({name:"n5", sex:"m", hobby:"h3"}),
+ new Guest({name:"n6", sex:"m", hobby:"h2"}),
+ new Guest({name:"n6", sex:"m", hobby:"h1"}),
+ new Guest({name:"n7", sex:"f", hobby:"h2"}),
+ new Guest({name:"n7", sex:"f", hobby:"h1"}),
+ new Guest({name:"n7", sex:"f", hobby:"h3"}),
+ new Guest({name:"n8", sex:"f", hobby:"h3"}),
+ new Guest({name:"n8", sex:"f", hobby:"h2"}),
+ new Guest({name:"n9", sex:"f", hobby:"h1"}),
+ new Guest({name:"n9", sex:"f", hobby:"h3"}),
+ new Guest({name:"n9", sex:"f", hobby:"h2"}),
+ new Guest({name:"n10", sex:"m", hobby:"h2"}),
+ new Guest({name:"n10", sex:"m", hobby:"h3"}),
+ new Guest({name:"n11", sex:"m", hobby:"h3"}),
+ new Guest({name:"n11", sex:"m", hobby:"h2"}),
+ new Guest({name:"n11", sex:"m", hobby:"h1"}),
+ new Guest({name:"n12", sex:"m", hobby:"h3"}),
+ new Guest({name:"n12", sex:"m", hobby:"h1"}),
+ new Guest({name:"n13", sex:"m", hobby:"h2"}),
+ new Guest({name:"n13", sex:"m", hobby:"h3"}),
+ new Guest({name:"n13", sex:"m", hobby:"h1"}),
+ new Guest({name:"n14", sex:"f", hobby:"h3"}),
+ new Guest({name:"n14", sex:"f", hobby:"h1"}),
+ new Guest({name:"n15", sex:"f", hobby:"h3"}),
+ new Guest({name:"n15", sex:"f", hobby:"h2"}),
+ new Guest({name:"n15", sex:"f", hobby:"h1"}),
+ new Guest({name:"n16", sex:"f", hobby:"h3"}),
+ new Guest({name:"n16", sex:"f", hobby:"h2"}),
+ new Guest({name:"n16", sex:"f", hobby:"h1"}),
+ new LastSeat({seat:16})],
+
+ guests32:[
+ new Guest({name:"n1", sex:"m", hobby:"h1"}),
+ new Guest({name:"n1", sex:"m", hobby:"h3"}),
+ new Guest({name:"n2", sex:"f", hobby:"h3"}),
+ new Guest({name:"n2", sex:"f", hobby:"h2"}),
+ new Guest({name:"n2", sex:"f", hobby:"h1"}),
+ new Guest({name:"n3", sex:"f", hobby:"h1"}),
+ new Guest({name:"n3", sex:"f", hobby:"h2"}),
+ new Guest({name:"n4", sex:"f", hobby:"h3"}),
+ new Guest({name:"n4", sex:"f", hobby:"h1"}),
+ new Guest({name:"n5", sex:"f", hobby:"h1"}),
+ new Guest({name:"n5", sex:"f", hobby:"h2"}),
+ new Guest({name:"n6", sex:"m", hobby:"h1"}),
+ new Guest({name:"n6", sex:"m", hobby:"h2"}),
+ new Guest({name:"n6", sex:"m", hobby:"h3"}),
+ new Guest({name:"n7", sex:"f", hobby:"h2"}),
+ new Guest({name:"n7", sex:"f", hobby:"h1"}),
+ new Guest({name:"n7", sex:"f", hobby:"h3"}),
+ new Guest({name:"n8", sex:"f", hobby:"h1"}),
+ new Guest({name:"n8", sex:"f", hobby:"h3"}),
+ new Guest({name:"n8", sex:"f", hobby:"h2"}),
+ new Guest({name:"n9", sex:"f", hobby:"h1"}),
+ new Guest({name:"n9", sex:"f", hobby:"h3"}),
+ new Guest({name:"n9", sex:"f", hobby:"h2"}),
+ new Guest({name:"n10", sex:"m", hobby:"h2"}),
+ new Guest({name:"n10", sex:"m", hobby:"h1"}),
+ new Guest({name:"n11", sex:"m", hobby:"h2"}),
+ new Guest({name:"n11", sex:"m", hobby:"h1"}),
+ new Guest({name:"n12", sex:"m", hobby:"h3"}),
+ new Guest({name:"n12", sex:"m", hobby:"h2"}),
+ new Guest({name:"n13", sex:"m", hobby:"h1"}),
+ new Guest({name:"n13", sex:"m", hobby:"h3"}),
+ new Guest({name:"n14", sex:"m", hobby:"h3"}),
+ new Guest({name:"n14", sex:"m", hobby:"h2"}),
+ new Guest({name:"n15", sex:"f", hobby:"h2"}),
+ new Guest({name:"n15", sex:"f", hobby:"h1"}),
+ new Guest({name:"n15", sex:"f", hobby:"h3"}),
+ new Guest({name:"n16", sex:"f", hobby:"h3"}),
+ new Guest({name:"n16", sex:"f", hobby:"h2"}),
+ new Guest({name:"n16", sex:"f", hobby:"h1"}),
+ new Guest({name:"n17", sex:"m", hobby:"h3"}),
+ new Guest({name:"n17", sex:"m", hobby:"h2"}),
+ new Guest({name:"n18", sex:"f", hobby:"h2"}),
+ new Guest({name:"n18", sex:"f", hobby:"h1"}),
+ new Guest({name:"n19", sex:"f", hobby:"h1"}),
+ new Guest({name:"n19", sex:"f", hobby:"h2"}),
+ new Guest({name:"n19", sex:"f", hobby:"h3"}),
+ new Guest({name:"n20", sex:"f", hobby:"h1"}),
+ new Guest({name:"n20", sex:"f", hobby:"h2"}),
+ new Guest({name:"n20", sex:"f", hobby:"h3"}),
+ new Guest({name:"n21", sex:"m", hobby:"h2"}),
+ new Guest({name:"n21", sex:"m", hobby:"h3"}),
+ new Guest({name:"n21", sex:"m", hobby:"h1"}),
+ new Guest({name:"n22", sex:"f", hobby:"h1"}),
+ new Guest({name:"n22", sex:"f", hobby:"h2"}),
+ new Guest({name:"n22", sex:"f", hobby:"h3"}),
+ new Guest({name:"n23", sex:"f", hobby:"h3"}),
+ new Guest({name:"n23", sex:"f", hobby:"h1"}),
+ new Guest({name:"n23", sex:"f", hobby:"h2"}),
+ new Guest({name:"n24", sex:"m", hobby:"h1"}),
+ new Guest({name:"n24", sex:"m", hobby:"h3"}),
+ new Guest({name:"n25", sex:"f", hobby:"h3"}),
+ new Guest({name:"n25", sex:"f", hobby:"h2"}),
+ new Guest({name:"n25", sex:"f", hobby:"h1"}),
+ new Guest({name:"n26", sex:"f", hobby:"h3"}),
+ new Guest({name:"n26", sex:"f", hobby:"h2"}),
+ new Guest({name:"n26", sex:"f", hobby:"h1"}),
+ new Guest({name:"n27", sex:"m", hobby:"h3"}),
+ new Guest({name:"n27", sex:"m", hobby:"h1"}),
+ new Guest({name:"n27", sex:"m", hobby:"h2"}),
+ new Guest({name:"n28", sex:"m", hobby:"h3"}),
+ new Guest({name:"n28", sex:"m", hobby:"h1"}),
+ new Guest({name:"n29", sex:"m", hobby:"h3"}),
+ new Guest({name:"n29", sex:"m", hobby:"h2"}),
+ new Guest({name:"n29", sex:"m", hobby:"h1"}),
+ new Guest({name:"n30", sex:"m", hobby:"h2"}),
+ new Guest({name:"n30", sex:"m", hobby:"h1"}),
+ new Guest({name:"n30", sex:"m", hobby:"h3"}),
+ new Guest({name:"n31", sex:"m", hobby:"h2"}),
+ new Guest({name:"n31", sex:"m", hobby:"h1"}),
+ new Guest({name:"n32", sex:"m", hobby:"h1"}),
+ new Guest({name:"n32", sex:"m", hobby:"h3"}),
+ new Guest({name:"n32", sex:"m", hobby:"h2"}),
+ new LastSeat({seat:32})]
+ }
+};
+
+
View
68 benchmark/mannersJson/manners.nools → benchmark/mannersDsl/manners.nools
@@ -23,7 +23,8 @@ define Count {
define Guest {
name : "",
- sex : "hobby",
+ sex : "",
+ hobby : "",
toString:function () {
return ["[Guest name=", this.name, ", sex=", this.sex, ", hobbies=", this.hobby, "]"].join("");
}
@@ -66,21 +67,23 @@ rule assignFirstSeat {
count : Count;
}
then {
- assert(new Seating({
- id : $count.value,
- pid : 0,
- path : true,
- leftSeat : 1,
- leftGuestName : $leftGuestName,
- rightSeat : 1,
- rightGuestName : $leftGuestName
- }));
- assert(new Path({id : $count.value, seat : 1, guestName : $leftGuestName}));
- modify($count, function(){
+ var seating = new Seating({
+ id : count.value,
+ pid : 0,
+ path : true,
+ leftSeat : 1,
+ leftGuestName : leftGuestName,
+ rightSeat : 1,
+ rightGuestName : leftGuestName
+ });
+ assert(seating);
+ var path = new Path({id : count.value, seat : 1, guestName : leftGuestName});
+ assert(path);
+ modify(count, function(){
this.value++
});
console.log('assign first seat : %s : %s', seating, path);
- modify($c, function(){
+ modify(c, function(){
this.state = 'assign';
});
}
@@ -99,18 +102,19 @@ rule findSeating {
}
then {
assert(new Seating({
- id : $count.value,
- pid : $sid,
- path : true,
- leftSeat : $s.rightSeat,
- leftGuestName : $seatingRightGuestName,
- rightSeat : $rightSeat + 1,
- rightGuestName : $leftGuestName
+ id : countValue,
+ pid : sid,
+ path : false,
+ leftSeat : s.rightSeat,
+ leftGuestName : seatingRightGuestName,
+ rightSeat : rightSeat + 1,
+ rightGuestName : leftGuestName
}));
- assert(new Path({id : countValue, seat : rightSeat + 1, guestName : leftGuestName}));
- assert(new Chosen({id : $sid, guestName : $leftGuestName, hobby : $rightGuestHobby}));
- modify($count, function(){this.value++;});
- modify($c, function(){this.state = 'make'});
+ var path = new Path({id : countValue, seat : rightSeat + 1, guestName : leftGuestName});
+ assert(path);
+ assert(new Chosen({id : sid, guestName : leftGuestName, hobby : rightGuestHobby}));
+ modify(count, function(){this.value++;});
+ modify(c, function(){this.state = 'make'});
}
}
@@ -118,11 +122,11 @@ rule makePath {
when {
c : Context c.state == 'make';
s : Seating s.path == false {id : sid, pid : seatingPid};
- p : Path p, p.id == seatingPid {guestName : pathGuestName, seat : pathSeat};
- not( p2 : Path p2.id == sid && p2.guestName == pathGuestName];
+ p : Path p.id == seatingPid {guestName : pathGuestName, seat : pathSeat};
+ not( p2 : Path p2.id == sid && p2.guestName == pathGuestName);
}
then {
- assert(new Path({id : $sid, seat : $pathSeat, guestName : $pathGuestName}));
+ assert(new Path({id : sid, seat : pathSeat, guestName : pathGuestName}));
}
}
@@ -132,13 +136,13 @@ rule pathDone {
s : Seating s.path == false;
}
then {
- modify($s, function(){
+ modify(s, function(){
this.path = true;
});
- modify($c, function(){
+ modify(c, function(){
this.state = 'check';
});
- console.log('path Done : %s', $s);
+ console.log('path Done : %s', s);
}
}
@@ -149,7 +153,7 @@ rule areWeDone {
s : Seating s.rightSeat == lastSeat;
}
then {
- modify($c, {this.state = 'print';})
+ modify(c, function(){this.state = 'print';})
}
}
@@ -158,7 +162,7 @@ rule continue {
c : Context c.state == 'check';
}
then {
- modify($c, {this.state = 'assign'});
+ modify(c, function(){this.state = 'assign'});
}
}
View
145 benchmark/mannersJson/data.js
@@ -1,145 +0,0 @@
-exports.load = function (Guest, LastSeat) {
- return {
- guests5:[
- new Guest({name:"n1", sex:"n1", hobby:"h1"}),
- new Guest({name:"n2", sex:"n2", hobby:"h1"}),
- new Guest({name:"n2", sex:"n2", hobby:"h3"}),
- new Guest({name:"n3", sex:"n3", hobby:"h3"}),
- new Guest({name:"n4", sex:"n4", hobby:"h1"}),
- new Guest({name:"n4", sex:"n4", hobby:"h2"}),
- new Guest({name:"n4", sex:"n4", hobby:"h3"}),
- new Guest({name:"n5", sex:"n5", hobby:"h2"}),
- new Guest({name:"n5", sex:"n5", hobby:"h1"}),
- new LastSeat({seat:5})
- ],
-
- guests16:[
- new Guest({name:"n1", sex:"n1", hobby:"h3"}),
- new Guest({name:"n1", sex:"n1", hobby:"h1"}),
- new Guest({name:"n1", sex:"n1", hobby:"h2"}),
- new Guest({name:"n2", sex:"n2", hobby:"h3"}),
- new Guest({name:"n2", sex:"n2", hobby:"h2"}),
- new Guest({name:"n3", sex:"n3", hobby:"h1"}),
- new Guest({name:"n3", sex:"n3", hobby:"h3"}),
- new Guest({name:"n4", sex:"n4", hobby:"h2"}),
- new Guest({name:"n4", sex:"n4", hobby:"h1"}),
- new Guest({name:"n5", sex:"n5", hobby:"h2"}),
- new Guest({name:"n5", sex:"n5", hobby:"h3"}),
- new Guest({name:"n6", sex:"n6", hobby:"h2"}),
- new Guest({name:"n6", sex:"n6", hobby:"h1"}),
- new Guest({name:"n7", sex:"n7", hobby:"h2"}),
- new Guest({name:"n7", sex:"n7", hobby:"h1"}),
- new Guest({name:"n7", sex:"n7", hobby:"h3"}),
- new Guest({name:"n8", sex:"n8", hobby:"h3"}),
- new Guest({name:"n8", sex:"n8", hobby:"h2"}),
- new Guest({name:"n9", sex:"n9", hobby:"h1"}),
- new Guest({name:"n9", sex:"n9", hobby:"h3"}),
- new Guest({name:"n9", sex:"n9", hobby:"h2"}),
- new Guest({name:"n10", sex:"n10", hobby:"h2"}),
- new Guest({name:"n10", sex:"n10", hobby:"h3"}),
- new Guest({name:"n11", sex:"n11", hobby:"h3"}),
- new Guest({name:"n11", sex:"n11", hobby:"h2"}),
- new Guest({name:"n11", sex:"n11", hobby:"h1"}),
- new Guest({name:"n12", sex:"n12", hobby:"h3"}),
- new Guest({name:"n12", sex:"n12", hobby:"h1"}),
- new Guest({name:"n13", sex:"n13", hobby:"h2"}),
- new Guest({name:"n13", sex:"n13", hobby:"h3"}),
- new Guest({name:"n13", sex:"n13", hobby:"h1"}),
- new Guest({name:"n14", sex:"n14", hobby:"h3"}),
- new Guest({name:"n14", sex:"n14", hobby:"h1"}),
- new Guest({name:"n15", sex:"n15", hobby:"h3"}),
- new Guest({name:"n15", sex:"n15", hobby:"h2"}),
- new Guest({name:"n15", sex:"n15", hobby:"h1"}),
- new Guest({name:"n16", sex:"n16", hobby:"h3"}),
- new Guest({name:"n16", sex:"n16", hobby:"h2"}),
- new Guest({name:"n16", sex:"n16", hobby:"h1"}),
- new LastSeat({seat:16})],
-
- guests32:[
- new Guest({name:"n1", sex:"n1", hobby:"h1"}),
- new Guest({name:"n1", sex:"n1", hobby:"h3"}),
- new Guest({name:"n2", sex:"n2", hobby:"h3"}),
- new Guest({name:"n2", sex:"n2", hobby:"h2"}),
- new Guest({name:"n2", sex:"n2", hobby:"h1"}),
- new Guest({name:"n3", sex:"n3", hobby:"h1"}),
- new Guest({name:"n3", sex:"n3", hobby:"h2"}),
- new Guest({name:"n4", sex:"n4", hobby:"h3"}),
- new Guest({name:"n4", sex:"n4", hobby:"h1"}),
- new Guest({name:"n5", sex:"n5", hobby:"h1"}),
- new Guest({name:"n5", sex:"n5", hobby:"h2"}),
- new Guest({name:"n6", sex:"n6", hobby:"h1"}),
- new Guest({name:"n6", sex:"n6", hobby:"h2"}),
- new Guest({name:"n6", sex:"n6", hobby:"h3"}),
- new Guest({name:"n7", sex:"n7", hobby:"h2"}),
- new Guest({name:"n7", sex:"n7", hobby:"h1"}),
- new Guest({name:"n7", sex:"n7", hobby:"h3"}),
- new Guest({name:"n8", sex:"n8", hobby:"h1"}),
- new Guest({name:"n8", sex:"n8", hobby:"h3"}),
- new Guest({name:"n8", sex:"n8", hobby:"h2"}),
- new Guest({name:"n9", sex:"n9", hobby:"h1"}),
- new Guest({name:"n9", sex:"n9", hobby:"h3"}),
- new Guest({name:"n9", sex:"n9", hobby:"h2"}),
- new Guest({name:"n10", sex:"n10", hobby:"h2"}),
- new Guest({name:"n10", sex:"n10", hobby:"h1"}),
- new Guest({name:"n11", sex:"n11", hobby:"h2"}),
- new Guest({name:"n11", sex:"n11", hobby:"h1"}),
- new Guest({name:"n12", sex:"n12", hobby:"h3"}),
- new Guest({name:"n12", sex:"n12", hobby:"h2"}),
- new Guest({name:"n13", sex:"n13", hobby:"h1"}),
- new Guest({name:"n13", sex:"n13", hobby:"h3"}),
- new Guest({name:"n14", sex:"n14", hobby:"h3"}),
- new Guest({name:"n14", sex:"n14", hobby:"h2"}),
- new Guest({name:"n15", sex:"n15", hobby:"h2"}),
- new Guest({name:"n15", sex:"n15", hobby:"h1"}),
- new Guest({name:"n15", sex:"n15", hobby:"h3"}),
- new Guest({name:"n16", sex:"n16", hobby:"h3"}),
- new Guest({name:"n16", sex:"n16", hobby:"h2"}),
- new Guest({name:"n16", sex:"n16", hobby:"h1"}),
- new Guest({name:"n17", sex:"n17", hobby:"h3"}),
- new Guest({name:"n17", sex:"n17", hobby:"h2"}),
- new Guest({name:"n18", sex:"n18", hobby:"h2"}),
- new Guest({name:"n18", sex:"n18", hobby:"h1"}),
- new Guest({name:"n19", sex:"n19", hobby:"h1"}),
- new Guest({name:"n19", sex:"n19", hobby:"h2"}),
- new Guest({name:"n19", sex:"n19", hobby:"h3"}),
- new Guest({name:"n20", sex:"n20", hobby:"h1"}),
- new Guest({name:"n20", sex:"n20", hobby:"h2"}),
- new Guest({name:"n20", sex:"n20", hobby:"h3"}),
- new Guest({name:"n21", sex:"n21", hobby:"h2"}),
- new Guest({name:"n21", sex:"n21", hobby:"h3"}),
- new Guest({name:"n21", sex:"n21", hobby:"h1"}),
- new Guest({name:"n22", sex:"n22", hobby:"h1"}),
- new Guest({name:"n22", sex:"n22", hobby:"h2"}),
- new Guest({name:"n22", sex:"n22", hobby:"h3"}),
- new Guest({name:"n23", sex:"n23", hobby:"h3"}),
- new Guest({name:"n23", sex:"n23", hobby:"h1"}),
- new Guest({name:"n23", sex:"n23", hobby:"h2"}),
- new Guest({name:"n24", sex:"n24", hobby:"h1"}),
- new Guest({name:"n24", sex:"n24", hobby:"h3"}),
- new Guest({name:"n25", sex:"n25", hobby:"h3"}),
- new Guest({name:"n25", sex:"n25", hobby:"h2"}),
- new Guest({name:"n25", sex:"n25", hobby:"h1"}),
- new Guest({name:"n26", sex:"n26", hobby:"h3"}),
- new Guest({name:"n26", sex:"n26", hobby:"h2"}),
- new Guest({name:"n26", sex:"n26", hobby:"h1"}),
- new Guest({name:"n27", sex:"n27", hobby:"h3"}),
- new Guest({name:"n27", sex:"n27", hobby:"h1"}),
- new Guest({name:"n27", sex:"n27", hobby:"h2"}),
- new Guest({name:"n28", sex:"n28", hobby:"h3"}),
- new Guest({name:"n28", sex:"n28", hobby:"h1"}),
- new Guest({name:"n29", sex:"n29", hobby:"h3"}),
- new Guest({name:"n29", sex:"n29", hobby:"h2"}),
- new Guest({name:"n29", sex:"n29", hobby:"h1"}),
- new Guest({name:"n30", sex:"n30", hobby:"h2"}),
- new Guest({name:"n30", sex:"n30", hobby:"h1"}),
- new Guest({name:"n30", sex:"n30", hobby:"h3"}),
- new Guest({name:"n31", sex:"n31", hobby:"h2"}),
- new Guest({name:"n31", sex:"n31", hobby:"h1"}),
- new Guest({name:"n32", sex:"n32", hobby:"h1"}),
- new Guest({name:"n32", sex:"n32", hobby:"h3"}),
- new Guest({name:"n32", sex:"n32", hobby:"h2"}),
- new LastSeat({seat:32})]
- }
-};
-
-
View
34 examples/fibonacci.dsl.js
@@ -0,0 +1,34 @@
+(function () {
+ "use strict";
+
+ var nools = require("../index");
+
+ var flow = nools.compile(__dirname + "/fibonacci.nools");
+
+ var Fibonacci = flow.getDefined("fibonacci"), Result = flow.getDefined("result");
+
+ var r1 = new Result(),
+ session1 = flow.getSession(new Fibonacci({sequence:10}), r1),
+ s1 = +(new Date());
+ session1.match().then(function () {
+ console.log("%d [%dms]", r1.result, +(new Date()) - s1);
+ session1.dispose();
+ });
+
+ var r2 = new Result(),
+ session2 = flow.getSession(new Fibonacci({sequence:150}), r2),
+ s2 = +(new Date());
+ session2.match().then(function () {
+ console.log("%d [%dms]", r2.result, +(new Date()) - s2);
+ session2.dispose();
+ });
+
+ var r3 = new Result(),
+ session3 = flow.getSession(new Fibonacci({sequence:1000}), r3),
+ s3 = +(new Date());
+ session3.match().then(function () {
+ console.log("%d [%dms]", r3.result, +(new Date()) - s3);
+ session3.dispose();
+ });
+
+})();
View
46 examples/fibonacci.json
@@ -1,46 +0,0 @@
-{
- "name":"Fibonacci",
- "define":{
- "Fibonacci":{
- "value":-1,
- "sequence":null
- },
- "Result":{
- "value":-1
- }
- },
- "Recurse":{
- "options":{
- "priority":1
- },
- "rules":[
- ["not", "Fibonacci", "f", "f.sequence == 1"],
- ["Fibonacci", "f1", "f1.sequence != 1"]
- ],
- "action":"assert(new Fibonacci({sequence : f1.sequence - 1}));"
- },
- "Bootstrap":{
- "rules":["Fibonacci", "f", "f.value == -1 && (f.sequence == 1 || f.sequence == 2)"],
- "action":[
- "f.value = 1;",
- "modify(f);"
- ]
- },
- "Calculate":{
- "rules":[
- ["Fibonacci", "f1", "f1.value != -1", {
- "sequence":"s1"
- }],
- ["Fibonacci", "f2", "f2.value != -1 && f2.sequence == s1 + 1", {
- "sequence":"s2"
- }],
- ["Fibonacci", "f3", "f3.value == -1 && f3.sequence == s2 + 1"],
- ["Result", "r"]
- ],
- "action":[
- "var v = f3.value = f1.value + f2.value;",
- "r.result = v;",
- "modify(f3);retract(f1);"
- ]
- }
-}
View
44 examples/fibonacci.nools
@@ -0,0 +1,44 @@
+define Fibonacci {
+ "value":-1,
+ "sequence":null
+ }
+define Result {
+ value : -1
+}
+
+rule Recurse {
+ priority:1,
+ when {
+ not(f : Fibonacci f.sequence == 1);
+ f1 : Fibonacci f1.sequence != 1;
+ }
+ then {
+ assert(new Fibonacci({sequence : f1.sequence - 1}));
+ }
+}
+
+rule Bootstrap {
+ when {
+ f : Fibonacci f.value == -1 && (f.sequence == 1 || f.sequence == 2);
+ }
+ then{
+ modify(f, function(){
+ this.value = 1;
+ });
+ }
+}
+
+rule Calculate {
+ when {
+ f1 : Fibonacci f1.value != -1 {sequence : s1};
+ f2 : Fibonacci f2.value != -1 && f2.sequence == s1 + 1 {"sequence":"s2"};
+ f3 : Fibonacci f3.value == -1 && f3.sequence == s2 + 1;
+ r : Result
+ }
+ then {
+ modify(f3, function(){
+ this.value = r.result = f1.value + f2.value;
+ });
+ retract(f1);
+ }
+}
View
31 examples/fibonacciFromJson.js
@@ -1,31 +0,0 @@
-"use strict";
-
-var nools = require("../index");
-
-var flow = nools.parse(__dirname + "/fibonacci.json");
-
-var Fibonacci = flow.getDefined("fibonacci"), Result = flow.getDefined("result");
-
-var r1 = new Result(),
- session1 = flow.getSession(new Fibonacci({sequence : 10}), r1),
- s1 = new Date;
-session1.match().then(function () {
- console.log("%d [%dms]", r1.result, new Date - s1);
- session1.dispose();
-});
-
-var r2 = new Result(),
- session2 = flow.getSession(new Fibonacci({sequence : 150}), r2),
- s2 = new Date;
-session2.match().then(function () {
- console.log("%d [%dms]", r2.result, new Date - s2);
- session2.dispose();
-});
-
-var r3 = new Result(),
- session3 = flow.getSession(new Fibonacci({sequence : 1000}), r3),
- s3 = new Date;
-session3.match().then(function () {
- console.log("%d [%dms]", r3.result, new Date - s3);
- session3.dispose();
-});
View
53 examples/helloWorld-strings.js
@@ -1,34 +1,37 @@
-var nools = require("../index");
-
-var flow = nools.flow("Hello World", function (flow) {
-
- //find any message that starts with hello
- this.rule("Hello", [String, "s", "s =~ /^hello(\\s*world)?$/"], function (facts) {
- var s = facts.s + " goodbye";
- this.assert(s);
- });
-
- //find all messages then end in goodbye
- this.rule("Goodbye", [String, "s", "s =~ /.*goodbye$/"], function (facts) {
- console.log(facts.s);
+(function () {
+ "use strict";
+ var nools = require("../index");
+
+ var flow = nools.flow("Hello World", function (flow) {
+
+ //find any message that starts with hello
+ this.rule("Hello", [String, "s", "s =~ /^hello(\\s*world)?$/"], function (facts) {
+ var s = facts.s + " goodbye";
+ this.assert(s);
+ });
+
+ //find all messages then end in goodbye
+ this.rule("Goodbye", [String, "s", "s =~ /.*goodbye$/"], function (facts) {
+ console.log(facts.s);
+ });
});
-});
-var session = flow.getSession();
+ var session = flow.getSession();
//assert your different messages
-session.assert("goodbye");
-session.assert("hello");
-session.assert("hello world");
-session.match();
+ session.assert("goodbye");
+ session.assert("hello");
+ session.assert("hello world");
+ session.match();
//same as above getSession will assert the passed in objects
-var session2 = flow.getSession(
- "goodbye",
- "hello",
- "hello world"
-);
-session2.match();
+ var session2 = flow.getSession(
+ "goodbye",
+ "hello",
+ "hello world"
+ );
+ session2.match();
+})();
View
55 examples/helloWorld.js
@@ -1,40 +1,43 @@
-var nools = require("../index");
+(function () {
+ "use strict";
+ var nools = require("../index");
-var Message = function (message) {
- this.message = message;
-};
+ var Message = function (message) {
+ this.message = message;
+ };
-var flow = nools.flow("Hello World", function (flow) {
+ var flow = nools.flow("Hello World", function (flow) {
- //find any message that starts with hello
- this.rule("Hello", [Message, "m", "m.message =~ /^hello(\\s*world)?$/"], function (facts) {
- facts.m.message = facts.m.message + " goodbye";
- this.modify(facts.m);
- });
+ //find any message that starts with hello
+ this.rule("Hello", [Message, "m", "m.message =~ /^hello(\\s*world)?$/"], function (facts) {
+ facts.m.message = facts.m.message + " goodbye";
+ this.modify(facts.m);
+ });
- //find all messages then end in goodbye
- this.rule("Goodbye", [Message, "m", "m.message =~ /.*goodbye$/"], function (facts) {
- console.log(facts.m.message);
+ //find all messages then end in goodbye
+ this.rule("Goodbye", [Message, "m", "m.message =~ /.*goodbye$/"], function (facts) {
+ console.log(facts.m.message);
+ });
});
-});
-var session = flow.getSession();
+ var session = flow.getSession();
//assert your different messages
-session.assert(new Message("goodbye"));
-session.assert(new Message("hello"));
-session.assert(new Message("hello world"));
-session.match();
+ session.assert(new Message("goodbye"));
+ session.assert(new Message("hello"));
+ session.assert(new Message("hello world"));
+ session.match();
//same as above getSession will assert the passed in objects
-var session2 = flow.getSession(
- new Message("goodbye"),
- new Message("hello"),
- new Message("hello world")
-);
-session2.match();
-
+ var session2 = flow.getSession(
+ new Message("goodbye"),
+ new Message("hello"),
+ new Message("hello world")
+ );
+ session2.match();
+
+})();
View
157 lib/compile.js
@@ -0,0 +1,157 @@
+(function () {
+ "use strict";
+ var comb = require("comb"),
+ fs = require("fs"),
+ path = require("path"),
+ parser = require("./parser"),
+ constraintMatcher = require("./constraintMatcher.js"),
+ removeDuplicates = comb.array.removeDuplicates,
+ rules = require("./rule");
+
+ var modifiers = ["assert", "modify", "retract"];
+ var parseAction = function (action, identifiers, defined) {
+ var declares = [], needFlow = false;
+ identifiers.forEach(function (i) {
+ if (action.indexOf(i) !== -1) {
+ declares.push("var " + i + "= facts." + i + ";");
+ }
+ });
+ modifiers.forEach(function (i) {
+ if (action.indexOf(i) !== -1) {
+ declares.push("var " + i + "= flow." + i + ".bind(flow);");
+ }
+ });
+ Object.keys(defined).forEach(function (i) {
+ if (action.indexOf(i) !== -1) {
+ declares.push("var " + i + "= defined." + i + ";");
+ }
+ });
+ var params = ["facts", 'flow'];
+ if (/next\(.*\)/.test(action)) {
+ params.push("next");
+ }
+ action = declares.join("") + action;
+ action = ["(function(", params.join(","), ")", "{\n\t", action, "\n})"].join("");
+ try {
+ return eval(action);
+ } catch (e) {
+ throw new Error("Invalid action : " + action + "\n" + e.message);
+ }
+ };
+
+ var createRuleFromObject = function (obj, defined) {
+ var name = obj.name;
+ if (comb.isEmpty(obj)) {
+ throw new Error("Rule is empty");
+ }
+ var options = obj.options || {};
+ var constraints = obj.constraints || [], l = constraints.length;
+ if (!l) {
+ throw new Error("no rules defined for rule " + name);
+ }
+ var action = obj.action;
+ if (!action) {
+ throw new Error("No action was defined for rule " + name);
+ }
+ var conditions = [], identifiers = [];
+ for (var i = 0; i < l; i++) {
+ var rule = constraints[i], condition = [];
+ if (rule.length) {
+ var r0 = rule[0];
+ if (r0 === "not" || r0 === "or") {
+ condition.push(r0);
+ rule.shift();
+ }
+ var definedClass = rule[0], alias = rule[1], constraint = rule[2], refs = rule[3];
+ if (comb.isHash(constraint)) {
+ refs = constraint;
+ constraint = null;
+ }
+ if (definedClass && !!(definedClass = defined[definedClass])) {
+ condition.push(definedClass);
+ } else {
+ throw new Error("Invalid class " + rule[0] + " for rule " + name);
+ }
+ condition.push(alias, constraint, refs);
+ conditions.push(condition);
+ identifiers.push(alias);
+ if (constraint) {
+ identifiers = identifiers.concat(constraintMatcher.getIdentifiers(parser.parseConstraint(constraint)));
+ }
+ if (comb.isObject(refs)) {
+ for (var j in refs) {
+ if (identifiers.indexOf(j) === -1) {
+ identifiers.push(refs[j]);
+ }
+ }
+ }
+ identifiers = removeDuplicates(identifiers);
+ }
+ }
+ return rules.createRule(name, options, conditions, parseAction(action, identifiers, defined));
+ };
+
+ exports.compile = function (file, options, cb, Container) {
+ if (comb.isFunction(options)) {
+ cb = options;
+ options = {};
+ } else {
+ options = options || {};
+ cb = null;
+ }
+ var flowObj;
+
+ //parse flow from file
+ flowObj = parser.parseRuleSet(fs.readFileSync(file, "utf8"));
+
+ var name = flowObj.name || options.name || path.basename(file, path.extname(file));
+ //if !name throw an error
+ if (!name) {
+ throw new Error("Name must be present in JSON or options");
+ }
+ var flow = new Container(name);
+ var defined = {"Array":Array, "String":String, Number:Number, Boolean:Boolean, RegExp:RegExp, Buffer:Buffer};
+ if (!defined) {
+ defined = options.define;
+ } else {
+ flowObj.define.forEach(function (d) {
+ defined[d.name] = createDefined(d, flow);
+ });
+ }
+ var rules = flowObj.rules, l = rules.length;
+ if (rules.length) {
+ rules.forEach(function (rule) {
+ flow.__rules = flow.__rules.concat(createRuleFromObject(rule, defined));
+ });
+ }
+ if (cb) {
+ cb.call(flow, flow);
+ }
+ return flow;
+
+ };
+
+ var createDefined = (function () {
+
+ var _createDefined = function (options) {
+ var ret = function (opts) {
+ opts = opts || {};
+ for (var i in opts) {
+ if (i in options) {
+ this[i] = opts[i];
+ }
+ }
+ };
+ var proto = ret.prototype;
+ for (var i in options) {
+ proto[i] = options[i];
+ }
+ return ret;
+
+ };
+
+ return function (options, flow) {
+ return flow.addDefined(options.name, _createDefined(options.properties));
+ };
+ })();
+})();
View
14 lib/index.js
@@ -9,7 +9,7 @@
WorkingMemory = wm.WorkingMemory,
InitialFact = require("./pattern").InitialFact,
Fact = wm.Fact,
- util = require("./util");
+ compile = require("./compile");
var sortAgenda = function (a, b) {
@@ -192,9 +192,12 @@
// This method is called to alter an existing fact. It is essentially a
// retract followed by an assert.
- modify:function (fact) {
+ modify:function (fact, cb) {
//fact = this.workingMemory.getFact(fact);
this.retract(fact);
+ if ("function" === typeof cb) {
+ cb.call(fact, fact);
+ }
return this.assert(fact);
},
@@ -224,7 +227,7 @@
rootNode.incrementCounter();
flow.__wmAltered = false;
}
- fire();
+ process.nextTick(fire);
}, comb.hitch(ret, "errback"));
} else {
ret.callback();
@@ -288,6 +291,7 @@
addDefined:function (name, cls) {
//normalize
this.__defined[name.toLowerCase()] = cls;
+ return cls;
},
rule:function () {
@@ -321,8 +325,8 @@
return new FlowContainer(name, cb);
};
- exports.parse = function (file, options, cb) {
- return util.parse(file, options, cb, FlowContainer);
+ exports.compile = function (file, options, cb) {
+ return compile.compile(file, options, cb, FlowContainer);
};
View
69 lib/matchResult.js
@@ -1,40 +1,45 @@
-var comb = require("comb"),
- define = comb.define,
- merge = comb.merge;
+(function () {
+ "use strict";
+ var comb = require("comb"),
+ define = comb.define,
+ merge = comb.merge,
+ union = comb.array.union;
-define(null, {
- instance:{
- constructor:function (assertable) {
- assertable = assertable || {};
- this.variables = [];
- this.facts = [];
- assertable.fact && this.facts.push(assertable.fact);
- this.factHash = {};
- this.recency = [];
- this.constraints = [];
- this.isMatch = false;
- assertable.fact && this.recency.push(assertable.fact.recency);
+ define(null, {
+ instance:{
+ constructor:function (assertable) {
+ assertable = assertable || {};
+ this.variables = [];
+ this.facts = [];
+ assertable.fact && this.facts.push(assertable.fact);
+ this.factHash = {};
+ this.recency = [];
+ this.constraints = [];
+ this.isMatch = false;
+ assertable.fact && this.recency.push(assertable.fact.recency);
- },
+ },
- merge:function (mr) {
- var ret = new this._static();
- ret.isMatch = mr.isMatch;
- ret.facts = this.facts.concat(mr.facts);
- merge(ret.factHash, this.factHash, mr.factHash);
- ret.recency = union(this.recency, mr.recency);
- return ret;
- },
+ merge:function (mr) {
+ var ret = new this._static();
+ ret.isMatch = mr.isMatch;
+ ret.facts = this.facts.concat(mr.facts);
+ merge(ret.factHash, this.factHash, mr.factHash);
+ ret.recency = union(this.recency, mr.recency);
+ return ret;
+ },
- getters:{
+ getters:{
- factIds:function () {
- return this.facts.map(
- function (fact) {
- return fact.id;
- }).sort();
+ factIds:function () {
+ return this.facts.map(
+ function (fact) {
+ return fact.id;
+ }).sort();
+ }
}
+
}
+ }).as(module);
- }
-}).as(module);
+})();
View
1,459 lib/nodes.js
@@ -1,822 +1,843 @@
-var comb = require("comb"),
- array = comb.array,
- flatten = array.flatten,
- intersect = array.intersect,
- union = array.union,
- define = comb.define,
- merge = comb.merge,
- isInstanceOf = comb.isInstanceOf,
- removeDuplicates = array.removeDuplicates,
- HashTable = comb.collections.HashTable,
- pattern = require("./pattern.js"),
- ObjectPattern = pattern.ObjectPattern,
- NotPattern = pattern.NotPattern,
- CompositePattern = pattern.CompositePattern,
- InitialFactPattern = pattern.InitialFactPattern,
- constraints = require("./constraint"),
- HashConstraint = constraints.HashConstraint,
- ReferenceConstraint = constraints.ReferenceConstraint;
-
-
-var MatchResult = define(null, {
- instance:{
- constructor:function (assertable) {
- assertable = assertable || {};
- this.variables = [];
- this.facts = [];
- assertable.fact && this.facts.push(assertable.fact);
- this.factHash = {};
- this.recency = [];
- this.constraints = [];
- this.isMatch = false;
- assertable.fact && this.recency.push(assertable.fact.recency);
-
- },
-
- merge:function (mr) {
- var ret = new this._static();
- ret.isMatch = mr.isMatch;
- ret.facts = this.facts.concat(mr.facts);
- merge(ret.factHash, this.factHash, mr.factHash);
- ret.recency = union(this.recency, mr.recency);
- return ret;
- },
-
- getters:{
-
- factIds:function () {
- return this.facts.map(
- function (fact) {
- return fact.id;
- }).sort();
+(function () {
+ "use strict";
+ var comb = require("comb"),
+ array = comb.array,
+ flatten = array.flatten,
+ intersect = array.intersect,
+ union = array.union,
+ define = comb.define,
+ merge = comb.merge,
+ isInstanceOf = comb.isInstanceOf,
+ removeDuplicates = array.removeDuplicates,
+ HashTable = comb.collections.HashTable,
+ pattern = require("./pattern.js"),
+ ObjectPattern = pattern.ObjectPattern,
+ NotPattern = pattern.NotPattern,
+ CompositePattern = pattern.CompositePattern,
+ InitialFactPattern = pattern.InitialFactPattern,
+ constraints = require("./constraint"),
+ HashConstraint = constraints.HashConstraint,
+ ReferenceConstraint = constraints.ReferenceConstraint;
+
+
+ var MatchResult = define(null, {
+ instance:{
+ constructor:function (assertable) {
+ assertable = assertable || {};
+ this.variables = [];
+ this.facts = [];
+ this.factHash = {};
+ this.recency = [];
+ this.constraints = [];
+ this.isMatch = false;
+ var fact = assertable.fact;
+ if (fact) {
+ this.facts.push(fact);
+ this.recency.push(fact.recency);
+ }
+
+ },
+
+ merge:function (mr) {
+ var ret = new this._static();
+ ret.isMatch = mr.isMatch;
+ ret.facts = this.facts.concat(mr.facts);
+ merge(ret.factHash, this.factHash, mr.factHash);
+ ret.recency = union(this.recency, mr.recency);
+ return ret;
+ },
+
+ getters:{
+
+ factIds:function () {
+ return this.facts.map(
+ function (fact) {
+ return fact.id;
+ }).sort();
+ }
}
+
}
+ });
+
+
+ define(null, {
+ instance:{
+ constructor:function (wm, agendaTree) {
+ this.terminalNodes = [];
+ this.nodes = [];
+ this.constraints = [];
+ this.typeNodes = [];
+ this.bucket = {
+ counter:0,
+ recency:0
+ };
+ this.agendaTree = agendaTree;
+ },
+
+ assertRule:function (rule) {
+ var terminalNode = new TerminalNode(this.bucket, rule, this.agendaTree);
+ this.__addToNetwork(rule.pattern, terminalNode);
+ this.terminalNodes.push(terminalNode);
+ },
+
+ resetCounter:function () {
+ this.bucket.counter = 0;
+ },
+
+ incrementCounter:function () {
+ this.bucket.counter++;
+ },
+
+ assertFact:function (fact) {
+ var typeNodes = this.typeNodes, i = typeNodes.length - 1;
+ for (; i >= 0; i--) {
+ typeNodes[i].assert(fact);
+ }
+ },
- }
-});
-
-
-define(null, {
- instance:{
- constructor:function (wm, agendaTree) {
- this.terminalNodes = [];
- this.nodes = [];
- this.constraints = [];
- this.typeNodes = [];
- this.bucket = {
- counter:0,
- recency:0
- };
- this.agendaTree = agendaTree;
- },
-
- assertRule:function (rule) {
- var terminalNode = new TerminalNode(this.bucket, rule, this.agendaTree);
- this.__addToNetwork(rule.pattern, terminalNode);
- this.terminalNodes.push(terminalNode);
- },
-
- resetCounter:function () {
- this.bucket.counter = 0;
- },
-
- incrementCounter:function () {
- this.bucket.counter++;
- },
-
- assertFact:function (fact) {
- var typeNodes = this.typeNodes, i = typeNodes.length - 1;
- for (; i >= 0; i--) {
- typeNodes[i].assert(fact);
- }
- },
+ retractFact:function (fact) {
+ var typeNodes = this.typeNodes, i = typeNodes.length - 1;
+ for (; i >= 0; i--) {
+ typeNodes[i].retract(fact);
+ }
+ },
- retractFact:function (fact) {
- var typeNodes = this.typeNodes, i = typeNodes.length - 1;
- for (; i >= 0; i--) {
- typeNodes[i].retract(fact);
- }
- },
+ containsRule:function (name) {
+ return this.terminalNodes.some(function (n) {
+ return n.rule.name === name;
+ });
+ },
- containsRule:function (name) {
- return this.terminalNodes.some(function (n) {
- return n.rule.name === name;
- });
- },
+ dispose:function () {
+ var typeNodes = this.typeNodes, i = typeNodes.length - 1;
+ for (; i >= 0; i--) {
+ typeNodes[i].dispose();
+ }
+ },
- dispose:function () {
- var typeNodes = this.typeNodes, i = typeNodes.length - 1;
- for (; i >= 0; i--) {
- typeNodes[i].dispose();
- }
- },
+ __checkEqual:function (node) {
+ var constraints = this.constraints, i = constraints.length - 1;
+ for (; i >= 0; i--) {
+ var n = constraints[i];
+ if (node.equal(n)) {
+ return n;
+ }
+ }
+ this.constraints.push(node);
+ return node;
+ },
- __checkEqual:function (node) {
- var constraints = this.constraints, i = constraints.length - 1;
- for (; i >= 0; i--) {
- var n = constraints[i];
- if (node.equal(n)) {
- return n;
+ __createTypeNode:function (pattern) {
+ var ret = new TypeNode(pattern.constraints[0]);
+ var constraints = this.typeNodes, i = constraints.length - 1;
+ for (; i >= 0; i--) {
+ var n = constraints[i];
+ if (ret.equal(n)) {
+ return n;
+ }
}
- }
- this.constraints.push(node);
- return node;
- },
-
- __createTypeNode:function (pattern) {
- var ret = new TypeNode(pattern.constraints[0]);
- var constraints = this.typeNodes, i = constraints.length - 1;
- for (; i >= 0; i--) {
- var n = constraints[i];
- if (ret.equal(n)) {
- return n;
+ this.typeNodes.push(ret);
+ return ret;
+ },
+
+ __createEqualityNode:function (constraint) {
+ return this.__checkEqual(new EqualityNode(constraint));
+ },
+
+ __createReferenceNode:function (constraint) {
+ return this.__checkEqual(new ReferenceNode(constraint));
+ },
+
+ __createPropertyNode:function (constraint) {
+ return this.__checkEqual(new PropertyNode(constraint));
+ },
+
+ __createBridgeNode:function (pattern) {
+ return new BridgeNode(pattern);
+ },
+
+ __createAdapterNode:function (side) {
+ return side === "left" ? new LeftAdapterNode() : new RightAdapterNode();
+ },
+
+ __createJoinNode:function (pattern, outNode, side) {
+ var joinNode;
+ if (isInstanceOf(pattern.rightPattern, NotPattern)) {
+ joinNode = new NotNode();
+ } else {
+ joinNode = new JoinNode();
}
- }
- this.typeNodes.push(ret);
- return ret;
- },
-
- __createEqualityNode:function (constraint) {
- return this.__checkEqual(new EqualityNode(constraint));
- },
-
- __createReferenceNode:function (constraint) {
- return this.__checkEqual(new ReferenceNode(constraint));
- },
-
- __createPropertyNode:function (constraint) {
- return this.__checkEqual(new PropertyNode(constraint));
- },
-
- __createBridgeNode:function (pattern) {
- return new BridgeNode(pattern);
- },
-
- __createAdapterNode:function (side) {
- return side == "left" ? new LeftAdapterNode() : new RightAdapterNode();
- },
-
- __createJoinNode:function (pattern, outNode, side) {
- var joinNode;
- if (isInstanceOf(pattern.rightPattern, NotPattern)) {
- joinNode = new NotNode()
- } else {
- joinNode = new JoinNode()
- }
- var parentNode = joinNode;
- if (isInstanceOf(outNode, JoinNode)) {
- var adapterNode = this.__createAdapterNode(side);
- parentNode.addOutNode(adapterNode, pattern);
- parentNode = adapterNode;
- }
- parentNode.addOutNode(outNode, pattern);
- return joinNode;
- },
-
- __addToNetwork:function (pattern, outNode, side) {
- if (isInstanceOf(pattern, ObjectPattern)) {
- if (isInstanceOf(pattern, NotPattern) && (!side || side === "left")) {
- return this.__addToNetwork(new CompositePattern(new InitialFactPattern(), pattern), outNode, side);
- }
- return this.__createAlphaNode(pattern, outNode, side);
- } else if (isInstanceOf(pattern, CompositePattern)) {
- var joinNode = this.__createJoinNode(pattern, outNode, side);
- this.__addToNetwork(pattern.leftPattern, joinNode, "left");
- this.__addToNetwork(pattern.rightPattern, joinNode, "right");
- outNode.addParentNode(joinNode);
+ var parentNode = joinNode;
+ if (isInstanceOf(outNode, JoinNode)) {
+ var adapterNode = this.__createAdapterNode(side);
+ parentNode.addOutNode(adapterNode, pattern);
+ parentNode = adapterNode;
+ }
+ parentNode.addOutNode(outNode, pattern);
return joinNode;
- }
- },
-
-
- __createAlphaNode:function (pattern, outNode, side) {
- var constraints = pattern.constraints;
- var typeNode = this.__createTypeNode(pattern);
- var parentAtom = constraints[0];
- var parentNode = typeNode;
- var i = constraints.length - 1;
- for (; i > 0; i--) {
- var constraint = constraints[i], node;
- if (constraint instanceof HashConstraint) {
- node = this.__createPropertyNode(constraint);
- } else if (constraint instanceof ReferenceConstraint) {
- node = this.__createReferenceNode(constraint);
- outNode.refNodes.push(node);
- } else {
- node = this.__createEqualityNode(constraint);
+ },
+
+ __addToNetwork:function (pattern, outNode, side) {
+ if (isInstanceOf(pattern, ObjectPattern)) {
+ if (isInstanceOf(pattern, NotPattern) && (!side || side === "left")) {
+ return this.__addToNetwork(new CompositePattern(new InitialFactPattern(), pattern), outNode, side);
+ }
+ return this.__createAlphaNode(pattern, outNode, side);
+ } else if (isInstanceOf(pattern, CompositePattern)) {
+ var joinNode = this.__createJoinNode(pattern, outNode, side);
+ this.__addToNetwork(pattern.leftPattern, joinNode, "left");
+ this.__addToNetwork(pattern.rightPattern, joinNode, "right");
+ outNode.addParentNode(joinNode);
+ return joinNode;
}
- parentNode.addOutNode(node, pattern, parentAtom);
- node.parentNodes.push(parentNode);
- parentNode = node;
- parentAtom = constraint;
- }
- var bridgeNode = this.__createBridgeNode(pattern);
- parentNode.addOutNode(bridgeNode, pattern, parentAtom);
- bridgeNode.addParentNode(parentNode);
- parentNode = bridgeNode;
- outNode.addParentNode(parentNode);
- if (outNode instanceof JoinNode) {
- var adapterNode = this.__createAdapterNode(side);
- parentNode.addOutNode(adapterNode, pattern);
- parentNode = adapterNode;
+ },
+
+
+ __createAlphaNode:function (pattern, outNode, side) {
+ var constraints = pattern.constraints;
+ var typeNode = this.__createTypeNode(pattern);
+ var parentAtom = constraints[0];
+ var parentNode = typeNode;
+ var i = constraints.length - 1;
+ for (; i > 0; i--) {
+ var constraint = constraints[i], node;
+ if (constraint instanceof HashConstraint) {
+ node = this.__createPropertyNode(constraint);
+ } else if (constraint instanceof ReferenceConstraint) {
+ node = this.__createReferenceNode(constraint);
+ outNode.refNodes.push(node);
+ } else {
+ node = this.__createEqualityNode(constraint);
+ }
+ parentNode.addOutNode(node, pattern, parentAtom);
+ node.parentNodes.push(parentNode);
+ parentNode = node;
+ parentAtom = constraint;
+ }
+ var bridgeNode = this.__createBridgeNode(pattern);
+ parentNode.addOutNode(bridgeNode, pattern, parentAtom);
+ bridgeNode.addParentNode(parentNode);
+ parentNode = bridgeNode;
+ outNode.addParentNode(parentNode);
+ if (outNode instanceof JoinNode) {
+ var adapterNode = this.__createAdapterNode(side);
+ parentNode.addOutNode(adapterNode, pattern);
+ parentNode = adapterNode;
+ }
+ parentNode.addOutNode(outNode, pattern);
+ return typeNode;
+ },
+
+ print:function () {
+ this.terminalNodes.forEach(function (t) {
+ t.print(" ");
+ });
}
- parentNode.addOutNode(outNode, pattern);
- return typeNode;
- },
-
- print:function () {
- this.terminalNodes.forEach(function (t) {
- t.print(" ");
- });
}
- }
-}).as(exports, "RootNode");
-
-var Node = define(null, {
- instance:{
- constructor:function () {
- this.nodes = new HashTable();
- this.parentNodes = [];
-
- },
-
- resolve:function (mr1, mr2) {
- var mr1FactHash = mr1.factHash, mr2FactHash = mr2.factHash;
- var fhKeys1 = Object.keys(mr1FactHash),
- fhKeys2 = Object.keys(mr2FactHash);
- var i = fhKeys1.length - 1, j = fhKeys2.length - 1;
- if (i != j) return false;
- fhKeys1.sort();
- fhKeys2.sort();
- for (; i >= 0; i--) {
- var k1 = fhKeys1[i], k2 = fhKeys2[i];
- if (k1 == k2 && mr1FactHash[k1] !== mr2FactHash[k2]) {
+ }).as(exports, "RootNode");
+
+ var Node = define(null, {
+ instance:{
+ constructor:function () {
+ this.nodes = new HashTable();
+ this.parentNodes = [];
+
+ },
+
+ resolve:function (mr1, mr2) {
+ var mr1FactHash = mr1.factHash, mr2FactHash = mr2.factHash;
+ var fhKeys1 = Object.keys(mr1FactHash),
+ fhKeys2 = Object.keys(mr2FactHash);
+ var i = fhKeys1.length - 1, j = fhKeys2.length - 1;
+ if (i !== j) {
return false;
}
- }
+ fhKeys1.sort();
+ fhKeys2.sort();
+ for (; i >= 0; i--) {
+ var k1 = fhKeys1[i], k2 = fhKeys2[i];
+ if (k1 === k2 && mr1FactHash[k1] !== mr2FactHash[k2]) {
+ return false;
+ }
+ }
- return true;
- },
+ return true;
+ },
- print:function (tab) {
- console.log(tab + this.toString());
- this.parentNodes.forEach(function (n) {
- n.print(" " + tab);
- });
- },
+ print:function (tab) {
+ console.log(tab + this.toString());
+ this.parentNodes.forEach(function (n) {
+ n.print(" " + tab);
+ });
+ },
- addOutNode:function (outNode, pattern) {
- if (!this.nodes.contains(outNode)) {
- this.nodes.put(outNode, []);
- }
- this.nodes.get(outNode).push(pattern);
- },
-
- addParentNode:function (n) {
- this.parentNodes.push(n);
- },
-
- shareable:function () {
- return false;
- },
-
- __propagate:function (method, assertable, outNodes) {
- outNodes = outNodes || this.nodes;
- var entrySet = outNodes.entrySet, i = entrySet.length - 1;
- for (; i >= 0; i--) {
- var entry = entrySet[i], outNode = entry.key, paths = entry.value;
- if (assertable.paths) {
- var continuingPaths = intersect(paths, assertable.paths);
- if (continuingPaths.length) {
- outNode[method]({fact:assertable.fact, factHash:{}, paths:continuingPaths});
+ addOutNode:function (outNode, pattern) {
+ if (!this.nodes.contains(outNode)) {
+ this.nodes.put(outNode, []);
+ }
+ this.nodes.get(outNode).push(pattern);
+ },
+
+ addParentNode:function (n) {
+ this.parentNodes.push(n);
+ },
+
+ shareable:function () {
+ return false;
+ },
+
+ __propagate:function (method, assertable, outNodes) {
+ outNodes = outNodes || this.nodes;
+ var entrySet = outNodes.entrySet, i = entrySet.length - 1;
+ for (; i >= 0; i--) {
+ var entry = entrySet[i], outNode = entry.key, paths = entry.value;
+ if (assertable.paths) {
+ var continuingPaths = intersect(paths, assertable.paths);
+ if (continuingPaths.length) {
+ outNode[method]({fact:assertable.fact, factHash:{}, paths:continuingPaths});
+ }
+ } else {
+ outNode[method](assertable);
}
- } else {
- outNode[method](assertable);
}
- }
- },
-
- dispose:function (assertable) {
- this.propagateDispose(assertable);
- },
-
- retract:function (assertable) {
- this.propagateRetract(assertable);
- },
-
- propagateDispose:function (assertable, outNodes) {
- outNodes = outNodes || this.nodes;
- var entrySet = outNodes.entrySet, i = entrySet.length - 1;
- for (; i >= 0; i--) {
- var entry = entrySet[i], outNode = entry.key;
- outNode.dispose(assertable);
- }
- },
+ },
+
+ dispose:function (assertable) {
+ this.propagateDispose(assertable);
+ },
+
+ retract:function (assertable) {
+ this.propagateRetract(assertable);
+ },
+
+ propagateDispose:function (assertable, outNodes) {
+ outNodes = outNodes || this.nodes;
+ var entrySet = outNodes.entrySet, i = entrySet.length - 1;
+ for (; i >= 0; i--) {
+ var entry = entrySet[i], outNode = entry.key;
+ outNode.dispose(assertable);
+ }
+ },
- propagateAssert:function (assertable, outNodes) {
- this.__propagate("assert", assertable, outNodes || this.nodes);
- },
+ propagateAssert:function (assertable, outNodes) {
+ this.__propagate("assert", assertable, outNodes || this.nodes);
+ },
- propagateRetract:function (assertable, outNodes) {
- this.__propagate("retract", assertable, outNodes || this.nodes);
- },
+ propagateRetract:function (assertable, outNodes) {
+ this.__propagate("retract", assertable, outNodes || this.nodes);
+ },
- assert:function (assertable) {
- this.propagateAssert(assertable);
- },
+ assert:function (assertable) {
+ this.propagateAssert(assertable);
+ },
- propagateModify:function (assertable, outNodes) {
- this.__propagate("modify", assertable, outNodes || this.nodes);
+ propagateModify:function (assertable, outNodes) {
+ this.__propagate("modify", assertable, outNodes || this.nodes);
+ }
}
- }
-});
+ });
-var AlphaNode = define(Node, {
- instance:{
- constructor:function (constraint) {
- this._super([]);
- this.constraint = constraint;
- },
+ var AlphaNode = define(Node, {
+ instance:{
+ constructor:function (constraint) {
+ this._super([]);
+ this.constraint = constraint;
+ },
- toString:function () {
- return JSON.stringify(this.constraint.constraint);
- },
+ toString:function () {
+ return JSON.stringify(this.constraint.constraint);
+ },
- equal:function (constraint) {
- return this.constraint.equal(constraint.constraint);
+ equal:function (constraint) {
+ return this.constraint.equal(constraint.constraint);
+ }
}
- }
-});
+ });
-var TypeNode = define(AlphaNode, {
- instance:{
+ var TypeNode = define(AlphaNode, {
+ instance:{
- assert:function (fact) {
- if (this.constraint.assert(fact.object)) {
- this.propagateAssert({fact:fact});
- }
- },
+ assert:function (fact) {
+ if (this.constraint.assert(fact.object)) {
+ this.propagateAssert({fact:fact});
+ }
+ },
- retract:function (fact) {
- if (this.constraint.assert(fact.object)) {
- this.propagateRetract({fact:fact});
- }
- },
+ retract:function (fact) {
+ if (this.constraint.assert(fact.object)) {
+ this.propagateRetract({fact:fact});
+ }
+ },
- toString:function () {
- return "Type Node" + this.constraint.constraint;
- },
+ toString:function () {
+ return "Type Node" + this.constraint.constraint;
+ },
- dispose:function () {
- var es = this.nodes.entrySet, i = es.length - 1;
- for (; i >= 0; i--) {
- var e = es[i], outNode = e.key, paths = e.value;
- outNode.dispose({paths:paths});
- }
- },
-
- __propagate:function (method, assertion, outNodes) {
- var es = (outNodes || this.nodes).entrySet, i = es.length - 1;
- for (; i >= 0; i--) {
- var e = es[i], outNode = e.key, paths = e.value;
- assertion.factHash = {};
- assertion.paths = paths;
- outNode[method](assertion);
+ dispose:function () {
+ var es = this.nodes.entrySet, i = es.length - 1;
+ for (; i >= 0; i--) {
+ var e = es[i], outNode = e.key, paths = e.value;
+ outNode.dispose({paths:paths});
+ }
+ },
+
+ __propagate:function (method, assertion, outNodes) {
+ var es = (outNodes || this.nodes).entrySet, i = es.length - 1;
+ for (; i >= 0; i--) {
+ var e = es[i], outNode = e.key, paths = e.value;
+ assertion.factHash = {};
+ assertion.paths = paths;
+ outNode[method](assertion);
+ }
}
}
- }
-});
-
-var PropertyNode = define(AlphaNode, {
- instance:{
-
- assert:function (assertable) {
- var fh = {}, constraint = this.constraint, o = assertable.fact.object, alias = constraint.alias;
- fh[alias] = o;
- if (constraint.assert(fh)) {
- assertable.factHash[alias] = o;
- this._super([assertable])
- }
- },
+ });
- toString:function () {
- return "Property Node" + this._super();
- }
- }
-});
-
-var ReferenceNode = define(AlphaNode, {
- instance:{
-
- //used by NotNode to avoid creating match Result for efficiency
- isMatch:function (leftContext, rightContext) {
- var leftMatch = leftContext.match,
- match = leftMatch.factHash,
- constraint = this.constraint,
- rightFact = rightContext.fact;
- var fh = {};
- fh[constraint.alias] = rightFact.object;
- var vars = constraint.variables, i = vars.length - 1;
- for (; i >= 0; i--) {
- var v = vars[i];
- fh[v] = match[v];
- }
- return constraint.assert(fh);
- },
-
-
- match:function (leftContext, rightContext) {
- var leftMatch = leftContext.match, match = leftMatch.factHash, constraint = this.constraint, alias = constraint.alias, rightFact = rightContext.fact;
- var fh = {};
- fh[alias] = rightFact.object;
- var vars = constraint.variables, i = vars.length - 1;
- for (; i >= 0; i--) {
- var v = vars[i];
- fh[v] = match[v];
+ var PropertyNode = define(AlphaNode, {
+ instance:{
+
+ assert:function (assertable) {
+ var fh = {}, constraint = this.constraint, o = assertable.fact.object, alias = constraint.alias;
+ fh[alias] = o;
+ if (constraint.assert(fh)) {
+ assertable.factHash[alias] = o;
+ this._super([assertable]);
+ }
+ },
+
+ toString:function () {
+ return "Property Node" + this._super();
}
- var m = constraint.assert(fh);
- if (m) {
- var mr = new MatchResult().merge(leftMatch);
- mr.isMatch = true;
- mr.factHash[alias] = rightFact.object;
- mr.recency.push(rightFact.recency);
- return mr;
- } else {
- return new MatchResult();
+ }
+ });
+
+ var ReferenceNode = define(AlphaNode, {
+ instance:{
+
+ //used by NotNode to avoid creating match Result for efficiency
+ isMatch:function (leftContext, rightContext) {
+ var leftMatch = leftContext.match,
+ match = leftMatch.factHash,
+ constraint = this.constraint,
+ rightFact = rightContext.fact;
+ var fh = {};
+ fh[constraint.alias] = rightFact.object;
+ var vars = constraint.variables, i = vars.length - 1;
+ for (; i >= 0; i--) {
+ var v = vars[i];
+ fh[v] = match[v];
+ }
+ return constraint.assert(fh);
+ },
+
+
+ match:function (leftContext, rightContext) {
+ var leftMatch = leftContext.match, match = leftMatch.factHash, constraint = this.constraint, alias = constraint.alias, rightFact = rightContext.fact;
+ var fh = {};
+ fh[alias] = rightFact.object;
+ var vars = constraint.variables, i = vars.length - 1;
+ for (; i >= 0; i--) {
+ var v = vars[i];
+ fh[v] = match[v];
+ }
+ var m = constraint.assert(fh);
+ if (m) {
+ var mr = new MatchResult().merge(leftMatch);
+ mr.isMatch = true;
+ mr.factHash[alias] = rightFact.object;
+ mr.recency.push(rightFact.recency);
+ return mr;
+ } else {
+ return new MatchResult();
+ }
+ },
+ toString:function () {
+ return "Reference Node" + this._super();
}
- },
- toString:function () {
- return "Reference Node" + this._super();
}
- }
-});
+ });
-var EqualityNode = define(AlphaNode, {
- instance:{
+ var EqualityNode = define(AlphaNode, {
+ instance:{
- assert:function (assertable) {
- var fh = {}, constraint = this.constraint;
- fh[constraint.alias] = assertable.fact.object;
- if (constraint.assert(fh)) {
- this._super([assertable])
- }
- },
+ assert:function (assertable) {
+ var fh = {}, constraint = this.constraint;
+ fh[constraint.alias] = assertable.fact.object;
+ if (constraint.assert(fh)) {
+ this._super([assertable]);
+ }
+ },
- toString:function () {
- return "Equality Node" + this._super();
+ toString:function () {
+ return "Equality Node" + this._super();
+ }
}
- }
-});
-
-
-var BridgeNode = define(Node, {
-
- instance:{
-
- constructor:function (pattern) {
- this._super([]);
- this.pattern = pattern;
- },
-
- toString:function () {
- return "Base Bridge Node " + this.pattern;
- },
-
- assert:function (assertable) {
- var mr = new MatchResult(assertable), pattern = this.pattern, constraints = pattern.constraints;
- mr.isMatch = true;
- var fact = assertable.fact, o = fact.object, fh = mr.factHash;
- var i = constraints.length - 1;
- fh[pattern.alias] = o;
- for (; i > 0; i--) {
- var constraint = constraints[i];
- if (constraint instanceof HashConstraint) {
- var hash = constraint.variables;
- for (var j in hash) {
- fh[hash[j]] = o[j];
+ });
+
+
+ var BridgeNode = define(Node, {
+
+ instance:{
+
+ constructor:function (pattern) {
+ this._super([]);
+ this.pattern = pattern;
+ },
+
+ toString:function () {
+ return "Base Bridge Node " + this.pattern;
+ },
+
+ assert:function (assertable) {
+ var mr = new MatchResult(assertable), pattern = this.pattern, constraints = pattern.constraints;
+ mr.isMatch = true;
+ var fact = assertable.fact, o = fact.object, fh = mr.factHash;
+ var i = constraints.length - 1;
+ fh[pattern.alias] = o;
+ for (; i > 0; i--) {