/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0

syntax = "proto2";

message VarDecl {
  required Expression expr = 1;
}

message MultiVarDecl {
  required uint32 num_vars = 1;
}

message LowLevelCall {
  enum Type {
    CALL = 0;
    CALLCODE = 1;
    DELEGATECALL = 2;
    STATICCALL = 3;
  }
  required Type callty = 1;
  required Expression gas = 2;
  required Expression addr = 3;
  // Valid for call and callcode only
  required Expression wei = 4;
  required Expression in = 5;
  required Expression insize = 6;
  required Expression out = 7;
  required Expression outsize = 8;
}

message Create {
  enum Type {
    CREATE = 0;
    CREATE2 = 1;
  }
  required Type createty = 1;
  required Expression wei = 2;
  required Expression position = 3;
  required Expression size = 4;
  // Valid for create2 only
  required Expression value = 5;
}

message FunctionCall {
  required Expression in_param1 = 1;
  required Expression in_param2 = 2;
  required Expression in_param3 = 3;
  required Expression in_param4 = 4;
}

message TypedVarDecl {
  enum TypeName {
    BOOL = 1;
    U8 = 2;
    U32 = 3;
    U64 = 4;
    U128 = 5;
    U256 = 6;
    S8 = 7;
    S32 = 8;
    S64 = 9;
    S128 = 10;
    S256 = 11;
  };
  required int32 id = 1;
  required TypeName type = 2;
  required Expression expr = 3;
}

message VarRef {
  required int32 varnum = 1;
}

message Literal {
  oneof literal_oneof {
    uint64 intval = 1;
    string hexval = 2;
    string strval = 3;
    bool boolval = 4;
  }
}

message TypedLiteral {
  enum TypeName {
    BOOL = 1;
    U8 = 2;
    U32 = 3;
    U64 = 4;
    U128 = 5;
    U256 = 6;
    S8 = 7;
    S32 = 8;
    S64 = 9;
    S128 = 10;
    S256 = 11;
  };
  required int32 val = 1;
  required TypeName type = 2;
}

message BinaryOp {
  enum BOp {
    ADD = 0;
    SUB = 1;
    MUL = 2;
    DIV = 3;
    MOD = 4;
    XOR = 5;
    AND = 6;
    OR = 7;
    EQ = 8;
    LT = 9;
    GT = 10;
    SHR = 11;
    SHL = 12;
    SAR = 13;
    SDIV = 14;
    SMOD = 15;
    EXP = 16;
    SLT = 17;
    SGT = 18;
    BYTE = 19;
    SI = 20;
    KECCAK = 21;
  };
  required BOp op = 1;
  required Expression left = 2;
  required Expression right = 3;
}

message UnaryOp {
  enum UOp {
    NOT = 0;
    MLOAD = 1;
    SLOAD = 2;
    ISZERO = 3;
    CALLDATALOAD = 4;
    EXTCODESIZE = 5;
    EXTCODEHASH = 6;
    BALANCE = 7;
    BLOCKHASH = 8;
  }
  required UOp op = 1;
  required Expression operand = 2;
}

message UnaryOpData {
  enum UOpData {
    SIZE = 1;
    OFFSET = 2;
  }
  required UOpData op = 1;
  required uint64 identifier = 2;
}

message TernaryOp {
  enum TOp {
    ADDM = 0;
    MULM = 1;
  }
  required TOp op = 1;
  required Expression arg1 = 2;
  required Expression arg2 = 3;
  required Expression arg3 = 4;
}

message CopyFunc {
  enum CopyType {
    CALLDATA = 0;
    CODE = 1;
    RETURNDATA = 2;
    DATA = 3;
  }
  required CopyType ct = 1;
  required Expression target = 2;
  required Expression source = 3;
  required Expression size = 4;
}

message ExtCodeCopy {
  required Expression addr = 1;
  required Expression target = 2;
  required Expression source = 3;
  required Expression size = 4;
}

message NullaryOp {
  enum NOp {
    MSIZE = 1;
    GAS = 2;
    CALLDATASIZE = 3;
    CODESIZE = 4;
    RETURNDATASIZE = 5;
    ADDRESS = 6;
    ORIGIN = 7;
    CALLER = 8;
    CALLVALUE = 9;
    GASPRICE = 10;
    COINBASE = 11;
    TIMESTAMP = 12;
    NUMBER = 13;
    DIFFICULTY = 14;
    GASLIMIT = 15;
    SELFBALANCE = 16;
    CHAINID = 17;
  }
  required NOp op = 1;
}

message StoreFunc {
  enum Storage {
    MSTORE = 0;
    SSTORE = 1;
    MSTORE8 = 2;
  }
  required Expression loc = 1;
  required Expression val = 2;
  required Storage st = 3;
}

message LogFunc {
  enum NumTopics {
    ZERO = 0;
    ONE = 1;
    TWO = 2;
    THREE = 3;
    FOUR = 4;
  }
  required Expression pos = 1;
  required Expression size = 2;
  required NumTopics num_topics = 3;
  required Expression t1 = 4;
  required Expression t2 = 5;
  required Expression t3 = 6;
  required Expression t4 = 7;
}

message Expression {
  oneof expr_oneof {
    VarRef varref = 1;
    Literal cons = 2;
    BinaryOp binop = 3;
    UnaryOp unop = 4;
    TernaryOp top = 5;
    NullaryOp nop = 6;
    FunctionCall func_expr = 7;
    LowLevelCall lowcall = 8;
    Create create = 9;
    UnaryOpData unopdata = 10;
  }
}

message AssignmentStatement {
  required VarRef ref_id = 1;
  required Expression expr = 2;
}

message IfStmt {
  required Expression cond = 1;
  required Block if_body = 2;
}

message BoundedForStmt {
  required Block for_body = 1;
}

message ForStmt {
  required Block for_body = 1;
  required Block for_init = 2;
  required Block for_post = 3;
  required Expression for_cond = 4;
}

message CaseStmt {
  required Literal case_lit = 1;
  required Block case_block = 2;
}

message SwitchStmt {
  required Expression switch_expr = 1;
  repeated CaseStmt case_stmt = 2;
  optional Block default_block = 3;
}

message BreakStmt {}
message ContinueStmt {}

message StopInvalidStmt {
  enum Type {
    STOP = 0;
    INVALID = 1;
  }
  required Type stmt = 1;
}

message RetRevStmt {
  enum Type {
    RETURN = 0;
    REVERT = 1;
  }
  required Type stmt = 1;
  required Expression pos = 2;
  required Expression size = 3;
}

message SelfDestructStmt {
  required Expression addr = 1;
}

message TerminatingStmt {
  oneof term_oneof {
    StopInvalidStmt   stop_invalid = 1;
    RetRevStmt        ret_rev = 2;
    SelfDestructStmt  self_des = 3;
  }
}

message FunctionDef {
  required uint32 num_input_params = 1;
  required uint32 num_output_params = 2;
  required Block block = 3;
  required bool force_call = 4;
}

message PopStmt {
  required Expression expr = 1;
}

message LeaveStmt {}

message Statement {
  oneof stmt_oneof {
    VarDecl             decl            = 1;
    AssignmentStatement assignment      = 2;
    IfStmt              ifstmt          = 3;
    StoreFunc           storage_func    = 4;
    Block               blockstmt       = 5;
    ForStmt             forstmt         = 6;
    SwitchStmt          switchstmt      = 7;
    BreakStmt           breakstmt       = 8;
    ContinueStmt        contstmt        = 9;
    LogFunc             log_func        = 10;
    CopyFunc            copy_func       = 11;
    ExtCodeCopy         extcode_copy    = 12;
    TerminatingStmt     terminatestmt   = 13;
    FunctionCall        functioncall    = 14;
    BoundedForStmt      boundedforstmt  = 15;
    FunctionDef         funcdef         = 16;
    PopStmt             pop             = 17;
    LeaveStmt           leave           = 18;
    MultiVarDecl        multidecl       = 19;
  }
}

message Block {
  repeated Statement statements = 1;
}

message Object {
  required Code code = 1;
  optional Data data = 2;
  repeated Object sub_obj = 3;
}

message Code {
  required Block block = 1;
}

message Data {
  required string hex = 1;
}

message Program {
  enum Version {
    HOMESTEAD = 0;
    TANGERINE = 1;
    SPURIOUS = 2;
    BYZANTIUM = 3;
    CONSTANTINOPLE = 4;
    PETERSBURG = 5;
    ISTANBUL = 6;
    BERLIN = 7;
  }
  oneof program_oneof {
    Block block = 1;
    Object obj = 2;
  }
  required Version ver = 3;
  required uint32 step = 4;
}

package solidity.yul.test.yul_fuzzer;
