| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const native_arch = builtin.cpu.arch; |
| 4 | const expectEqual = std.testing.expectEqual; |
| 5 | |
| 6 | // Functions are declared like this |
| 7 | fn add(a: i8, b: i8) i8 { |
| 8 | if (a == 0) { |
| 9 | return b; |
| 10 | } |
| 11 | |
| 12 | return a + b; |
| 13 | } |
| 14 | |
| 15 | // The export specifier makes a function externally visible in the generated |
| 16 | // object file, and makes it use the C ABI. |
| 17 | export fn sub(a: i8, b: i8) i8 { |
| 18 | return a - b; |
| 19 | } |
| 20 | |
| 21 | // The extern specifier is used to declare a function that will be resolved |
| 22 | // at link time, when linking statically, or at runtime, when linking |
| 23 | // dynamically. The quoted identifier after the extern keyword specifies |
| 24 | // the library that has the function. (e.g. "c" -> libc.so) |
| 25 | // The callconv specifier changes the calling convention of the function. |
| 26 | extern "kernel32" fn ExitProcess(exit_code: u32) callconv(.winapi) noreturn; |
| 27 | extern "c" fn atan2(a: f64, b: f64) f64; |
| 28 | |
| 29 | // The @branchHint builtin can be used to tell the optimizer that a function is rarely called ("cold"). |
| 30 | fn abort() noreturn { |
| 31 | @branchHint(.cold); |
| 32 | while (true) {} |
| 33 | } |
| 34 | |
| 35 | // The naked calling convention makes a function not have any function prologue or epilogue. |
| 36 | // This can be useful when integrating with assembly. |
| 37 | fn _start() callconv(.naked) noreturn { |
| 38 | abort(); |
| 39 | } |
| 40 | |
| 41 | // The inline calling convention forces a function to be inlined at all call sites. |
| 42 | // If the function cannot be inlined, it is a compile-time error. |
| 43 | inline fn shiftLeftOne(a: u32) u32 { |
| 44 | return a << 1; |
| 45 | } |
| 46 | |
| 47 | // The pub specifier allows the function to be visible when importing. |
| 48 | // Another file can use @import and call sub2 |
| 49 | pub fn sub2(a: i8, b: i8) i8 { |
| 50 | return a - b; |
| 51 | } |
| 52 | |
| 53 | // Function pointers are prefixed with `*const `. |
| 54 | const Call2Op = *const fn (a: i8, b: i8) i8; |
| 55 | fn doOp(fnCall: Call2Op, op1: i8, op2: i8) i8 { |
| 56 | return fnCall(op1, op2); |
| 57 | } |
| 58 | |
| 59 | test "function" { |
| 60 | try expectEqual(11, doOp(add, 5, 6)); |
| 61 | try expectEqual(-1, doOp(sub2, 5, 6)); |
| 62 | } |
| 63 | |
| 64 | // test |