@@ -683,6 +683,99 @@ e_irgen_rule_from_string(String8 string)
683683 return rule ;
684684}
685685
686+ ////////////////////////////////
687+ //~ rjf: Auto Hooks
688+
689+ internal E_AutoHookMap
690+ e_auto_hook_map_make (Arena * arena , U64 slots_count )
691+ {
692+ E_AutoHookMap map = {0 };
693+ map .slots_count = slots_count ;
694+ map .slots = push_array (arena , E_AutoHookSlot , map .slots_count );
695+ return map ;
696+ }
697+
698+ internal void
699+ e_auto_hook_map_insert_new (Arena * arena , E_AutoHookMap * map , String8 pattern , String8 tag_expr_string )
700+ {
701+ Temp scratch = scratch_begin (& arena , 1 );
702+ E_TokenArray tokens = e_token_array_from_text (scratch .arena , pattern );
703+ E_Parse parse = e_parse_type_from_text_tokens (scratch .arena , pattern , & tokens );
704+ E_IRTreeAndType irtree = e_irtree_and_type_from_expr (scratch .arena , parse .expr );
705+ E_TypeKey type_key = irtree .type_key ;
706+ E_AutoHookNode * node = push_array (arena , E_AutoHookNode , 1 );
707+ node -> type_key = type_key ;
708+ U8 pattern_split = '?' ;
709+ node -> type_pattern_parts = str8_split (arena , pattern , & pattern_split , 1 , 0 );
710+ node -> tag_expr = e_parse_expr_from_text (arena , push_str8_copy (arena , tag_expr_string ));
711+ if (!e_type_key_match (e_type_key_zero (), type_key ))
712+ {
713+ U64 hash = e_hash_from_type_key (type_key );
714+ U64 slot_idx = map -> slots_count ;
715+ SLLQueuePush_N (map -> slots [slot_idx ].first , map -> slots [slot_idx ].last , node , hash_next );
716+ }
717+ else
718+ {
719+ SLLQueuePush_N (map -> first_pattern , map -> last_pattern , node , pattern_order_next );
720+ }
721+ scratch_end (scratch );
722+ }
723+
724+ internal E_ExprList
725+ e_auto_hook_tag_exprs_from_type_key (Arena * arena , E_TypeKey type_key )
726+ {
727+ E_ExprList exprs = {0 };
728+ {
729+ Temp scratch = scratch_begin (& arena , 1 );
730+ E_AutoHookMap * map = e_ir_ctx -> auto_hook_map ;
731+
732+ //- rjf: gather exact-type-key-matches from the map
733+ {
734+ U64 hash = e_hash_from_type_key (type_key );
735+ U64 slot_idx = hash %map -> slots_count ;
736+ for (E_AutoHookNode * n = map -> slots [slot_idx ].first ; n != 0 ; n = n -> hash_next )
737+ {
738+ if (e_type_key_match (n -> type_key , type_key ))
739+ {
740+ e_expr_list_push (arena , & exprs , n -> tag_expr );
741+ }
742+ }
743+ }
744+
745+ //- rjf: gather fuzzy matches from all patterns in the map
746+ if (map -> first_pattern != 0 )
747+ {
748+ String8 type_string = str8_skip_chop_whitespace (e_type_string_from_key (scratch .arena , type_key ));
749+ for (E_AutoHookNode * auto_hook_node = map -> first_pattern ; auto_hook_node != 0 ; auto_hook_node = auto_hook_node -> pattern_order_next )
750+ {
751+ B32 fits_this_type_string = 1 ;
752+ U64 scan_pos = 0 ;
753+ for (String8Node * n = auto_hook_node -> type_pattern_parts .first ; n != 0 ; n = n -> next )
754+ {
755+ U64 pattern_part_pos = str8_find_needle (type_string , scan_pos , n -> string , 0 );
756+ if (pattern_part_pos >= type_string .size )
757+ {
758+ fits_this_type_string = 0 ;
759+ break ;
760+ }
761+ scan_pos = pattern_part_pos + n -> string .size ;
762+ }
763+ if (scan_pos < type_string .size )
764+ {
765+ fits_this_type_string = 0 ;
766+ }
767+ if (fits_this_type_string )
768+ {
769+ e_expr_list_push (arena , & exprs , auto_hook_node -> tag_expr );
770+ }
771+ }
772+ }
773+
774+ scratch_end (scratch );
775+ }
776+ return exprs ;
777+ }
778+
686779////////////////////////////////
687780//~ rjf: IR-ization Functions
688781
@@ -1767,9 +1860,12 @@ E_IRGEN_FUNCTION_DEF(default)
17671860internal E_IRTreeAndType
17681861e_irtree_and_type_from_expr (Arena * arena , E_Expr * expr )
17691862{
1863+ Temp scratch = scratch_begin (& arena , 1 );
17701864 E_IRTreeAndType result = {& e_irnode_nil };
1771- E_IRGenRule * irgen_rule = & e_irgen_rule__default ;
1772- E_Expr * irgen_rule_tag = & e_expr_nil ;
1865+
1866+ //- rjf: pick the ir-generation rule from explicitly-stored expressions
1867+ E_IRGenRule * explicit_irgen_rule = & e_irgen_rule__default ;
1868+ E_Expr * explicit_irgen_rule_tag = & e_expr_nil ;
17731869 for (E_Expr * tag = expr -> first_tag ; tag != & e_expr_nil ; tag = tag -> next )
17741870 {
17751871 String8 name = tag -> first -> string ;
@@ -1789,29 +1885,80 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr)
17891885 }
17901886 if (!tag_is_poisoned )
17911887 {
1792- E_UsedTagNode * n = push_array (arena , E_UsedTagNode , 1 );
1793- n -> tag = tag ;
1794- DLLPushBack (e_ir_ctx -> used_tag_map -> slots [slot_idx ].first , e_ir_ctx -> used_tag_map -> slots [slot_idx ].last , n );
1795- irgen_rule_tag = tag ;
1796- irgen_rule = irgen_rule_candidate ;
1888+ explicit_irgen_rule = irgen_rule_candidate ;
1889+ explicit_irgen_rule_tag = tag ;
17971890 break ;
17981891 }
17991892 }
18001893 }
1801- result = irgen_rule -> irgen (arena , expr , irgen_rule_tag );
1802- if (irgen_rule_tag != & e_expr_nil )
1894+
1895+ //- rjf: apply all ir-generation steps
1896+ typedef struct Task Task ;
1897+ struct Task
1898+ {
1899+ Task * next ;
1900+ E_IRGenRule * rule ;
1901+ E_Expr * tag ;
1902+ };
1903+ Task start_task = {0 , explicit_irgen_rule , explicit_irgen_rule_tag };
1904+ Task * first_task = & start_task ;
1905+ Task * last_task = first_task ;
1906+ for (Task * t = first_task ; t != 0 ; t = t -> next )
18031907 {
1804- U64 hash = e_hash_from_string (5381 , str8_struct (& irgen_rule_tag ));
1805- U64 slot_idx = hash %e_ir_ctx -> used_tag_map -> slots_count ;
1806- for (E_UsedTagNode * n = e_ir_ctx -> used_tag_map -> slots [slot_idx ].first ; n != 0 ; n = n -> next )
1908+ // rjf: poison the tag we are about to use, so we don't recursively use it
1909+ if (t -> tag != & e_expr_nil )
18071910 {
1808- if (n -> tag == irgen_rule_tag )
1911+ U64 hash = e_hash_from_string (5381 , str8_struct (& t -> tag ));
1912+ U64 slot_idx = hash %e_ir_ctx -> used_tag_map -> slots_count ;
1913+ E_UsedTagNode * n = push_array (arena , E_UsedTagNode , 1 );
1914+ n -> tag = t -> tag ;
1915+ DLLPushBack (e_ir_ctx -> used_tag_map -> slots [slot_idx ].first , e_ir_ctx -> used_tag_map -> slots [slot_idx ].last , n );
1916+ }
1917+
1918+ // rjf: do this rule's generation
1919+ result = t -> rule -> irgen (arena , expr , t -> tag );
1920+
1921+ // rjf: find any auto hooks according to this generation's type
1922+ {
1923+ E_ExprList exprs = e_auto_hook_tag_exprs_from_type_key (scratch .arena , result .type_key );
1924+ for (E_ExprNode * n = exprs .first ; n != 0 ; n = n -> next )
18091925 {
1810- DLLRemove (e_ir_ctx -> used_tag_map -> slots [slot_idx ].first , e_ir_ctx -> used_tag_map -> slots [slot_idx ].last , n );
1811- break ;
1926+ for (E_Expr * tag = n -> v ; tag != & e_expr_nil ; tag = tag -> next )
1927+ {
1928+ E_IRGenRule * rule = e_irgen_rule_from_string (tag -> first -> string );
1929+ if (rule == & e_irgen_rule__default ) { rule = e_irgen_rule_from_string (tag -> string ); }
1930+ if (rule != & e_irgen_rule__default )
1931+ {
1932+ Task * task = push_array (scratch .arena , Task , 1 );
1933+ SLLQueuePush (first_task , last_task , task );
1934+ task -> rule = rule ;
1935+ task -> tag = tag ;
1936+ break ;
1937+ }
1938+ }
18121939 }
18131940 }
18141941 }
1942+
1943+ //- rjf: unpoison the tags we used
1944+ for (Task * t = first_task ; t != 0 ; t = t -> next )
1945+ {
1946+ if (t -> tag != & e_expr_nil )
1947+ {
1948+ U64 hash = e_hash_from_string (5381 , str8_struct (& t -> tag ));
1949+ U64 slot_idx = hash %e_ir_ctx -> used_tag_map -> slots_count ;
1950+ for (E_UsedTagNode * n = e_ir_ctx -> used_tag_map -> slots [slot_idx ].first ; n != 0 ; n = n -> next )
1951+ {
1952+ if (n -> tag == t -> tag )
1953+ {
1954+ DLLRemove (e_ir_ctx -> used_tag_map -> slots [slot_idx ].first , e_ir_ctx -> used_tag_map -> slots [slot_idx ].last , n );
1955+ break ;
1956+ }
1957+ }
1958+ }
1959+ }
1960+
1961+ scratch_end (scratch );
18151962 return result ;
18161963}
18171964
0 commit comments