Skip to content

Commit

Permalink
Implements the extends keyword for types defined in the dsl.
Browse files Browse the repository at this point in the history
Fixes issue with test for extends.

Working to get the tests to pass.

The nools parser test for defines uses a deep equal to a known
structure.  There is a new property in the define parse output, extend:
<typename> , this is null unless there is an actual base class.  Adding
null, trivial change for this.

Implements the extends keyword for types defined in the dsl.
  • Loading branch information
markbjerke committed Jan 25, 2016
1 parent ca15994 commit b8a61e5
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 16 deletions.
16 changes: 13 additions & 3 deletions lib/compile/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ var createFunction = function (body, defined, scope, scopeNames, definedNames) {

var createDefined = (function () {

var _createDefined = function (action, defined, scope) {
var _createDefined = function (options, defined, scope) {
var action = options.properties
,proto, base;
//
if (isString(action)) {
var declares = [];
extd(defined).keys().forEach(function (i) {
Expand Down Expand Up @@ -57,7 +60,14 @@ var createDefined = (function () {
}
}
};
var proto = ret.prototype;
if (options.extend) {
base = defined[options.extend];
proto = Object.create(base.prototype);
ret.prototype = proto;
}
else {
proto = ret.prototype;
}
for (var i in action) {
proto[i] = action[i];
}
Expand All @@ -66,7 +76,7 @@ var createDefined = (function () {
};

return function (options, defined, scope) {
return _createDefined(options.properties, defined, scope);
return _createDefined(options, defined, scope);
};
})();

Expand Down
40 changes: 31 additions & 9 deletions lib/compile/transpile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,48 @@ var extd = require("../extended"),
constraintMatcher = require("../constraintMatcher"),
parser = require("../parser");

function definedToJs(options) {
function definedToJs(options, extend) {
/*jshint evil:true*/
options = isString(options) ? new Function("return " + options + ";")() : options;
var ret = ["(function(){"], value;

var ret = ["(function(flow){"], value;
if (options.hasOwnProperty("constructor") && "function" === typeof options.constructor) {
ret.push("var Defined = " + options.constructor.toString() + ";");
} else {
ret.push("var Defined = function(opts){ for(var i in opts){if(opts.hasOwnProperty(i)){this[i] = opts[i];}}};");
}
ret.push("var proto = Defined.prototype;");
if (extend) {
ret.push("var proto = Object.create(flow.getDefined('" + extend + "').prototype); proto.constructor = Defined; Defined.prototype = proto;");
}
else {
ret.push("var proto = Defined.prototype;");
}

for (var key in options) {
if (options.hasOwnProperty(key)) {
var str;
if (options.hasOwnProperty(key) && key !== 'constructor') {
value = options[key];
ret.push("proto." + key + " = " + (extd.isFunction(value) ? value.toString() : extd.format("%j", value)) + ";");
str = ("proto." + key + " = ");
if (extd.isFunction(value)) {
str += value.toString();
}
else {
if (value instanceof Array) {
str += JSON.stringify(value);
}
else {
str += extd.format("%j", value);
}
str += ";"
}
ret.push(str);
}
}
ret.push("return Defined;");
ret.push("}())");
return ret.join("");
ret.push("}(this))");
var sJoin = ret.join("");
debugger;
return sJoin;

}

Expand Down Expand Up @@ -148,7 +170,7 @@ exports.transpile = function (flowObj, options) {
ret.push(extd(flowObj.define || []).map(function (defined) {
var name = defined.name;
defined[name] = {};
return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties) + ");"].join(" ");
return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties, defined.extend) + ");"].join(" ");
}).value().join("\n"));
ret.push(extd(flowObj.scope || []).map(function (s) {
var name = s.name;
Expand Down
7 changes: 6 additions & 1 deletion lib/parser/nools/tokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,17 @@ var topLevelTokens = {
var name = src.match(/^([a-zA-Z_$][0-9a-zA-Z_$]*)/);
if (name) {
src = src.replace(name[0], "").replace(/^\s*|\s*$/g, "");
var extend = src.match(/^extends\s+([a-zA-Z_$][0-9a-zA-Z_$]*)/);
if (extend) {
src = src.replace(extend[0], "").replace(/^\s*|\s*$/g, "");
extend = extend[1];
}
if (utils.findNextToken(src) === "{") {
name = name[1];
var body = utils.getTokensBetween(src, "{", "}", true).join("");
src = src.replace(body, "");
//should
context.define.push({name: name, properties: "(" + body + ")"});
context.define.push({ name: name, extend: extend, properties: "(" + body + ")" });
return src;
} else {
throw new Error("unexpected token : expected : '{' found : '" + utils.findNextToken(src) + "'");
Expand Down
15 changes: 13 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ To use the flow
var flow = nools.compile(__dirname + "/helloworld.nools"),
Message = flow.getDefined("message");
```
# Type Declaration 'extends'
Defined types in the DSL no support 'extends' keyword for inheritance.

Any type present in the flow can be extended. Base types must be defined before extended types.

```
define EncodedMessage extends Message {
encoding: 'sha1'
,constructor: function(message, encoding) {
Message.call(this, message); // call superclass manually
this.encoding = encoding
}
}
### Flow Events
Expand Down Expand Up @@ -341,7 +354,6 @@ session.getFacts(Number); //[1, 2];
session.getFacts(String); //["A", "B"];
```


<a name="firing"></a>
## Firing the rules

Expand Down Expand Up @@ -1004,7 +1016,6 @@ flow1
```



<a name="rule-scope"></a>
### Scope

Expand Down
22 changes: 22 additions & 0 deletions test/flow.dsl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,4 +593,26 @@ it.describe("Flow dsl", function (it) {
});
});
});
it.describe("extended Fact types", function (it) {
var Person, Student, LongTermStudent, Count, session1Fired = {}, session1;
var flow = nools.compile(resolve(__dirname, "./rules/extends.nools"), {
name: 'extendsTest'
});
Person = flow.getDefined('Person');
Student = flow.getDefined('Student');
LongTermStudent = flow.getDefined('LongTermStudent');
//
session1 = flow.getSession(new Person('Bob'), new Student('Sue', 'harvard'), new LongTermStudent('Jim', 'princeton', 1)).on('fire', function (name) {
session1Fired[name] = session1Fired[name] || { cnt: 0 };
session1Fired[name].cnt++;
});
//
it.should(" fire rule(s) correctly according to type. each rule matching a single type ", function (next) {
return session1.match().then(function () {
assert(session1Fired['PersonTest'].cnt === 3);
assert(session1Fired['StudentTest'].cnt === 2);
assert(session1Fired['LongTermStudentTest'].cnt === 1);
})
});
});
});
5 changes: 4 additions & 1 deletion test/noolsParser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ it.describe("nools dsl parser", function (it) {
define: [
{
name: "Test",
properties: "({myProp : 'value'})"
extend: null,
properties: "({myProp : 'value'})"
}
],
"rules": [],
Expand All @@ -28,6 +29,7 @@ it.describe("nools dsl parser", function (it) {
define: [
{
name: "Test",
extend: null,
properties: "({myFunc : function(){}})"
}
],
Expand Down Expand Up @@ -183,6 +185,7 @@ it.describe("nools dsl parser", function (it) {
"define": [
{
"name": "Count",
extend: null,
"properties": "({ constructor: function(){ this.called = 0; } })"
}
],
Expand Down
46 changes: 46 additions & 0 deletions test/rules/extends.nools
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

define Person {
constructor: function(name){
this.name = name;
}
}

define Student extends Person {
constructor: function(name, school) {
Person.call(this, name);
this.school = school;
}
}

define LongTermStudent extends Student {
constructor: function(name, school, years) {
Student.call(this, name, school);
this.years = years;
}
}


rule PersonTest {
when {
p: Person;
}
then {
}
}

rule StudentTest {
when {
s: Student;
}
then {
}
}


rule LongTermStudentTest {
when {
s: LongTermStudent;
}
then {
}
}

0 comments on commit b8a61e5

Please sign in to comment.