A minimalistic programming language written in C89.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
12 KiB

пре 6 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 6 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
  1. #pragma once
  2. #include "stddef.h"
  3. #include "stdint.h"
  4. /**
  5. * Represents the natively defined type of integers
  6. */
  7. #define INK_INTEGER 0
  8. /**
  9. * Represents the natively defined type of natively defined functions
  10. */
  11. #define INK_NATIVE_FUNCTION 1
  12. /**
  13. * Represents the natively defined type of functions defined from within ink
  14. */
  15. #define INK_FUNCTION 2
  16. /**
  17. * Represents the special coroutine state that means that it was disposed of and is ready for reuse
  18. */
  19. #define INK_ROUTINE_CAN_REUSE 32
  20. /**
  21. * Represents the special coroutine state that means that it was terminated without errors
  22. */
  23. #define INK_ROUTINE_SUCCESS 1
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. /**
  28. * Represents arbitrary values within ink
  29. */
  30. struct elem {
  31. int type;
  32. int value;
  33. };
  34. /**
  35. * Represents a stack-frame within the execution context
  36. */
  37. struct stack_frame {
  38. struct elem executing;
  39. int index;
  40. };
  41. /**
  42. * Represents a function within ink, defined in ink, using the homoiconic representation of ink
  43. */
  44. struct fn {
  45. char *name;
  46. struct elem *things;
  47. int size;
  48. };
  49. struct context;
  50. /**
  51. * Represents natively defined words within ink
  52. */
  53. struct native_fn {
  54. char *name;
  55. void (*value)(struct context *);
  56. };
  57. struct parse_error {
  58. int is_set;
  59. const char* error_message;
  60. size_t offset;
  61. };
  62. struct runtime_error {
  63. int is_set;
  64. const char* error_message;
  65. };
  66. /**
  67. * Represents the narrow execution context of a single thread of execution within ink.
  68. */
  69. struct ink_routine {
  70. int panic;
  71. struct parse_error parse_error;
  72. struct runtime_error runtime_error;
  73. struct elem *stack;
  74. int capacity;
  75. int top;
  76. struct stack_frame *function_stack;
  77. int function_stack_capacity;
  78. int function_stack_top;
  79. /**
  80. * This user data can be set to any value convenient for the user to track a state local to the routine that is executing
  81. */
  82. void *routine_userdata;
  83. };
  84. /**
  85. * Contains a list of element on which garbage collection is to not be performed
  86. */
  87. struct ink_collection_list {
  88. struct elem* elements;
  89. int count;
  90. };
  91. /**
  92. * Contains the data and metadata of an embedded element including the pointer to the element
  93. */
  94. struct element_slab {
  95. void* data;
  96. int is_protected;
  97. int uses;
  98. int in_use;
  99. };
  100. /**
  101. * Contains all the data for every element of any type and its garbage collection information.
  102. */
  103. struct ink_type {
  104. const char* name; /**< The name of the type */
  105. int element_size; /**< The size of individual elements of the type, 0 for int adjacent, negative for unmanaged size */
  106. struct element_slab* elements; /**< The elements that are still live */
  107. int elements_top; /**< The top of the elements list */
  108. int elements_capacity; /**< The allocated capacity of the elements list */
  109. void (*collect)(struct context*,void*); /**< The "destructor" of the object */
  110. struct ink_collection_list (*gc)(struct context*,void*); /**< A function that returns an in-interpreter allocated list of elem references within the object */
  111. };
  112. /**
  113. * Represents a complete execution context for the ink interpreter
  114. */
  115. struct context {
  116. int panic;
  117. void *(*inner_malloc)(struct context*,size_t);
  118. void *(*inner_realloc)(struct context*,void *, size_t);
  119. void (*inner_free)(struct context*,void *);
  120. void *(*malloc)(struct context*,size_t);
  121. void *(*realloc)(struct context*,void *, size_t);
  122. void (*free)(struct context*,void *);
  123. int (*putchar)(struct context*,int);
  124. struct ink_routine *routines;
  125. int routines_capacity;
  126. int routines_top;
  127. struct ink_type *types;
  128. int types_capacity;
  129. int types_top;
  130. /**
  131. * Contains the id of the routine that is currently being manipulated
  132. */
  133. int routine_current;
  134. struct native_fn *native_words;
  135. int native_words_capacity;
  136. int native_words_top;
  137. struct fn *words;
  138. int words_capacity;
  139. int words_top;
  140. char **lex_reserved_words;
  141. int lex_reserved_words_capacity;
  142. int lex_reserved_words_top;
  143. unsigned int steps;
  144. unsigned int collections;
  145. /**
  146. * Can be set to any data that is convenient to the user to track and use within natively defined functions
  147. */
  148. void *persistent_userdata;
  149. };
  150. /**
  151. * Creates a routine to execute within the context
  152. * @param ctx The context in which to create the routine
  153. * @warning Does not set the `routine_current` of the context to the newly created routine
  154. * @return either a negative error value or the id of the created routine
  155. */
  156. int ink_make_routine(struct context *ctx);
  157. /**
  158. * Cleans the targeted routine id data from the context
  159. * @param ctx The context to operate in
  160. * @param routine The id of the routine to destroy
  161. * @return 0 if nothing could or needed to be performed, 1 otherwise
  162. */
  163. int ink_kill_routine(struct context *ctx, int routine);
  164. /**
  165. * Declares and defines a native function within the context
  166. * @param ctx The context tpo operate in
  167. * @param name The name to give to the newly declared word
  168. * @param value A pointer to a valid word-function
  169. * @return a negative value in case of error, 0 otherwise
  170. */
  171. int ink_add_native(struct context *ctx, const char *name, void(*value)(struct context *));
  172. /**
  173. * Pushes a value on the current routine's value stack
  174. * @param ctx The context to manipulate
  175. * @param value The value to push
  176. * @return 0 on success, a negative value on failure
  177. */
  178. int ink_push(struct context *ctx, struct elem value);
  179. /**
  180. * Pushes a function on the execution stack of the current routine of the context
  181. * @param ctx The context to operate in
  182. * @param value the function that will be pushed. in the state one wants it to run from
  183. * @return 0 on success, a negative value on failure
  184. */
  185. int ink_push_fn(struct context *ctx, struct stack_frame value);
  186. /**
  187. * Create a context to execute routines
  188. * @param malloc the memory allocation function, with a signature similar to the standard malloc
  189. * @param realloc the memory allocation function, with a signature similar to the standard realloc
  190. * @param free the memory allocation function, with a signature similar to the standard free
  191. * @param putchar a function to print to the output character by character
  192. * @return a pointer to a context allocated within the malloc function itself.
  193. */
  194. struct context* ink_make_context(void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int));
  195. /**
  196. * Create a context to execute routines in-place
  197. * @param location a pointer to where the context should be built, userdata can be set in advance
  198. * @param malloc the memory allocation function, with a signature similar to the standard malloc
  199. * @param realloc the memory allocation function, with a signature similar to the standard realloc
  200. * @param free the memory allocation function, with a signature similar to the standard free
  201. * @param putchar a function to print to the output character by character
  202. * @return a pointer to a context allocated within the malloc function itself.
  203. */
  204. void ink_make_context_inplace(struct context* location, void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int));
  205. #ifndef NOSTDLIB
  206. /**
  207. * Creates a context that includes the standard library of ink, as well as uses the C standard library to operate
  208. * @return a pointer to a context allocated with malloc and with predefined functions added
  209. */
  210. struct context* ink_make_default_context(void);
  211. #endif
  212. /**
  213. * Steps the current routine by one execution step
  214. * @param pContext The context of the routine to advance
  215. * @return A negative value in case of error, 0 if execution is finished, a positive value if more steps are required to execute
  216. */
  217. int ink_step(struct context *pContext);
  218. /**
  219. * Examine the context to see if any routines can execute
  220. * @param pContext the context
  221. * @return 0 if no coroutines are available, 1 otherwise
  222. */
  223. int ink_can_run(struct context *pContext);
  224. /**
  225. * Step every routine that can be executed.
  226. * @param pContext The context, the `routine_current` value may be modified.
  227. * @return 0
  228. */
  229. int ink_step_everyone(struct context *pContext);
  230. /**
  231. * Compiles the code and starts a main routine to execute it
  232. * @param pContext The context to execute the code in
  233. * @param buffer The buffer that contains the source as a NULL terminated string
  234. * @return the routine that was created when compiling the code or -1 in case an error occured
  235. */
  236. int ink_compile(struct context *pContext, const char *buffer);
  237. /**
  238. * Includes the standard library in the specified context
  239. * @param ctx The context
  240. * @return 0
  241. */
  242. int ink_std_library(struct context *ctx);
  243. /**
  244. * Removes the top element of the function stack of the current routine of the specified context
  245. * @param ctx the context
  246. */
  247. void ink_pop_fn(struct context *ctx);
  248. /**
  249. * Removes the top element of the stack of the current routine of the specified context
  250. * @param ctx the context
  251. */
  252. void ink_pop(struct context *ctx);
  253. /**
  254. * Declares a new type that can be stored within the interpreter
  255. * @param ctx The context in which to add the file
  256. * @param type_name The name of the type we want to add
  257. * @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.
  258. * @param collect A "destructor" function for the data
  259. * @param gc A function that returns a list (allocated with the `inner_malloc`) of all the elements this element holds references to
  260. * @return if positive, a new type id, if negative an error value
  261. * @internal user defined type ids minimal value is 15, we keep the first 16 types as reserved, just like negative type ids
  262. */
  263. int ink_new_type(
  264. struct context* ctx,
  265. const char* type_name,
  266. int size,
  267. void (*collect)(struct context*,void*),
  268. struct ink_collection_list (*gc)(struct context*,void*)
  269. );
  270. /**
  271. *
  272. * @param ctx The context of the interpreter
  273. * @param ref The in-interpreter reference
  274. * @return A pointer to the created value or NULL if it can't be found or has a size of 0
  275. */
  276. void* ink_get_value(struct context* ctx, struct elem ref);
  277. /**
  278. * Builds a native type from the provided memory by copying it using memcpy
  279. * @param ctx The context in which we operate
  280. * @param type_id The type_id to use
  281. * @param ptr The pointer from which to copy
  282. * @return The in-interpreter reference of the newly created element
  283. */
  284. struct elem ink_make_native(struct context* ctx, int type_id, void* ptr);
  285. /**
  286. * Builds a transparent type from the provided pointer
  287. * @param ctx The context in which we operate
  288. * @param type_id The type_id to use
  289. * @param ptr The pointer
  290. * @return The in-interpreter reference of the newly created element
  291. */
  292. struct elem ink_make_transparent(struct context* ctx, int type_id, void* ptr);
  293. /**
  294. * Launch the mark and sweep garbage collection
  295. * @param ctx The context to clean
  296. */
  297. void ink_gc(struct context* ctx);
  298. /**
  299. * Cleans up coroutine stacks before reuse
  300. * @param ctx
  301. */
  302. void ink_clean_routines(struct context* ctx);
  303. /**
  304. * Obtains the type id from the declared name of the type
  305. * @param ctx The context where we want to detect the type
  306. * @param name The name of the type
  307. * @return the type id if it exists, -1 otherwise
  308. */
  309. int get_type_by_name(struct context* ctx, const char* name);
  310. /**
  311. * The internal representation of arrays in ink
  312. */
  313. struct ink_array {
  314. int top;
  315. int capacity;
  316. struct elem* elements;
  317. uint16_t flags;
  318. };
  319. /**
  320. * Pushes a value in an array. in case of failure, panics the routine
  321. *
  322. * @param ctx the working context
  323. * @param currentRoutine the routine that will panic
  324. * @param ary the array to be incremented
  325. * @param value the value to push
  326. */
  327. void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct ink_array* ary, struct elem value);
  328. #ifdef __cplusplus
  329. };
  330. #endif