def make_none(p: YaccProduction, token: int) -> Literal: assert namespace none = Literal(NoneValue()) none.location = Location(file, p.lineno(token)) none.namespace = namespace none.lexpos = p.lexpos(token) return none
def p_expr_arithmetic(p: YaccProduction): """expr : LPAREN expr RPAREN | expr PLUS expr | expr MINUS expr | expr TIMES expr | expr DIVIDE expr""" if p[1] == "(" and p[3] == ")": p[0] = Arithmetic("()", [p[2]], p.lineno(1), p.lineno(3), p.lexpos(1), p.lexpos(3)) else: p[0] = Arithmetic(p[2], [p[1], p[3]], p[1].start_line_number, p[3].end_line_number, p[1].start_position, p[3].end_position)
def p_funccall_or_exp_ident(p: yacc.YaccProduction): """FUNCCALL_OR_EXPRESSION : IDENT FOLLOW_IDENT""" node = Node(None, None, p[1], get_var_type(p[1], p.lineno(1))) if p[2] is None or p[2]['node'] == None: return if p[2]: node.value += p[2]['vec_access'] result_type = check_type(node, p[2]['node'], p[2]['operation'], p.lineno(1)) node = Node(node, p[2]['node'], p[2]['operation'], result_type) num_expressions.append((node, p.lineno(1)))
def p_error(self, p: P) -> None: filepath = self.current_filepath() if p is None: raise GrammarError(message="Grammar error at eof.", filepath=filepath) if isinstance(p, LexToken): raise GrammarError(filepath=filepath, token=str(p.value), lineno=p.lineno) if len(p) > 1: raise GrammarError(filepath=filepath, token=p.value(1), lineno=p.lineno(1)) raise GrammarError()
def p_expr_number(p: YaccProduction): """expr : INTEGER | FLOAT | INTEGER FLOAT""" if len(p) == 2: p[0] = Number([p[1]], p.lineno(1), p.lineno(1), p.lexpos(1), p.lexpos(1) + len(str(p[1])) - 1) elif len(p) == 3: p[0] = Number([p[1] + p[2]], p.lineno(1), p.lineno(2), p.lexpos(1), p.lexpos(2) + len(str(p[2])))
def p_paralist_param(p: yacc.YaccProduction): """PARAMLIST : DATATYPE IDENT PARAMLISTAUX | empty """ if len(p) > 2: scope = scope_stack.seek() entry = TableEntry(p[2], p[1], [], p.lineno(2)) scope.add_entry(entry)
def p_optional_extensible_flag(self, p: P) -> None: extensible = len(p) == 2 p[0] = extensible if extensible and self.traditional_mode: raise ExtensibleGrammarFoundInTraditionalMode( filepath=self.current_filepath(), lineno=p.lineno(1), token=p[1])
def p_funccal_or_exp_string_const(p: yacc.YaccProduction): """FUNCCALL_OR_EXPRESSION : STRING_CONSTANT REC_UNARYEXPR REC_PLUS_MINUS_TERM OPT_REL_OP_NUM_EXPR""" node = Node(None, None, p[1], 'string') if p[2]: result_type = check_type(node, p[2]['node'], p[2]['operation'], p.lineno(1)) node = Node(node, p[2]['node'], p[2]['operation'], result_type) if p[3]: result_type = check_type(node, p[3]['node'], p[3]['operation'], p.lineno(1)) node = Node(node, p[3]['node'], p[3]['operation'], result_type) p[0] = {'node': node} num_expressions.append((node, p.lineno(1)))
def p_funccall_or_exp_parentesis(p: yacc.YaccProduction): """FUNCCALL_OR_EXPRESSION : LPAREN NUMEXPRESSION RPAREN REC_UNARYEXPR REC_PLUS_MINUS_TERM OPT_REL_OP_NUM_EXPR""" node = p[2]['node'] if p[4]: result_type = check_type(node, p[4]['node'], p[4]['operation'], p.lineno(1)) node = Node(node, p[4]['node'], p[4]['operation'], result_type) if p[5]: result_type = check_type(node, p[5]['node'], p[5]['operation'], p.lineno(1)) node = Node(node, p[5]['node'], p[5]['operation'], result_type) p[0] = {'node': node} num_expressions.append((node, p.lineno(1)))
def p_type_reference(self, p: P) -> None: d = self._lookup_referenced_member(p[1]) if d is None: raise ReferencedTypeNotDefined( message="referenced type {0} not defined".format(p[1]), filepath=self.current_filepath(), token=p[1], lineno=p.lineno(1), ) if not isinstance(d, Type): raise ReferencedNotType( message="referenced defintion is not a type", filepath=self.current_filepath(), token=p[1], lineno=p.lineno(1), ) p[0] = d self.copy_p_tracking(p)
def p_proto(self, p: P) -> None: scope = self.current_scope() if isinstance(scope, Proto): proto = cast(Proto, self.current_scope()) proto.set_name(p[2]) proto.set_comment_block(self.collect_comment_block()) else: raise UnsupportedToDeclareProtoNameOutofProtoScope( lineno=p.lineno(1), filepath=self.current_filepath())
def p_opt_rel_op_num_expr(p: yacc.YaccProduction): """OPT_REL_OP_NUM_EXPR : REL_OP NUMEXPRESSION | empty """ if len(p) < 3: pass else: num_expressions.append((p[2]['node'], p.lineno(1)))
def p_message_item_unsupported(self, p: P) -> None: if isinstance(p[1], Alias): raise AliasInMessageUnsupported.from_token(token=p[1]) if isinstance(p[1], Constant): raise ConstInMessageUnsupported.from_token(token=p[1]) if isinstance(p[1], Proto): raise ImportInMessageUnsupported.from_token(token=p[0]) raise StatementInMessageUnsupported(lineno=p.lineno(1), filepath=self.current_filepath())
def p_lvalue_ident(p: yacc.YaccProduction): """LVALUE : IDENT OPT_ALLOC_NUMEXP""" p[0] = { 'node': Node(None, None, p[1] + p[2], result_type=get_var_type(p[1], p.lineno(1))) }
def p_funcdef(p: yacc.YaccProduction): """FUNCDEF : DEF IDENT new_scope LPAREN PARAMLIST RPAREN LBRACKETS STATELIST RBRACKETS""" # Go back to upper scope scope_stack.pop() # Add function declaration to current scope scope = scope_stack.seek() entry = TableEntry(p[2], 'function', [], p.lineno(2)) scope.add_entry(entry)
def p_relation_deprecated(p: YaccProduction) -> None: "relation : class_ref ID multi REL multi class_ref ID" if not (p[4] == "--"): LOGGER.warning( "DEPRECATION: use of %s in relation definition is deprecated, use -- (in %s)" % (p[4], Location(file, p.lineno(4)))) p[0] = DefineRelation((p[1], p[2], p[3]), (p[6], p[7], p[5])) attach_lnr(p, 2) deprecated_relation_warning(p)
def p_opt_allocexp(p: yacc.YaccProduction): """OPT_ALLOC_NUMEXP : LSQBRACKETS NUMEXPRESSION RSQBRACKETS OPT_ALLOC_NUMEXP | empty """ if len(p) < 3: p[0] = '' else: p[0] = '[' + str(p[2]) + ']' + p[4] num_expressions.append((p[2]['node'], p.lineno(1)))
def p_array_type(self, p: P) -> None: p[0] = Array( element_type=p[1], cap=p[3], extensible=p[5], token="{0}[{1}]".format(p[1], p[3]), lineno=p.lineno(2), filepath=self.current_filepath(), ) self.copy_p_tracking(p)
def p_constant_reference(self, p: P) -> None: d = self._lookup_referenced_member(p[1]) if d is None: raise ReferencedConstantNotDefined( message="referenced constant {0} not defined".format(p[1]), filepath=self.current_filepath(), token=p[1], lineno=p.lineno(1), ) if not isinstance(d, Constant): raise ReferencedNotConstant( message="referenced defintion is not a constant", filepath=self.current_filepath(), token=p[1], lineno=p.lineno(1), ) p[0] = d self.copy_p_tracking(p)
def p_funccall_or_exp_plus(p: yacc.YaccProduction): """FUNCCALL_OR_EXPRESSION : PLUS FACTOR REC_UNARYEXPR REC_PLUS_MINUS_TERM OPT_REL_OP_NUM_EXPR | MINUS FACTOR REC_UNARYEXPR REC_PLUS_MINUS_TERM OPT_REL_OP_NUM_EXPR""" right_node = p[2]['node'] if p[1] == '-': right_node.value *= -1 if p[3]: result_type = check_type(p[3]['node'], right_node, p[3]['operation'], p.lineno(1)) right_node = Node(p[3]['node'], right_node, p[3]['operation'], result_type) if p[4]: result_type = check_type(p[4]['node'], right_node, p[4]['operation'], p.lineno(1)) right_node = Node(p[4]['node'], right_node, p[4]['operation'], result_type) num_expressions.append(right_node)
def p_alias(self, p: P) -> None: if len(p) == 6: name, type, lineno, token = p[2], p[4], p.lineno(2), p[2] else: name, type, lineno, token = p[3], p[2], p.lineno(3), p[3] write_stderr( f"syntax warning: keyword typedef deprecated, suggestion: type {name} = ..." ) p[0] = alias = Alias( name=name, type=type, filepath=self.current_filepath(), lineno=lineno, token=token, indent=self.current_indent(p), scope_stack=self.current_scope_stack(), comment_block=self.collect_comment_block(), _bound=self.current_proto(), ) self.current_scope().push_member(alias)
def p_numexp(p: yacc.YaccProduction): """NUMEXPRESSION : TERM REC_PLUS_MINUS_TERM""" if p[2] is None: p[0] = p[1] else: result_type = check_type(p[1]['node'], p[2]['node'], p[2]['operation'], p.lineno(1)) p[0] = { 'node': Node(p[1]['node'], p[2]['node'], p[2]['operation'], result_type) }
def p_constant_reference_for_calculation(self, p: P) -> None: referenced = p[1] if isinstance(referenced, IntegerConstant): integer_constant = cast(IntegerConstant, referenced) p[0] = integer_constant.unwrap() else: raise CalculationExpressionError( message= "Non integer constant referenced to use in calculation expression.", filepath=self.current_filepath(), token=p[1].name, lineno=p.lineno(1), )
def p_constant_reference_for_array_capacity(self, p: P) -> None: referenced = p[1] if isinstance(referenced, IntegerConstant): integer_constant = cast(IntegerConstant, referenced) p[0] = integer_constant.unwrap() # Using int format else: raise InvalidArrayCap( message= "Non integer constant referenced to use as array capacity.", filepath=self.current_filepath(), token=p[1].name, lineno=p.lineno(1), )
def p_open_enum_scope(self, p: P) -> None: enum = Enum( name=p[2], type=p[4], token=p[2], lineno=p.lineno(2), filepath=self.current_filepath(), indent=self.current_indent(p), comment_block=self.collect_comment_block(), scope_stack=self.current_scope_stack(), _bound=self.current_proto(), ) self.push_scope(enum)
def merge_lnr_to_string(p: YaccProduction, starttoken: int = 1, endtoken: int = 2) -> None: assert namespace v = p[0] et = p[endtoken] st = p[starttoken] expanded_range: Range = expand_range( st.location, et.location) if isinstance( st, LocatableString) else et.location p[0] = LocatableString(v, expanded_range, p.lexpos(endtoken), namespace)
def p_open_message_scope(self, p: P) -> None: message = Message( name=p[2], extensible=p[3], token=p[2], lineno=p.lineno(2), filepath=self.current_filepath(), indent=self.current_indent(p), comment_block=self.collect_comment_block(), scope_stack=self.current_scope_stack(), _bound=self.current_proto(), ) self.push_scope(message)
def p_import(self, p: P) -> None: # Get filepath to import. importing_path = p[len(p) - 2] filepath = self._get_child_filepath(importing_path) # Check if this filepath already in parsing. if self._check_parsing_file(filepath): raise CyclicImport( message=f"cyclic importing {filepath}", filepath=self.current_filepath(), token=importing_path, lineno=p.lineno(2), ) # Check if this filepath already parsed by current proto. for _, proto in self.current_proto().protos(recursive=False): if os.path.samefile(proto.filepath, filepath): raise DuplicatedImport(filepath=self.current_filepath(), token=filepath, lineno=p.lineno(1)) # Parse. p[0] = child = self.parse_child(filepath) name = child.name if len(p) == 5: # Importing as `name` name = p[2] # Check if import (as) name already taken. if name in self.current_proto().members: raise DuplicatedDefinition( message="imported proto name already used", token=name, lineno=p.lineno(1), filepath=self.current_filepath(), ) # Push to current scope self.current_scope().push_member(child, name)
def p_option(self, p: P) -> None: name, value = p[2], p[4] p[0] = option = Option.from_value( value=value, name=name, scope_stack=self.current_scope_stack(), comment_block=self.collect_comment_block(), indent=self.current_indent(p), _bound=self.current_proto(), filepath=self.current_filepath(), lineno=p.lineno(2), token=p[2], ) self.current_scope().push_member(option)
def p_statement_break(p: yacc.YaccProduction): """STATEMENT : BREAK SEMICOLON""" # If is not inside loop scope, consider semantic failure current_scope = scope_stack.seek() # Go into upper scopes trying to find a for loop while True: if current_scope.is_loop: break current_scope = current_scope.upper_scope if current_scope is None: raise BreakWithoutLoopError(p.lineno(2))