Contributing

AtomVM is open to any contribution.

Pull requests, bug reports and feature requests are welcome.

However before contributing, please read carefully our Code of Conduct and the following contribution guidelines.

Please, also make sure to understand the Apache 2.0 license and the Developer Certificate of Origin.

Last but not least, do not use GitHub issues for vulnerability reports, read instead the security policy for instructions.

Coding Style

For all source code modules:

  • Remove all trailing whitespace

  • Newlines (\n) at end of file

  • Use line ending conventions appropriate for the platform (e.g., \n on UNIX-like systems)

C Code

C source code style is enforced with clang-format-16. To automatically fix a file, run:

clang-format-16 --style=file -i file.c

Indentation

Good:

void f(bool reverse)
{
    if (reverse) {
        puts("!dlroW olleH");
    } else {
        puts("Hello world");
    }
}

Bad:

void f(bool reverse) {
    if (reverse)
        puts ("!dlroW olleH");
    else
        puts ("Hello world");
}

Naming Conventions

  • Struct names are PascalCase (e.g. Context)

  • Scalar types are lower case (e.g. term)

  • All other names (e.g. functions and variables) are snake_case (e.g. term_is_integer)

  • Always prefix exported function names with the module in which they are defined (e.g. term_is_nil, term_is_integer, context_new, context_destroy)

Other Coding Conventions

  • Pointers (*) should be with the variable name rather than with the type (e.g. char *name, not char* name)

  • Avoid long lines, use intermediate variables with meaningful names.

  • Function definitions should be separated by 1 empty line

Function declarations should be structured as follows:

func(main_input, additional_inputs, main_output, additional_outputs, opts, [context])

where context is a context structure (such as Context or GlobalContext).

Any functions that are not exported should be qualified with the static keyword.

Functions that return booleans should be named is_something (or possibly module_is_something, if the function is exported).

C header modules (.h) should be organized as follows:

+-------------------
| Copyright Header
|
| #ifdef MODULE__H__
| #define MODULE__H__
|
| #ifdef __cplusplus
| extern "C" {
| #endif
|
| #includes (alphabetical)
|
| #defines
|
| type definitions
|
| function declarations
|
| #ifdef __cplusplus
| }
| #endif
|
| #endif
+-------------------
 module.h

C source modules (.c) should be organized as follows:

+-------------------
| Copyright Header
|
| #includes (alphabetical)
|
| #defines
|
| type definitions
|
| forward declarations (only if necessary)
|
| function definitions
|   dependent static functions first
|   exported functions and entrypoints last
+-------------------
 module.c

Documentation

Doxygen Javadoc style code comments will be picked up and added to the documentation. Changes will automatically be added to the libAtomVM Source Files and the libAtomVM Index. But to have Data Structures, Types, MACROS, and Functions appear in the correct C Library APIs section the corresponding entries must be added to the similarly named *.rst files in the AtomVM/doc/src/apidocs/libatomvm/ directory. The exact names of the files that need to be altered are: data_structures.rst, functions.rst, macros.rst, and types.rst. The other files in the directory handle auto`generated content and do not need to be altered.

In the rare case that a function declaration and definition are both in different header files (rather than the definition in a *.c file) this can cause rendering errors for Doxygen. The work around for these cases can be demonstrated with this example for the function sys_listener_destroy it is documented and declared in sys.h and defined as follows in listeners.h:

#ifndef DOXYGEN_SKIP_SECTION /* documented in sys.h */
void sys_listener_destroy(struct ListHead *item)
{
    EventListener *listener = GET_LIST_ENTRY(item, EventListener, listeners_list_head);
    free(listener);
}
#endif /* DOXYGEN_SKIP_SECTION */

Note: You should include a short /* comment */ trailing the #ifndef entry mentioning the file where the function is actually documented.

Erlang Code

Erlang source code style is enforced using erlfmt.

Elixir Code

Just use Elixir formatter enforced style.