text.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import lark
  2. from sccd.action_lang.parser import text as action_lang
  3. from sccd.statechart.static.tree import *
  4. from sccd.statechart.static.globals import *
  5. from sccd.statechart.static.state_ref import *
  6. # Lark transformer for parsetree-less parsing of expressions
  7. # Extends action language's ExpressionTransformer
  8. class Transformer(action_lang.Transformer):
  9. def __init__(self, globals):
  10. super().__init__()
  11. self.globals = globals
  12. def absolute_path(self, node):
  13. # print("ABS", node[0])
  14. return StatePath(is_absolute=True, sequence=node[0])
  15. def relative_path(self, node):
  16. # print("REL", node[0])
  17. return StatePath(is_absolute=False, sequence=node[0])
  18. def path_sequence(self, node):
  19. # print("PATH_SEQ", node)
  20. if node[0].type == "PARENT_NODE":
  21. item = ParentNode()
  22. elif node[0].type == "CURRENT_NODE":
  23. item = CurrentNode()
  24. elif node[0].type == "IDENTIFIER":
  25. item = Identifier(value=node[0].value)
  26. # Concatenate with rest of path
  27. if len(node) == 2:
  28. return [item] + node[1]
  29. else:
  30. return [item]
  31. # override: all durations must be added to 'globals'
  32. def duration_literal(self, node):
  33. val = int(node[0])
  34. suffix = node[1]
  35. unit = {
  36. "d": None, # 'd' stands for "duration", the non-unit for all zero-durations.
  37. # need this to parse zero-duration as a duration instead of int.
  38. "fs": FemtoSecond,
  39. "ps": PicoSecond,
  40. "ns": Nanosecond,
  41. "us": Microsecond,
  42. "ms": Millisecond,
  43. "s": Second,
  44. "m": Minute,
  45. "h": Hour
  46. }[suffix]
  47. d = SCDurationLiteral(duration(val, unit))
  48. self.globals.durations.append(d)
  49. return d
  50. # Event declaration parsing
  51. def event_decl_list(self, node):
  52. pos_events = []
  53. neg_events = []
  54. for n in node:
  55. if n.data == "pos":
  56. pos_events.append(n.children[0])
  57. elif n.data == "neg":
  58. neg_events.append(n.children[0])
  59. return (pos_events, neg_events)
  60. def event_decl(self, node):
  61. event_name = node[0].value
  62. event_id = self.globals.events.assign_id(event_name)
  63. return EventDecl(id=event_id, name=event_name, params_decl=node[1])
  64. import os, pathlib
  65. grammar_dir = os.path.dirname(__file__)
  66. grammar_path = os.path.join(grammar_dir,"statechart.g")
  67. with open(grammar_path) as file:
  68. # Concatenate Action Lang and SC grammars
  69. grammar = action_lang.grammar + file.read()
  70. cache_file = action_lang.cache_file+'_'+str(pathlib.Path(grammar_path).stat().st_mtime_ns)
  71. # Parses action language expressions and statements, and also event decls, state refs and semantic choices.
  72. class TextParser(action_lang.TextParser):
  73. def __init__(self, globals):
  74. # Building the parser is actually the slowest step of parsing a statechart model.
  75. # Doesn't have to happen every time, so should find a way to speed this up.
  76. parser = lark.Lark(grammar, parser="lalr", start=["expr", "block", "event_decl_list", "path", "semantic_choice"], transformer=Transformer(globals), cache=cache_file)
  77. super().__init__(parser)
  78. def parse_semantic_choice(self, text: str):
  79. return self.parser.parse(text, start="semantic_choice")
  80. def parse_events_decl(self, text: str) -> Tuple[List[EventDecl], List[EventDecl]]:
  81. return self.parser.parse(text, start="event_decl_list")
  82. def parse_path(self, text: str):
  83. return self.parser.parse(text, start="path")