123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- import lark
- from sccd.action_lang.parser import text as action_lang
- from sccd.statechart.static.tree import *
- from sccd.statechart.static.globals import *
- from sccd.statechart.static.state_ref import *
- # Lark transformer for parsetree-less parsing of expressions
- # Extends action language's ExpressionTransformer
- class Transformer(action_lang.Transformer):
- def __init__(self, globals):
- super().__init__()
- self.globals = globals
- def absolute_path(self, node):
- # print("ABS", node[0])
- return StatePath(is_absolute=True, sequence=node[0])
- def relative_path(self, node):
- # print("REL", node[0])
- return StatePath(is_absolute=False, sequence=node[0])
- def path_sequence(self, node):
- # print("PATH_SEQ", node)
- if node[0].type == "PARENT_NODE":
- item = ParentNode()
- elif node[0].type == "CURRENT_NODE":
- item = CurrentNode()
- elif node[0].type == "IDENTIFIER":
- item = Identifier(value=node[0].value)
- # Concatenate with rest of path
- if len(node) == 2:
- return [item] + node[1]
- else:
- return [item]
- # override: all durations must be added to 'globals'
- def duration_literal(self, node):
- val = int(node[0])
- suffix = node[1]
- unit = {
- "d": None, # 'd' stands for "duration", the non-unit for all zero-durations.
- # need this to parse zero-duration as a duration instead of int.
- "fs": FemtoSecond,
- "ps": PicoSecond,
- "ns": Nanosecond,
- "us": Microsecond,
- "ms": Millisecond,
- "s": Second,
- "m": Minute,
- "h": Hour
- }[suffix]
- d = SCDurationLiteral(duration(val, unit))
- 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])
- import os, pathlib
- grammar_dir = os.path.dirname(__file__)
- grammar_path = os.path.join(grammar_dir,"statechart.g")
- with open(grammar_path) as file:
- # Concatenate Action Lang and SC grammars
- grammar = action_lang.grammar + file.read()
- cache_file = action_lang.cache_file+'_'+str(pathlib.Path(grammar_path).stat().st_mtime_ns)
- # Parses action language expressions and statements, and also event decls, state refs and semantic choices.
- class TextParser(action_lang.TextParser):
- def __init__(self, globals):
- # Building the parser is actually the slowest step of parsing a statechart model.
- # Doesn't have to happen every time, so should find a way to speed this up.
- parser = lark.Lark(grammar, parser="lalr", start=["expr", "block", "event_decl_list", "path", "semantic_choice"], transformer=Transformer(globals), cache=cache_file)
- super().__init__(parser)
- def parse_semantic_choice(self, text: str):
- return self.parser.parse(text, start="semantic_choice")
- def parse_events_decl(self, text: str) -> Tuple[List[EventDecl], List[EventDecl]]:
- return self.parser.parse(text, start="event_decl_list")
- def parse_path(self, text: str):
- return self.parser.parse(text, start="path")
|