Преглед изворни кода

MPIDE-27: track all references in a behavior

Systems and behaviors now keep a list of what other entities they're
referencing in their body, making it simpler to handle certain errors
and fetch information on related events.
Austin Meagher пре 10 година
родитељ
комит
f1f62820a2
1 измењених фајлова са 34 додато и 21 уклоњено
  1. 34 21
      src/lib/parser/modellang.pegjs

+ 34 - 21
src/lib/parser/modellang.pegjs

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