Using Notes

Notes are a way to tag a struct, function, or struct member. Notes are represented as strings. This tag will show up in a metaprogram. In the metaprogram, you can use the note to do special metaprogramming such custom program typechecking and modifying the executable based on the metaprogram. Notes in Jai are represented as strings, and unlike Java or C#, are not structured (but structured notes may be added in the future).

Here is a simple metaprogram that finds all the functions tagged @note and creates a main function that calls all functions tagged @note in alphabetical order.

Metaprogram build.jai:

#run {
  w := compiler_create_workspace();

  options := get_build_options(w);
  options.output_executable_name = "exe";
  set_build_options(options, w);

  compiler_begin_intercept(w);
  add_build_file("main.jai", w);  

  // find all functions tagged @note, sort all functions alphabetically,
  // and call all functions in alphabetical order from a generated "main"
  functions: [..] string;
  gen_code := false;
  while true {
    message := compiler_wait_for_message();
    if !message break;
    if message.kind == {
    case .TYPECHECKED;
      typechecked := cast(*Message_Typechecked) message;
      for decl: typechecked.declarations {
        if equal(decl.expression.name , "main") {
          continue;
        }

        for note: decl.expression.notes {
          if equal(note.text, "note") {
            array_add(*functions, copy_string(decl.expression.name));
          }
        }

      }
    case .PHASE;
      phase := cast(*Message_Phase) message;
      if gen_code == false && phase.phase == .TYPECHECKED_ALL_WE_CAN {
        code := generate_code();
        add_build_string(code, w);
        gen_code = true;
      }

    case .COMPLETE;
      break;
    }
  }
  compiler_end_intercept(w);
  set_build_options_dc(.{do_output=false});

  generate_code :: () -> string #expand {
    bubble_sort(functions, compare);
    builder: String_Builder;
    append(*builder, "main :: () {\n");
    for func: functions {
      print_to_builder(*builder, "  %1();\n", func);
    }
    append(*builder, "}\n");
    return builder_to_string(*builder);
  }

}

#import "Compiler";
#import "String";
#import "Basic";
#import "Sort";

The main program main.jai:

apple :: () {
  print("apple\n");
} @note

bannana :: () {
  print("bannana\n");
} @note

cherry :: () {
  print("cherry\n");
} @note

dog :: () {
  print("dog\n");
} @note

elephant :: () {
  print("elephant\n");
} @note

#import "Basic";

// create the main() function using the metaprogram.

When you hit jai build.jai followed by running the executable, you should get the following output:

apple
bannana
cherry
dog
elephant
1 Like