Просмотр исходного кода

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 лет назад
Родитель
Сommit
f1f62820a2
1 измененных файлов с 34 добавлено и 21 удалено
  1. 34 21
      src/lib/parser/modellang.pegjs

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

@@ -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()); }