Browse Source

Action language components are now completely independent from anything statechart-related.

Joeri Exelmans 5 years ago
parent
commit
14719055bb

+ 6 - 40
src/sccd/action_lang/parser/action_language.g

@@ -4,39 +4,6 @@
 %ignore WS
 %import common.ESCAPED_STRING
 
-// state id, variable name, event name
-IDENTIFIER: /[A-Za-z_][A-Za-z_0-9]*/ 
-
-// Parsing target of a transition as a sequence of nodes
-
-_PATH_SEP: "/" 
-PARENT_NODE: ".." 
-CURRENT_NODE: "."
-
-// target of a transition
-state_ref: path | "(" path ("," path)+ ")" 
-
-?path: absolute_path | relative_path 
-absolute_path: _PATH_SEP _path_sequence
-relative_path: _path_sequence
-_path_sequence: (CURRENT_NODE | PARENT_NODE | IDENTIFIER) (_PATH_SEP _path_sequence)?
-
-
-// Event declaration parsing
-
-event_decl_list: neg_event_decl ("," neg_event_decl)*
-
-?neg_event_decl: event_decl -> pos
-               | "not" event_decl -> neg
-
-?event_decl: IDENTIFIER params_decl
-
-// params_decl rule shared with function declaration
-params_decl: ( "(" param_decl ("," param_decl)* ")" )?
-
-?param_decl: IDENTIFIER ":" TYPE
-
-TYPE: "int" | "str" | "dur" | "float"
 
 // Expression parsing
 
@@ -75,10 +42,16 @@ TYPE: "int" | "str" | "dur" | "float"
      | func_decl
      | array
 
+IDENTIFIER: /[A-Za-z_][A-Za-z_0-9]*/ 
+
 func_call: atom "(" param_list ")"
 param_list: ( expr ("," expr)* )?  -> params
 
 func_decl: "func" params_decl stmt
+params_decl: ( "(" param_decl ("," param_decl)* ")" )?
+?param_decl: IDENTIFIER ":" TYPE_ANNOT
+TYPE_ANNOT: "int" | "str" | "dur" | "float"
+
 
 array: "[" (expr ("," expr)*)? "]"
 
@@ -158,10 +131,3 @@ FLOORDIVIDE: "//="
 
 COMMENT: "#" /(.)*/ "\n"
 %ignore COMMENT
-
-
-// Semantic option parsing
-
-WILDCARD: "*"
-?semantic_choice: WILDCARD -> wildcard
-                | IDENTIFIER ("," IDENTIFIER)* -> list

+ 7 - 54
src/sccd/action_lang/parser/parser.py

@@ -1,23 +1,15 @@
 import os
 from lark import Lark, Transformer
 from sccd.action_lang.static.statement import *
-from sccd.model.globals import *
-from sccd.action_lang.static.scope import *
-from sccd.statechart.static.tree import *
 
 _grammar_dir = os.path.dirname(__file__)
 
-with open(os.path.join(_grammar_dir,"action_language.g")) as file:
-  _action_lang_grammar = file.read()
+with open(os.path.join(_grammar_dir,"action_lang.g")) as file:
+  action_lang_grammar = file.read()
 
 
 # Lark transformer for parsetree-less parsing of expressions
 class ExpressionTransformer(Transformer):
-  def __init__(self):
-    super().__init__()
-    self.globals: Globals = None
-
-  # Expression and statement parsing
 
   array = Array
 
@@ -80,9 +72,7 @@ class ExpressionTransformer(Transformer):
       "h": Hour
     }[suffix]
 
-    d = duration(val, unit)
-    self.globals.durations.append(d)
-    return d
+    return duration(val, unit)
 
   def expression_stmt(self, node):
     return ExpressionStatement(node[0])
@@ -96,25 +86,6 @@ class ExpressionTransformer(Transformer):
     else:
       return IfStatement(cond=node[0], if_body=node[1], else_body=node[2])
 
-  # Event declaration parsing
-
-  def event_decl_list(self, node):
-    pos_events = []
-    neg_events = []
-
-    for n in node:
-      if n.data == "pos":
-        pos_events.append(n.children[0])
-      elif n.data == "neg":
-        neg_events.append(n.children[0])
-
-    return (pos_events, neg_events)
-
-  def event_decl(self, node):
-    event_name = node[0].value
-    event_id = self.globals.events.assign_id(event_name)
-    return EventDecl(id=event_id, name=event_name, params_decl=node[1])
-
   params_decl = list
 
   def param_decl(self, node):
@@ -129,34 +100,16 @@ class ExpressionTransformer(Transformer):
   def func_decl(self, node):
     return FunctionDeclaration(params_decl=node[0], body=node[1])
 
+
 # Global variables so we don't have to rebuild our parser every time
 # Obviously not thread-safe
 _transformer = ExpressionTransformer()
-_parser = Lark(_action_lang_grammar, parser="lalr", start=["expr", "block", "duration", "event_decl_list", "func_decl", "state_ref", "semantic_choice"], transformer=_transformer)
+_parser = Lark(action_lang_grammar, parser="lalr", start=["expr", "block"], transformer=_transformer)
 
 # Exported functions:
 
-def parse_expression(globals: Globals, text: str) -> Expression:
-  _transformer.globals = globals
+def parse_expression(text: str) -> Expression:
   return _parser.parse(text, start="expr")
 
-def parse_duration(globals: Globals, text: str) -> Duration:
-  _transformer.globals = globals
-  return _parser.parse(text, start="duration")
-
-def parse_block(globals: Globals, text: str) -> Statement:
-  _transformer.globals = globals
+def parse_block(text: str) -> Block:
   return _parser.parse(text, start="block")
-
-def parse_events_decl(globals: Globals, text: str):
-  _transformer.globals = globals
-  return _parser.parse(text, start="event_decl_list")
-
-# def parse_func_decl(text: str) -> Tuple[str, List[Param]]:
-#   return _parser.parse(text, start="func_decl")
-
-def parse_state_ref(text: str):
-  return _parser.parse(text, start="state_ref")
-
-def parse_semantic_choice(choice: str):
-  return _parser.parse(choice, start="semantic_choice")

+ 0 - 11
src/sccd/model/globals.py

@@ -33,17 +33,6 @@ class Globals:
       else:
         self.delta = self.fixed_delta
 
-    # if self.delta == duration(0):
-    #   print_debug(termcolor.colored("Warning: model delta is 0: Model does not have any notion of time.", 'yellow'))
-    # else:
-    #   pass
-      # # Convert all DurationLiterals to model delta
-      # for d in self.durations:
-      #   # The following error is impossible: (i think)
-      #   # if d.original % self.delta != duration(0):
-      #   #   raise Exception("Duration %s cannot be represented by delta %s" % (str(d.original), str(self.delta)))
-      #   d.converted = d.original // self.delta
-
   def assert_ready(self):
     if self.delta is None:
       raise Exception("Globals not ready: durations not yet processed.")

+ 39 - 0
src/sccd/statechart/parser/statechart.g

@@ -0,0 +1,39 @@
+// Partial grammar file for Lark-parser
+// Concatenate this file with sccd/action_lang/parser/action_lang.g
+
+%import common.WS
+%ignore WS
+%import common.ESCAPED_STRING
+
+
+// Parsing target of a transition as a sequence of nodes
+
+state_ref: path | "(" path ("," path)+ ")" 
+
+?path: absolute_path | relative_path 
+absolute_path: _PATH_SEP _path_sequence
+relative_path: _path_sequence
+_path_sequence: (CURRENT_NODE | PARENT_NODE | IDENTIFIER) (_PATH_SEP _path_sequence)?
+
+_PATH_SEP: "/" 
+PARENT_NODE: ".." 
+CURRENT_NODE: "."
+
+
+
+// Event declaration parsing
+
+event_decl_list: neg_event_decl ("," neg_event_decl)*
+
+?neg_event_decl: event_decl -> pos
+               | "not" event_decl -> neg
+
+?event_decl: IDENTIFIER params_decl
+
+
+
+// Semantic option parsing
+
+WILDCARD: "*"
+?semantic_choice: WILDCARD -> wildcard
+                | IDENTIFIER ("," IDENTIFIER)* -> list

+ 68 - 0
src/sccd/statechart/parser/text.py

@@ -0,0 +1,68 @@
+import os
+from lark import Lark
+from sccd.action_lang.parser import text as action_lang
+from sccd.statechart.static.tree import *
+from sccd.model.globals import *
+
+_grammar_dir = os.path.dirname(__file__)
+
+with open(os.path.join(_grammar_dir, "statechart.g")) as file:
+  _sc_grammar = action_lang.action_lang_grammar + file.read()
+
+
+# Lark transformer for parsetree-less parsing of expressions
+class StatechartTransformer(action_lang.ExpressionTransformer):
+  def __init__(self):
+    super().__init__()
+    self.globals: Globals = None
+
+  # override: add all durations to 'globals'
+  def duration(self, node):
+    d = action_lang.ExpressionTransformer.duration(self, node)
+    self.globals.durations.append(d)
+    return d
+
+  # Event declaration parsing
+
+  def event_decl_list(self, node):
+    pos_events = []
+    neg_events = []
+
+    for n in node:
+      if n.data == "pos":
+        pos_events.append(n.children[0])
+      elif n.data == "neg":
+        neg_events.append(n.children[0])
+
+    return (pos_events, neg_events)
+
+  def event_decl(self, node):
+    event_name = node[0].value
+    event_id = self.globals.events.assign_id(event_name)
+    return EventDecl(id=event_id, name=event_name, params_decl=node[1])
+
+
+# Global variables so we don't have to rebuild our parser every time
+# Obviously not thread-safe
+_transformer = StatechartTransformer()
+_parser = Lark(_sc_grammar, parser="lalr", start=["expr", "block", "event_decl_list", "state_ref", "semantic_choice"], transformer=_transformer)
+
+# Exported functions:
+
+def parse_expression(globals: Globals, text: str) -> Expression:
+  _transformer.globals = globals
+  return _parser.parse(text, start="expr")
+
+def parse_block(globals: Globals, text: str) -> Block:
+  _transformer.globals = globals
+  return _parser.parse(text, start="block")
+
+def parse_events_decl(globals: Globals, text: str) -> Tuple[List[EventDecl], List[EventDecl]]:
+  _transformer.globals = globals
+  return _parser.parse(text, start="event_decl_list")
+
+def parse_state_ref(text: str):
+  return _parser.parse(text, start="state_ref")
+
+def parse_semantic_choice(text: str):
+  return _parser.parse(text, start="semantic_choice")

+ 1 - 1
src/sccd/statechart/parser/parser.py

@@ -3,7 +3,7 @@ from sccd.statechart.static.statechart import *
 from sccd.statechart.static.tree import *
 from sccd.statechart.dynamic.builtin_scope import *
 from sccd.util.xml_parser import *
-from sccd.action_lang.parser.parser import *
+from sccd.statechart.parser.text import *
 
 class SkipFile(Exception):
   pass

+ 1 - 1
test/lib/test_parser.py

@@ -1,4 +1,4 @@
-from sccd.statechart.parser.parser import *
+from sccd.statechart.parser.xml import *
 from sccd.model.globals import *
 from sccd.controller.controller import InputEvent
 from sccd.statechart.dynamic.event import Event

+ 1 - 1
test/render.py

@@ -5,7 +5,7 @@ import multiprocessing
 import os
 from lib.os_tools import *
 from sccd.util.indenting_writer import *
-from sccd.statechart.parser.parser import *
+from sccd.statechart.parser.xml import *
 import lxml.etree as ET
 
 if __name__ == '__main__':