def char_options_to_regex(r: Antlr4Rule): """ '0' | '1' -> [01] """ def match_replace_fn(o): if isinstance(o, Antlr4Selection): char_symb_to_replace = [] for orig_c in o: c = orig_c if isinstance(c, Antlr4Sequence): if len(c) > 1: continue else: c = c[0] if isinstance(c, Antlr4Symbol) and c.is_terminal and len( c.symbol) == 1: char_symb_to_replace.append((orig_c, c)) if len(char_symb_to_replace) > 1: # build an regex out of them # and replace them by the regex for c, _ in char_symb_to_replace: o.remove(c) re_str = "[%s]" % ("".join( [c._escaped() for _, c in char_symb_to_replace])) re = Antlr4Symbol(re_str, True, is_regex=True) if len(o): o.append(re) else: return Antlr4Sequence([ re, ]) replace_item_by_sequence(r, match_replace_fn)
def remove_any_visuals(rules): def match_replace_fn(o): if isinstance(o, (Antlr4Indent, Antlr4Newline)): return Antlr4Sequence([]) for r in rules: replace_item_by_sequence(r.body, match_replace_fn)
def rm_ambiguity(rules): rule = rule_by_name(rules, "variable_decl_assignment") to_repl = Antlr4parser().from_str("( ASSIGN class_new )?") def match_replace_fn(o): if o == to_repl: return o.body replace_item_by_sequence(rule, match_replace_fn)
def fix_dpi_import_export(rules): C_IDENTIFIER = Antlr4Symbol("C_IDENTIFIER", False) def match_replace_fn(o): if o == C_IDENTIFIER: return Antlr4Selection( [C_IDENTIFIER, Antlr4Symbol("ESCAPED_IDENTIFIER", False)]) r = rule_by_name(rules, "dpi_import_export") replace_item_by_sequence(r.body, match_replace_fn)
def optimize(self, rules): for r in rules: if r.optimalizer_keep_out: continue first = True while first or self.modified: self.modified = False first = False replace_item_by_sequence(r, self.match_replace_fn) if r.is_lexer_rule(): char_options_to_regex(r)
def rm_semi_from_cross_body_item(rules): """ Because SEMI is already part of cross_body_item """ rule = rule_by_name(rules, "cross_body") semi = Antlr4Symbol("SEMI", False) def match_replace_fn(o): if o == semi: return Antlr4Sequence([]) replace_item_by_sequence(rule.body[0], match_replace_fn)
def add_interface_class_declaration(rules): """ Because interface_class_definition is not used anywhere (is missing in specified rules) """ intf = Antlr4Symbol("interface_class_declaration", False) cls = Antlr4Symbol("class_declaration", False) def match_replace_fn(o): if o == cls: return Antlr4Selection([o, deepcopy(intf)]) for rule in rules: replace_item_by_sequence(rule, match_replace_fn)
def add_predicated_for_CLONE_ID_after_obj(rules, target_lang): c_id = Antlr4parser().from_str("( COLON identifier )?") la1 = target_lang.LA(1) def match_replace_fn(o: iAntlr4GramElem): if o == c_id: return Antlr4Selection([ o.body, Antlr4Sequence([ Antlr4Symbol("{%s != COLON}?" % la1, True, True), ]) ]) for r in rules: replace_item_by_sequence(r.body, match_replace_fn)
def remove_ambiguous_else_from_if_else_constructs(rules, target_lang): kw_else = Antlr4Symbol("KW_ELSE", False) la1 = target_lang.LA(1) def match_replace_fn(o: iAntlr4GramElem): if isinstance(o, Antlr4Option) and isinstance(o.body, Antlr4Sequence): if o.body[0] == kw_else: return Antlr4Selection([ o.body, Antlr4Sequence([ Antlr4Symbol("{%s != KW_ELSE}?" % la1, True, True), ]) ]) for r in rules: replace_item_by_sequence(r.body, match_replace_fn)
def move_iteration_up_in_parse_tree(rules, rule_name): r = rule_by_name(rules, rule_name) # remove ()* from the rule body if isinstance(r.body, Antlr4Sequence): assert len(r.body) == 1, r.body r.body = r.body[0] assert isinstance(r.body, Antlr4Iteration) and not r.body.positive r.body = r.body.body # wrap rule appearence in ()* r_symb = Antlr4Symbol(rule_name, False) def match_replace_fn(o): if o == r_symb: return Antlr4Iteration(o, positive=False) for r in rules: replace_item_by_sequence(r.body, match_replace_fn)
def fix_SYSTEM_TF_IDENTIFIER(rules): kws = collect_keywords(rules) SYSTEM_TF_IDENTIFIER = Antlr4Symbol("SYSTEM_TF_IDENTIFIER", False) any_system_tf_identifier = Antlr4Symbol("any_system_tf_identifier", False) def match_replace_fn(o): if o == SYSTEM_TF_IDENTIFIER: return deepcopy(any_system_tf_identifier) for rule in rules: replace_item_by_sequence(rule, match_replace_fn) rules.append( Antlr4Rule( "any_system_tf_identifier", Antlr4Selection([ SYSTEM_TF_IDENTIFIER, *[ Antlr4Symbol(kw.replace("$", "KW_DOLAR_").upper(), False) for kw in kws if kw.startswith("$") ] ])))
def fix_implications(rules): """ :note: variants of implications are as a independent tokens, otherwise lexer parses it as -= > instead of - => """ any_impl_rule = Antlr4Rule( "any_implication", Antlr4parser().from_str("IMPLIES | IMPLIES_P | IMPLIES_N")) orig = Antlr4parser().from_str("( polarity_operator )? IMPLIES") def apply_rewrite(o): if isinstance(o, Antlr4Sequence): found_i = None for i, o2 in enumerate(o): if o2.eq_relaxed(orig[0]) and o[i + 1].eq_relaxed(orig[1]): found_i = i break if found_i is not None: del o[found_i + 1] o[found_i] = Antlr4Symbol(any_impl_rule.name, False) for r in rules: replace_item_by_sequence(r, apply_rewrite) rules.append(any_impl_rule)
def rm_option_from_eps_rules(p): already_eps_rules = [ "tf_port_list", "data_type_or_implicit", "list_of_arguments", "let_list_of_arguments", "list_of_port_connections", "list_of_checker_port_connections", "sequence_list_of_arguments", "property_list_of_arguments", ] # because it already can be eps for r in already_eps_rules: rm_option_on_rule_usage(p.rules, r) # fix optinality on datatypes r = rule_by_name(p.rules, "implicit_data_type") # : (signing)? (packed_dimension)* # -> # : signing (packed_dimension)* # | (packed_dimension)+ # ; r.body = Antlr4parser().from_str("signing ( packed_dimension )* | ( packed_dimension )+") _inline_rules(p.rules, ["variable_port_header", "net_port_header", "interface_port_header"]) # make data_type_or_implicit optional for r in p.rules: to_optional = [ "port", "function_data_type_or_implicit", "var_data_type", "property_formal_type", "let_formal_type", "net_port_type"] if r.name not in ["sequence_formal_type", "let_formal_type", ]: to_optional.append("data_type_or_implicit") if r.name not in ["data_type_or_implicit", "function_data_type_or_implicit"]: to_optional.append("implicit_data_type") if r.name != "property_formal_type": to_optional.append("sequence_formal_type") def match_replace_fn(o): if isinstance(o, Antlr4Symbol) and o.symbol in to_optional: return Antlr4Option(o) replace_item_by_sequence(r, match_replace_fn) if r.name == "net_port_type": # net_port_type: # ( net_type )? data_type_or_implicit # | identifier # | KW_INTERCONNECT implicit_data_type; r.body[1] = Antlr4parser().from_str("data_type_or_implicit") r.body[0] = Antlr4parser().from_str("net_type ( data_type_or_implicit )?") port = rule_by_name(p.rules, "port") # ( port_expression )? # | DOT identifier LPAREN ( port_expression )? RPAREN; port.body[0] = Antlr4Symbol("port_expression", False) # var_data_type: data_type | KW_VAR data_type_or_implicit; # var_data_type = rule_by_name(p.rules, "var_data_type") # var_data_type.body = Antlr4parser().from_str("KW_VAR ( data_type_or_implicit )? | data_type_or_implicit") pa = Antlr4parser() data_declaration = rule_by_name(p.rules, "data_declaration") assert data_declaration.body[0].eq_relaxed( pa.from_str("""( KW_CONST )? ( KW_VAR )? ( lifetime )? ( data_type_or_implicit )? list_of_variable_decl_assignments SEMI""")) data_declaration.body[0] = pa.from_str("""( KW_CONST )? ( KW_VAR ( lifetime )? ( data_type_or_implicit )? | ( lifetime )? data_type_or_implicit ) list_of_variable_decl_assignments SEMI""")
def optimize_class_scope(rules): p = Antlr4parser() to_replace0 = p.from_str("( package_scope | class_scope )? identifier") to_replace1 = p.from_str("( class_scope | package_scope )? identifier") package_or_class_scoped_id = Antlr4Rule("package_or_class_scoped_id", p.from_str( """( identifier ( parameter_value_assignment )? | KW_DOLAR_UNIT ) ( DOUBLE_COLON identifier ( parameter_value_assignment )? )*""")) rules.append(package_or_class_scoped_id) def match_replace_fn_reduce_1_item_sequence(o): if isinstance(o, Antlr4Sequence) and len(o) == 1: return o[0] q0 = Antlr4Query(to_replace0) q1 = Antlr4Query(to_replace1) for r in rules: replace_item_by_sequence(r, match_replace_fn_reduce_1_item_sequence) # if r.name == "net_type_declaration": # print(r.toAntlr4()) m = q0.match(r.body) if not m: m = q1.match(r.body) if m: def apply_to_replace0_and_1(o): for match in m: v = match.get(id(o), None) if v is not None: del match[id(o)] if (v is to_replace0 or v is to_replace1 or (isinstance(v, Antlr4Symbol) and v.symbol == "identifier")): return Antlr4Symbol(package_or_class_scoped_id.name, False) else: return Antlr4Sequence([]) replace_item_by_sequence(r, apply_to_replace0_and_1) for _m in m: # assert that all matching items were replaced assert not _m # print(r.toAntlr4()) # print(m) # else: # if "package_scope | class_scope" in r.toAntlr4() or "class_scope | package_scope" in r.toAntlr4(): # print("not found " + r.toAntlr4()) # class_qualifier: # ( KW_LOCAL DOUBLE_COLON )? ( implicit_class_handle DOT # | class_scope # )?; # class_scope: # ps_identifier ( parameter_value_assignment )? # ( DOUBLE_COLON identifier # ( parameter_value_assignment )? # )* DOUBLE_COLON; # implicit_class_handle: # KW_THIS ( DOT KW_SUPER )? # | KW_SUPER # ; # package_scope: # ( KW_DOLAR_UNIT # | identifier # ) DOUBLE_COLON; # hierarchical_identifier: ( KW_DOLAR_ROOT DOT )? ( identifier constant_bit_select DOT )* identifier; to_replace2 = p.from_str("( class_qualifier | package_scope )? hierarchical_identifier") package_or_class_scoped_path = Antlr4Rule("package_or_class_scoped_path", p.from_str(""" ( KW_LOCAL DOUBLE_COLON )? ( KW_DOLAR_ROOT | implicit_class_handle | ( ( KW_DOLAR_UNIT | identifier ( parameter_value_assignment )? ) ( DOUBLE_COLON identifier ( parameter_value_assignment )? )* ) ) """)) package_or_class_scoped_hier_id_with_const_select = Antlr4Rule( "package_or_class_scoped_hier_id_with_const_select", p.from_str(""" package_or_class_scoped_path ( constant_bit_select )* ( DOT identifier ( constant_bit_select )* )* """)) # bit_select: # LSQUARE_BR expression RSQUARE_BR; # select: # ( DOT identifier # | bit_select # )* ( LSQUARE_BR part_select_range RSQUARE_BR )?; # part_select_range: # constant_range # | indexed_range # ; # indexed_range: # expression ( PLUS # | MINUS # ) COLON constant_expression; # constant_range: # constant_expression COLON constant_expression; package_or_class_scoped_hier_id_with_select = Antlr4Rule( "package_or_class_scoped_hier_id_with_select", p.from_str(""" package_or_class_scoped_path ( bit_select )* ( DOT identifier ( bit_select )* )* ( LSQUARE_BR expression ( PLUS | MINUS )? COLON constant_expression RSQUARE_BR )? """)) rules.append(package_or_class_scoped_path) rules.append(package_or_class_scoped_hier_id_with_const_select) rules.append(package_or_class_scoped_hier_id_with_select) primary_no_cast_no_call = rule_by_name(rules, "primary_no_cast_no_call") m = Antlr4Query(to_replace2).match(primary_no_cast_no_call.body) def apply_to_replace2(o): for match in m: v = match.get(id(o), None) if v is not None: if (v is to_replace2 or (isinstance(v, Antlr4Symbol) and v.symbol == "hierarchical_identifier")): return Antlr4Symbol(package_or_class_scoped_hier_id_with_const_select.name, False) else: return Antlr4Sequence([]) replace_item_by_sequence(primary_no_cast_no_call, apply_to_replace2) _optimize_ps_type_identifier(rules) _optimize_ps_parameter_identifier(rules) rules.remove(rule_by_name(rules, "class_qualifier"))