From c12bf134333212345f8b65ca530ba5bb828b4293 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 29 Oct 2021 11:39:54 -0500 Subject: [PATCH] added macro example --- examples/18_macros.onyx | 120 +++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 14 deletions(-) diff --git a/examples/18_macros.onyx b/examples/18_macros.onyx index 32e750e1..69bf03b1 100644 --- a/examples/18_macros.onyx +++ b/examples/18_macros.onyx @@ -1,20 +1,112 @@ -// Unfinished Example +// Macros allow you to write reusable blocks of code, much like procedures. Macros +// are different in that they are expanded at the call site, and then symbol resolution +// occurs. This means that every time a macro is called, it is expanded at the call site, +// and then it uses the symbols from the current scope. -#load "core/std" +main :: (args: [] cstr) { + // A macro in Onyx looks just like a procedure, just with the work "macro" in front of it. + a_simple_macro :: macro () { + println("This is a simple macro"); + } -use package core + a_simple_macro(); -say_something :: macro (thing: Code) { - #persist increment := 0; - increment += 1; - printf("[INFO:{}] {}\n", increment, #insert thing); -} + // The powerful thing about macros is that they can access variables from their enclosing scope. + // For example, this macro prints the value of 'x'. + print_x :: macro () { + printf("x is {}\n", x); + } -main :: (args: [] cstr) { - data := "Some string in the main function"; + { + x := 10; + print_x(); + } + + { + x := "a message"; + print_x(); + } + + // Macros can take on two different forms depending on if they return a value or not. + // Macros that return a value are called "expression macros". Expression macros behave + // mostly just like inlined functions, with the addition that they can access variables + // from the calling-site's scope. Below is a simple expression macro. + + add_x_y :: macro () -> i32 { + return x + y; + } + + { + x := 10; + y := 20; + z := add_x_y(); + printf("x + y is {}\n", z); + } + + // Macros that do not return a value are called "block macros". Block macros behave differently + // from expression macros when it comes to "return" and "defer" statements. Block macros do not + // flush deferred statements when they end. A return statement in a block macro behaves like a + // return in the caller. + + block_macro :: macro () { + defer println("Block macro's deferred print."); + + println("Block macro's print."); + } + + block_macro_that_returns :: macro () { + println("Returning..."); + return; + } - say_something(#code "Foo"); - say_something(#code 10); - say_something(#code context); - say_something(#code data); + calls_block_macro :: () { + block_macro(); + + println("This would be doing some work."); + + block_macro_that_returns(); + println("This will never be printed"); + } + + calls_block_macro(); + + + // A powerful feature of Onyx that enables macros to be very useful is code blocks. + // Code blocks allow you to capture code and treat it as a compile-time object that can + // be passed around. To create a code blocks, simply put '#code' in front of the block + // of code you want to capture. Notice that this uses '::' because this is a compile-time + // value. + simple_code :: #code { + println("This is a code block!"); + } + + // You can then use the '#insert' directive to place the code wherever you need it. + // We can paste it 3 times for examples: + #insert simple_code; + #insert simple_code; + #insert simple_code; + + // Because simple_code is a compile-time value, it can be passed to procedures as so: + triple :: ($body: Code) { + println("Running 3 times!"); + #insert simple_code; + #insert simple_code; + #insert simple_code; + } + + triple(simple_code); + + // Because macros just alias their parameter names to the values passed, you don't need the + // compile-time parameter (the '$'). + triple_macro :: macro (body: Code) { + println("Running 3 times in a macro!"); + #insert simple_code; + #insert simple_code; + #insert simple_code; + } + + triple_macro(simple_code); } + +#load "core/std" +use package core \ No newline at end of file -- 2.25.1