Skip to content

Commit

Permalink
Add macrokata01
Browse files Browse the repository at this point in the history
  • Loading branch information
tfpk committed Oct 19, 2022
0 parents commit a8f37be
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
208 changes: 208 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "macrokata"
version = "0.1.0"
edition = "2021"
default-run = "macrokata"

[[bin]]
name = "macrokata"
path = "src/main.rs"

[[bin]]
name = "01"
path = "exercises/01_my_first_macro/main.rs"

[[bin]]
name = "01_soln"
path = "exercises/01_my_first_macro/solutions/main.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.0.17", features = ["derive"] }
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# MacroKata

MacroKata is a set of exercises which you can use to learn how
to write macros in rust. Unlike most exercises, not only is your goal
to produce the same output with your code as with the files
in solution.rs; but it should *also* be to have your expanded code be the same
as `result.rs`.

You should complete the kata in order, as they increase in
difficulty, and depend on previous kata.

## Getting Started

Clone this repository:

``` sh
$ git clone https://www.github.com/tfpk/macrokata/
```

You will also need to install the rust "nightly" toolchain, so that we can show
expanded macros.

``` sh
$ rustup toolchain install nightly
```

Build the main binary provided with this repo:

``` sh
$ cargo build
```

You can find the first kata (`my_first_macro`) inside `tasks/01_my_first_macro`.
Read the `README.md` file, and get started by editing the `main.rs` file.

To test your code, run:

``` sh
$ cargo run 01_my_first_macro
```
59 changes: 59 additions & 0 deletions exercises/01_my_first_macro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Exercise 1: My First Macro

Welcome to this introduction to Rust's Macro system.
To complete each exercise (including this one), you should:

* [ ] Read the `README.md` file, to understand what your goal is.
* [ ] Try and complete the `main.rs` file.
* [ ] Run the binary in this file, `cargo run 01_my_first_macro`.
* [ ] Get your code to compile, run, and have the main file look the same as `result.rs`


## What are Macros?

Rust's macros are a way of automatically generating code before the compiler compiles it.
Because the generation happens before the compiler does anything; it doesn't
care about types; and it can output any Rust code you'd like.

This allows you to break some of the syntax rules rust imposes on you. For example,
Rust does not allow "variadic" functions -- functions with variable numbers of
arguments. This makes a `println` function impossible -- it can take any number
of arguments (`println!("hello")` and `println("{}", 123)`, for example).

Rust gets around this rule by using a `println!` macro. Before `println!` is compiled,
Rust rewrites it so it takes a single array of arguments. That way, even though
it looks to you like there are multiple arguments, once it's compiled there's always
just one array.

Macros can range from very simple -- reducing duplicated code; to very complex, implementing the
whole of HTML inside of Rust. This guide aims to build you up from the simple to the complex.

As you may have guessed, you've already used them -- `println!` for example, is a macro.
`vec![]` is as well. In general, macros always have a name. To run a macro, call it's name
with a bang (`!`) afterwards, and then brackets (any of `()`, `[]` or `{}`) containing
arguments.

In other words, to run the macro `my_macro`, you'd say `my_macro!()` or `my_macro![]` or `my_macro!{}`.

## How do I create one?

The simplest form of macro looks like this:

``` rust
macro_rules! my_macro {
() => {
my_code();
}
}
```

The `macro_rules!` instructs the compiler that there is a new macro you are defining.
It is followed by the name of the macro, `my_macro`.
The next line lets you specify variables for your macro, but for now we'll ignore it.
Any code inside the curly brackets is what Rust will replace `my_macro!()` with.

So, `my_macro!()` will be replaced by `my_code();`

## See it for yourself

You now know everything you need to in order to complete `01_my_first_macro`.
14 changes: 14 additions & 0 deletions exercises/01_my_first_macro/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
////////// DO NOT CHANGE BELOW HERE /////////
// This function should be called by the `show_output!()` macro
fn show_output() {
println!("I should appear as the output.")
}
////////// DO NOT CHANGE ABOVE HERE /////////

// TODO: create `show_output!()` macro.

////////// DO NOT CHANGE BELOW HERE /////////

fn main() {
show_output!()
}
3 changes: 3 additions & 0 deletions exercises/01_my_first_macro/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
show_output()
}
12 changes: 12 additions & 0 deletions exercises/01_my_first_macro/solutions/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This function should be called by the `show_output!()` macro
fn show_output() {
println!("I should appear as the output.")
}

macro_rules! show_output {
() => {show_output()}
}

fn main() {
show_output!()
}
Loading

0 comments on commit a8f37be

Please sign in to comment.