| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import os
- from lark import Lark, Transformer
- from sccd.syntax.statement import *
- from sccd.model.globals import *
- from sccd.syntax.scope import *
- from sccd.syntax.tree import *
- _grammar_dir = os.path.join(os.path.dirname(__file__), "grammar")
- with open(os.path.join(_grammar_dir,"action_language.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
- block = Block
- def string(self, node):
- return StringLiteral(node[0][1:-1])
- def int(self, node):
- return IntLiteral(int(node[0].value))
- def func_call(self, node):
- return FunctionCall(node[0], node[1].children)
- def identifier(self, node):
- name = node[0].value
- return Identifier(name)
- def binary_expr(self, node):
- return BinaryExpression(node[0], node[1].value, node[2])
- def unary_expr(self, node):
- return UnaryExpression(node[0].value, node[1])
- def bool(self, node):
- return BoolLiteral({
- "True": True,
- "False": False,
- }[node[0].value])
- def group(self, node):
- return Group(node[0])
- def assignment(self, node):
- return Assignment(node[0], node[1].value, node[2])
- def duration_literal(self, node):
- return DurationLiteral(node[0])
- def duration(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 = duration(val, unit)
- self.globals.durations.append(d)
- return d
- def expression_stmt(self, node):
- return ExpressionStatement(node[0])
- def return_stmt(self, node):
- return ReturnStatement(node[0])
- # 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]
- event_id = self.globals.events.assign_id(event_name)
- return EventDecl(id=event_id, name=event_name, params=node[1])
- params_decl = list
- def param_decl(self, node):
- type = {
- "int": int,
- "str": str,
- "Duration": Duration
- }[node[1]]
- return Param(name=node[0].value, type=type)
- def func_decl(self, node):
- return (node[0], 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)
- # Exported functions:
- def parse_expression(globals: Globals, text: str) -> Expression:
- _transformer.globals = globals
- 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
- 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")
|