#pragma once #include "stddef.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 *); }; /** * Represents the narrow execution context of a single thread of execution within ink. */ struct ink_routine { int panic; 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; }; /** * Represents a complete execution context for the ink interpreter */ struct context { int panic; 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; /** * 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; /** * 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(); #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 */ void ink_compile(struct context *pContext, 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); #ifdef __cplusplus }; #endif