Modules

A CSL module consists of a group of global symbols defined in a file, which can be imported into a CSL program through the @import_module builtin.

Builtin syntax

The @import_module builtin has two overloads:

@import_module(filename)
@import_module(filename, param_binding)

Where:

  • filename is a comptime string.

  • param_binding is a comptime anonymous struct.

Semantics

Unless filename is an absolute path, the compiler looks for a file named filename, relative to the location of the importer. The file is opened and its contents parsed. If no such file exists, a compilation error is issued. If the filename is enclosed in angled brackets, then the compiler imports the specified standard library. For instance, const math = @import_module("<math>") makes all math functions available under the math module variable.

For each name in param_binding, the imported module is searched for a param/color with a matching name. The initial value of the param/color is set to corresponding value in param_binding. Warnings are raised if a name doesn’t exist inside the module.

A value of imported_module type is returned. Such values must always be assigned to a const global variable. This variable has no runtime footprint.

Importing the same file twice results in two independent copies of the module.

If the imported module contains a layout block, the block is ignored.

Values of imported_module type contain a name for the imported module. Copying these values does not create a new copy of the module, creates a new name for the same module.

The compiler must be able to resolve access to module members at compile time, as such the module values themselves must be comptime.

Using a module

To access the symbols contained in a module, the . operator can be used.

Example

/// A/B/multiply.csl

param factor:i16;

fn multiply(arg:i16) i16 {
  return arg * factor;
}
/// A/accumulate.csl

var accumulator:i16 = 0;
/// A/main.csl

const multiply_module = @import_module("B/multiply.csl", .{.factor = 42});
const accumulate_module = @import_module("accumulate.csl");

fn foo() void {
  const x = multiply_module.multiply(10);
  accumulate_module.accumulator += x;
}

Binary symbol names

To find an imported symbol in the compiled program binary, the module name and . should be included in the name being searched for. Given a module variable basename = @import_module(...), containing a global importedname, its symbol name in the resulting binary will be basename.importedname.