NULLC library reference

  1. Interface
    1. Library compilation options
    2. Initialization and termination
    3. Execution settings and environment
    4. Basic functions
    5. Interaction functions
    6. Special modules
    7. Extended functions
    8. Debug functions
  2. Interoperability with C code
    1. Binding functions to NULLC

1. Interface

1.1 Library compilation options

Various library configuration options are available in "nullcdef.h" file.

#define NULLC_MAX_VARIABLE_NAME_LENGTH 2048

This define control the maximum variable, function or class name that NULLC will attempt to handle.

#define NULLC_DEFAULT_GLOBAL_MEMORY_LIMIT 1024 * 1024 * 1024

This define control the default maximum global memory limit (1Gb by default).
You can change this constant or use the nullcSetGlobalMemoryLimit function.

#define NULLC_STACK_TRACE_WITH_LOCALS

This define control whether NULLC will write information about locals in call stack on execution error.
This define is enabled by default.

#define NULLC_ENABLE_C_TRANSLATION

This define enables an ability to translate NULLC code into C++ code.
Keep in mind that enabling this define will degrade performance of NULLC VM and JiT executors (additionally, NULLC_OPTIMIZE_X86 will be disabled).
This define is disabled by default.

#define NULLC_PURE_FUNCTIONS

This define enables compile-time function evaluation.
This define is enabled by default.

#define NULLC_BUILD_X86_JIT

This define enables x86 JiT executor.
This define is enabled by default on platforms and compilers that support it.

#define NULLC_OPTIMIZE_X86

This define enables x86 JiT executor code optimization.
Code compilation speed is reduced greatly when JiT is in use and this flag is enabled.
This define is enabled by default on platforms and compilers that support it, unless the NULLC_ENABLE_C_TRANSLATION is enabled.

#define NULLC_NO_EXECUTOR

This define will build a compiler-only version of NULLC library.
This define is disabled by default.

#define NULLC_AUTOBINDING

This define will enable an automatic function binding on Windows and Linux. More information in a topic Binding functions to NULLC
This define is enabled by default.

1.2 Initialization and termination

void nullcInit(const char* importPath);

Function initializes NULLC library with default allocation and deallocation functions.
-importPath parameter sets that path in which the modules will be searched.
Function is equivalent to nullcInitCustomAlloc(NULL, NULL, importPath);

void nullcSetImportPath(const char* importPath);

This function will update the module import path.
-importPath parameter sets that path in which the modules will be searched.

void nullcInitCustomAlloc(void* (NCDECL *allocFunc)(int), void (NCDECL *deallocFunc)(void*), const char* importPath);

Function initializes NULLC library with specified allocation and deallocation functions.
-allocFunc parameter sets the allocation function. It must be _cdecl function accepting one argument (allocation size) and returning pointer to allocated memory block.
-deallocFunc parameter sets the deallocation function. It must be _cdecl function accepting one argument (pointer to a memory block to be freed). Return type must be void.
-importPath parameter sets that path in which the modules will be searched.

void nullcSetFileReadHandler(const void* (NCDECL *fileLoadFunc)(const char* name, unsigned int* size, int* nullcShouldFreePtr));

Function allows to set a handler for module file read operation. By default, fopen/ftell/fread/fclose function are used.
-fileLoadFunc parameter sets the handler function. It must be _cdecl function accepting three arguments and returning pointer to a memory, where file contents are placed.
    name argument contains the path to a module.
    size argument is a pointer to a variable that should receive file size.
    nullcShouldFreePtr argument is a pointer to a variable that will tell whether NULLC should free memory to which return pointer points to.

void nullcSetGlobalMemoryLimit(unsigned int limit);

Function sets the global memory limit and override the one set by NULLC_DEFAULT_GLOBAL_MEMORY_LIMIT define.
- limit parameter is the new global memory limit.

void nullcTerminate();

This function performs NULLC library deinitialization.

1.3 Execution settings and environment

void nullcSetExecutor(unsigned int id);

Change current executor.
- id is executor ID. Can be either NULLC_VM or NULLC_X86 (JiT).

nullres nullcSetJiTStack(void* start, void* end, unsigned int flagMemoryAllocated);

Set memory range where JiT parameter stack will be placed.

Windows specific:
    If flagMemoryAllocated is not set, executor will allocate memory itself using VirtualAlloc with base == start.
Linux specific:
    If flagMemoryAllocated is not set, start parameter is ignored.

When flagMemoryAllocated is not set, end can be set to NULL, meaning that x86 parameter stack can grow indefinitely.
When flagMemoryAllocated is set, start and end should point to a user-allocated buffer. After a call it shouldn't be accessed or deallocated before a call to nullcTerminate or a call to nullcSetJiTStack with a different buffer.
Default mode: start = 0x20000000, end = NULL, flagMemoryAllocated = false
Function is available if NULLC_BUILD_X86_JIT is enabled.

nullres nullcBindModuleFunction(const char* module, void (NCDECL *ptr)(), const char* name, int index);

Function is used to bind unresolved module functions to external C functions.
Read more abount C function binding in interoperability section.
- module parameter is the module name (as in NULLC import expression), where the function will be searched.
- ptr parameter is the pointer to C function (use a cast operation to bind functions with different types).
- name parameter is the function name.
- index parameter is the number of a function overload in order of definition in the source code.

nullres nullcLoadModuleBySource(const char* module, const char* code);

Builds module and saves its binary into binary cache.
- module parameter is the module name as in NULLC import expression.
- code parameter is the module source code.

nullres nullcLoadModuleByBinary(const char* module, const char* binary);

Loads module into binary cache.
- module parameter is the module name as in NULLC import expression.
- binary parameter is the module binary code.

1.4 Basic functions

nullres nullcBuild(const char* code);

Compiles and links code.
- code parameter is the module name as in NULLC import expression.

nullres nullcRun();

Run global code.
This function should be called at least once, before nullcRunFunction can be safely called, since it calculates global variable values.

nullres nullcRunFunction(const char* funcName, ...);

Run function code.
- funcName parameter is the name of the function to run. If it's NULL, the result is the same as calling nullcRun.
- ... arguments that will be passed into a function.

const char* nullcGetResult();
int nullcGetResultInt();
double nullcGetResultDouble();
long long nullcGetResultLong();

Functions that retrieve last execution result of global code or function.

const char* nullcGetLastError();

Function returns last error description.

1.5 Interaction functions

void* nullcAllocate(unsigned int size);

Function allocates memory block that is managed by GC.
- size parameter is an allocation size.

void nullcThrowError(const char* error, ...);

Function aborts NULLC program execution with a specified error (formatting as in printf function is supported).
- error parameter is a format string.
- ... extra arguments.

nullres nullcCallFunction(NULLCFuncPtr ptr, ...);

Call function using NULLC function pointer with optional arguments.
- ptr parameter is a pointer to NULLC function.
- ... arguments that will be passed into a function.

nullres nullcSetGlobal(const char* name, void* data);

Set global variable value.
- name parameter is a global variable name.
- data parameter is a pointer to new variable data.

void* nullcGetGlobal(const char* name);

Get global variable value (can be modified).
- name parameter is a global variable name.

nullres nullcGetFunction(const char* name, NULLCFuncPtr* func);

Get function pointer to use it in nullcCallFunction or to redirect it to some other function using nullcSetFunction.
- name parameter is the function name.
- func parameter is the pointer to NULLCFuncPtr struct that will receive pointer to function.

nullres nullcSetFunction(const char* name, NULLCFuncPtr func);

Set function using function pointer to redirect function to another one.
- name parameter is a global variable name.
- func parameter is the NULLCFuncPtr struct that contains pointer to source function.

nullres nullcIsStackPointer(void* ptr);

Function returns 1 if passed pointer points to NULLC stack; otherwise, the return value is 0.
- ptr parameter is a pointer to check.

nullres nullcIsManagedPointer(void* ptr);

Function returns 1 if passed pointer points to a memory managed by NULLC GC; otherwise, the return value is 0.
- ptr parameter is a pointer to check.

1.7 Special modules

Some modules heavily rely on internal NULLC structure, and because of that, they are initialized through NULLC interface.

int nullcInitTypeinfoModule();

Function initializes std.typeinfo module.

int nullcInitDynamicModule();

Function initializes std.dynamic module.

1.8 Extended functions

nullres nullcCompile(const char* code);

Function compiles the source code.
- code parameter is a pointer to a string with source code.

unsigned int nullcGetBytecode(char** bytecode);

Function is used to get bytecode for compiled source code.
Bytecode can be later linked with nullcLinkCode and executed.
- bytecode parameter is a pointer to pointer that will receive the bytecode. Memory must be freed by user.
Function returns the size of the bytecode.

unsigned int nullcGetBytecodeNoCache(char** bytecode);

This function is similar to nullcGetBytecode, with one exception:
After bytecode is retrieved by nullcGetBytecode, it is put into bytecode cache as "__last" module that can be imported later to implement advanced features like dynamic code evaluation (see std.dynamic).
If you wish that "__last" module bytecode is not changed, you should use this function.

void nullcClean();

Clean all accumulated bytecode from linker.

nullres nullcLinkCode(const char* bytecode);

Link new chunk of bytecode.
Type or function redefinition generates an error.
Global variables with the same name are handled silently.

void nullcSaveListing(const char* fileName);

This function saves disassembly of last compiled code into file.

void nullcTranslateToC(const char* fileName, const char* mainName);

This function saved analog of C++ code of last compiled code into file.
Function works only if NULLC_ENABLE_C_TRANSLATION is defined.

1.9 Debug functions


2. Interoperability with C code

2.1 Binding functions to NULLC

Only functions with cdecl calling convention can be binded to NULLC.

All basic numeric types are equal in representation to C++ types, except for "long" type which corresponds to 64bit "long long" type in C++.
NULLC reference types are simple pointers.
NULLC array with implicit size corresponds to NULLCArray struct.
NULLC "auto ref" type corresponds to NULLCRef struct.
NULLC function pointers correspond to NULLCFuncPtr struct.
NULLC "auto[]" type corresponds to NULLCAutoArray struct.

It is not recommended to pass NULLC classes and explicitly-sized arrays by value.

If you want to bind class member function, it must accept pointer to class type as the last parameter.

NULLC classes can be transformed into C structures by applying the same transformations used for function arguments.
A care must be taken for class member alignment: members are aligned to their default align values, but no more than 4 bytes (see Basic types topic in language reference).
So it is recommended to wrap C struct definition into a "#pragma pack(push, 4) ... #pragma pack(pop)".

When binding a class member function, add "class::" before the function name (that's two ':' instead of one you see in externally defined member function).

If NULLC_AUTOBINDING define is enabled, you can write NULLC_BIND before your functions and NULLC linker will bind them automatically.
This works only for plain functions and not for class member functions.
Under gcc, you must build NULLC with "-ldl" flag and build your application with "-rdynamic" and "-ldl" flags, in order for auto binding to work.