forked from shramee/starklings-cairo1
-
Notifications
You must be signed in to change notification settings - Fork 0
/
info.toml
486 lines (414 loc) · 16.6 KB
/
info.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# INTRO
[[exercises]]
name = "intro1"
path = "exercises/intro/intro1.cairo"
mode = "compile"
hint = """"""
[[exercises]]
name = "intro2"
path = "exercises/intro/intro2.cairo"
mode = "compile"
hint = """"""
[[exercises]]
name = "intro3"
path = "exercises/intro/intro3.cairo"
mode = "compile"
hint = """"""
[[exercises]]
name = "intro4"
path = "exercises/intro/intro4.cairo"
mode = "compile"
hint = """"""
# VARIABLES
[[exercises]]
name = "variables1"
path = "exercises/variables/variables1.cairo"
mode = "compile"
hint = """
The declaration on line 8 is missing a keyword that is needed in Cairo
to create a new variable binding."""
[[exercises]]
name = "variables2"
path = "exercises/variables/variables2.cairo"
mode = "compile"
hint = """
What happens if you annotate line 7 with a type annotation?
What if you give x a value?
What if you do both?
What type should x be, anyway? (remember what the basic type in Cairo is?)
What if x is the same type as 10? What if it's a different type? (e.g. a u8)"""
[[exercises]]
name = "variables3"
path = "exercises/variables/variables3.cairo"
mode = "compile"
hint = """
Oops! In this exercise, we have a variable binding that we've created on
line 7, and we're trying to use it on line 8, but we haven't given it a
value. We can't print out something that isn't there; try giving x a value!
This is an error that can cause bugs that's very easy to make in any
programming language -- thankfully the Cairo compiler has caught this for us!"""
[[exercises]]
name = "variables4"
path = "exercises/variables/variables4.cairo"
mode = "compile"
hint = """
In Cairo, variable bindings are immutable by default. But here we're trying
to reassign a different value to x! There's a keyword we can use to make
a variable binding mutable instead."""
[[exercises]]
name = "variables5"
path = "exercises/variables/variables5.cairo"
mode = "compile"
hint = """
In variables4 we already learned how to make an immutable variable mutable
using a special keyword. Unfortunately this doesn't help us much in this exercise
because we want to assign a different typed value to an existing variable. Sometimes
you may also like to reuse existing variable names because you are just converting
values to different types like in this exercise.
Fortunately Cairo has a powerful solution to this problem: 'Shadowing'!
You can see an example of variables and 'shadowing' here: https://link.medium.com/c8TqX7R3qxb#4fe8
You can read about the different integer types here: https://link.medium.com/c8TqX7R3qxb#6d64
If you want to learn more about this concept, you can also read about it in the Rust Book:
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
Try to solve this exercise afterwards using this technique."""
[[exercises]]
name = "variables6"
path = "exercises/variables/variables6.cairo"
mode = "compile"
hint = """
We know about variables and mutability, but there is another important type of
variable available: constants.
Constants are always immutable and they are declared with keyword 'const' rather
than keyword 'let'.
Constants types must also always be annotated.
You can read about the different integer types here: https://link.medium.com/c8TqX7R3qxb#6d64
"""
# PRIMITIVE TYPES
[[exercises]]
name = "primitive_types1"
path = "exercises/primitive_types/primitive_types1.cairo"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types2"
path = "exercises/primitive_types/primitive_types2.cairo"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types3"
path = "exercises/primitive_types/primitive_types3.cairo"
mode = "compile"
hint = """
You'll need to make a pattern to bind `name` and `age` to the appropriate parts
of the tuple.
If you're familiar with Rust, you should know that Cairo has a similar syntax for tuple destructuration.
You can do it!!
"""
[[exercises]]
name = "primitive_types4"
path = "exercises/primitive_types/primitive_types4.cairo"
mode = "test"
hint = """
There are multiple integer types in Cairo. You can read about them here: https://link.medium.com/c8TqX7R3qxb#6d64
If you try to sum two integers and the result is bigger than the biggest integer of this type, you'll get a compilation error.
You can convert integers to felts using the `.into()` method. Make sure that you imported the `Into` trait.
You can convert felts to integers using the `.try_into()` method. Make sure that you imported the `TryInto` trait.
This method will return an `Option` type, so you'll need to unwrap it. To use the `unwrap()` method, you'll need to import the `OptionTrait` trait.
Take a look at the top of the file to see how these traits are imported.
"""
# OPERATIONS
[[exercises]]
name = "operations1"
path = "exercises/operations/operations1.cairo"
mode = "test"
hint = """No hints this time ;)"""
[[exercises]]
name = "operations2"
path = "exercises/operations/operations2.cairo"
mode = "test"
hint = """Use % for modulus, / for division, and * for multiplication."""
# IF
[[exercises]]
name = "if1"
path = "exercises/if/if1.cairo"
mode = "test"
hint = """
Remember in Cairo that:
- the `if` condition does not need to be surrounded by parentheses
- `if`/`else` conditionals are expressions
- Each condition is followed by a `{}` block."""
[[exercises]]
name = "if2"
path = "exercises/if/if2.cairo"
mode = "test"
hint = """
For that first compiler error, it's important in Cairo that each conditional
block returns the same type! To get the tests passing, you will need a couple
conditions checking different input values."""
# FUNCTIONS
[[exercises]]
name = "functions1"
path = "exercises/functions/functions1.cairo"
mode = "compile"
hint = """
This main function is calling a function that it expects to exist, but the
function doesn't exist. It expects this function to have the name `call_me`.
It expects this function to not take any arguments and not return a value.
Sounds a lot like `main`, doesn't it?"""
[[exercises]]
name = "functions2"
path = "exercises/functions/functions2.cairo"
mode = "compile"
hint = """
Cairo requires that all parts of a function's signature have type annotations,
but `call_me` is missing the type annotation of `num`. What is the basic type in Cairo?"""
[[exercises]]
name = "functions3"
path = "exercises/functions/functions3.cairo"
mode = "compile"
hint = """
This time, the function *declaration* is okay, but there's something wrong
with the place where we're calling the function.
Remember how we can use a suffix to specify the type of a literal? https://link.medium.com/c8TqX7R3qxb#6d64
As a reminder, you can freely play around with different solutions in Starklings!
Watch mode will only jump to the next exercise if you remove the I AM NOT DONE comment."""
[[exercises]]
name = "functions4"
path = "exercises/functions/functions4.cairo"
mode = "compile"
hint = """
The error message points to line 18 and says it expects a type after the
`->`. This is where the function's return type should be -- take a look at
the `is_even` function for an example!
"""
# QUIZ 1
[[exercises]]
name = "quizs1"
path = "exercises/quizs/quizs1.cairo"
mode = "test"
hint = """No hints this time ;)"""
# ENUMS
[[exercises]]
name = "enums1"
path = "exercises/enums/enums1.cairo"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "enums2"
path = "exercises/enums/enums2.cairo"
mode = "compile"
hint = """
You can create enumerations that have different variants with different types
such as no data, structs, a single felt string, tuples, ...etc"""
[[exercises]]
name = "enums3"
path = "exercises/enums/enums3.cairo"
mode = "test"
hint = """
As a first step, you can define enums to compile this code without errors.
and then create a match expression in `process()`.
Note that you need to deconstruct some message variants
in the match expression to get value in the variant.
"""
# OPTIONS
[[exercises]]
name = "options1"
path = "exercises/options/options1.cairo"
mode = "test"
hint = """
Options can have a Some value, with an inner value, or a None value, without an inner value.
There's multiple ways to get at the inner value, you can use unwrap, or pattern match. Unwrapping
is the easiest, but how do you do it safely so that it doesn't panic in your face later?"""
[[exercises]]
name = "options2"
path = "exercises/options/options2.cairo"
mode = "test"
hint = """
check out: https://github.com/starkware-libs/cairo/blob/main/corelib/src/option.cairo
to see the implementation of the Option type and its methods.
"""
[[exercises]]
name = "options3"
path = "exercises/options/options3.cairo"
mode = "test"
hint = """
Reminder: You can use a match statement with an Option to handle both the Some and None cases.
This syntax is more flexible than using unwrap, which only handles the Some case, and contributes to more robust code.
"""
# Arrays
[[exercises]]
name = "arrays1"
path = "exercises/arrays/arrays1.cairo"
mode = "test"
hint = """
You can declare an array in Cairo using the following syntax:
`let your_array = ArrayTrait::new();`
You can append elements to an array using the following syntax:
`your_array.append(element);`
The `pop_front` method removes the first element from the array and returns an Option::Some(value) if the array is not empty, or Option::None() if the array is empty.
"""
[[exercises]]
name = "arrays2"
path = "exercises/arrays/arrays2.cairo"
mode = "test"
hint = """
How can you remove the first element from the array?
Take a look at the previous exercise for a hint. Don't forget to call `.unwrap()` on the returned value.
This will prevent the `Variable not dropped` error.
"""
[[exercises]]
name = "arrays3"
path = "exercises/arrays/arrays3.cairo"
mode = "test"
hint = """
The test fails because you are trying to access an element that is out of bounds!
By using array.pop_front(), we remove the first element from the array, so the index of the last element is no longer 2.
Without changing the index accessed, how can we make the test pass? Is there a method that returns an option that could help us?
"""
# STRUCTS
[[exercises]]
name = "structs1"
path = "exercises/structs/structs1.cairo"
mode = "test"
hint = """
Cairo has a single type of struct that are named collections of related data stored in fields.
In this exercise you need to complete and implement a struct.
Here is how we describe a person struct that stores a name and an age,
#[derive(Copy, Drop)]
struct Person {
name: felt,
age: felt,
}
You'd use the struct like so,
let john = Person { name: 'John', age: 29 };
Read more about structs in the Structs section of this article: https://link.medium.com/c8TqX7R3qxb#ff54 """
[[exercises]]
name = "structs2"
path = "exercises/structs/structs2.cairo"
mode = "test"
hint = """
Cairo requires you to initialize all fields when creating a struct and there is no update syntax available at the moment.
You can have multiple data types in a struct, and even other structs.
There are some shortcuts that can be taken when destructuring structs,
```
let Foo {x, y} = foo; // Creates variables x and y with values foo.x and foo.y
let Foo {x: a, y: b} = foo; // Creates variables a and b with values foo.x and foo.y
```
Read more about structs in the Structs section of this article: https://link.medium.com/c8TqX7R3qxb#ff54 """
[[exercises]]
name = "structs3"
path = "exercises/structs/structs3.cairo"
mode = "test"
hint = """
For is_international: What makes a package international? Seems related to the places it goes through right?
For get_fees: This method takes an additional argument, is there a field in the Package struct that this relates to?
Looking at the test functions will also help you understand more about the syntax.
This section will help you understanding more about impls and traits: https://link.medium.com/c8TqX7R3qxb#83b5.
"""
# MOVE SEMANTICS
[[exercises]]
name = "move_semantics1"
path = "exercises/move_semantics/move_semantics1.cairo"
mode = "compile"
hint = """
So you've got the "ref argument must be a mutable variable." error on line 17,
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 17
where the error is.
Also: Try accessing `arr0` after having called `fill_arr()`. See what happens!"""
[[exercises]]
name = "move_semantics2"
path = "exercises/move_semantics/move_semantics2.cairo"
mode = "compile"
hint = """
So, `arr0` is passed into the `fill_arr` function as an argument. In Cairo,
when an argument is passed to a function and it's not explicitly returned,
you can't use the original variable anymore. We call this "moving" a variable.
Variables that are moved into a function (or block scope) and aren't explicitly
returned get "dropped" at the end of that function. This is also what happens here.
There's a few ways to fix this, try them all if you want:
1. Make another, separate version of the data that's in `arr0` and pass that
to `fill_arr` instead.
2. Make `fill_arr` *mutably* borrow a reference to its argument (which will need to be
mutable) with the `ref` keyword , modify it directly, then not return anything. Then you can get rid
of `arr1` entirely -- note that this will change what gets printed by the
first `print`
3. Make `fill_arr` borrow an immutable view of its argument instead of taking ownership by using the snapshot operator `@`,
and then copy the data within the function in order to return an owned
`Array<felt>`. This requires an explicit clone of the array and should generally be avoided in Cairo, as the memory is write-once and cloning can be expensive."""
[[exercises]]
name = "move_semantics3"
path = "exercises/move_semantics/move_semantics3.cairo"
mode = "compile"
hint = """
The difference between this one and the previous ones is that the first line
of `fn fill_arr` that had `let mut arr = arr;` is no longer there. You can,
instead of adding that line back, add `mut` in one place that will change
an existing binding to be a mutable binding instead of an immutable one :)"""
[[exercises]]
name = "move_semantics4"
path = "exercises/move_semantics/move_semantics4.cairo"
mode = "compile"
hint = """
Stop reading whenever you feel like you have enough direction :) Or try
doing one step and then fixing the compiler errors that result!
So the end goal is to:
- get rid of the first line in main that creates the new array
- so then `arr0` doesn't exist, so we can't pass it to `fill_arr`
- we don't want to pass anything to `fill_arr`, so its signature should
reflect that it does not take any arguments
- since we're not creating a new vec in `main` anymore, we need to create
a new vec in `fill_arr`, similarly to the way we did in `main`"""
[[exercises]]
name = "move_semantics5"
path = "exercises/move_semantics/move_semantics5.cairo"
mode = "compile"
hint = """
Carefully reason about how each function takes ownership of the variable passed.
It depends on the keyword used to pass the variable.
What happens when a function takes ownership of a variable and then returns it?
Can we still use it later on?
"""
[[exercises]]
name = "move_semantics6"
path = "exercises/move_semantics/move_semantics6.cairo"
mode = "compile"
hint = """
The first problem is that `get_value` is taking ownership of the Number struct.
So `Number` is moved and can't be used for `set_value`
`number` is moved to `get_value` first, meaning that `set_value` cannot manipulate the data.
What can we use to pass an immutable reference to `get_value`? What special operator do we use for that?
What other operator do we use to "desnap" a snapshot?
Hint: It involves the `@` and `*` operators.
Once you've fixed that, `set_value`'s function signature will also need to be adjusted.
Can you figure out how?
"""
# TRAITS
[[exercises]]
name = "traits1"
path = "exercises/traits/traits1.cairo"
mode = "test"
hint = """
If you want to implement a trait for a type, you have to implement all the methods in the trait.
Based on the signature of the method, you can easily implement it.
In the test, you need to instantiate two objects of type `Animal`.
You can call the method of a trait by using the MyTrait::foo() syntax.
How would you instantiate the two objects with AnimalTrait?
Maybe you need to specify the type of the object?
"""
[[exercises]]
name = "traits2"
path = "exercises/traits/traits2.cairo"
mode = "test"
hint = """ No hints for this one! It is very similar to the previous exercise."""
[[exercises]]
name = "traits3"
path = "exercises/traits/traits3.cairo"
mode = "test"
hint = """
You can implement multiple traits for a type.
When a trait is destined to be implemented by a single type, you don't need to use generics.
If you're having trouble updating the distance value in the `Fish` and `Dog` impls, remember that you need to first
1. Destructure the object into mutable variables
2. Update the distance variable
3. Reconstruct `self` with the updated variables (`self = MyStruct { ... }`)
"""