diff --git a/.patches/registers/registers02.cairo.patch b/.patches/registers/registers02.cairo.patch index ce23b8ad..87e1dc5e 100644 --- a/.patches/registers/registers02.cairo.patch +++ b/.patches/registers/registers02.cairo.patch @@ -1,78 +1,16 @@ ---- exercises/registers/registers02.cairo 2022-05-18 12:53:44.000000000 -0400 -+++ .tmp_solution/registers02.cairo 2022-05-18 11:40:22.000000000 -0400 -@@ -3,0 +4 @@ -+ -@@ -9,6 +10,2 @@ --func sum_array(array_len : felt, array : felt*) -> (sum : felt): -- # [ap] = [fp - 4]; ap++ -- # [ap] = [fp - 3]; ap++ -- # [ap] = 0; ap++ -- # call rec_sum_array -- # ret -+func sum_array(array_len: felt, array: felt*) -> (sum: felt): -+ return rec_sum_array(array_len, array, 0) -@@ -17,16 +14,6 @@ --func rec_sum_array(array_len : felt, array : felt*, sum : felt) -> (sum : felt): -- # jmp continue if [fp - 5] != 0 -- -- # stop: -- # [ap] = [fp - 3]; ap++ -- # jmp done -- -- # continue: -- # [ap] = [[fp - 4]]; ap++ -- # [ap] = [fp - 5] - 1; ap++ -- # [ap] = [fp - 4] + 1; ap++ -- # [ap] = [ap - 3] + [fp - 3]; ap++ -- # call rec_sum_array -- -- # done: -- # ret -+func rec_sum_array(array_len: felt, array: felt*, sum: felt) -> (sum: felt): -+ if array_len == 0: -+ return (sum) -+ end -+ -+ return rec_sum_array(array_len - 1, array + 1, sum + array[0]) -@@ -39,7 +26,31 @@ --func max{range_check_ptr}(a : felt, b : felt) -> (max : felt): -- # let (res) = is_le(a, b) -- # if res == 1: -- # return (b) -- # else: -- # return (a) -- # end -+func max{range_check_ptr}(a: felt, b: felt) -> (max: felt): -+ # Push arguments to the stack -+ [ap] = [fp - 5]; ap++ # range_check_ptr -+ [ap] = [fp - 4]; ap++ # a -+ [ap] = [fp - 3]; ap++ # b -+ -+ # This call will return two values -+ # 1) the updated range_check_ptr -+ # 2) 0 or 1 depending on which of a and b is greater -+ call is_le -+ -+ # Push return values to the stack -+ # There is two of them to push: range_check_ptr and max -+ -+ # Push the first one, the updated range_check_ptr, onto the stack -+ [ap] = [ap - 2]; ap++ -+ -+ # Conditional jump -+ # The following blocks are an assembly level equivalent of the if/else pattern -+ jmp b_is_more if [ap - 2] !=0 # here [ap-2] is the second value returned by is_le, our boolean -+ -+ # Push either a or b to the stack -+ a_is_more: -+ [ap] = [fp - 4]; ap++ -+ jmp done -+ -+ b_is_more: -+ [ap] = [fp -3]; ap++ -+ -+ done: -+ ret -@@ -79 +90 @@ -- -+ +--- exercises/registers/registers02.cairo 2022-06-11 22:20:43.000000000 -0400 ++++ ./registers02.cairo 2022-06-11 22:18:21.000000000 -0400 +@@ -17,3 +17,3 @@ +- # [ap] = 42; ap++ +- # [ap - 1] = 42 +- # [ap - 1] = 21 ++ tempvar x = 42 ++ assert x = 42 ++ assert x = 21 +@@ -27 +27 @@ +- # assert number = 42 ++ [fp -3] = 42 +@@ -37,0 +38 @@ ++ assert [p_number] = 42 +@@ -45,0 +47 @@ ++ assert 42 = [p_number] diff --git a/.patches/registers/registers03.cairo.patch b/.patches/registers/registers03.cairo.patch new file mode 100644 index 00000000..580e7564 --- /dev/null +++ b/.patches/registers/registers03.cairo.patch @@ -0,0 +1,78 @@ +--- exercises/registers/registers03.cairo 2022-05-18 12:53:44.000000000 -0400 ++++ .tmp_solution/registers03.cairo 2022-05-18 11:40:22.000000000 -0400 +@@ -3,0 +4 @@ ++ +@@ -9,6 +10,2 @@ +-func sum_array(array_len : felt, array : felt*) -> (sum : felt): +- # [ap] = [fp - 4]; ap++ +- # [ap] = [fp - 3]; ap++ +- # [ap] = 0; ap++ +- # call rec_sum_array +- # ret ++func sum_array(array_len: felt, array: felt*) -> (sum: felt): ++ return rec_sum_array(array_len, array, 0) +@@ -17,16 +14,6 @@ +-func rec_sum_array(array_len : felt, array : felt*, sum : felt) -> (sum : felt): +- # jmp continue if [fp - 5] != 0 +- +- # stop: +- # [ap] = [fp - 3]; ap++ +- # jmp done +- +- # continue: +- # [ap] = [[fp - 4]]; ap++ +- # [ap] = [fp - 5] - 1; ap++ +- # [ap] = [fp - 4] + 1; ap++ +- # [ap] = [ap - 3] + [fp - 3]; ap++ +- # call rec_sum_array +- +- # done: +- # ret ++func rec_sum_array(array_len: felt, array: felt*, sum: felt) -> (sum: felt): ++ if array_len == 0: ++ return (sum) ++ end ++ ++ return rec_sum_array(array_len - 1, array + 1, sum + array[0]) +@@ -39,7 +26,31 @@ +-func max{range_check_ptr}(a : felt, b : felt) -> (max : felt): +- # let (res) = is_le(a, b) +- # if res == 1: +- # return (b) +- # else: +- # return (a) +- # end ++func max{range_check_ptr}(a: felt, b: felt) -> (max: felt): ++ # Push arguments to the stack ++ [ap] = [fp - 5]; ap++ # range_check_ptr ++ [ap] = [fp - 4]; ap++ # a ++ [ap] = [fp - 3]; ap++ # b ++ ++ # This call will return two values ++ # 1) the updated range_check_ptr ++ # 2) 0 or 1 depending on which of a and b is greater ++ call is_le ++ ++ # Push return values to the stack ++ # There is two of them to push: range_check_ptr and max ++ ++ # Push the first one, the updated range_check_ptr, onto the stack ++ [ap] = [ap - 2]; ap++ ++ ++ # Conditional jump ++ # The following blocks are an assembly level equivalent of the if/else pattern ++ jmp b_is_more if [ap - 2] !=0 # here [ap-2] is the second value returned by is_le, our boolean ++ ++ # Push either a or b to the stack ++ a_is_more: ++ [ap] = [fp - 4]; ap++ ++ jmp done ++ ++ b_is_more: ++ [ap] = [fp -3]; ap++ ++ ++ done: ++ ret +@@ -79 +90 @@ +- ++ diff --git a/exercises/registers/registers02.cairo b/exercises/registers/registers02.cairo index 4f606c09..ee74d6e0 100644 --- a/exercises/registers/registers02.cairo +++ b/exercises/registers/registers02.cairo @@ -1,48 +1,46 @@ %lang starknet -from starkware.cairo.common.math_cmp import is_le # I AM NOT DONE +# Cairo memory is immutable. +# Once a memory cell has been assigned, its value CANNOT be changed. +# The program will crash if someone tries to assign a new, different, value to an already initialized memory cell. +# However, trying to assign a memory cell twice, or more, **with the same value** won't cause any harm. +# This property can be used to assert the value of a cell. + # TODO -# Rewrite those functions with a high level syntax -@external -func sum_array(array_len : felt, array : felt*) -> (sum : felt): - # [ap] = [fp - 4]; ap++ - # [ap] = [fp - 3]; ap++ - # [ap] = 0; ap++ - # call rec_sum_array - # ret -end +# Rewrite this function in a high level syntax, using tempvar and assert +func crash(): + # [ap] = 42; ap++ + # [ap - 1] = 42 + # [ap - 1] = 21 -func rec_sum_array(array_len : felt, array : felt*, sum : felt) -> (sum : felt): - # jmp continue if [fp - 5] != 0 + ret +end - # stop: - # [ap] = [fp - 3]; ap++ - # jmp done +# TODO +# Rewrite this funtion in a low level syntax +func assert_42(number : felt): + # assert number = 42 - # continue: - # [ap] = [[fp - 4]]; ap++ - # [ap] = [fp - 5] - 1; ap++ - # [ap] = [fp - 4] + 1; ap++ - # [ap] = [ap - 3] + [fp - 3]; ap++ - # call rec_sum_array + return () +end - # done: - # ret +# TODO +# Write this function body so: +# if the memory cell pointed by `p_number` is not initialized, set it to 42 +# else, if the value is initialized and different from 42, crash +# else, do nothing and return +func assert_pointer_42(p_number : felt*): + return () end # TODO -# Rewrite this function with a low level syntax -# It's possible to do it with only registers, labels and conditional jump. No reference or localvar -@external -func max{range_check_ptr}(a : felt, b : felt) -> (max : felt): - # let (res) = is_le(a, b) - # if res == 1: - # return (b) - # else: - # return (a) - # end +# Write this function body so: +# if the memory cell pointed by `p_number` is set to 42, do nothing and return +# else crash +func assert_pointer_42_no_set(p_number : felt*): + return () end ######### @@ -52,30 +50,82 @@ end from starkware.cairo.common.alloc import alloc @external -func test_max{range_check_ptr}(): - let (m) = max(21, 42) - assert m = 42 - let (m) = max(42, 21) - assert m = 42 +func test_crash(): + %{ expect_revert() %} + crash() + return () end @external -func test_sum(): - let (array) = alloc() - assert array[0] = 1 - assert array[1] = 2 - assert array[2] = 3 - assert array[3] = 4 - assert array[4] = 5 - assert array[5] = 6 - assert array[6] = 7 - assert array[7] = 8 - assert array[8] = 9 - assert array[9] = 10 - - let (s) = sum_array(10, array) - assert s = 55 +func test_assert_42(): + assert_42(42) + + %{ expect_revert() %} + assert_42(21) + + return () +end + +@external +func test_assert_pointer_42_initialized(): + let (mem_zone : felt*) = alloc() + assert mem_zone[0] = 42 + assert mem_zone[1] = 21 + + assert_pointer_42(mem_zone) + + %{ expect_revert() %} + assert_pointer_42(mem_zone + 1) + + return () +end + +@external +func test_assert_pointer_42_not_initialized_ok(): + let (mem_zone : felt*) = alloc() + assert mem_zone[0] = 42 + assert_pointer_42(mem_zone) + + assert_pointer_42(mem_zone + 1) + assert mem_zone[1] = 42 + + return () +end + +@external +func test_assert_pointer_42_not_initialized_revert(): + let (mem_zone : felt*) = alloc() + assert mem_zone[0] = 42 + assert_pointer_42(mem_zone) + + assert_pointer_42(mem_zone + 1) + %{ expect_revert() %} + assert mem_zone[1] = 21 + + return () +end + +@external +func test_assert_pointer_42_no_set(): + let (mem_zone : felt*) = alloc() + assert mem_zone[0] = 42 + assert mem_zone[1] = 21 + + assert_pointer_42_no_set(mem_zone) + + %{ expect_revert() %} + assert_pointer_42_no_set(mem_zone + 1) + + return () +end + +@external +func test_assert_pointer_42_no_set_crash(): + let (mem_zone : felt*) = alloc() + + %{ expect_revert() %} + assert_pointer_42_no_set(mem_zone) return () end diff --git a/exercises/registers/registers03.cairo b/exercises/registers/registers03.cairo new file mode 100644 index 00000000..4f606c09 --- /dev/null +++ b/exercises/registers/registers03.cairo @@ -0,0 +1,81 @@ +%lang starknet +from starkware.cairo.common.math_cmp import is_le + +# I AM NOT DONE + +# TODO +# Rewrite those functions with a high level syntax +@external +func sum_array(array_len : felt, array : felt*) -> (sum : felt): + # [ap] = [fp - 4]; ap++ + # [ap] = [fp - 3]; ap++ + # [ap] = 0; ap++ + # call rec_sum_array + # ret +end + +func rec_sum_array(array_len : felt, array : felt*, sum : felt) -> (sum : felt): + # jmp continue if [fp - 5] != 0 + + # stop: + # [ap] = [fp - 3]; ap++ + # jmp done + + # continue: + # [ap] = [[fp - 4]]; ap++ + # [ap] = [fp - 5] - 1; ap++ + # [ap] = [fp - 4] + 1; ap++ + # [ap] = [ap - 3] + [fp - 3]; ap++ + # call rec_sum_array + + # done: + # ret +end + +# TODO +# Rewrite this function with a low level syntax +# It's possible to do it with only registers, labels and conditional jump. No reference or localvar +@external +func max{range_check_ptr}(a : felt, b : felt) -> (max : felt): + # let (res) = is_le(a, b) + # if res == 1: + # return (b) + # else: + # return (a) + # end +end + +######### +# TESTS # +######### + +from starkware.cairo.common.alloc import alloc + +@external +func test_max{range_check_ptr}(): + let (m) = max(21, 42) + assert m = 42 + let (m) = max(42, 21) + assert m = 42 + return () +end + +@external +func test_sum(): + let (array) = alloc() + assert array[0] = 1 + assert array[1] = 2 + assert array[2] = 3 + assert array[3] = 4 + assert array[4] = 5 + assert array[5] = 6 + assert array[6] = 7 + assert array[7] = 8 + assert array[8] = 9 + assert array[9] = 10 + + let (s) = sum_array(10, array) + assert s = 55 + + return () +end diff --git a/src/exercises/__init__.py b/src/exercises/__init__.py index f4274ca9..91844698 100644 --- a/src/exercises/__init__.py +++ b/src/exercises/__init__.py @@ -25,6 +25,7 @@ "registers/registers00", "registers/registers01", "registers/registers02", + "registers/registers03", "revoked_references/revoked_references01", "tricks/no_conditionals", "tricks/assert_bool",