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

MPIDE-27: 🐛 various parser bugfixes

Parser no longer misreports undefined reference and recursive definition
errors. Alternations now operate on elements instead of sequences,
leading to a more typical result when not wrapping it in a group.
Embedded code now accounts for characters following a nested brace.

Updated docs to reflect changes.
Austin Meagher 10 лет назад
Родитель
Сommit
201febca1f
3 измененных файлов с 16 добавлено и 19 удалено
  1. 2 2
      docs/modellang.bnf
  2. 0 2
      docs/overview.md
  3. 14 15
      src/lib/parser/modellang.pegjs

+ 2 - 2
docs/modellang.bnf

@@ -18,8 +18,8 @@
     |  <sequence>
     |  <sequence>
 
 
 <alternation> ::=
 <alternation> ::=
-    <sequence> "|" <alternation>
-    |  <sequence> "|" <sequence>
+    <element> "|" <alternation>
+    |  <element> "|" <element>
 
 
 <sequence> ::=
 <sequence> ::=
     <element> <sequence>
     <element> <sequence>

+ 0 - 2
docs/overview.md

@@ -48,8 +48,6 @@ SYSTEM: alternation = a (pipe | vertical bar | stick) delimited list of sequence
 BEHAVIOR: quantifiers = none_or_more* one_or_more+ none_or_one?;
 BEHAVIOR: quantifiers = none_or_more* one_or_more+ none_or_one?;
 BEHAVIOR: ranges = do_exactly_n_times{n} do_at_least_n_times{n,} do_n_to_m{n,m};
 BEHAVIOR: ranges = do_exactly_n_times{n} do_at_least_n_times{n,} do_n_to_m{n,m};
 ```  
 ```  
-Notes on patterns:
-- alternations operate on sequences and groups, not individual events, so `a b c | d e | f` would separate into `a b c`, `d e`, and `f`
 
 
 **Whitespace** is insignificant.  
 **Whitespace** is insignificant.  
 **Comments** are C-style.
 **Comments** are C-style.

+ 14 - 15
src/lib/parser/modellang.pegjs

@@ -76,14 +76,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 (sys.type === "Selector" && !model.systems[sys.system])
                     model.errors.push(err("ERROR: 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 i in model.triggers) {
-            var sys = model.triggers[i].on;
-            if (!model.systems[sys.system])
+        for (var t in model.triggers) {
+            var sys = model.triggers[t].on;
+            if (sys.type === "Selector" && !model.systems[sys.system])
                 model.errors.push(err("ERROR: 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));
         }
         }
 
 
@@ -203,13 +203,13 @@ system_statement "System"
     = _SYSTEM_ _COLON_ id:system_id
     = _SYSTEM_ _COLON_ id:system_id
     !{ ast.toplevelname = id; ast.localrefs = []; }
     !{ ast.toplevelname = id; ast.localrefs = []; }
     _EQ_ body:behavior_pattern
     _EQ_ body:behavior_pattern
-    { return new ast.System(id, [body], ast.localrefs); }
+    { return new ast.System(id, body, ast.localrefs); }
 
 
 behavior_statement "Behavior"
 behavior_statement "Behavior"
     = _BEHAVIOR_ _COLON_ id:behavior_id
     = _BEHAVIOR_ _COLON_ id:behavior_id
     !{ ast.toplevelname = id; ast.localrefs = []; }
     !{ ast.toplevelname = id; ast.localrefs = []; }
     _EQ_ body:behavior_pattern
     _EQ_ body:behavior_pattern
-    { return new ast.Behavior(id, [body], ast.localrefs); }
+    { return new ast.Behavior(id, body, ast.localrefs); }
 
 
 interaction_statement "Interaction"
 interaction_statement "Interaction"
     = _INTERACTION_ _COLON_ first:( system_item_selector / expression )
     = _INTERACTION_ _COLON_ first:( system_item_selector / expression )
@@ -249,11 +249,10 @@ operator
     / _ o:"==" _ { return o; }
     / _ o:"==" _ { return o; }
 
 
 behavior_pattern "Behavior Pattern"
 behavior_pattern "Behavior Pattern"
-    = alternation
-    / sequence
+    = (alternation / sequence)+
 
 
 alternation
 alternation
-    = head:sequence tail:( _PIPE_ item:sequence { return item; } )+
+    = head:behavior_pattern_item tail:( _PIPE_ item:behavior_pattern_item { return item; } )+
     { return new ast.Alternation([head].concat(tail)); }
     { return new ast.Alternation([head].concat(tail)); }
 
 
 sequence
 sequence
@@ -285,7 +284,7 @@ trigger "Trigger"
     { return new ast.Trigger(selector, body); }
     { return new ast.Trigger(selector, body); }
 
 
 embedded_code
 embedded_code
-    = [^{}]* _ ( "{" embedded_code "}")? _
+    = [^{}]* ( "{" embedded_code "}")? [^{}]*
     { return text().trim(); }
     { return text().trim(); }
 
 
 behavior_id = id:ID { return id; }
 behavior_id = id:ID { return id; }
@@ -294,11 +293,11 @@ property    = id:ID { return id; }
 
 
 event_ref   = id:ID
 event_ref   = id:ID
     {
     {
-        if (id === ast.toplevelname) {
-            ast.errors.push(err("ERROR: Definition is recursive (" + id + ")"));
-            ast.toplevelname = null;
-        } else if (!ast.selector) {
-            ast.references.push(id);
+        if (!ast.selector) {
+            if (id === ast.toplevelname) {
+                ast.errors.push(err("ERROR: Definition is recursive (" + id + ")"));
+                ast.toplevelname = null;
+            } else ast.references.push(id);
         }
         }
         return { type: "Behavior", id:id };
         return { type: "Behavior", id:id };
     }
     }