An upgraded version of Default_Metaprogram
. To use it either copy the Metaprogram
folder into your jai modules folder, or symlink it there. Then edit the following code into the modules/Default_Metaprogram.jai
file in the compiler.
Below the line files, run_strings := compiler_get_source_files();
add:
{
// User-added block for Metaprogram module, non-standard!
metaprogram :: #import "Metaprogram";
metaprogram.update_options();
}
Below the line if !message break;
add:
{
// User-added block for Metaprogram module, non-standard!
metaprogram :: #import "Metaprogram";
metaprogram.check_message(message);
}
If you'd rather not directly edit the compiler Default_Metaprogram.jai
then copy it, make the edit, then use the -meta
command line option to use your new version.
You can toggle the metaprogram features by editing the constants at the top of Metaprogram.jai
Features:
- Use Environment Variables
- Pointer-into-resizable-array check
- Carriage-Return check
build
string for single file programs- Managed Imports
When enabled the metaprogram will check for the following environment variables:
JAI_IMPORT_DIR
- set to a collection of folder paths separated by;
to add them as if with-import_dir
JAI_CHECK_BINDINGS
- if set to non-zero will enable the-check_bindings
option.JAI_QUIET
- if set to non-zero will enable the-quiet
option.
Enable as either a .WARNING
or .ERROR
: it will try and detect when you take a pointer into a resizable array ([..] $T
); such a pointer will become invalid when the array reallocates itself (which can happen any time you add to it).
When enabled as either .WARNING
or .ERROR
it will report any string literal which contains a carriage return (\r
) character.
When enabled as .FIX
it will remove the carriage returns from the string. (WIP: currently it pads the end of the string with as many nulls as there were \r
)
You may mark a string with @Contains_Carriage_Return
to have it ignore this check.
Allows you to create a build script inside your program, so even a simple single-file program can set compiler options, check compiler messages, etc.
Add a #string to your program called build
, and it will be ran as a build script for your program. For example:
build :: #string __jai
#import "Compiler";
build_options := get_build_options();
build_options.output_executable_name = "not_the_same_name.exe";
workspace := compiler_create_workspace();
set_build_options(build_options, workspace);
add_build_file(#file, workspace);
__jai
Managed imports provides a mechanism to (a) allow for importing files via a specified path and (b) automatically download modules hosted on github (currently hard-coded to only use github, more sites can be added later).
Since jai provides arbitary compile-time execution, using this feature is a vector for RCE. This is just the same as any other package manager, the only difference being you can get owned simply by compiling the code; you don't need to run it. Only import modules you trust!
This is using a new compiler feature so is new code; it probably has bugs! If you run into problems you can raise an issue, but it's probably easier to just msg me on the SB discord.
- You need to be on compiler version
beta 0.0.101
or later. - For downloading you need
git
installed and working.
To specify a path for a module place it after a |
character in the import string. i.e.:
#import "<module>|<path>";
For example:
#import "Foo|c:/repos/modules";
The path can be absolute or relative (to the project);
The syntax to download a module from Github is:
#import "<module>|<version>|<repo>.<user>";
For example:
#import "Strings|v1.0.8|jai-string.onelivesleft";
Note that <version>
must be in the form v#.#.#
.
When you use this syntax the compiler will check the downloaded modules folder (a path set at the top of Metaprogram.jai
) for the specified module. If it doesn't find it it'll use git
to download it.
Alternatively, you may import directly into your program by prefixing the module name with a .
:
#import ".<module>|<version>|<repo>.<user>";
For example:
#import ".Strings|v1.0.8|jai-string.onelivesleft";
This will search inside / download into your program directory in the modules
sub-folder.
To set up a module which can be downloaded automatically in this manner:
- Create a github repository for it.
- Create the module as a folder in that repo, with a
module.jai
file inside (as normal). - Create a
modules.lst
file in the root of the repo, which lists every folder ni the repo that is a module. - Create a release of the repo, and tag it with the version. The version tag must be of the form
v#.#.#
. For example, the tag for theStrings
module above isv1.0.8
.
Example module: https://github.com/onelivesleft/jai-string
(Currently the entire repo is downloaded and held, but in future versions all files/folders in the repo which are not listed in the modules.lst
file will be deleted)
You can inline a module directly in the string if you use a #string
. For example:
Foo :: #import #string __jai
my_module_has_a_string :: "It does!\n";
__jai;
main :: () {
write_string(Foo.my_module_has_a_string);
}