master
1const std = @import("std");
2const builtin = @import("builtin");
3const native_arch = builtin.cpu.arch;
4const expect = std.testing.expect;
5
6// Functions are declared like this
7fn 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.
17export 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.
26extern "kernel32" fn ExitProcess(exit_code: u32) callconv(.winapi) noreturn;
27extern "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").
30fn 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.
37fn _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.
43inline 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
49pub fn sub2(a: i8, b: i8) i8 {
50 return a - b;
51}
52
53// Function pointers are prefixed with `*const `.
54const Call2Op = *const fn (a: i8, b: i8) i8;
55fn doOp(fnCall: Call2Op, op1: i8, op2: i8) i8 {
56 return fnCall(op1, op2);
57}
58
59test "function" {
60 try expect(doOp(add, 5, 6) == 11);
61 try expect(doOp(sub2, 5, 6) == -1);
62}
63
64// test