Hooks

Hooks are used to attach CVL code to certain low-level operations, such as loads and stores to specific storage slots.

Todo

This documentation is incomplete. See the old documentation for partial information. See also Ghosts.

Contents

Syntax

The syntax for hooks is given by the following EBNF grammar:

hook ::= store_hook | load_hook

load_hook ::= "hook" "Sload"
              cvl_type id
              slot_pattern
              "STORAGE" block

store_hook ::= "hook" "Sstore"
               slot_pattern
               cvl_type id [ "(" cvl_type id ")" ]
               "STORAGE" block

TODO: the following needs condensing and explaining
      it is a description of slot_pattern (from cvl.cup)

/**
   (slot 2) -> 3rd storage slot
   (slot 0, offset 8) -> 1st storage slot, variable packed at 8 bytes
                        [ ... 8 bytes ... (* match! *) ... ? bytes ... | ... slot 2 ... | ... ]
   (slot 1)[uint key] -> an element of the mapping found at storage slot 1, whose key will be bound to the variable 'key'
   (slot 1).(offset 64) -> in the struct located in the 2nd slot, the member of the struct located 64 bytes (2 evm words)
                            from the start of the struct
                            [ ... 32 bytes ... { ... 64 bytes ... (* match! *) ... } ... ]
*/

static_slot_part ::= ID:id                                                                      {: RESULT = new StaticSlotPatternNamed(id); :}
                 |   LP ID:keyword NUMBER:number RP                                             {: RESULT = new StaticSlotPatternNumber(keyword, new NumberExp(number)); :}
                 |   LP ID:slot_keyword NUMBER:slot COMMA ID:offset_keyword NUMBER:offset RP    {: RESULT = new StaticSlotPatternTwoNumbers(slot_keyword, new NumberExp(slot), offset_keyword, new NumberExp(offset)); :}
;

static_slot_pattern ::= static_slot_part:part {: StaticSlotPattern p = new StaticSlotPattern(theFilename, partxleft); p.add(part); RESULT = p; :}
                    |   static_slot_pattern:pattern DOT static_slot_part:part {: pattern.add(part); RESULT = pattern; :}
;

slot_pattern_break_dots ::= static_slot_pattern:sp LSQB ID:key_or_index single_param:p RSQB
                        {: if (key_or_index.equals("KEY")) {
                                RESULT = new MapAccessSlotPattern(sp, p);
                           } else if (key_or_index.equals("INDEX")) {
                                RESULT = new ArrayAccessSlotPattern(sp, p);
                           } else {
                                report_fatal_error("A mapping or array access pattern must use either the keyword 'key' or 'index' respectively", cur_token);
                           }
                        :}
;

slot_pattern_nested ::= slot_pattern_break_dots:sp {: RESULT = sp; :}
             |   slot_pattern_nested:sp LSQB ID:key_or_index single_param:p RSQB
                        {: if (key_or_index.equals("KEY")) {
                                RESULT = new MapAccessSlotPattern(sp, p);
                           } else if (key_or_index.equals("INDEX")) {
                                RESULT = new ArrayAccessSlotPattern(sp, p);
                           } else {
                                report_fatal_error("A mapping or array access pattern must use either the keyword 'key' or 'index' respectively", cur_token);
                           }
                        :}
             |   slot_pattern_nested:sp DOT ID:field {: RESULT = new FieldAccessSlotPattern(sp, field); :}
             |   slot_pattern_nested:sp DOT LP ID:offset_keyword NUMBER:offset RP
                        {: if (!offset_keyword.equals("offset")) {
                                report_fatal_error("A struct access pattern must use the keyword 'offset'", cur_token);
                           } else {
                                RESULT = new StructAccessSlotPattern(sp, new NumberExp(offset));
                           }
                        :}
;

slot_pattern ::= slot_pattern_nested:sp {: RESULT = sp; :}
             |   static_slot_pattern:sp {: RESULT = sp; :}
             ;