#pragma once
|
|
#include "stddef.h"
|
|
#include "stdint.h"
|
|
|
|
|
|
/**
|
|
* Represents the natively defined type of integers
|
|
*/
|
|
#define INK_INTEGER 0
|
|
|
|
/**
|
|
* Represents the natively defined type of natively defined functions
|
|
*/
|
|
#define INK_NATIVE_FUNCTION 1
|
|
|
|
/**
|
|
* Represents the natively defined type of functions defined from within ink
|
|
*/
|
|
#define INK_FUNCTION 2
|
|
|
|
/**
|
|
* Represents the special coroutine state that means that it was disposed of and is ready for reuse
|
|
*/
|
|
#define INK_ROUTINE_CAN_REUSE 32
|
|
|
|
/**
|
|
* Represents the special coroutine state that means that it was terminated without errors
|
|
*/
|
|
#define INK_ROUTINE_SUCCESS 1
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* Represents arbitrary values within ink
|
|
*/
|
|
struct elem {
|
|
int type;
|
|
int value;
|
|
};
|
|
|
|
/**
|
|
* Represents a stack-frame within the execution context
|
|
*/
|
|
struct stack_frame {
|
|
struct elem executing;
|
|
int index;
|
|
};
|
|
|
|
/**
|
|
* Represents a function within ink, defined in ink, using the homoiconic representation of ink
|
|
*/
|
|
struct fn {
|
|
char *name;
|
|
struct elem *things;
|
|
int size;
|
|
};
|
|
|
|
struct context;
|
|
|
|
/**
|
|
* Represents natively defined words within ink
|
|
*/
|
|
struct native_fn {
|
|
char *name;
|
|
void (*value)(struct context *);
|
|
};
|
|
|
|
struct parse_error {
|
|
int is_set;
|
|
const char* error_message;
|
|
size_t offset;
|
|
};
|
|
|
|
struct runtime_error {
|
|
int is_set;
|
|
const char* error_message;
|
|
};
|
|
|
|
/**
|
|
* Represents the narrow execution context of a single thread of execution within ink.
|
|
*/
|
|
struct ink_routine {
|
|
int panic;
|
|
|
|
struct parse_error parse_error;
|
|
struct runtime_error runtime_error;
|
|
|
|
struct elem *stack;
|
|
int capacity;
|
|
int top;
|
|
|
|
struct stack_frame *function_stack;
|
|
int function_stack_capacity;
|
|
int function_stack_top;
|
|
|
|
/**
|
|
* This user data can be set to any value convenient for the user to track a state local to the routine that is executing
|
|
*/
|
|
void *routine_userdata;
|
|
};
|
|
|
|
/**
|
|
* Contains a list of element on which garbage collection is to not be performed
|
|
*/
|
|
struct ink_collection_list {
|
|
struct elem* elements;
|
|
int count;
|
|
};
|
|
|
|
/**
|
|
* Contains the data and metadata of an embedded element including the pointer to the element
|
|
*/
|
|
struct element_slab {
|
|
void* data;
|
|
int is_protected;
|
|
int uses;
|
|
int in_use;
|
|
};
|
|
|
|
/**
|
|
* Contains all the data for every element of any type and its garbage collection information.
|
|
*/
|
|
struct ink_type {
|
|
const char* name; /**< The name of the type */
|
|
int element_size; /**< The size of individual elements of the type, 0 for int adjacent, negative for unmanaged size */
|
|
struct element_slab* elements; /**< The elements that are still live */
|
|
int elements_top; /**< The top of the elements list */
|
|
int elements_capacity; /**< The allocated capacity of the elements list */
|
|
void (*collect)(struct context*,void*); /**< The "destructor" of the object */
|
|
struct ink_collection_list (*gc)(struct context*,void*); /**< A function that returns an in-interpreter allocated list of elem references within the object */
|
|
};
|
|
|
|
/**
|
|
* Represents a complete execution context for the ink interpreter
|
|
*/
|
|
struct context {
|
|
int panic;
|
|
|
|
void *(*inner_malloc)(size_t);
|
|
void *(*inner_realloc)(void *, size_t);
|
|
void (*inner_free)(void *);
|
|
|
|
void *(*malloc)(size_t);
|
|
void *(*realloc)(void *, size_t);
|
|
void (*free)(void *);
|
|
int (*putchar)(int);
|
|
|
|
struct ink_routine *routines;
|
|
int routines_capacity;
|
|
int routines_top;
|
|
|
|
struct ink_type *types;
|
|
int types_capacity;
|
|
int types_top;
|
|
|
|
/**
|
|
* Contains the id of the routine that is currently being manipulated
|
|
*/
|
|
int routine_current;
|
|
|
|
struct native_fn *native_words;
|
|
int native_words_capacity;
|
|
int native_words_top;
|
|
|
|
struct fn *words;
|
|
int words_capacity;
|
|
int words_top;
|
|
|
|
char **lex_reserved_words;
|
|
int lex_reserved_words_capacity;
|
|
int lex_reserved_words_top;
|
|
|
|
unsigned int steps;
|
|
unsigned int collections;
|
|
|
|
/**
|
|
* Can be set to any data that is convenient to the user to track and use within natively defined functions
|
|
*/
|
|
void *persistent_userdata;
|
|
};
|
|
|
|
/**
|
|
* Creates a routine to execute within the context
|
|
* @param ctx The context in which to create the routine
|
|
* @warning Does not set the `routine_current` of the context to the newly created routine
|
|
* @return either a negative error value or the id of the created routine
|
|
*/
|
|
int ink_make_routine(struct context *ctx);
|
|
|
|
/**
|
|
* Cleans the targeted routine id data from the context
|
|
* @param ctx The context to operate in
|
|
* @param routine The id of the routine to destroy
|
|
* @return 0 if nothing could or needed to be performed, 1 otherwise
|
|
*/
|
|
int ink_kill_routine(struct context *ctx, int routine);
|
|
|
|
/**
|
|
* Declares and defines a native function within the context
|
|
* @param ctx The context tpo operate in
|
|
* @param name The name to give to the newly declared word
|
|
* @param value A pointer to a valid word-function
|
|
* @return a negative value in case of error, 0 otherwise
|
|
*/
|
|
int ink_add_native(struct context *ctx, const char *name, void(*value)(struct context *));
|
|
|
|
/**
|
|
* Pushes a value on the current routine's value stack
|
|
* @param ctx The context to manipulate
|
|
* @param value The value to push
|
|
* @return 0 on success, a negative value on failure
|
|
*/
|
|
int ink_push(struct context *ctx, struct elem value);
|
|
|
|
/**
|
|
* Pushes a function on the execution stack of the current routine of the context
|
|
* @param ctx The context to operate in
|
|
* @param value the function that will be pushed. in the state one wants it to run from
|
|
* @return 0 on success, a negative value on failure
|
|
*/
|
|
int ink_push_fn(struct context *ctx, struct stack_frame value);
|
|
|
|
/**
|
|
* Create a context to execute routines
|
|
* @param malloc the memory allocation function, with a signature similar to the standard malloc
|
|
* @param realloc the memory allocation function, with a signature similar to the standard realloc
|
|
* @param free the memory allocation function, with a signature similar to the standard free
|
|
* @param putchar a function to print to the output character by character
|
|
* @return a pointer to a context allocated within the malloc function itself.
|
|
*/
|
|
struct context* ink_make_context(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void(*free)(void *), int(*putchar)(int));
|
|
|
|
#ifndef NOSTDLIB
|
|
/**
|
|
* Creates a context that includes the standard library of ink, as well as uses the C standard library to operate
|
|
* @return a pointer to a context allocated with malloc and with predefined functions added
|
|
*/
|
|
struct context* ink_make_default_context(void);
|
|
#endif
|
|
|
|
/**
|
|
* Steps the current routine by one execution step
|
|
* @param pContext The context of the routine to advance
|
|
* @return A negative value in case of error, 0 if execution is finished, a positive value if more steps are required to execute
|
|
*/
|
|
int ink_step(struct context *pContext);
|
|
|
|
/**
|
|
* Examine the context to see if any routines can execute
|
|
* @param pContext the context
|
|
* @return 0 if no coroutines are available, 1 otherwise
|
|
*/
|
|
int ink_can_run(struct context *pContext);
|
|
|
|
/**
|
|
* Step every routine that can be executed.
|
|
* @param pContext The context, the `routine_current` value may be modified.
|
|
* @return 0
|
|
*/
|
|
int ink_step_everyone(struct context *pContext);
|
|
|
|
/**
|
|
* Compiles the code and starts a main routine to execute it
|
|
* @param pContext The context to execute the code in
|
|
* @param buffer The buffer that contains the source as a NULL terminated string
|
|
* @return the routine that was created when compiling the code or -1 in case an error occured
|
|
*/
|
|
int ink_compile(struct context *pContext, const char *buffer);
|
|
|
|
/**
|
|
* Includes the standard library in the specified context
|
|
* @param ctx The context
|
|
* @return 0
|
|
*/
|
|
int ink_std_library(struct context *ctx);
|
|
|
|
/**
|
|
* Removes the top element of the function stack of the current routine of the specified context
|
|
* @param ctx the context
|
|
*/
|
|
void ink_pop_fn(struct context *ctx);
|
|
|
|
/**
|
|
* Removes the top element of the stack of the current routine of the specified context
|
|
* @param ctx the context
|
|
*/
|
|
void ink_pop(struct context *ctx);
|
|
|
|
/**
|
|
* Declares a new type that can be stored within the interpreter
|
|
* @param ctx The context in which to add the file
|
|
* @param type_name The name of the type we want to add
|
|
* @param size The size in bytes of the type to add, size of 0 mean no size, in which case the type is adjacent to C int, negative size means that the memory is not managed by the interpreter.
|
|
* @param collect A "destructor" function for the data
|
|
* @param gc A function that returns a list (allocated with the `inner_malloc`) of all the elements this element holds references to
|
|
* @return if positive, a new type id, if negative an error value
|
|
* @internal user defined type ids minimal value is 15, we keep the first 16 types as reserved, just like negative type ids
|
|
*/
|
|
int ink_new_type(
|
|
struct context* ctx,
|
|
const char* type_name,
|
|
int size,
|
|
void (*collect)(struct context*,void*),
|
|
struct ink_collection_list (*gc)(struct context*,void*)
|
|
);
|
|
|
|
/**
|
|
*
|
|
* @param ctx The context of the interpreter
|
|
* @param ref The in-interpreter reference
|
|
* @return A pointer to the created value or NULL if it can't be found or has a size of 0
|
|
*/
|
|
void* ink_get_value(struct context* ctx, struct elem ref);
|
|
|
|
/**
|
|
* Builds a native type from the provided memory by copying it using memcpy
|
|
* @param ctx The context in which we operate
|
|
* @param type_id The type_id to use
|
|
* @param ptr The pointer from which to copy
|
|
* @return The in-interpreter reference of the newly created element
|
|
*/
|
|
struct elem ink_make_native(struct context* ctx, int type_id, void* ptr);
|
|
|
|
/**
|
|
* Builds a transparent type from the provided pointer
|
|
* @param ctx The context in which we operate
|
|
* @param type_id The type_id to use
|
|
* @param ptr The pointer
|
|
* @return The in-interpreter reference of the newly created element
|
|
*/
|
|
struct elem ink_make_transparent(struct context* ctx, int type_id, void* ptr);
|
|
|
|
/**
|
|
* Launch the mark and sweep garbage collection
|
|
* @param ctx The context to clean
|
|
*/
|
|
void ink_gc(struct context* ctx);
|
|
|
|
/**
|
|
* Cleans up coroutine stacks before reuse
|
|
* @param ctx
|
|
*/
|
|
void ink_clean_routines(struct context* ctx);
|
|
|
|
/**
|
|
* Obtains the type id from the declared name of the type
|
|
* @param ctx The context where we want to detect the type
|
|
* @param name The name of the type
|
|
* @return the type id if it exists, -1 otherwise
|
|
*/
|
|
int get_type_by_name(struct context* ctx, const char* name);
|
|
|
|
/**
|
|
* The internal representation of arrays in ink
|
|
*/
|
|
struct ink_array {
|
|
int top;
|
|
int capacity;
|
|
struct elem* elements;
|
|
uint16_t flags;
|
|
};
|
|
|
|
/**
|
|
* Pushes a value in an array. in case of failure, panics the routine
|
|
*
|
|
* @param ctx the working context
|
|
* @param currentRoutine the routine that will panic
|
|
* @param ary the array to be incremented
|
|
* @param value the value to push
|
|
*/
|
|
void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct ink_array* ary, struct elem value);
|
|
|
|
#ifdef __cplusplus
|
|
};
|
|
#endif
|