A minimalistic programming language written in C89.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

370 行
11 KiB

6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
6 个月前
  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)(size_t);
  118. void *(*inner_realloc)(void *, size_t);
  119. void (*inner_free)(void *);
  120. void *(*malloc)(size_t);
  121. void *(*realloc)(void *, size_t);
  122. void (*free)(void *);
  123. int (*putchar)(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)(size_t), void *(*realloc)(void *, size_t), void(*free)(void *), int(*putchar)(int));
  195. #ifndef NOSTDLIB
  196. /**
  197. * Creates a context that includes the standard library of ink, as well as uses the C standard library to operate
  198. * @return a pointer to a context allocated with malloc and with predefined functions added
  199. */
  200. struct context* ink_make_default_context(void);
  201. #endif
  202. /**
  203. * Steps the current routine by one execution step
  204. * @param pContext The context of the routine to advance
  205. * @return A negative value in case of error, 0 if execution is finished, a positive value if more steps are required to execute
  206. */
  207. int ink_step(struct context *pContext);
  208. /**
  209. * Examine the context to see if any routines can execute
  210. * @param pContext the context
  211. * @return 0 if no coroutines are available, 1 otherwise
  212. */
  213. int ink_can_run(struct context *pContext);
  214. /**
  215. * Step every routine that can be executed.
  216. * @param pContext The context, the `routine_current` value may be modified.
  217. * @return 0
  218. */
  219. int ink_step_everyone(struct context *pContext);
  220. /**
  221. * Compiles the code and starts a main routine to execute it
  222. * @param pContext The context to execute the code in
  223. * @param buffer The buffer that contains the source as a NULL terminated string
  224. * @return the routine that was created when compiling the code or -1 in case an error occured
  225. */
  226. int ink_compile(struct context *pContext, const char *buffer);
  227. /**
  228. * Includes the standard library in the specified context
  229. * @param ctx The context
  230. * @return 0
  231. */
  232. int ink_std_library(struct context *ctx);
  233. /**
  234. * Removes the top element of the function stack of the current routine of the specified context
  235. * @param ctx the context
  236. */
  237. void ink_pop_fn(struct context *ctx);
  238. /**
  239. * Removes the top element of the stack of the current routine of the specified context
  240. * @param ctx the context
  241. */
  242. void ink_pop(struct context *ctx);
  243. /**
  244. * Declares a new type that can be stored within the interpreter
  245. * @param ctx The context in which to add the file
  246. * @param type_name The name of the type we want to add
  247. * @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.
  248. * @param collect A "destructor" function for the data
  249. * @param gc A function that returns a list (allocated with the `inner_malloc`) of all the elements this element holds references to
  250. * @return if positive, a new type id, if negative an error value
  251. * @internal user defined type ids minimal value is 15, we keep the first 16 types as reserved, just like negative type ids
  252. */
  253. int ink_new_type(
  254. struct context* ctx,
  255. const char* type_name,
  256. int size,
  257. void (*collect)(struct context*,void*),
  258. struct ink_collection_list (*gc)(struct context*,void*)
  259. );
  260. /**
  261. *
  262. * @param ctx The context of the interpreter
  263. * @param ref The in-interpreter reference
  264. * @return A pointer to the created value or NULL if it can't be found or has a size of 0
  265. */
  266. void* ink_get_value(struct context* ctx, struct elem ref);
  267. /**
  268. * Builds a native type from the provided memory by copying it using memcpy
  269. * @param ctx The context in which we operate
  270. * @param type_id The type_id to use
  271. * @param ptr The pointer from which to copy
  272. * @return The in-interpreter reference of the newly created element
  273. */
  274. struct elem ink_make_native(struct context* ctx, int type_id, void* ptr);
  275. /**
  276. * Builds a transparent type from the provided pointer
  277. * @param ctx The context in which we operate
  278. * @param type_id The type_id to use
  279. * @param ptr The pointer
  280. * @return The in-interpreter reference of the newly created element
  281. */
  282. struct elem ink_make_transparent(struct context* ctx, int type_id, void* ptr);
  283. /**
  284. * Launch the mark and sweep garbage collection
  285. * @param ctx The context to clean
  286. */
  287. void ink_gc(struct context* ctx);
  288. /**
  289. * Obtains the type id from the declared name of the type
  290. * @param ctx The context where we want to detect the type
  291. * @param name The name of the type
  292. * @return the type id if it exists, -1 otherwise
  293. */
  294. int get_type_by_name(struct context* ctx, const char* name);
  295. /**
  296. * The internal representation of arrays in ink
  297. */
  298. struct ink_array {
  299. int top;
  300. int capacity;
  301. struct elem* elements;
  302. uint16_t flags;
  303. };
  304. /**
  305. * Pushes a value in an array. in case of failure, panics the routine
  306. *
  307. * @param ctx the working context
  308. * @param currentRoutine the routine that will panic
  309. * @param ary the array to be incremented
  310. * @param value the value to push
  311. */
  312. void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct ink_array* ary, struct elem value);
  313. #ifdef __cplusplus
  314. };
  315. #endif