def build_block(phrase: Phrase, context: Phrase, temp_phrase: List[Token], phrase_line: int): if temp_phrase[0].token_class == TokenClass.word: phrase.keyword = temp_phrase[0] else: raise InterpretationError( PeaceError(f"Unexpected phrase sequence.", ErrorType.phrase_build_error, phrase_line)) if phrase.keyword.value == "main": if context.phrase_subclass == PhraseSubclass.program: phrase.phrase_subclass = PhraseSubclass.body else: raise InterpretationError( PeaceError(f"Main block can not be defined inside {context.phrase_subclass.name}.", ErrorType.phrase_build_error, phrase_line)) elif context.phrase_subclass == PhraseSubclass.program: phrase.phrase_subclass = PhraseSubclass.expression elif context.phrase_subclass == PhraseSubclass.body or context.phrase_subclass == PhraseSubclass.expression: phrase.phrase_subclass = PhraseSubclass.device else: raise InterpretationError( PeaceError(f"Unspecified \"{phrase.keyword.value}\" block subclass.", ErrorType.phrase_build_error, phrase_line)) if len(temp_phrase) > 1: if phrase.phrase_subclass == PhraseSubclass.device: phrase.params = temp_phrase[1:] else: raise InterpretationError( PeaceError(f"Not allowed to use parameters in \"{phrase.keyword.value}\" definition.", ErrorType.phrase_build_error, phrase_line))
def build_operator(phrase: Phrase, context: Phrase, temp_phrase: List[Token], phrase_line): if context.phrase_subclass != PhraseSubclass.program: if temp_phrase[0].token_class == TokenClass.word: phrase.keyword = temp_phrase[0] else: raise InterpretationError( PeaceError(f"Unexpected phrase sequence.", ErrorType.phrase_build_error, phrase_line)) phrase.params = temp_phrase[1:] else: raise InterpretationError( PeaceError(f"Operator \"{temp_phrase[0].value}\" not allowed to be used outside blocks.", ErrorType.phrase_build_error, phrase_line))
def test_build_parametrised_label(self): built_phrase = phrase_builder(self.expression_context, PhraseClass.label, [Token(TokenClass.word, "label"), Token(TokenClass.parameter, "@")], 0) expected_expr = Phrase(PhraseClass.label, phrase_subclass=None, keyword=Token(TokenClass.word, "label"), params=[Token(TokenClass.parameter, "@")]) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def _signature_inference(self, phrase: Phrase, line_number: int): if phrase.phrase_class == PhraseClass.operator: candidates = self.lang_dict.get_candidates(phrase.keyword.value) unsuitable_candidates = InterpretationError() temp_params: Optional[dict] = None for signature_id in candidates: signature = self.lang_dict.get_signature(signature_id) if self._expr_params is not None: temp_params = self._expr_params.copy() try: self._signature_check(signature, phrase, temp_params, line_number) except PeaceError as error: unsuitable_candidates.add_error(error) else: if self._expr_params is not None: self._expr_params.update(temp_params) phrase.signature_id = signature_id break if phrase.signature_id is None: raise unsuitable_candidates elif phrase.phrase_class == PhraseClass.label: if len(phrase.params) > 0: if self._expr_signature is not None: self._expr_signature.contains_param = True elif phrase.phrase_subclass == PhraseSubclass.device: if len(phrase.params) > 0: if self._expr_signature is not None: self._expr_signature.contains_param = True
def test_build_empty_operator(self): built_phrase = phrase_builder(self.expression_context, PhraseClass.operator, [ Token(TokenClass.word, "delay") ], 0) expected_expr = Phrase(PhraseClass.operator, phrase_subclass=None, keyword=Token(TokenClass.word, "delay"), params=[]) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def test_build_comment(self): built_phrase = phrase_builder(self.body_context, PhraseClass.comment, [Token(TokenClass.word, "w1"), Token(TokenClass.word, "w2"), Token(TokenClass.word, "w3")], 0) expected_expr = Phrase(PhraseClass.comment, phrase_subclass=None, params=[Token(TokenClass.word, "w1"), Token(TokenClass.word, "w2"), Token(TokenClass.word, "w3")]) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def build_label(phrase: Phrase, context: Phrase, temp_phrase: List[Token], phrase_line): if context.phrase_subclass != PhraseSubclass.program: if temp_phrase[0].token_class == TokenClass.word: phrase.keyword = temp_phrase[0] else: raise InterpretationError( PeaceError(f"Unexpected phrase sequence.", ErrorType.phrase_build_error, phrase_line)) if len(temp_phrase) > 1 and context.phrase_subclass != PhraseSubclass.expression: raise InterpretationError( PeaceError(f"Parametrised label name can not be used inside main.", ErrorType.phrase_build_error, phrase_line)) else: phrase.params = temp_phrase[1:] else: raise InterpretationError(PeaceError(f"Label \"{temp_phrase[0].value}\" " f"not allowed to be used outside blocks.", ErrorType.phrase_build_error, phrase_line))
def _name_processing(self, phrase: Phrase, line_number: int): if phrase.phrase_class == PhraseClass.block: identifier: str = phrase.get_identifier() if not self.table.is_symbol_presence(identifier): self.table.add_symbol(identifier, phrase.phrase_subclass) else: raise InterpretationError( PeaceError(f"\nName \"{identifier}\" already used by " f"{self.table.get_symbol(identifier).phrase_class.name}.", ErrorType.naming_error, line_number, identifier)) elif phrase.phrase_class == PhraseClass.label: identifier: str = phrase.get_identifier() if not self.table.is_symbol_presence(identifier): self.table.add_symbol(identifier, phrase.phrase_class) else: raise InterpretationError( PeaceError(f"\nName \"{identifier}\" already used by " f"{self.table.get_symbol(identifier).phrase_class.name}.", ErrorType.naming_error, line_number, identifier)) elif phrase.phrase_class == PhraseClass.operator: operator: str = phrase.keyword.value sig_type = self.lang_dict.get_signature(phrase.signature_id).signature_type if sig_type == SignatureType.operator: if len(phrase.params): identifier: str = phrase.get_identifier() if operator == "q": if not self.table.is_symbol_presence(identifier): self.table.add_symbol(identifier, phrase.phrase_class) else: raise InterpretationError( PeaceError(f"Name \"{identifier}\" already used by " f"{self.table.get_symbol(identifier).phrase_class.name}.", ErrorType.naming_error, line_number, identifier)) elif operator == "dq": if not self.table.is_symbol_presence(identifier): raise InterpretationError( PeaceError(f"\nName \"{identifier}\" was never defined.", ErrorType.naming_error, line_number, identifier))
def test_build_operator_with_parameters(self): built_phrase = phrase_builder(self.expression_context, PhraseClass.operator, [ Token(TokenClass.word, "delay"), Token(TokenClass.num, "1"), Token(TokenClass.word, "two"), Token(TokenClass.string, "\"3\""), Token(TokenClass.parameter, "@4") ], 0) expected_expr = Phrase(PhraseClass.operator, phrase_subclass=None, keyword=Token(TokenClass.word, "delay"), params=[Token(TokenClass.num, "1"), Token(TokenClass.word, "two"), Token(TokenClass.string, "\"3\""), Token(TokenClass.parameter, "@4")]) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def phrase_builder(context: Phrase, phrase_class: PhraseClass, temp_phrase: List[Token], phrase_line: int) -> Phrase: phrase = Phrase(phrase_class, params=list()) if phrase_class == PhraseClass.block: build_block(phrase, context, temp_phrase, phrase_line) elif phrase_class == PhraseClass.operator: build_operator(phrase, context, temp_phrase, phrase_line) elif phrase_class == PhraseClass.comment: build_comment(phrase, temp_phrase) elif phrase_class == PhraseClass.label: build_label(phrase, context, temp_phrase, phrase_line) elif phrase_class == PhraseClass.blockClose: build_block_close(phrase, temp_phrase) else: raise InterpretationError( PeaceError(f"Unexpected phrase class.", ErrorType.phrase_build_error, phrase_line)) return phrase
def setUpClass(cls) -> None: cls.program_context = Phrase(PhraseClass.block, PhraseSubclass.program) cls.expression_context = Phrase(PhraseClass.block, PhraseSubclass.expression) cls.device_context = Phrase(PhraseClass.block, PhraseSubclass.device) cls.body_context = Phrase(PhraseClass.block, PhraseSubclass.body)
def setUpClass(cls) -> None: cls.tree = ParseTree() cls.tree.add_leaf(Phrase(PhraseClass.block, PhraseSubclass.expression)) cls.tree.submerge()
def test_build_expression(self): built_phrase = phrase_builder(self.program_context, PhraseClass.block, [Token(TokenClass.word, "expression")], 0) expected_expr = Phrase(PhraseClass.block, PhraseSubclass.expression, keyword=Token(TokenClass.word, "expression")) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def test_build_device_in_body(self): built_phrase = phrase_builder(self.body_context, PhraseClass.block, [Token(TokenClass.word, "device_in_body")], 0) expected_expr = Phrase(PhraseClass.block, PhraseSubclass.device, keyword=Token(TokenClass.word, "device_in_body")) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))
def build_comment(phrase: Phrase, temp_phrase: List[Token]): phrase.params = temp_phrase
def __init__(self): self.root: Node = Node( None, Phrase(PhraseClass.block, PhraseSubclass.program)) self.head: Node = self.root
def test_get_context(self): context = Phrase(PhraseClass.block, PhraseSubclass.program) self.assertTrue(are_phrases_equal(self.tree.get_context(), context))
def test_add_node(self): phrase_in_node = Phrase(PhraseClass.blockClose) expected_node = Node(self.tree.get_head(), phrase_in_node) self.tree.add_leaf(phrase_in_node) self.assertTrue(are_nodes_equal(self.tree.head.nodes[0], expected_node))
def test_build_block_close(self): built_phrase = phrase_builder(self.program_context, PhraseClass.blockClose, [], 0) expected_expr = Phrase(PhraseClass.blockClose, phrase_subclass=None, keyword=None, params=None) self.assertTrue(are_phrases_equal(built_phrase, expected_expr))