|
|
@@ -38,6 +38,7 @@
|
|
|
triggers: [],
|
|
|
};
|
|
|
|
|
|
+ // accumulate varying statements into a flatter structure
|
|
|
for (var s in statements) {
|
|
|
var statement = statements[s];
|
|
|
|
|
|
@@ -59,11 +60,12 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // add atomic events to behaviors list
|
|
|
for (var r in ast.references) {
|
|
|
var ref = ast.references[r];
|
|
|
|
|
|
if (!model.behaviors[ref])
|
|
|
- model.behaviors[ref] = { type:"Behavior", id:ref, body:[] };
|
|
|
+ model.behaviors[ref] = { type:"Behavior", id:ref, body:[], refs:[] };
|
|
|
}
|
|
|
|
|
|
return warnify(model);
|
|
|
@@ -75,7 +77,14 @@
|
|
|
for (var i in model.interactions) {
|
|
|
model.interactions[i].body.forEach(function (sys) {
|
|
|
if (!model.systems[sys.system])
|
|
|
- model.errors.push(err("WARNING: reference to an undefined system (" + sys.system + ")", null, sys.location));
|
|
|
+ model.errors.push(err("ERROR: reference to an undefined system (" + sys.system + ")", null, sys.location));
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var b in model.behaviors) {
|
|
|
+ model.behaviors[b].refs.forEach(function (ref) {
|
|
|
+ if (model.systems[ref])
|
|
|
+ model.errors.push(err("ERROR: reference to system (" + ref + ") in a behavior (" + model.behaviors[b].id + ")", null, model.behaviors[b].location));
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -112,14 +121,16 @@
|
|
|
this.id = id;
|
|
|
},
|
|
|
|
|
|
- System: function System(id, body) {
|
|
|
+ System: function System(id, body, refs) {
|
|
|
ast.Id.call(this, "System", id);
|
|
|
this.body = body;
|
|
|
+ this.refs = refs;
|
|
|
},
|
|
|
|
|
|
- Behavior: function Behavior(id, body) {
|
|
|
+ Behavior: function Behavior(id, body, refs) {
|
|
|
ast.Id.call(this, "Behavior", id);
|
|
|
this.body = body;
|
|
|
+ this.refs = refs;
|
|
|
},
|
|
|
|
|
|
Interaction: function Interaction(type, body) {
|
|
|
@@ -172,7 +183,7 @@
|
|
|
|
|
|
start
|
|
|
= s:statement*
|
|
|
- { return model(s); }
|
|
|
+ { return model(s); }
|
|
|
|
|
|
statement
|
|
|
= s:( system_statement
|
|
|
@@ -182,19 +193,19 @@ statement
|
|
|
_SEMI_
|
|
|
{ return s; }
|
|
|
|
|
|
-system_statement
|
|
|
+system_statement "System"
|
|
|
= _SYSTEM_ _COLON_ id:system_id
|
|
|
- !{ ast.toplevelname = id; }
|
|
|
+ !{ ast.toplevelname = id; ast.localrefs = []; }
|
|
|
_EQ_ body:behavior_pattern
|
|
|
- { return new ast.System(id, body); }
|
|
|
+ { return new ast.System(id, [body], ast.localrefs); }
|
|
|
|
|
|
-behavior_statement
|
|
|
+behavior_statement "Behavior"
|
|
|
= _BEHAVIOR_ _COLON_ id:behavior_id
|
|
|
- !{ ast.toplevelname = id; }
|
|
|
+ !{ ast.toplevelname = id; ast.localrefs = []; }
|
|
|
_EQ_ body:behavior_pattern
|
|
|
- { return new ast.Behavior(id, body); }
|
|
|
+ { return new ast.Behavior(id, [body], ast.localrefs); }
|
|
|
|
|
|
-interaction_statement
|
|
|
+interaction_statement "Interaction"
|
|
|
= _INTERACTION_ _COLON_ first:( system_item_selector / expression )
|
|
|
type:interaction_type second:( system_item_selector / expression )
|
|
|
!{ ast.interactionType = type; }
|
|
|
@@ -210,11 +221,11 @@ interaction_type
|
|
|
= _ t:( ORDER / JOIN ) _
|
|
|
{ return t; }
|
|
|
|
|
|
-system_item_selector
|
|
|
+system_item_selector "Selector"
|
|
|
= !([a-z0-9 ]i+ operator) _ sys:system_id ":" _ p:behavior_pattern _
|
|
|
{ return new ast.Selector(sys, p); }
|
|
|
|
|
|
-expression
|
|
|
+expression "Expression"
|
|
|
= term:term op:operator expr:expression
|
|
|
{ return new ast.Expression(op, term, expr); }
|
|
|
/ term
|
|
|
@@ -231,7 +242,7 @@ operator
|
|
|
/ _ o:"<=" _ { return o; }
|
|
|
/ _ o:"==" _ { return o; }
|
|
|
|
|
|
-behavior_pattern
|
|
|
+behavior_pattern "Behavior Pattern"
|
|
|
= alternation
|
|
|
/ sequence
|
|
|
|
|
|
@@ -244,14 +255,16 @@ sequence
|
|
|
{ return new ast.Sequence(body); }
|
|
|
|
|
|
behavior_pattern_item
|
|
|
- = _ i:( group / event_ref ) q:quantifier? _
|
|
|
+ = _ i:group q:quantifier? _
|
|
|
{ return scopify(i, q); }
|
|
|
+ / _ i:event_ref q:quantifier? _
|
|
|
+ { if (ast.localrefs.indexOf(i.id) === -1) { ast.localrefs.push(i.id); } return scopify(i, q); }
|
|
|
|
|
|
-group
|
|
|
+group "Group"
|
|
|
= _ async:ASYNC? "(" _ body:behavior_pattern _ ")"
|
|
|
{ return new ast.Group(async, body); }
|
|
|
|
|
|
-quantifier
|
|
|
+quantifier "Quantifier"
|
|
|
= "+" _ { return {min:1, max:null}; }
|
|
|
/ "*" _ { return {min:0, max:null}; }
|
|
|
/ "?" _ { return {min:0, max:1}; }
|
|
|
@@ -261,7 +274,7 @@ quantifier_range
|
|
|
= "{" _ lo:INT_GTE0 hi:( u:_COMMA_ v:INT_GT0? { return {u:u, v:v}; } )? _ "}" _
|
|
|
{ return minmaxify(lo, hi); }
|
|
|
|
|
|
-trigger
|
|
|
+trigger "Trigger"
|
|
|
= _WHEN_ _COLON_ selector:( system_item_selector / expression ) "{" body:embedded_code "}"
|
|
|
{ return new ast.Trigger(selector, body); }
|
|
|
|
|
|
@@ -273,7 +286,7 @@ embedded_code
|
|
|
behavior_id = id:ID { return id; }
|
|
|
system_id = id:ID { return id; }
|
|
|
property = id:ID { return id; }
|
|
|
-/* FIXME: it's possible, though not correct, to reference systems from a behavior; this will mark them as behaviors */
|
|
|
+
|
|
|
event_ref = id:ID
|
|
|
{
|
|
|
if (id === ast.toplevelname) {
|
|
|
@@ -311,7 +324,7 @@ ID "Identifier" /*TODO: UNICODE?*/
|
|
|
= !KEYWORD [A-Za-z] [a-zA-Z0-9_]*
|
|
|
{ return text(); }
|
|
|
|
|
|
-INT
|
|
|
+INT "Integer"
|
|
|
= [0-9]+
|
|
|
{ return parseInt(text()); }
|
|
|
|