def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.Integer import Integer number_zero_to_bytes = b'\x00' jmp_place_holder = (Opcode.JMP, b'\x01') verify_number_is_zero = [ (Opcode.DUP, b''), (Opcode.NZ, b''), jmp_place_holder ] number_is_not_zero = super().opcode.copy() number_is_not_zero.append(jmp_place_holder) number_is_zero = [ (Opcode.DROP, b''), (Opcode.PUSHDATA1, Integer(len(number_zero_to_bytes)).to_byte_array() + number_zero_to_bytes), ] number_is_not_zero[-1] = Opcode.get_jump_and_data(Opcode.JMP, get_bytes_count(number_is_zero)) verify_number_is_zero[-1] = Opcode.get_jump_and_data(Opcode.JMPIFNOT, get_bytes_count(number_is_not_zero)) return ( verify_number_is_zero + number_is_not_zero + number_is_zero + [(Opcode.NOP, b'')] # TODO: change this when refactoring calling methods with methods as args )
def is_instance_opcodes(self) -> List[Tuple[Opcode, bytes]]: is_type_opcodes = [ (Opcode.DUP, b''), # if is the same internal type (Opcode.ISTYPE, self.stack_item) ] return_false = [ (Opcode.DROP, b''), (Opcode.PUSH0, b''), # return False ] return_false_bytes_size = get_bytes_count(return_false) final_instructions = [] final_jmp = [(Opcode.JMP, Integer(2 + return_false_bytes_size).to_byte_array(min_length=1))] validate_type = self._is_instance_inner_opcodes(get_bytes_count(final_jmp)) if len(validate_type) > 0: final_instructions += (validate_type + final_jmp) bytes_size = get_bytes_count(final_instructions) jmp_opcode, jmp_arg = Opcode.get_jump_and_data(Opcode.JMPIFNOT, bytes_size + 1) final_instructions = (is_type_opcodes + [(jmp_opcode, jmp_arg)] + final_instructions + return_false) else: is_type_opcodes.remove((Opcode.DUP, b'')) final_instructions = is_type_opcodes return final_instructions
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.model.builtin.interop.interop import Interop from boa3.neo.vm.type.Integer import Integer copy_list_and_reverse = [ (Opcode.UNPACK, b''), # copy - it must not change the original (Opcode.PACK, b''), (Opcode.DUP, b''), (Opcode.REVERSEITEMS, b'') ] check_if_arg_is_empty = [ (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.PUSH0, b''), ] complete_loop = ([ (Opcode.DUP, b''), (Opcode.POPITEM, b''), ] + Interop.Log.opcode + check_if_arg_is_empty) complete_loop.append( (Opcode.JMPNE, Integer(-get_bytes_count(complete_loop)).to_byte_array( signed=True))) return (check_if_arg_is_empty + [ ( Opcode.JMPEQ, Integer( get_bytes_count(copy_list_and_reverse) + 1 # the size of the JMPEQ arg + get_bytes_count(complete_loop)).to_byte_array( signed=True)), ] + copy_list_and_reverse + complete_loop + [(Opcode.DROP, b'')])
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.neo.vm.type.Integer import Integer from boa3.neo.vm.type.StackItem import StackItemType ECPOINT_SIZE = 33 throw_if_invalid = [ (Opcode.THROW, b''), ] check_bytestr_size = [ (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.PUSHINT8, Integer(ECPOINT_SIZE).to_byte_array(signed=True)), Opcode.get_jump_and_data(Opcode.JMPEQ, get_bytes_count(throw_if_invalid), jump_through=True), ] return [ (Opcode.CONVERT, StackItemType.ByteString), # convert to ECPoint (Opcode.DUP, b''), (Opcode.ISNULL, b''), Opcode.get_jump_and_data(Opcode.JMPIF, get_bytes_count(check_bytestr_size), jump_through=True), ] + check_bytestr_size + throw_if_invalid
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') create_auxiliary_vars = [ # initializes auxiliary variables (Opcode.NEWMAP, b''), # dict_copy = {} (Opcode.OVER, b''), (Opcode.KEYS, b''), # list_keys = list(dict_target) (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), # index = len(list_keys) - 1 ] verify_while_condition = [ # if index < 0: go clean stack (Opcode.DUP, b''), (Opcode.PUSH0, b''), jmp_place_holder # jump to clean_stack ] while_loop = [ # while index >= 0: add key value pair into new dict (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PICKITEM, b''), # key = list_keys[index] (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b''), # value = dict_target[key] (Opcode.SETITEM, b''), # dict_copy[key] = value (Opcode.DEC, b''), # index-- # jump back to verify_while_condition ] jmp_back_to_verify = Opcode.get_jump_and_data(Opcode.JMP, -get_bytes_count(while_loop + verify_while_condition)) while_loop.append(jmp_back_to_verify) jmp_while_loop = Opcode.get_jump_and_data(Opcode.JMPLT, get_bytes_count(while_loop)) verify_while_condition[-1] = jmp_while_loop clean_stack = [ # remove all values from stack except the dict_copy (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.NIP, b'') ] return ( create_auxiliary_vars + verify_while_condition + while_loop + clean_stack )
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.Integer import Integer from boa3.neo.vm.type.String import String message = String("decimals cannot be negative").to_bytes() if_negative_decimal = [ (Opcode.PUSHDATA1, Integer(len(message)).to_byte_array(signed=True, min_length=1) + message), (Opcode.THROW, b''), ] decimals_unit = [ (Opcode.OVER, b''), (Opcode.PUSH0, b''), Opcode.get_jump_and_data(Opcode.JMPGE, get_bytes_count(if_negative_decimal), True), ] + if_negative_decimal + [ (Opcode.DUP, b''), (Opcode.REVERSE3, b''), Opcode.get_push_and_data(10), (Opcode.SWAP, b''), (Opcode.POW, b''), (Opcode.SWAP, b''), (Opcode.OVER, b''), (Opcode.MOD, b'') ] if_negative_mod = [ (Opcode.ADD, b''), (Opcode.JMP, b'') ] else_negative_mod = [ (Opcode.NIP, b'') ] num_jmp_code = get_bytes_count(else_negative_mod) if_negative_mod[-1] = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code, True) num_jmp_code = get_bytes_count(if_negative_mod) floor_computation = [ (Opcode.DUP, b''), (Opcode.PUSH0, b''), Opcode.get_jump_and_data(Opcode.JMPGE, num_jmp_code, True), ] + if_negative_mod + else_negative_mod + [ (Opcode.SUB, b'') ] return decimals_unit + floor_computation
def opcode(self) -> List[Tuple[Opcode, bytes]]: jmp_place_holder = (Opcode.JMP, b'') mod = [ ( Opcode.SWAP, b'' ), # neo's mod has a different result from python's mod in some cases (Opcode.OVER, b''), (Opcode.MOD, b''), (Opcode.DUP, b''), (Opcode.SIGN, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIGN, b''), ( Opcode.OVER, b'' ), # if the result is not zero and the sign is different than the second operator (Opcode.NUMEQUAL, b''), # the result is different (Opcode.SWAP, b''), (Opcode.PUSH0, b''), (Opcode.NUMEQUAL, b''), # the result is different (Opcode.BOOLOR, b''), jmp_place_holder, ] from boa3.compiler.codegenerator import get_bytes_count if_negative = [(Opcode.ADD, b''), jmp_place_holder] num_jmp_code = get_bytes_count(if_negative) mod[-1] = Opcode.get_jump_and_data(Opcode.JMPIF, num_jmp_code, True) else_negative = [(Opcode.NIP, b'')] num_jmp_code = get_bytes_count(else_negative) if_negative[-1] = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code, True) return mod + if_negative + else_negative
def _is_instance_inner_opcodes(self, jmp_to_if_false: int = 0) -> List[Tuple[Opcode, bytes]]: if self.stack_item not in (StackItemType.Array, StackItemType.Struct, StackItemType.Map): return [] variables_count_is_equal = [ (Opcode.DUP, b''), (Opcode.SIZE, b''), Opcode.get_push_and_data(len(self._all_variables)), (Opcode.NUMEQUAL, b''), ] total_size = jmp_to_if_false variables_type_validations = [] for var_index, (var_id, var) in reversed(list(enumerate(self._all_variables.items()))): if var.type.stack_item != StackItemType.Any: # validate primitive types only to avoid recursive code if self.stack_item == StackItemType.Map: get = Opcode.get_pushdata_and_data(var_id) else: get = Opcode.get_push_and_data(var_index) new_opcodes = [ (Opcode.DUP, b''), get, (Opcode.PICKITEM, b''), (Opcode.ISTYPE, var.type.stack_item) ] if len(variables_type_validations) == 0: new_opcodes.append((Opcode.NIP, b'')) elif total_size > 0: new_opcodes.append((Opcode.get_jump_and_data(Opcode.JMPIFNOT, total_size + 1))) variables_type_validations = new_opcodes + variables_type_validations total_size += get_bytes_count(new_opcodes) if total_size > 0: if len(variables_type_validations) > 0: final_opcode = (Opcode.get_jump_and_data(Opcode.JMPIFNOT, total_size + 1)) else: final_opcode = (Opcode.NIP, b'') variables_count_is_equal.append(final_opcode) return variables_count_is_equal + variables_type_validations
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType jmp_place_holder = (Opcode.JMP, b'\x01') message = String("substring not found").to_bytes() # receives: end, start, substr, str verify_negative_index = [ # verifies if index in a negative value (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if index >= 0, jump to verify_big_end or verify_big_start ] fix_negative_end = [ # gets the correspondent positive value of end (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.INC, b''), # end = end + len(str) + 1 (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if end is not negative anymore, start verifying start ] fix_still_negative_index = [ # if index is still negative, consider it 0 then (Opcode.DROP, b''), (Opcode.PUSH0, b''), # end = 0 ] jmp_fix_negative_index = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_negative_end + fix_still_negative_index), True) verify_negative_index[-1] = jmp_fix_negative_index verify_big_end = [ # verify if end is bigger then len(str) (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # if end <= len(str), start verifying start ] fix_big_end = [ # consider end as len(str) (Opcode.DROP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), # end = len(str) ] jmp_other_verifies = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_still_negative_index + verify_big_end + fix_big_end), True) fix_negative_end[-1] = jmp_other_verifies jmp_fix_big_index = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(fix_big_end), True) verify_big_end[-1] = jmp_fix_big_index verify_and_fix_end = [ # collection of Opcodes regarding verifying and fixing end index (Opcode.REVERSE4, b''), ] verify_and_fix_end.extend(verify_negative_index) verify_and_fix_end.extend(fix_negative_end) verify_and_fix_end.extend(fix_still_negative_index) verify_and_fix_end.extend(verify_big_end) verify_and_fix_end.extend(fix_big_end) verify_and_fix_start = [ # collection of Opcodes regarding verifying and fixing start index (Opcode.SWAP, b'') ] verify_and_fix_start.extend(verify_negative_index) verify_and_fix_start.extend(fix_negative_end) verify_and_fix_start.extend(fix_still_negative_index) verify_and_fix_start.extend(verify_big_end) verify_and_fix_start.extend(fix_big_end) change_stack_order = [ # change order of items on the stack (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), # size = len(substr) (Opcode.ROT, b''), (Opcode.ROT, b''), ] verify_while = [ # verify already compared all that was need (Opcode.OVER, b''), (Opcode.OVER, b''), (Opcode.SUB, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), jmp_place_holder # if end - index >= size, jump to not_inside_sequence ] compare_item = [ # compare str[index:index+size] with substr (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.NUMEQUAL, b''), jmp_place_holder # if str[index:index+size] == substr, return index ] not_found = [ # increments index and goes back to verify again (Opcode.INC, b''), # index++ # jump to verify_while ] jmp_back_to_verify = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_while + compare_item + not_found), True) not_found.append(jmp_back_to_verify) jmp_to_error = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(compare_item + not_found), True) verify_while[-1] = jmp_to_error not_inside_sequence = [ # send error message saying that substring not found (Opcode.PUSHDATA1, Integer(len(message)).to_byte_array(signed=True, min_length=1) + message), (Opcode.THROW, b''), ] jmp_to_return_index = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(not_found + not_inside_sequence), True) compare_item[-1] = jmp_to_return_index return_index = [ # removes all values in the stack but the index (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), ] return (verify_and_fix_end + verify_and_fix_start + change_stack_order + verify_while + compare_item + not_found + not_inside_sequence + return_index)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.model.type.type import Type jmp_place_holder = (Opcode.JMP, b'\x01') # region verify end verify_end_null = [ # verifies if end is null (Opcode.REVERSE4, b''), (Opcode.DUP, b''), (Opcode.ISNULL, b''), jmp_place_holder ] end_null = [ # if end is null, end = len(self) (Opcode.DROP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # skip the other end verifications ] num_jmp_code = get_bytes_count(end_null) jmp_str_end_null_statement = Opcode.get_jump_and_data( Opcode.JMPIFNOT, num_jmp_code, True) verify_end_null[-1] = jmp_str_end_null_statement verify_end_neg = [ # verifies if end is < 0 (Opcode.DUP, b''), (Opcode.PUSH0, b''), jmp_place_holder ] end_neg = [ # if end is < 0, then get the positive equivalent number (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.DUP, b''), (Opcode.PUSH0, b''), jmp_place_holder ] end_still_neg = [ # if end is still < 0 after adding it to len(self), end = 0 (Opcode.DROP, b''), (Opcode.PUSH0, b''), ] num_jmp_code = get_bytes_count(end_still_neg) jmp_end_still_neg_statement = Opcode.get_jump_and_data( Opcode.JMPGE, num_jmp_code, True) end_neg[-1] = jmp_end_still_neg_statement skip_end_gt_size = [ jmp_place_holder # skip the other end verification ] num_jmp_code = get_bytes_count(end_still_neg + end_neg + skip_end_gt_size) jmp_end_neg_statement = Opcode.get_jump_and_data( Opcode.JMPGE, num_jmp_code, True) verify_end_neg[-1] = jmp_end_neg_statement verify_end_gt_size = [ # verifies if end >= len(self) (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder, ] end_gt_size = [ # if end >= len(self), end = len(self) (Opcode.DROP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), ] num_jmp_code = get_bytes_count(end_gt_size) jmp_end_gt_size_statement = Opcode.get_jump_and_data( Opcode.JMPLE, num_jmp_code, True) verify_end_gt_size[-1] = jmp_end_gt_size_statement num_jmp_code = get_bytes_count(end_gt_size + verify_end_gt_size) jmp_whole_end_gt_size_statement = Opcode.get_jump_and_data( Opcode.JMP, num_jmp_code, True) skip_end_gt_size[-1] = jmp_whole_end_gt_size_statement num_jmp_code = get_bytes_count(end_gt_size + verify_end_gt_size + skip_end_gt_size + end_still_neg + end_neg + verify_end_neg) jmp_whole_end_gt_size_statement = Opcode.get_jump_and_data( Opcode.JMP, num_jmp_code, True) end_null[-1] = jmp_whole_end_gt_size_statement verify_end = (verify_end_null + end_null + verify_end_neg + end_neg + end_still_neg + skip_end_gt_size + verify_end_gt_size + end_gt_size) # endregion # region verify start verify_start_neg = [ # verifies if start is < 0 (Opcode.OVER, b''), (Opcode.PUSH0, b''), jmp_place_holder ] start_neg = [ # if start is < 0, then get the positive equivalent index (Opcode.SWAP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.DUP, b''), (Opcode.PUSH0, b''), jmp_place_holder ] start_still_neg = [ # if start is still < 0 after adding it to len(self), start = 0 (Opcode.DROP, b''), (Opcode.PUSH0, b''), ] num_jmp_code = get_bytes_count(start_still_neg) jmp_str_start_still_neg_statement = Opcode.get_jump_and_data( Opcode.JMPGE, num_jmp_code, True) start_neg[-1] = jmp_str_start_still_neg_statement correct_start_position = [ # put start on the correct position (Opcode.SWAP, b'') ] num_jmp_code = get_bytes_count(correct_start_position + start_still_neg + start_neg) jmp_str_start_neg_statement = Opcode.get_jump_and_data( Opcode.JMPGE, num_jmp_code, True) verify_start_neg[-1] = jmp_str_start_neg_statement verify_start = (verify_start_neg + start_neg + start_still_neg + correct_start_position) # endregion # region Count logic initialize = [ # initialize variables (Opcode.PUSH0, b''), # count = 0 (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), # substr_size = len(substr) (Opcode.SWAP, b''), ] verify_while = [ # verifies if substr_size + index >= end (Opcode.OVER, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.ADD, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), jmp_place_holder ] count_substring = [ # verifies if self[index: index+substr_size] == substr (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, Type.str.stack_item), (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.NUMEQUAL, b''), jmp_place_holder ] count_plusplus = [ # if self[index: index+substr_size] == substr (Opcode.INC, b''), # count++ ] num_jmp_code = get_bytes_count(count_plusplus) jmp_count_plusplus_statement = Opcode.get_jump_and_data( Opcode.JMPIFNOT, num_jmp_code, True) count_substring[-1] = jmp_count_plusplus_statement go_back_to_while = [ # go back to while verification (Opcode.REVERSE4, b''), (Opcode.INC, b''), # index ++ (Opcode.REVERSE4, b''), # jump back to while ] num_jmp_code = -get_bytes_count(go_back_to_while + count_plusplus + count_substring + verify_while) jmp_back_to_while_statement = Opcode.get_jump_and_data( Opcode.JMP, num_jmp_code) go_back_to_while.append(jmp_back_to_while_statement) num_jmp_code = get_bytes_count(go_back_to_while + count_plusplus + count_substring) jmp_to_clean_stack_statement = Opcode.get_jump_and_data( Opcode.JMPGT, num_jmp_code, True) verify_while[-1] = jmp_to_clean_stack_statement clean_stack = [ # remove auxiliary values (Opcode.REVERSE4, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.REVERSE3, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), ] count_logic = (initialize + verify_while + count_substring + count_plusplus + go_back_to_while + clean_stack) # endregion # count string logic is verify_end + verify_start + count_logic return (verify_end + verify_start + count_logic)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType jmp_place_holder = (Opcode.JMP, b'\x01') # receive: string, chars initializing_first_loop = [ # initializes the variables for the first loop (Opcode.OVER, b''), (Opcode.SIZE, b''), # string_size = len(string) (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.PUSH0, b''), # index = 0 ] verify_leading_chars = [ # verifies if all leading characters are in chars (Opcode.DUP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), jmp_place_holder, # if index >= string_size, jump to initialize_second_loop ] get_leading_char_at_index = [ # gets the character at the current index and create another index variable (Opcode.PUSH4, b''), # to go through the chars (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), # char = string[index] (Opcode.CONVERT, StackItemType.ByteString), (Opcode.PUSH0, b''), # index_chars = 0 ] verify_if_index_gt_len_chars = [ # verify if already compared all chars with char (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), jmp_place_holder, # if index >= string_size, jump to remove_extras ] verify_if_char_in_chars = [ # compares char with chars[index_chars] (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.NUMEQUAL, b''), # equal = char == chars[index_chars] (Opcode.SWAP, b''), (Opcode.INC, b''), # index_chars++ (Opcode.SWAP, b''), # jump back to verify_if_index_gt_len_chars if not equal ] jmp_back_to_verify_index = Opcode.get_jump_and_data( Opcode.JMPIFNOT, -get_bytes_count(verify_if_char_in_chars + verify_if_index_gt_len_chars)) verify_if_char_in_chars.append(jmp_back_to_verify_index) leading_char_found = [ # char is in chars, so go back to verify_leading_chars (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.INC, b''), # index++ # jump back to verify_leading_chars ] jmp_back_to_verify_leading_chars = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_leading_chars + get_leading_char_at_index + verify_if_index_gt_len_chars + verify_if_char_in_chars + leading_char_found)) leading_char_found.append(jmp_back_to_verify_leading_chars) jmp_to_leading_chars = Opcode.get_jump_and_data( Opcode.JMPGE, get_bytes_count(verify_if_char_in_chars + leading_char_found), True) verify_if_index_gt_len_chars[-1] = jmp_to_leading_chars remove_extras = [ # remove opcodes that won't be used anymore (Opcode.DROP, b''), (Opcode.DROP, b''), ] jmp_to_leading_chars = Opcode.get_jump_and_data( Opcode.JMPGE, get_bytes_count(get_leading_char_at_index + verify_if_index_gt_len_chars + verify_if_char_in_chars + leading_char_found + remove_extras), True) verify_leading_chars[-1] = jmp_to_leading_chars get_number_of_leading_chars = (initializing_first_loop + verify_leading_chars + get_leading_char_at_index + verify_if_index_gt_len_chars + verify_if_char_in_chars + leading_char_found + remove_extras) initialize_second_loop = [ # initializes the variables for the second loop (Opcode.REVERSE3, b''), # n_leading = index (Opcode.DEC, b''), # index = string_size - 1 ] verify_trailing_chars = [ # verifies if leading and trailing characters are the same (Opcode.DUP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), jmp_place_holder, # if index <= n_leading, go strip the string ] get_trailing_char_at_index = [ # gets the character at the current index and create another index variable (Opcode.PUSH4, b''), # to go through the chars (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), # char = string[index] (Opcode.CONVERT, StackItemType.ByteString), (Opcode.PUSH0, b''), # index_chars = 0 ] get_trailing_char_at_index.extend(verify_if_index_gt_len_chars) get_trailing_char_at_index.extend(verify_if_char_in_chars) trailing_char_found = [ # char is in chars, so go back to get_trailing_char_at_index (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DEC, b''), # index-- # jump back to get_trailing_char_at_index ] jmp_back_to_verify_trailing_chars = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(get_trailing_char_at_index + trailing_char_found)) trailing_char_found.append(jmp_back_to_verify_trailing_chars) remove_extras = [ # remove opcodes that won't be used anymore (Opcode.DROP, b''), (Opcode.DROP, b''), ] jmp_to_strip_string = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(get_trailing_char_at_index + trailing_char_found + remove_extras), True) verify_trailing_chars[-1] = jmp_to_strip_string get_number_of_trailing_chars = (initialize_second_loop + verify_trailing_chars + get_trailing_char_at_index + trailing_char_found + remove_extras) strip_string = [ # strips the string using chars (Opcode.NIP, b''), (Opcode.OVER, b''), (Opcode.SUB, b''), (Opcode.INC, b''), (Opcode.REVERSE3, b''), (Opcode.DROP, b''), (Opcode.SWAP, b''), (Opcode.SUBSTR, b''), # string.strip(chars) (Opcode.CONVERT, StackItemType.ByteString), ] return (get_number_of_leading_chars + get_number_of_trailing_chars + strip_string)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') # Receives: string, iterable verify_empty_string = [ # verify if string is empty (Opcode.DUP, b''), (Opcode.SIZE, b''), # iterable_size = len(iterable) (Opcode.PUSH0, b''), # index = 0 (Opcode.OVER, b''), (Opcode.OVER, b''), jmp_place_holder # if iterable_size is less than or equals to 0, return empty string ] initialize_string = [ # initializes the return value (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b''), # joined = iterable[0] (Opcode.SWAP, b''), (Opcode.INC, b''), # index++ (Opcode.SWAP, b''), ] from boa3.model.type.type import Type if Type.dict.is_type_of(self._arg_iterable.type): get_dict_keys = [ # get dictionary keys as an array (Opcode.REVERSE3, b''), (Opcode.KEYS, b''), (Opcode.REVERSE3, b''), ] initialize_string = get_dict_keys + initialize_string verify_index = [ # verify if all items on the iterable were visited (Opcode.OVER, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), jmp_place_holder # jump to remove_extra_values if every item was already visited ] concat_strings = [ # concatenate the items inside de interable (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.CAT, b''), # joined = joined + string (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PICKITEM, b''), (Opcode.CAT, b''), # joined = joined + iterable[index] (Opcode.SWAP, b''), (Opcode.INC, b''), # index++ (Opcode.SWAP, b''), # jump back to verify_index ] jmp_back_to_verify = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_index + concat_strings)) concat_strings.append(jmp_back_to_verify) jmp_concatenation = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(initialize_string + verify_index + concat_strings), True) verify_empty_string[-1] = jmp_concatenation add_empty_string = [ # add a empty string at the top of the stack (Opcode.PUSHDATA1, b'\x00') ] jmp_concatenation = Opcode.get_jump_and_data( Opcode.JMPGE, get_bytes_count(concat_strings + add_empty_string), True) verify_index[-1] = jmp_concatenation remove_extra_values = [ # remove all values from stack except the joined string (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), ] return (verify_empty_string + initialize_string + verify_index + concat_strings + add_empty_string + remove_extra_values)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') message = String("x not in sequence").to_bytes() # receives: end, start, x, sequence verify_negative_index = [ # verifies if index in a negative value (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if index >= 0, jump to verify_big_end or verify_big_start ] fix_negative_end = [ # gets the correspondent positive value of end (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.INC, b''), # end = end + len(sequence) + 1 (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if end is not negative anymore, start verifying start ] fix_still_negative_index = [ # if index is still negative, consider it 0 then (Opcode.DROP, b''), (Opcode.PUSH0, b''), # end = 0 ] jmp_fix_negative_index = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_negative_end + fix_still_negative_index), True) verify_negative_index[-1] = jmp_fix_negative_index verify_big_end = [ # verify if end is bigger then len(sequence) (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # if end <= len(sequence), start verifying start ] fix_big_end = [ # consider end as len(sequence) (Opcode.DROP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), # end = len(sequence) ] jmp_other_verifies = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_still_negative_index + verify_big_end + fix_big_end), True) fix_negative_end[-1] = jmp_other_verifies jmp_fix_big_index = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(fix_big_end), True) verify_big_end[-1] = jmp_fix_big_index verify_and_fix_end = [ # collection of Opcodes regarding verifying and fixing end index (Opcode.REVERSE4, b''), ] verify_and_fix_end.extend(verify_negative_index) verify_and_fix_end.extend(fix_negative_end) verify_and_fix_end.extend(fix_still_negative_index) verify_and_fix_end.extend(verify_big_end) verify_and_fix_end.extend(fix_big_end) verify_and_fix_start = [ # collection of Opcodes regarding verifying and fixing start index (Opcode.SWAP, b'') ] verify_and_fix_start.extend(verify_negative_index) verify_and_fix_start.extend(fix_negative_end) verify_and_fix_start.extend(fix_still_negative_index) verify_and_fix_start.extend(verify_big_end) verify_and_fix_start.extend(fix_big_end) verify_while = [ # verify if already went through all items on the sequence[start:end] (Opcode.OVER, b''), # index = start (Opcode.OVER, b''), jmp_place_holder # if index <= start, jump to not_inside_sequence ] compare_item = [ # verifies if x is in sequence (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.NUMEQUAL, b''), # found_x = sequence[index] == x jmp_place_holder # if found_x, jump to return_index ] not_found = [ # increments index and goes back to verify again (Opcode.INC, b''), # index++ # jump to verify_while ] jmp_back_to_verify = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_while + compare_item + not_found), True) not_found.append(jmp_back_to_verify) jmp_to_error = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(compare_item + not_found), True) verify_while[-1] = jmp_to_error not_inside_sequence = [ # send error message saying that x is not in sequence (Opcode.PUSHDATA1, Integer(len(message)).to_byte_array(signed=True, min_length=1) + message), (Opcode.THROW, b''), ] jmp_to_return_index = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(not_found + not_inside_sequence), True) compare_item[-1] = jmp_to_return_index return_index = [ # removes all values in the stack but the index (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), ] return (verify_and_fix_end + verify_and_fix_start + verify_while + compare_item + not_found + not_inside_sequence + return_index)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType from boa3.neo.vm.type.Integer import Integer upper_a = Integer(ord('A')).to_byte_array() upper_z = Integer(ord('Z')).to_byte_array() jmp_place_holder = (Opcode.JMP, b'\x01') initializing = [ # initialize auxiliary values (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.PUSH0, b''), # index = 0 ] verify_while = [ # verifies if while is over (Opcode.OVER, b''), (Opcode.OVER, b''), jmp_place_holder, # jump to last statement to clean the stack if index >= len(string) ] get_substring_left = [ # gets the substring to the left of the index (Opcode.REVERSE3, b''), (Opcode.DUP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.OVER, b''), (Opcode.LEFT, b''), # substr_left = string[:index] (Opcode.CONVERT, StackItemType.ByteString), (Opcode.ROT, b''), (Opcode.ROT, b''), ] get_substring_middle = [ # gets the substring on the index ( Opcode.OVER, b'' ), # TODO: verify if string[index] < c0 when other values are implemented (Opcode.OVER, b''), ( Opcode.PUSH1, b'' ), # modifier = 1, since using upper is only supported with ASCII for now (Opcode.SUBSTR, b''), # substr_middle = string[index:index+modifier] (Opcode.CONVERT, StackItemType.ByteString), (Opcode.DUP, b''), (Opcode.PUSHDATA1, Integer(len(upper_a)).to_byte_array() + upper_a), jmp_place_holder, # jump to get the substring to the right if substr_middle value is lower than 'A' ] verify_greater_than_z = [ # verifies if substr_middle is between 'A' and 'Z' (Opcode.DUP, b''), (Opcode.PUSHDATA1, Integer(len(upper_z)).to_byte_array() + upper_z), jmp_place_holder, # jump to get the substring to the right if substr_middle value is greater than 'Z' ] swap_upper_to_lower_case = [ # change middle_substr to lowercase equivalent (Opcode.PUSHINT8, Integer(32).to_byte_array(signed=True)), (Opcode.ADD, b''), (Opcode.CONVERT, StackItemType.ByteString), ] jmp_to_join_substring = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(verify_greater_than_z + swap_upper_to_lower_case), True) get_substring_middle[-1] = jmp_to_join_substring jmp_to_join_substring = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(swap_upper_to_lower_case), True) verify_greater_than_z[-1] = jmp_to_join_substring get_substring_middle.extend(verify_greater_than_z) get_substring_middle.extend(swap_upper_to_lower_case) get_substring_right = [ # gets the substring to the right of the index (Opcode.ROT, b''), (Opcode.ROT, b''), (Opcode.INC, b''), (Opcode.NEGATE, b''), (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.RIGHT, b''), # substr_right = string[index+modifier:] ] join_substrings = [ # concatenate substr_left, substr_middle, substr_right (Opcode.CAT, b''), (Opcode.CAT, b''), # substr_left + substr_middle + substr_right (Opcode.NIP, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.REVERSE3, b''), (Opcode.INC, b''), # index ++ # jump back to verify, ] jmp_to_verify_while = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_while + get_substring_left + get_substring_middle + get_substring_right + join_substrings)) join_substrings.append(jmp_to_verify_while) clean_stack = [ # removes all auxiliary values (Opcode.DROP, b''), (Opcode.DROP, b''), ] while_body = (get_substring_left + get_substring_middle + get_substring_right + join_substrings) jmp_to_clean_stack = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(while_body), True) verify_while[-1] = jmp_to_clean_stack return (initializing + verify_while + while_body + clean_stack)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.model.type.type import Type from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') if_statement = [ (Opcode.DUP, b''), (Opcode.ISTYPE, Type.str.stack_item ), # if isinstance(arg1, (str, bytes)) continue # if not isinstance(arg1, (str, bytes)) will jump into the else_body ] if_true_body = [ # if isinstance(arg1, (str, bytes)) body will continue until else_body (Opcode.NEWARRAY0, b''), # list_aux = [] (Opcode.SWAP, b''), (Opcode.DUP, b''), (Opcode.SIZE, b''), # limit = len(arg) (Opcode.PUSH0, b''), # index = 0 ] while_statement = [ # index and limit will be at the top of the stack (Opcode.DUP, b''), # verifies if index < limit (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.LT, b''), jmp_place_holder # if index >= limit, go to break_opcode ] while_body = [ # will add every byte or character into the array and increase the index (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, Type.int.stack_item if Type.bytes.is_type_of( self.args['sequence'].type) else Type.str.stack_item), (Opcode.APPEND, b''), # list_aux.append(arg[index]) (Opcode.INC, b''), # index++ # returns to beginning of the while to verify if it index < limit ] jmp_back_to_while_statement = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(while_body + while_statement)) while_body.append(jmp_back_to_while_statement) jmp_to_break_body = Opcode.get_jump_and_data( Opcode.JMPIFNOT, get_bytes_count(while_body), True) while_statement[-1] = jmp_to_break_body break_opcode = [ # remove auxiliary values from stack after leaving `while` (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), # skips the else_body, because it's a bytestring value and unpacking and packing are expensive ] else_body = [ # creates a new array from an array, used when the arg is not a str or bytes value (Opcode.UNPACK, b''), (Opcode.PACK, b''), ] jmp_else_body = Opcode.get_jump_and_data(Opcode.JMP, get_bytes_count(else_body), True) break_opcode.append(jmp_else_body) if_true_body = if_true_body + while_statement + while_body + break_opcode jmp_if_true_body = Opcode.get_jump_and_data( Opcode.JMPIFNOT, get_bytes_count(if_true_body)) if_statement.append(jmp_if_true_body) reverse_array = [ # reverse the array (Opcode.DUP, b''), (Opcode.REVERSEITEMS, b''), # return reversed(arg) ] return (if_statement + if_true_body + else_body + reverse_array)
def _verify_is_specific_base(self, char: str, base: int) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType jmp_place_holder = (Opcode.JMP, b'\x01') verify_top_stack = [ # verify if True is in the top of the stack jmp_place_holder ] top_stack_is_true = [ # if True is indeed at the top, ignore the rest of this method (Opcode.PUSH1, b''), jmp_place_holder # jumps everything below ] compare_char = [ # compares the char with b, B, o, O, x, or X (Opcode.DUP, b''), Opcode.get_pushdata_and_data(char), jmp_place_holder ] char_not_equal = [ # if char at the top of the stack is not b, B, o, O, x, or X, (Opcode.PUSH0, b''), # put False at the top of the stack jmp_place_holder # jumps everything below ] verify_base_is_the_same = [ # verify if the equivalent base is the same as current base (Opcode.PUSH2, b''), (Opcode.PICK, b''), Opcode.get_push_and_data(base), jmp_place_holder # jump to remove_base_char if equivalent base is the same as current base ] verify_base_is_0 = [ # verify if the current base is 0 (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH0, b''), jmp_place_holder # if base is not 0, jump to put_true_in_stack ] change_base = [ # if base was 0, then change it to the equivalent base (Opcode.REVERSE3, b''), (Opcode.DROP, b''), Opcode.get_push_and_data(base), (Opcode.REVERSE3, b''), ] remove_base_char = [ # if base was 0 or 16, remove the char in value (Opcode.SWAP, b''), (Opcode.PUSH1, b''), (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.SWAP, b''), ] put_true_in_stack = [ # puts True in the top of the stack to skip the next verifications (Opcode.PUSH1, b'') ] # region jmp logic jump_instructions = change_base + remove_base_char verify_base_is_0[-1] = Opcode.get_jump_and_data( Opcode.JMPNE, get_bytes_count(jump_instructions), True) jump_instructions = change_base + verify_base_is_0 verify_base_is_the_same[-1] = Opcode.get_jump_and_data( Opcode.JMPEQ, get_bytes_count(jump_instructions), True) jump_instructions = change_base + remove_base_char + put_true_in_stack + verify_base_is_0 + verify_base_is_the_same char_not_equal[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = char_not_equal compare_char[-1] = Opcode.get_jump_and_data( Opcode.JMPEQ, get_bytes_count(jump_instructions), True) jump_instructions = (compare_char + char_not_equal + change_base + put_true_in_stack + verify_base_is_the_same + verify_base_is_0 + remove_base_char) top_stack_is_true[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = top_stack_is_true verify_top_stack[-1] = Opcode.get_jump_and_data( Opcode.JMPIFNOT, get_bytes_count(jump_instructions), True) # endregion return (verify_top_stack + top_stack_is_true + compare_char + char_not_equal + verify_base_is_the_same + verify_base_is_0 + change_base + remove_base_char + put_true_in_stack)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.neo.vm.type.StackItem import StackItemType from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') verify_is_none = [ # verify if value is None (Opcode.DUP, b''), (Opcode.ISNULL, b''), jmp_place_holder ] value_is_none = [ # if value is None, then return False (Opcode.DROP, b''), (Opcode.PUSH0, b''), jmp_place_holder ] verify_is_array = [ # if value is an array, check the length of it (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Array), jmp_place_holder ] verify_is_map = [ # if value is a map, check the length of it (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Map), jmp_place_holder ] verify_is_int = [ # if value is an int, check if it is non zero (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Integer), jmp_place_holder ] verify_is_bytestring = [ # if value is a bytestring, check if it is non zero (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.ByteString), jmp_place_holder ] put_true = [ # if value it's not a type from above, return True (Opcode.DROP, b''), (Opcode.PUSH1, b''), jmp_place_holder ] collection_non_zero = [ # get length of collection (Opcode.SIZE, b''), ] non_zero = [ # verify if it's non zero (Opcode.NZ, b''), ] # region jump logic jump_instructions = collection_non_zero + non_zero put_true[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = collection_non_zero + put_true verify_is_bytestring[-1] = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(jump_instructions), True) jump_instructions = collection_non_zero + put_true + verify_is_bytestring verify_is_int[-1] = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(jump_instructions), True) jump_instructions = put_true + verify_is_int + verify_is_bytestring verify_is_map[-1] = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(jump_instructions), True) jump_instructions = verify_is_map + verify_is_int + verify_is_bytestring + put_true verify_is_array[-1] = Opcode.get_jump_and_data( Opcode.JMPIF, get_bytes_count(jump_instructions), True) jump_instructions = (verify_is_array + verify_is_map + verify_is_int + verify_is_bytestring + put_true + collection_non_zero + non_zero) value_is_none[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = value_is_none verify_is_none[-1] = Opcode.get_jump_and_data( Opcode.JMPIFNOT, get_bytes_count(jump_instructions), True) # endregion bool_method = (verify_is_none + value_is_none + verify_is_array + verify_is_map + verify_is_int + verify_is_bytestring + put_true + collection_non_zero + non_zero) return bool_method
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.Integer import Integer from boa3.neo.vm.type.StackItem import StackItemType number0 = Integer(ord('0')).to_byte_array() number9 = Integer(ord('9')).to_byte_array() jmp_place_holder = (Opcode.JMP, b'\x01') initializing = [ # initialize auxiliary values (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), # index = len(string) - 1 (Opcode.PUSH1, b''), # isdigit = True ] verify_empty_string = [ # verifies if string is empty (Opcode.OVER, b''), (Opcode.PUSHM1, b''), jmp_place_holder, # jump to change_to_false if index == -1 ] skip_first_verify_while = [ # skips the first while verification, since string is not empty jmp_place_holder ] verify_while = [ # verifies if while is over (Opcode.OVER, b''), (Opcode.PUSH0, b''), jmp_place_holder, # jump to return_bool if index >= len(string) ] jmp_verify_while = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(verify_while), True) skip_first_verify_while[-1] = jmp_verify_while while_verify_lt_0 = [ # verifies if ord(string[index]) is < ord('0') (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.DUP, b''), (Opcode.PUSHDATA1, Integer(len(number0)).to_byte_array() + number0), jmp_place_holder, # if ord(string[index]) < ord('0'), return False ] while_verify_gt_9 = [ # verifies if ord(string[index]) is > ord('9') (Opcode.PUSHDATA1, Integer(len(number9)).to_byte_array() + number9), jmp_place_holder, # if ord(string[index]) > ord('9'), return False ] while_go_to_verify = [ # decreases index and goes back to verify if there all characters were visited already (Opcode.SWAP, b''), (Opcode.DEC, b''), # index-- (Opcode.SWAP, b''), # jump back to verify_while ] jmp_back_to_verify = Opcode.get_jump_and_data( Opcode.JMP, -get_bytes_count(verify_while + while_verify_lt_0 + while_verify_gt_9 + while_go_to_verify)) while_go_to_verify.append(jmp_back_to_verify) jmp_out_of_while = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(while_verify_gt_9 + while_go_to_verify), True) while_verify_lt_0[-1] = jmp_out_of_while drop_char = [ # remove extra char from stack (Opcode.DROP, b'') ] jmp_to_change_to_false = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(while_go_to_verify + drop_char), True) while_verify_gt_9[-1] = jmp_to_change_to_false change_to_false = [ # remove True on top of stack and put False (Opcode.DROP, b''), (Opcode.PUSH0, b''), ] jmp_to_return = Opcode.get_jump_and_data( Opcode.JMPEQ, get_bytes_count(skip_first_verify_while + verify_while + while_verify_lt_0 + while_verify_gt_9 + while_go_to_verify + drop_char), True) verify_empty_string[-1] = jmp_to_return jmp_to_return = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(while_verify_lt_0 + while_verify_gt_9 + while_go_to_verify + drop_char + change_to_false), True) verify_while[-1] = jmp_to_return clean_and_return_bool = [ # remove extra values from stack (Opcode.NIP, b''), (Opcode.NIP, b'') ] return (initializing + verify_empty_string + skip_first_verify_while + verify_while + while_verify_lt_0 + while_verify_gt_9 + while_go_to_verify + drop_char + change_to_false + clean_and_return_bool)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType jmp_place_holder = (Opcode.JMP, b'\x01') # string, end, start, substring verify_negative_index = [ # verify if index is negative value (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if not index < 0, jump to verify_big_end ] fix_negative_end = [ # fix negative value to a positive equivalent (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.INC, b''), # end = end + len(string) + 1 (Opcode.DUP, b''), (Opcode.PUSHM1, b''), jmp_place_holder # if not end < 0, jump to verify_and_fix_start ] fix_still_negative_index = [ # if end still is less than 0, then it should be 0 (Opcode.DROP, b''), (Opcode.PUSH0, b''), # end = 0 ] jmp_fix_negative_index = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_negative_end + fix_still_negative_index), True) verify_negative_index[-1] = jmp_fix_negative_index verify_big_end = [ # verify if end is greater or equals to len(string) (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # if not end >= len(string), jump to verify_and_fix_start ] fix_big_end = [ # fix end value to a positive equivalent (Opcode.DROP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), # end = len(string) ] jmp_other_verifies = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_still_negative_index + verify_big_end + fix_big_end), True) fix_negative_end[-1] = jmp_other_verifies jmp_fix_big_index = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(fix_big_end), True) verify_big_end[-1] = jmp_fix_big_index verify_and_fix_end = [ # verify and fix end index (Opcode.REVERSE3, b''), # change positions on stack ] verify_and_fix_end.extend(verify_negative_index) verify_and_fix_end.extend(fix_negative_end) verify_and_fix_end.extend(fix_still_negative_index) verify_and_fix_end.extend(verify_big_end) verify_and_fix_end.extend(fix_big_end) verify_and_fix_start = [ # verify and fix end index (Opcode.SWAP, b''), # change positions on stack ] # fix_negative_start is the same as fix_negative_end, but jump is different fix_negative_start = fix_negative_end.copy() verify_big_start = [ # verify if start is greater or equals to len(string) (Opcode.DUP, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # if start >= len(string), return False ] jmp_other_verifies = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(fix_still_negative_index + verify_big_start), True) fix_negative_end[-1] = jmp_other_verifies verify_size = [ # verify if len(string[start:end]) > len(substring) (Opcode.REVERSE3, b''), (Opcode.REVERSE4, b''), (Opcode.REVERSE3, b''), (Opcode.OVER, b''), (Opcode.SUB, b''), (Opcode.SUBSTR, b''), (Opcode.PUSH0, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), (Opcode.DUP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''), jmp_place_holder # if len(string[start:end]) > len(substring), return False ] compare_starts = [ # string.startswith(substring) (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), (Opcode.NUMEQUAL, b''), # return string[start:end][0:len(substring)] == substring jmp_place_holder # jumps other opcodes ] jmp_compare_starts = Opcode.get_jump_and_data( Opcode.JMPGT, get_bytes_count(compare_starts), True) verify_size[-1] = jmp_compare_starts jmp_to_false = Opcode.get_jump_and_data( Opcode.JMPGE, get_bytes_count(verify_size + compare_starts), True) verify_big_start[-1] = jmp_to_false verify_and_fix_start.extend(verify_negative_index) verify_and_fix_start.extend(fix_negative_start) verify_and_fix_start.extend(fix_still_negative_index) verify_and_fix_start.extend(verify_big_start) return_false = [ # remove all values from stack and put False (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.PUSH0, b''), # return False ] jmp_bigger_substr = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(return_false), True) compare_starts[-1] = jmp_bigger_substr return (verify_and_fix_end + verify_and_fix_start + verify_size + compare_starts + return_false)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count jmp_place_holder = (Opcode.JMP, b'\x01') # region Sequence logic repack_array = [ # recreates an array to not change the original one (Opcode.UNPACK, b''), (Opcode.PACK, b''), ] sequence_initialize = [ # initializes variables (Opcode.PUSH0, b''), # count = 0 (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), # index = len(sequence) - -1 ] sequence_verify_while = [ # verifies if all the elements from the sequence were visited (Opcode.DUP, b''), # would be equivalent to: while (index >= 0) (Opcode.SIGN, b''), (Opcode.PUSH0, b''), # if index < 0: jmp_place_holder, # jump to clean the stack ] sequence_get_element = [ # gets a element from the sequence (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b'') # element = sequence[index] ] sequence_equals = [ # verifies if the element and the given value are the same (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.EQUAL, b''), # if element != value: jmp_place_holder # jump to list_tuple_count_index_dec ] sequence_count_inc = [ # increment count if element == value (Opcode.SWAP, b''), (Opcode.INC, b''), # count++ (Opcode.SWAP, b''), ] num_jmp_code = get_bytes_count(sequence_count_inc) jmp_to_dec_statement = Opcode.get_jump_and_data(Opcode.JMPIFNOT, num_jmp_code, True) sequence_equals[-1] = jmp_to_dec_statement list_tuple_count_index_dec = [ # decreases the index (Opcode.DEC, b''), # index-- # return to the while verification ] num_jmp_code = -get_bytes_count(list_tuple_count_index_dec + sequence_count_inc + sequence_equals + sequence_get_element + sequence_verify_while) jmp_back_to_while_verify_statement = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code) list_tuple_count_index_dec.append(jmp_back_to_while_verify_statement) num_jmp_code = get_bytes_count(sequence_get_element + sequence_equals + sequence_count_inc + list_tuple_count_index_dec) jmp_to_clean_statement = Opcode.get_jump_and_data(Opcode.JMPLT, num_jmp_code, True) sequence_verify_while[-1] = jmp_to_clean_statement sequence_clean_stack = [ (Opcode.DROP, b''), (Opcode.REVERSE3, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), ] # endregion return ( repack_array + sequence_initialize + sequence_verify_while + sequence_get_element + sequence_equals + sequence_count_inc + list_tuple_count_index_dec + sequence_clean_stack )
def _compare_values(self) -> List[Tuple[Opcode, bytes]]: from boa3.neo.vm.type.Integer import Integer jmp_place_holder = (Opcode.JMP, b'\x01') test_if_are_equal = [ (Opcode.OVER, b''), (Opcode.OVER, b''), (Opcode.EQUAL, b''), # if str1 == str2: Opcode.get_jump_and_data(Opcode.JMPIFNOT, 4), (Opcode.PUSH1, b''), jmp_place_holder, # go to final test ] get_limit_index = [ (Opcode.OVER, b''), # limit = min((len(str1), len(str2)) (Opcode.SIZE, b''), (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.MIN, b''), (Opcode.PUSH0, b''), # index = 0 ] while_body_before_compare = [ (Opcode.PUSH3, b''), # value1 = str1[index] (Opcode.get_dup(3), b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b''), (Opcode.OVER, b''), (Opcode.PUSH4, b''), # value2 = str2[index] (Opcode.get_dup(4), b''), (Opcode.SWAP, b''), (Opcode.PICKITEM, b''), ] while_body_compare = [ (Opcode.OVER, b''), (Opcode.OVER, b''), (Opcode.JMPEQ, Integer(7).to_byte_array( signed=True)), # if value1 != value2 jmp to end (Opcode.GT, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), jmp_place_holder, # jmp to end ] while_body_after_compare = [ (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.INC, b''), # index++ ] while_full_body = while_body_before_compare + while_body_compare + while_body_after_compare while_bytes_size = get_bytes_count(while_full_body) get_limit_index.append( Opcode.get_jump_and_data(Opcode.JMP, while_bytes_size, True)) while_condition = [(Opcode.OVER, b''), (Opcode.OVER, b'')] while_condition_bytes_size = get_bytes_count(while_condition) while_condition.append( Opcode.get_jump_and_data( Opcode.JMPGT, -while_bytes_size - while_condition_bytes_size)) while_else_body = [ (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.OVER, b''), # if len(str1) > len(str2) jmp to end (Opcode.SIZE, b''), (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.GT, b''), ] everything_after_while_check = while_body_after_compare + while_condition + while_else_body jmp_while_check = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(everything_after_while_check), True) while_body_compare[-1] = jmp_while_check everything_after_equal_check = (get_limit_index + while_body_before_compare + while_body_compare + everything_after_while_check) jmp_test_equal = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(everything_after_equal_check), True) test_if_are_equal[-1] = jmp_test_equal final_test = [ (Opcode.JMPIF, Integer(4).to_byte_array( signed=True)), # if condition is not True (Opcode.DROP, b''), # remove str1 <=> return str2 (Opcode.JMP, Integer(3).to_byte_array(signed=True)), # else (Opcode.NIP, b'') # remove str2 <=> return str1 ] return (test_if_are_equal + everything_after_equal_check + final_test)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.StackItem import StackItemType jmp_place_holder = (Opcode.JMP, b'\x01') a_lower = ord('a') a_upper = ord('A') zero = ord('0') # region verify_base verify_base_ge37 = [ # verifies if base >= 37, base greater than 36 shouldn't be accepted (Opcode.OVER, b''), Opcode.get_push_and_data(37), jmp_place_holder, # jumps to an assertion error ] verify_base_equal1 = [ # verifies if base == 1, base equals 1 shouldn't be accepted (Opcode.OVER, b''), (Opcode.PUSH1, b''), jmp_place_holder # jumps to an assertion error ] verify_base_le_minus1 = [ # verifies if base <= -1, base less than 0 shouldn't be accepted (Opcode.OVER, b''), (Opcode.PUSHM1, b''), jmp_place_holder, # jumps to an assertion error ] verify_base_jump_error = [ # jumps the next set of instructions jmp_place_holder ] verify_base_error = [ # an invalid base was used (Opcode.PUSH0, b''), (Opcode.ASSERT, b''), ] # region verify_base jump logic jump_instructions = verify_base_error verify_base_jump_error[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = verify_base_jump_error verify_base_le_minus1[-1] = Opcode.get_jump_and_data( Opcode.JMPLE, get_bytes_count(jump_instructions), True) jump_instructions = verify_base_jump_error + verify_base_le_minus1 verify_base_equal1[-1] = Opcode.get_jump_and_data( Opcode.JMPEQ, get_bytes_count(jump_instructions), True) jump_instructions = verify_base_jump_error + verify_base_le_minus1 + verify_base_equal1 verify_base_ge37[-1] = Opcode.get_jump_and_data( Opcode.JMPGE, get_bytes_count(jump_instructions), True) # endregion verify_base = (verify_base_ge37 + verify_base_equal1 + verify_base_le_minus1 + verify_base_jump_error + verify_base_error) # endregion # region verify_code_literal verify_code_literal_first_char_is_0 = [ # verifies if the first char in the value is '0' (Opcode.DUP, b''), (Opcode.PUSH0, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), Opcode.get_pushdata_and_data('0'), jmp_place_holder, # if first char is not 0, skip all verify_code_literal methods ] verify_code_literal_remove_first_char = [ # the first char is 0, so it will be removed from the value (Opcode.PUSH1, b''), (Opcode.OVER, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), ] verify_code_literal_get_base_char = [ # puts the char that could refer to a base in the top of the stack (Opcode.DUP, b''), (Opcode.PUSH0, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), (Opcode.CONVERT, StackItemType.ByteString), ] verify_code_literal_initialize_verification = [ # puts a False in the top of the stack to assist the (Opcode.PUSH0, b'') # verifications above ] verify_code_literal_base_verification = ( # verifies if the original value starts with 0b, 0B, 0o, 0O self._verify_is_specific_base( 'b', 2) + # 0x, or 0X, and changes the base if necessary self._verify_is_specific_base('B', 2) + self._verify_is_specific_base('o', 8) + self._verify_is_specific_base('O', 8) + self._verify_is_specific_base('x', 16) + self._verify_is_specific_base('X', 16)) verify_code_literal_drop_aux = [ # drops auxiliary values from the stack and just keeps the (Opcode.DROP, b''), # base and value on it (Opcode.DROP, b''), ] # region verify_code_literal jump logic jump_instructions = (verify_code_literal_remove_first_char + verify_code_literal_get_base_char + verify_code_literal_initialize_verification + verify_code_literal_base_verification + verify_code_literal_drop_aux) verify_code_literal_first_char_is_0[-1] = Opcode.get_jump_and_data( Opcode.JMPNE_L, get_bytes_count(jump_instructions), True) # endregion verify_code_literal = (verify_code_literal_first_char_is_0 + verify_code_literal_remove_first_char + verify_code_literal_get_base_char + verify_code_literal_initialize_verification + verify_code_literal_base_verification + verify_code_literal_drop_aux) # endregion # region ascii to int ascii_to_int_initialize = [ # initialize auxiliary variables on the stack (Opcode.DUP, b''), (Opcode.SIZE, b''), (Opcode.DEC, b''), # index = len(value) - 1 (Opcode.DUP, b''), (Opcode.PUSH0, b''), (Opcode.GE, b''), (Opcode.ASSERT, b''), # verifies if value was empty (Opcode.PUSH0, b''), # sum = 0 (Opcode.PUSH1, b''), # mult = 1 ] ascii_to_int_while = [ # loops from left to right of the value to calculate the equivalent sum in base 10 (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH1, b''), (Opcode.SUBSTR, b''), # char = value[index] (Opcode.CONVERT, StackItemType.Integer), ] ascii_to_int_verify_az_lower_lt = [ # verifies ord(char) is less than ord('a') (Opcode.DUP, b''), # if ord(char) is indeed less, go to verify with ord('A') Opcode.get_push_and_data(a_lower), jmp_place_holder # jump to ascii_to_int_verify_az_upper_lt ] ascii_to_int_verify_az_lower_gt = [ # verifies ord(char) is greater than base + 86 ( Opcode.DUP, b'' ), # the minimum base that accepts letters is base 11, that's why it's (Opcode.PUSH6, b''), # adding 86 (Opcode.PICK, b'' ), # if ord(char) is greater than base + 86, the char is invalid Opcode.get_push_and_data(86), (Opcode.ADD, b''), (Opcode.LE, b''), (Opcode.ASSERT, b''), # if assert is False, then the char was indeed invalid ] ascii_to_int_verify_az_lower = [ # the char was in between 'a' and 'z', Opcode.get_push_and_data( 87 ), # so it will be converted to the respective base 10 number (Opcode.SUB, b''), (Opcode.OVER, b''), (Opcode.MUL, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.ADD, b''), # sum = sum + (ord(char) - 55)) * mult (Opcode.REVERSE3, b''), (Opcode.DROP, b''), jmp_place_holder # jumps to ascii_to_int_verify_while ] ascii_to_int_verify_az_upper_lt = [ # verifies ord(char) is less than ord('A') (Opcode.DUP, b''), # if ord(char) is indeed less, go to verify with ord('0') Opcode.get_push_and_data(a_upper), jmp_place_holder # jump to ascii_to_int_verify_09_lt ] ascii_to_int_verify_az_upper_gt = [ # verifies ord(char) is greater than base + 54 ( Opcode.DUP, b'' ), # the minimum base that accepts letters is base 11, that's why it's (Opcode.PUSH6, b''), # adding 54 (Opcode.PICK, b'' ), # if ord(char) is greater than base + 54, the char is invalid Opcode.get_push_and_data(54), (Opcode.ADD, b''), (Opcode.LE, b''), (Opcode.ASSERT, b''), # if assert is False, then the char was indeed invalid ] ascii_to_int_verify_az_upper = [ # the char was in between 'A' and 'Z', Opcode.get_push_and_data( 55 ), # so it will be converted to the respective base 10 number (Opcode.SUB, b''), (Opcode.OVER, b''), (Opcode.MUL, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.ADD, b''), # sum = sum + (ord(char) - 55)) * mult (Opcode.REVERSE3, b''), (Opcode.DROP, b''), jmp_place_holder # jumps to ascii_to_int_verify_while ] ascii_to_int_verify_09_lt = [ # verifies ord(char) is less than ord('0') (Opcode.DUP, b''), # if ord(char) is indeed less, the char is invalid Opcode.get_push_and_data(zero), (Opcode.GE, b''), (Opcode.ASSERT, b''), # if assert is False, then the char was indeed invalid ] ascii_to_int_verify_09_gt = [ # verifies ord(char) is greater than base + ord('0') ( Opcode.DUP, b'' ), # if ord(char) is greater than base + ord('0'), the char is invalid (Opcode.PUSH6, b''), (Opcode.PICK, b''), Opcode.get_push_and_data(zero), (Opcode.ADD, b''), (Opcode.LE, b''), (Opcode.ASSERT, b''), # if assert is False, then the char was indeed invalid ] ascii_to_int_verify_09 = [ # the char was in between '0' and '9', Opcode.get_push_and_data( zero ), # so it will be converted to the respective base 10 number (Opcode.SUB, b''), (Opcode.OVER, b''), (Opcode.MUL, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.ADD, b''), # sum = sum + (ord(char) - ord('0')) * mult (Opcode.REVERSE3, b''), (Opcode.DROP, b''), ] ascii_to_int_verify_while = [ # verifies if the loop already went through all the chars in value (Opcode.REVERSE3, b''), (Opcode.DEC, b''), # index-- (Opcode.REVERSE3, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''), (Opcode.MUL, b''), # mult = mult * base (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH0, b''), # jmp back to ascii_to_int_while if index >= 0 ] # region ascii to int jump logic jump_instructions = (ascii_to_int_verify_09_lt + ascii_to_int_verify_09_gt + ascii_to_int_verify_09) ascii_to_int_verify_az_upper[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = (ascii_to_int_verify_az_upper_gt + ascii_to_int_verify_az_upper) ascii_to_int_verify_az_upper_lt[-1] = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(jump_instructions), True) jump_instructions = (ascii_to_int_verify_az_upper_lt + ascii_to_int_verify_az_upper_gt + ascii_to_int_verify_az_upper + ascii_to_int_verify_09_lt + ascii_to_int_verify_09_gt + ascii_to_int_verify_09) ascii_to_int_verify_az_lower[-1] = Opcode.get_jump_and_data( Opcode.JMP, get_bytes_count(jump_instructions), True) jump_instructions = (ascii_to_int_verify_az_lower_gt + ascii_to_int_verify_az_lower) ascii_to_int_verify_az_lower_lt[-1] = Opcode.get_jump_and_data( Opcode.JMPLT, get_bytes_count(jump_instructions), True) jump_instructions = ( ascii_to_int_while + ascii_to_int_verify_az_lower_lt + ascii_to_int_verify_az_lower_gt + ascii_to_int_verify_az_lower + ascii_to_int_verify_az_upper_lt + ascii_to_int_verify_az_upper_gt + ascii_to_int_verify_az_upper + ascii_to_int_verify_09_gt + ascii_to_int_verify_09_lt + ascii_to_int_verify_09 + ascii_to_int_verify_while) ascii_to_int_verify_while.append( Opcode.get_jump_and_data(Opcode.JMPGE, -get_bytes_count(jump_instructions), True)) # endregion ascii_to_int = (ascii_to_int_initialize + ascii_to_int_while + ascii_to_int_verify_az_lower_lt + ascii_to_int_verify_az_lower_gt + ascii_to_int_verify_az_lower + ascii_to_int_verify_az_upper_lt + ascii_to_int_verify_az_upper_gt + ascii_to_int_verify_az_upper + ascii_to_int_verify_09_lt + ascii_to_int_verify_09_gt + ascii_to_int_verify_09 + ascii_to_int_verify_while) # endregion # region clean stack clean_stack = [ # clean everything but the number in base 10 (Opcode.DROP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), (Opcode.NIP, b''), ] # endregion return (verify_base + verify_code_literal + ascii_to_int + clean_stack)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.compiler.codegenerator import get_bytes_count from boa3.neo.vm.type.Integer import Integer jmp_place_holder = (Opcode.JMP, b'\x01') verify_number_of_parameters = [ # verifies if the stack has 2 or 3 items (Opcode.DEPTH, b''), (Opcode.PUSH2, b''), (Opcode.JMPEQ, b''), jmp_place_holder ] if_n_parameters_gt_2 = [ # if number of items in stack is 3 (Opcode.REVERSE3, b''), (Opcode.UNPACK, b''), (Opcode.INC, b''), (Opcode.INC, b''), jmp_place_holder # skips the next block of instructions ] if_n_parameters_eq_2 = [ # if number of items in stack is 2 (Opcode.PUSH2, b'') ] jmp_n_parameters_eq_2 = Opcode.get_jump_and_data(Opcode.JMP, get_bytes_count(if_n_parameters_eq_2), True) if_n_parameters_gt_2[-1] = jmp_n_parameters_eq_2 jmp_n_parameters_gt_2 = Opcode.get_jump_and_data(Opcode.JMPEQ, get_bytes_count(if_n_parameters_gt_2)) verify_number_of_parameters[-1] = jmp_n_parameters_gt_2 repack_array = [ # pack all the arguments in the array (Opcode.PACK, b''), ] is_int_initialize = [ # puts the last array element as the max value (Opcode.DUP, b''), # index = len(array) - 1 (Opcode.SIZE, b''), (Opcode.DEC, b''), (Opcode.OVER, b''), (Opcode.OVER, b''), (Opcode.PICKITEM, b''), # min = array[index] ] is_int_while = [ # this will get the next number in the array and compare it with the current min (Opcode.SWAP, b''), # index-- (Opcode.DEC, b''), (Opcode.SWAP, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.PUSH2, b''), (Opcode.PICK, b''), # min = min if min < array[index] else array[index] (Opcode.PICKITEM, b''), ] is_int_while.extend(self._compare_values()) is_int_while.extend([ (Opcode.OVER, b''), (Opcode.SIGN, b'') # if index != 0: go back to index-- # else go to the end ]) jmp_back_to_while_statement = (Opcode.JMPIF, Integer(-get_bytes_count(is_int_while)).to_byte_array(signed=True)) is_int_while.append(jmp_back_to_while_statement) clean_stack = [ # removes everything but min (Opcode.REVERSE3, b''), (Opcode.DROP, b''), (Opcode.DROP, b''), ] return ( verify_number_of_parameters + if_n_parameters_gt_2 + if_n_parameters_eq_2 + repack_array + is_int_initialize + is_int_while + clean_stack )