mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +00:00 
			
		
		
		
	Merge branch 'master' of github.com:janet-lang/janet
This commit is contained in:
		
							
								
								
									
										179
									
								
								src/core/array.c
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/core/array.c
									
									
									
									
									
								
							| @@ -122,14 +122,19 @@ Janet janet_array_peek(JanetArray *array) { | ||||
|  | ||||
| /* C Functions */ | ||||
|  | ||||
| static Janet cfun_array_new(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_new, | ||||
|               "(array/new capacity)", | ||||
|               "Creates a new empty array with a pre-allocated capacity. The same as " | ||||
|               "(array) but can be more efficient if the maximum size of an array is known.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     int32_t cap = janet_getinteger(argv, 0); | ||||
|     JanetArray *array = janet_array(cap); | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_new_filled(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_new_filled, | ||||
|               "(array/new-filled count &opt value)", | ||||
|               "Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     int32_t count = janet_getinteger(argv, 0); | ||||
|     Janet x = (argc == 2) ? argv[1] : janet_wrap_nil(); | ||||
| @@ -141,7 +146,10 @@ static Janet cfun_array_new_filled(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_fill(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_fill, | ||||
|               "(array/fill arr &opt value)", | ||||
|               "Replace all elements of an array with `value` (defaulting to nil) without changing the length of the array. " | ||||
|               "Returns the modified array.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     Janet x = (argc == 2) ? argv[1] : janet_wrap_nil(); | ||||
| @@ -151,19 +159,26 @@ static Janet cfun_array_fill(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_pop(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_pop, | ||||
|               "(array/pop arr)", | ||||
|               "Remove the last element of the array and return it. If the array is empty, will return nil. Modifies " | ||||
|               "the input array.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     return janet_array_pop(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_peek(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_peek, | ||||
|               "(array/peek arr)", | ||||
|               "Returns the last element of the array. Does not modify the array.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     return janet_array_peek(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_push(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_push, | ||||
|               "(array/push arr x)", | ||||
|               "Insert an element in the end of an array. Modifies the input array and returns it.") { | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     if (INT32_MAX - argc + 1 <= array->count) { | ||||
| @@ -176,7 +191,12 @@ static Janet cfun_array_push(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_ensure(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_ensure, | ||||
|               "(array/ensure arr capacity growth)", | ||||
|               "Ensures that the memory backing the array is large enough for `capacity` " | ||||
|               "items at the given rate of growth. Capacity and growth must be integers. " | ||||
|               "If the backing capacity is already enough, then this function does nothing. " | ||||
|               "Otherwise, the backing memory will be reallocated so that there is enough space.") { | ||||
|     janet_fixarity(argc, 3); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     int32_t newcount = janet_getinteger(argv, 1); | ||||
| @@ -186,7 +206,13 @@ static Janet cfun_array_ensure(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_slice(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_slice, | ||||
|               "(array/slice arrtup &opt start end)", | ||||
|               "Takes a slice of array or tuple from `start` to `end`. The range is half open, " | ||||
|               "[start, end). Indexes can also be negative, indicating indexing from the " | ||||
|               "end of the array. By default, `start` is 0 and `end` is the length of the array. " | ||||
|               "Note that index -1 is synonymous with index `(length arrtup)` to allow a full " | ||||
|               "negative slice range. Returns a new array.") { | ||||
|     JanetView view = janet_getindexed(argv, 0); | ||||
|     JanetRange range = janet_getslice(argc, argv); | ||||
|     JanetArray *array = janet_array(range.end - range.start); | ||||
| @@ -196,7 +222,12 @@ static Janet cfun_array_slice(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_concat(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_concat, | ||||
|               "(array/concat arr & parts)", | ||||
|               "Concatenates a variable number of arrays (and tuples) into the first argument, " | ||||
|               "which must be an array. If any of the parts are arrays or tuples, their elements will " | ||||
|               "be inserted into the array. Otherwise, each part in `parts` will be appended to `arr` in order. " | ||||
|               "Return the modified array `arr`.") { | ||||
|     int32_t i; | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
| @@ -219,7 +250,12 @@ static Janet cfun_array_concat(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_insert(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_insert, | ||||
|               "(array/insert arr at & xs)", | ||||
|               "Insert all `xs` into array `arr` at index `at`. `at` should be an integer between " | ||||
|               "0 and the length of the array. A negative value for `at` will index backwards from " | ||||
|               "the end of the array, such that inserting at -1 appends to the array. " | ||||
|               "Returns the array.") { | ||||
|     size_t chunksize, restsize; | ||||
|     janet_arity(argc, 2, -1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
| @@ -245,7 +281,12 @@ static Janet cfun_array_insert(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_remove(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_remove, | ||||
|               "(array/remove arr at &opt n)", | ||||
|               "Remove up to `n` elements starting at index `at` in array `arr`. `at` can index from " | ||||
|               "the end of the array with a negative index, and `n` must be a non-negative integer. " | ||||
|               "By default, `n` is 1. " | ||||
|               "Returns the array.") { | ||||
|     janet_arity(argc, 2, 3); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     int32_t at = janet_getinteger(argv, 1); | ||||
| @@ -270,7 +311,9 @@ static Janet cfun_array_remove(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_trim(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_trim, | ||||
|               "(array/trim arr)", | ||||
|               "Set the backing capacity of an array to its current length. Returns the modified array.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     if (array->count) { | ||||
| @@ -290,103 +333,33 @@ static Janet cfun_array_trim(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_array_clear(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_array_clear, | ||||
|               "(array/clear arr)", | ||||
|               "Empties an array, setting it's count to 0 but does not free the backing capacity. " | ||||
|               "Returns the modified array.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetArray *array = janet_getarray(argv, 0); | ||||
|     array->count = 0; | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static const JanetReg array_cfuns[] = { | ||||
|     { | ||||
|         "array/new", cfun_array_new, | ||||
|         JDOC("(array/new capacity)\n\n" | ||||
|              "Creates a new empty array with a pre-allocated capacity. The same as " | ||||
|              "(array) but can be more efficient if the maximum size of an array is known.") | ||||
|     }, | ||||
|     { | ||||
|         "array/new-filled", cfun_array_new_filled, | ||||
|         JDOC("(array/new-filled count &opt value)\n\n" | ||||
|              "Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/fill", cfun_array_fill, | ||||
|         JDOC("(array/fill arr &opt value)\n\n" | ||||
|              "Replace all elements of an array with `value` (defaulting to nil) without changing the length of the array. " | ||||
|              "Returns the modified array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/pop", cfun_array_pop, | ||||
|         JDOC("(array/pop arr)\n\n" | ||||
|              "Remove the last element of the array and return it. If the array is empty, will return nil. Modifies " | ||||
|              "the input array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/peek", cfun_array_peek, | ||||
|         JDOC("(array/peek arr)\n\n" | ||||
|              "Returns the last element of the array. Does not modify the array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/push", cfun_array_push, | ||||
|         JDOC("(array/push arr x)\n\n" | ||||
|              "Insert an element in the end of an array. Modifies the input array and returns it.") | ||||
|     }, | ||||
|     { | ||||
|         "array/ensure", cfun_array_ensure, | ||||
|         JDOC("(array/ensure arr capacity growth)\n\n" | ||||
|              "Ensures that the memory backing the array is large enough for `capacity` " | ||||
|              "items at the given rate of growth. Capacity and growth must be integers. " | ||||
|              "If the backing capacity is already enough, then this function does nothing. " | ||||
|              "Otherwise, the backing memory will be reallocated so that there is enough space.") | ||||
|     }, | ||||
|     { | ||||
|         "array/slice", cfun_array_slice, | ||||
|         JDOC("(array/slice arrtup &opt start end)\n\n" | ||||
|              "Takes a slice of array or tuple from `start` to `end`. The range is half open, " | ||||
|              "[start, end). Indexes can also be negative, indicating indexing from the " | ||||
|              "end of the array. By default, `start` is 0 and `end` is the length of the array. " | ||||
|              "Note that index -1 is synonymous with index `(length arrtup)` to allow a full " | ||||
|              "negative slice range. Returns a new array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/concat", cfun_array_concat, | ||||
|         JDOC("(array/concat arr & parts)\n\n" | ||||
|              "Concatenates a variable number of arrays (and tuples) into the first argument, " | ||||
|              "which must be an array. If any of the parts are arrays or tuples, their elements will " | ||||
|              "be inserted into the array. Otherwise, each part in `parts` will be appended to `arr` in order. " | ||||
|              "Return the modified array `arr`.") | ||||
|     }, | ||||
|     { | ||||
|         "array/insert", cfun_array_insert, | ||||
|         JDOC("(array/insert arr at & xs)\n\n" | ||||
|              "Insert all `xs` into array `arr` at index `at`. `at` should be an integer between " | ||||
|              "0 and the length of the array. A negative value for `at` will index backwards from " | ||||
|              "the end of the array, such that inserting at -1 appends to the array. " | ||||
|              "Returns the array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/remove", cfun_array_remove, | ||||
|         JDOC("(array/remove arr at &opt n)\n\n" | ||||
|              "Remove up to `n` elements starting at index `at` in array `arr`. `at` can index from " | ||||
|              "the end of the array with a negative index, and `n` must be a non-negative integer. " | ||||
|              "By default, `n` is 1. " | ||||
|              "Returns the array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/trim", cfun_array_trim, | ||||
|         JDOC("(array/trim arr)\n\n" | ||||
|              "Set the backing capacity of an array to its current length. Returns the modified array.") | ||||
|     }, | ||||
|     { | ||||
|         "array/clear", cfun_array_clear, | ||||
|         JDOC("(array/clear arr)\n\n" | ||||
|              "Empties an array, setting it's count to 0 but does not free the backing capacity. " | ||||
|              "Returns the modified array.") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* Load the array module */ | ||||
| void janet_lib_array(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, array_cfuns); | ||||
|     JanetRegExt array_cfuns[] = { | ||||
|         JANET_CORE_REG("array/new", cfun_array_new), | ||||
|         JANET_CORE_REG("array/new-filled", cfun_array_new_filled), | ||||
|         JANET_CORE_REG("array/fill", cfun_array_fill), | ||||
|         JANET_CORE_REG("array/pop", cfun_array_pop), | ||||
|         JANET_CORE_REG("array/peek", cfun_array_peek), | ||||
|         JANET_CORE_REG("array/push", cfun_array_push), | ||||
|         JANET_CORE_REG("array/ensure", cfun_array_ensure), | ||||
|         JANET_CORE_REG("array/slice", cfun_array_slice), | ||||
|         JANET_CORE_REG("array/concat", cfun_array_concat), | ||||
|         JANET_CORE_REG("array/insert", cfun_array_insert), | ||||
|         JANET_CORE_REG("array/remove", cfun_array_remove), | ||||
|         JANET_CORE_REG("array/trim", cfun_array_trim), | ||||
|         JANET_CORE_REG("array/clear", cfun_array_clear), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|     janet_core_cfuns_ext(env, NULL, array_cfuns); | ||||
| } | ||||
|   | ||||
| @@ -162,14 +162,20 @@ void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) { | ||||
|  | ||||
| /* C functions */ | ||||
|  | ||||
| static Janet cfun_buffer_new(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_new, | ||||
|               "(buffer/new capacity)", | ||||
|               "Creates a new, empty buffer with enough backing memory for capacity bytes. " | ||||
|               "Returns a new buffer of length 0.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     int32_t cap = janet_getinteger(argv, 0); | ||||
|     JanetBuffer *buffer = janet_buffer(cap); | ||||
|     return janet_wrap_buffer(buffer); | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_new_filled, | ||||
|               "(buffer/new-filled count &opt byte)", | ||||
|               "Creates a new buffer of length count filled with byte. By default, byte is 0. " | ||||
|               "Returns the new buffer.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     int32_t count = janet_getinteger(argv, 0); | ||||
|     int32_t byte = 0; | ||||
| @@ -183,7 +189,10 @@ static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_buffer(buffer); | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_fill(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_fill, | ||||
|               "(buffer/fill buffer &opt byte)", | ||||
|               "Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. " | ||||
|               "Returns the modified buffer.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
|     int32_t byte = 0; | ||||
| @@ -196,7 +205,10 @@ static Janet cfun_buffer_fill(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_trim(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_trim, | ||||
|               "(buffer/trim buffer)", | ||||
|               "Set the backing capacity of the buffer to the current length of the buffer. Returns the " | ||||
|               "modified buffer.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
|     if (buffer->count < buffer->capacity) { | ||||
| @@ -211,7 +223,10 @@ static Janet cfun_buffer_trim(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_u8(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_u8, | ||||
|               "(buffer/push-byte buffer & xs)", | ||||
|               "Append bytes to a buffer. Will expand the buffer as necessary. " | ||||
|               "Returns the modified buffer. Will throw an error if the buffer overflows.") { | ||||
|     int32_t i; | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
| @@ -221,7 +236,11 @@ static Janet cfun_buffer_u8(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_word(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_word, | ||||
|               "(buffer/push-word buffer & xs)", | ||||
|               "Append machine words to a buffer. The 4 bytes of the integer are appended " | ||||
|               "in twos complement, little endian order, unsigned for all x. Returns the modified buffer. Will " | ||||
|               "throw an error if the buffer overflows.") { | ||||
|     int32_t i; | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
| @@ -235,7 +254,12 @@ static Janet cfun_buffer_word(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_chars(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_chars, | ||||
|               "(buffer/push-string buffer & xs)", | ||||
|               "Push byte sequences onto the end of a buffer. " | ||||
|               "Will accept any of strings, keywords, symbols, and buffers. " | ||||
|               "Returns the modified buffer. " | ||||
|               "Will throw an error if the buffer overflows.") { | ||||
|     int32_t i; | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
| @@ -250,7 +274,13 @@ static Janet cfun_buffer_chars(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_push(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_push, | ||||
|               "(buffer/push buffer & xs)", | ||||
|               "Push both individual bytes and byte sequences to a buffer. For each x in xs, " | ||||
|               "push the byte if x is an integer, otherwise push the bytesequence to the buffer. " | ||||
|               "Thus, this function behaves like both `buffer/push-string` and `buffer/push-byte`. " | ||||
|               "Returns the modified buffer. " | ||||
|               "Will throw an error if the buffer overflows.") { | ||||
|     int32_t i; | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
| @@ -270,14 +300,19 @@ static Janet cfun_buffer_push(int32_t argc, Janet *argv) { | ||||
| } | ||||
|  | ||||
|  | ||||
| static Janet cfun_buffer_clear(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_clear, | ||||
|               "(buffer/clear buffer)", | ||||
|               "Sets the size of a buffer to 0 and empties it. The buffer retains " | ||||
|               "its memory so it can be efficiently refilled. Returns the modified buffer.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
|     buffer->count = 0; | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_popn(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_popn, | ||||
|               "(buffer/popn buffer n)", | ||||
|               "Removes the last n bytes from the buffer. Returns the modified buffer.") { | ||||
|     janet_fixarity(argc, 2); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
|     int32_t n = janet_getinteger(argv, 1); | ||||
| @@ -290,7 +325,12 @@ static Janet cfun_buffer_popn(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_slice(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_slice, | ||||
|               "(buffer/slice bytes &opt start end)", | ||||
|               "Takes a slice of a byte sequence from start to end. The range is half open, " | ||||
|               "[start, end). Indexes can also be negative, indicating indexing from the end of the " | ||||
|               "end of the array. By default, start is 0 and end is the length of the buffer. " | ||||
|               "Returns a new buffer.") { | ||||
|     JanetByteView view = janet_getbytes(argv, 0); | ||||
|     JanetRange range = janet_getslice(argc, argv); | ||||
|     JanetBuffer *buffer = janet_buffer(range.end - range.start); | ||||
| @@ -314,7 +354,9 @@ static void bitloc(int32_t argc, Janet *argv, JanetBuffer **b, int32_t *index, i | ||||
|     *bit = which_bit; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_bitset, | ||||
|               "(buffer/bit-set buffer index)", | ||||
|               "Sets the bit at the given bit-index. Returns the buffer.") { | ||||
|     int bit; | ||||
|     int32_t index; | ||||
|     JanetBuffer *buffer; | ||||
| @@ -323,7 +365,9 @@ static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_bitclear, | ||||
|               "(buffer/bit-clear buffer index)", | ||||
|               "Clears the bit at the given bit-index. Returns the buffer.") { | ||||
|     int bit; | ||||
|     int32_t index; | ||||
|     JanetBuffer *buffer; | ||||
| @@ -332,7 +376,9 @@ static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_bitget, | ||||
|               "(buffer/bit buffer index)", | ||||
|               "Gets the bit at the given bit-index. Returns true if the bit is set, false if not.") { | ||||
|     int bit; | ||||
|     int32_t index; | ||||
|     JanetBuffer *buffer; | ||||
| @@ -340,7 +386,9 @@ static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_boolean(buffer->data[index] & (1 << bit)); | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_bittoggle, | ||||
|               "(buffer/bit-toggle buffer index)", | ||||
|               "Toggles the bit at the given bit index in buffer. Returns the buffer.") { | ||||
|     int bit; | ||||
|     int32_t index; | ||||
|     JanetBuffer *buffer; | ||||
| @@ -349,7 +397,11 @@ static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_blit(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_blit, | ||||
|               "(buffer/blit dest src &opt dest-start src-start src-end)", | ||||
|               "Insert the contents of src into dest. Can optionally take indices that " | ||||
|               "indicate which part of src to copy into which part of dest. Indices can be " | ||||
|               "negative to index from the end of src or dest. Returns dest.") { | ||||
|     janet_arity(argc, 2, 5); | ||||
|     JanetBuffer *dest = janet_getbuffer(argv, 0); | ||||
|     JanetByteView src = janet_getbytes(argv, 1); | ||||
| @@ -386,7 +438,10 @@ static Janet cfun_buffer_blit(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_buffer_format(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_buffer_format, | ||||
|               "(buffer/format buffer format & args)", | ||||
|               "Snprintf like functionality for printing values into a buffer. Returns " | ||||
|               " the modified buffer.") { | ||||
|     janet_arity(argc, 2, -1); | ||||
|     JanetBuffer *buffer = janet_getbuffer(argv, 0); | ||||
|     const char *strfrmt = (const char *) janet_getstring(argv, 1); | ||||
| @@ -394,116 +449,26 @@ static Janet cfun_buffer_format(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static const JanetReg buffer_cfuns[] = { | ||||
|     { | ||||
|         "buffer/new", cfun_buffer_new, | ||||
|         JDOC("(buffer/new capacity)\n\n" | ||||
|              "Creates a new, empty buffer with enough backing memory for capacity bytes. " | ||||
|              "Returns a new buffer of length 0.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/new-filled", cfun_buffer_new_filled, | ||||
|         JDOC("(buffer/new-filled count &opt byte)\n\n" | ||||
|              "Creates a new buffer of length count filled with byte. By default, byte is 0. " | ||||
|              "Returns the new buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/fill", cfun_buffer_fill, | ||||
|         JDOC("(buffer/fill buffer &opt byte)\n\n" | ||||
|              "Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. " | ||||
|              "Returns the modified buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/trim", cfun_buffer_trim, | ||||
|         JDOC("(buffer/trim buffer)\n\n" | ||||
|              "Set the backing capacity of the buffer to the current length of the buffer. Returns the " | ||||
|              "modified buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/push-byte", cfun_buffer_u8, | ||||
|         JDOC("(buffer/push-byte buffer & xs)\n\n" | ||||
|              "Append bytes to a buffer. Will expand the buffer as necessary. " | ||||
|              "Returns the modified buffer. Will throw an error if the buffer overflows.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/push-word", cfun_buffer_word, | ||||
|         JDOC("(buffer/push-word buffer & xs)\n\n" | ||||
|              "Append machine words to a buffer. The 4 bytes of the integer are appended " | ||||
|              "in twos complement, little endian order, unsigned for all x. Returns the modified buffer. Will " | ||||
|              "throw an error if the buffer overflows.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/push-string", cfun_buffer_chars, | ||||
|         JDOC("(buffer/push-string buffer & xs)\n\n" | ||||
|              "Push byte sequences onto the end of a buffer. " | ||||
|              "Will accept any of strings, keywords, symbols, and buffers. " | ||||
|              "Returns the modified buffer. " | ||||
|              "Will throw an error if the buffer overflows.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/push", cfun_buffer_push, | ||||
|         JDOC("(buffer/push buffer & xs)\n\n" | ||||
|              "Push both individual bytes and byte sequences to a buffer. For each x in xs, " | ||||
|              "push the byte if x is an integer, otherwise push the bytesequence to the buffer. " | ||||
|              "Thus, this function behaves like both `buffer/push-string` and `buffer/push-byte`. " | ||||
|              "Returns the modified buffer. " | ||||
|              "Will throw an error if the buffer overflows.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/popn", cfun_buffer_popn, | ||||
|         JDOC("(buffer/popn buffer n)\n\n" | ||||
|              "Removes the last n bytes from the buffer. Returns the modified buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/clear", cfun_buffer_clear, | ||||
|         JDOC("(buffer/clear buffer)\n\n" | ||||
|              "Sets the size of a buffer to 0 and empties it. The buffer retains " | ||||
|              "its memory so it can be efficiently refilled. Returns the modified buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/slice", cfun_buffer_slice, | ||||
|         JDOC("(buffer/slice bytes &opt start end)\n\n" | ||||
|              "Takes a slice of a byte sequence from start to end. The range is half open, " | ||||
|              "[start, end). Indexes can also be negative, indicating indexing from the end of the " | ||||
|              "end of the array. By default, start is 0 and end is the length of the buffer. " | ||||
|              "Returns a new buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/bit-set", cfun_buffer_bitset, | ||||
|         JDOC("(buffer/bit-set buffer index)\n\n" | ||||
|              "Sets the bit at the given bit-index. Returns the buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/bit-clear", cfun_buffer_bitclear, | ||||
|         JDOC("(buffer/bit-clear buffer index)\n\n" | ||||
|              "Clears the bit at the given bit-index. Returns the buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/bit", cfun_buffer_bitget, | ||||
|         JDOC("(buffer/bit buffer index)\n\n" | ||||
|              "Gets the bit at the given bit-index. Returns true if the bit is set, false if not.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/bit-toggle", cfun_buffer_bittoggle, | ||||
|         JDOC("(buffer/bit-toggle buffer index)\n\n" | ||||
|              "Toggles the bit at the given bit index in buffer. Returns the buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/blit", cfun_buffer_blit, | ||||
|         JDOC("(buffer/blit dest src &opt dest-start src-start src-end)\n\n" | ||||
|              "Insert the contents of src into dest. Can optionally take indices that " | ||||
|              "indicate which part of src to copy into which part of dest. Indices can be " | ||||
|              "negative to index from the end of src or dest. Returns dest.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer/format", cfun_buffer_format, | ||||
|         JDOC("(buffer/format buffer format & args)\n\n" | ||||
|              "Snprintf like functionality for printing values into a buffer. Returns " | ||||
|              " the modified buffer.") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| void janet_lib_buffer(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, buffer_cfuns); | ||||
|     JanetRegExt buffer_cfuns[] = { | ||||
|         JANET_CORE_REG("buffer/new", cfun_buffer_new), | ||||
|         JANET_CORE_REG("buffer/new-filled", cfun_buffer_new_filled), | ||||
|         JANET_CORE_REG("buffer/fill", cfun_buffer_fill), | ||||
|         JANET_CORE_REG("buffer/trim", cfun_buffer_trim), | ||||
|         JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8), | ||||
|         JANET_CORE_REG("buffer/push-word", cfun_buffer_word), | ||||
|         JANET_CORE_REG("buffer/push-string", cfun_buffer_chars), | ||||
|         JANET_CORE_REG("buffer/push", cfun_buffer_push), | ||||
|         JANET_CORE_REG("buffer/popn", cfun_buffer_popn), | ||||
|         JANET_CORE_REG("buffer/clear", cfun_buffer_clear), | ||||
|         JANET_CORE_REG("buffer/slice", cfun_buffer_slice), | ||||
|         JANET_CORE_REG("buffer/bit-set", cfun_buffer_bitset), | ||||
|         JANET_CORE_REG("buffer/bit-clear", cfun_buffer_bitclear), | ||||
|         JANET_CORE_REG("buffer/bit", cfun_buffer_bitget), | ||||
|         JANET_CORE_REG("buffer/bit-toggle", cfun_buffer_bittoggle), | ||||
|         JANET_CORE_REG("buffer/blit", cfun_buffer_blit), | ||||
|         JANET_CORE_REG("buffer/format", cfun_buffer_format), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|     janet_core_cfuns_ext(env, NULL, buffer_cfuns); | ||||
| } | ||||
|   | ||||
| @@ -143,7 +143,18 @@ static int is_path_sep(char c) { | ||||
| } | ||||
|  | ||||
| /* Used for module system. */ | ||||
| static Janet janet_core_expand_path(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_expand_path, | ||||
|               "(module/expand-path path template)", | ||||
|               "Expands a path template as found in `module/paths` for `module/find`. " | ||||
|               "This takes in a path (the argument to require) and a template string, " | ||||
|               "to expand the path to a path that can be " | ||||
|               "used for importing files. The replacements are as follows:\n\n" | ||||
|               "* :all: -- the value of path verbatim\n\n" | ||||
|               "* :cur: -- the current file, or (dyn :current-file)\n\n" | ||||
|               "* :dir: -- the directory containing the current file\n\n" | ||||
|               "* :name: -- the name component of path, with extension if given\n\n" | ||||
|               "* :native: -- the extension used to load natives, .so or .dll\n\n" | ||||
|               "* :sys: -- the system path, or (dyn :syspath)") { | ||||
|     janet_fixarity(argc, 2); | ||||
|     const char *input = janet_getcstring(argv, 0); | ||||
|     const char *template = janet_getcstring(argv, 1); | ||||
| @@ -266,7 +277,9 @@ static Janet janet_core_expand_path(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_buffer(out); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_dyn(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_dyn, | ||||
|               "(dyn key &opt default)", | ||||
|               "Get a dynamic binding. Returns the default value (or nil) if no binding found.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     Janet value; | ||||
|     if (janet_vm.fiber->env) { | ||||
| @@ -280,7 +293,9 @@ static Janet janet_core_dyn(int32_t argc, Janet *argv) { | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| static Janet janet_core_setdyn(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_setdyn, | ||||
|               "(setdyn key value)", | ||||
|               "Set a dynamic binding. Returns value.") { | ||||
|     janet_fixarity(argc, 2); | ||||
|     if (!janet_vm.fiber->env) { | ||||
|         janet_vm.fiber->env = janet_table(2); | ||||
| @@ -289,7 +304,13 @@ static Janet janet_core_setdyn(int32_t argc, Janet *argv) { | ||||
|     return argv[1]; | ||||
| } | ||||
|  | ||||
| static Janet janet_core_native(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_native, | ||||
|               "(native path &opt env)", | ||||
|               "Load a native module from the given path. The path " | ||||
|               "must be an absolute or relative path on the file system, and is " | ||||
|               "usually a .so file on Unix systems, and a .dll file on Windows. " | ||||
|               "Returns an environment table that contains functions and other values " | ||||
|               "from the native module.") { | ||||
|     JanetModule init; | ||||
|     janet_arity(argc, 1, 2); | ||||
|     const uint8_t *path = janet_getstring(argv, 0); | ||||
| @@ -309,47 +330,72 @@ static Janet janet_core_native(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_table(env); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_describe(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_describe, | ||||
|               "(describe x)", | ||||
|               "Returns a string that is a human-readable description of a value x.") { | ||||
|     JanetBuffer *b = janet_buffer(0); | ||||
|     for (int32_t i = 0; i < argc; ++i) | ||||
|         janet_description_b(b, argv[i]); | ||||
|     return janet_stringv(b->data, b->count); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_string(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_string, | ||||
|               "(string & xs)", | ||||
|               "Creates a string by concatenating the elements of `xs` together. If an " | ||||
|               "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|               "Returns the new string.") { | ||||
|     JanetBuffer *b = janet_buffer(0); | ||||
|     for (int32_t i = 0; i < argc; ++i) | ||||
|         janet_to_string_b(b, argv[i]); | ||||
|     return janet_stringv(b->data, b->count); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_symbol(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_symbol, | ||||
|               "(symbol & xs)", | ||||
|               "Creates a symbol by concatenating the elements of `xs` together. If an " | ||||
|               "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|               "Returns the new symbol.") { | ||||
|     JanetBuffer *b = janet_buffer(0); | ||||
|     for (int32_t i = 0; i < argc; ++i) | ||||
|         janet_to_string_b(b, argv[i]); | ||||
|     return janet_symbolv(b->data, b->count); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_keyword(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_keyword, | ||||
|               "(keyword & xs)", | ||||
|               "Creates a keyword by concatenating the elements of `xs` together. If an " | ||||
|               "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|               "Returns the new keyword.") { | ||||
|     JanetBuffer *b = janet_buffer(0); | ||||
|     for (int32_t i = 0; i < argc; ++i) | ||||
|         janet_to_string_b(b, argv[i]); | ||||
|     return janet_keywordv(b->data, b->count); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_buffer(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_buffer, | ||||
|               "(buffer & xs)", | ||||
|               "Creates a buffer by concatenating the elements of `xs` together. If an " | ||||
|               "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|               "Returns the new buffer.") { | ||||
|     JanetBuffer *b = janet_buffer(0); | ||||
|     for (int32_t i = 0; i < argc; ++i) | ||||
|         janet_to_string_b(b, argv[i]); | ||||
|     return janet_wrap_buffer(b); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_is_abstract(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_is_abstract, | ||||
|               "(abstract? x)", | ||||
|               "Check if x is an abstract type.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     return janet_wrap_boolean(janet_checktype(argv[0], JANET_ABSTRACT)); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_scannumber(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_scannumber, | ||||
|               "(scan-number str)", | ||||
|               "Parse a number from a byte sequence an return that number, either and integer " | ||||
|               "or a real. The number " | ||||
|               "must be in the same format as numbers in janet source code. Will return nil " | ||||
|               "on an invalid number.") { | ||||
|     double number; | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetByteView view = janet_getbytes(argv, 0); | ||||
| @@ -358,18 +404,24 @@ static Janet janet_core_scannumber(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_number(number); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_tuple(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_tuple, | ||||
|               "(tuple & items)", | ||||
|               "Creates a new tuple that contains items. Returns the new tuple.") { | ||||
|     return janet_wrap_tuple(janet_tuple_n(argv, argc)); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_array(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_array, | ||||
|               "(array & items)", | ||||
|               "Create a new array that contains items. Returns the new array.") { | ||||
|     JanetArray *array = janet_array(argc); | ||||
|     array->count = argc; | ||||
|     safe_memcpy(array->data, argv, argc * sizeof(Janet)); | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_slice(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_slice, | ||||
|               "(slice x &opt start end)", | ||||
|               "Extract a sub-range of an indexed data structure or byte sequence.") { | ||||
|     JanetRange range; | ||||
|     JanetByteView bview; | ||||
|     JanetView iview; | ||||
| @@ -384,7 +436,12 @@ static Janet janet_core_slice(int32_t argc, Janet *argv) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static Janet janet_core_table(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_table, | ||||
|               "(table & kvs)", | ||||
|               "Creates a new table from a variadic number of keys and values. " | ||||
|               "kvs is a sequence k1, v1, k2, v2, k3, v3, ... If kvs has " | ||||
|               "an odd number of elements, an error will be thrown. Returns the " | ||||
|               "new table.") { | ||||
|     int32_t i; | ||||
|     if (argc & 1) | ||||
|         janet_panic("expected even number of arguments"); | ||||
| @@ -395,7 +452,12 @@ static Janet janet_core_table(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_table(table); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_struct(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_struct, | ||||
|               "(struct & kvs)", | ||||
|               "Create a new struct from a sequence of key value pairs. " | ||||
|               "kvs is a sequence k1, v1, k2, v2, k3, v3, ... If kvs has " | ||||
|               "an odd number of elements, an error will be thrown. Returns the " | ||||
|               "new struct.") { | ||||
|     int32_t i; | ||||
|     if (argc & 1) | ||||
|         janet_panic("expected even number of arguments"); | ||||
| @@ -406,20 +468,30 @@ static Janet janet_core_struct(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_struct(janet_struct_end(st)); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_gensym(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_gensym, | ||||
|               "(gensym)", | ||||
|               "Returns a new symbol that is unique across the runtime. This means it " | ||||
|               "will not collide with any already created symbols during compilation, so " | ||||
|               "it can be used in macros to generate automatic bindings.") { | ||||
|     (void) argv; | ||||
|     janet_fixarity(argc, 0); | ||||
|     return janet_wrap_symbol(janet_symbol_gen()); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_gccollect(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_gccollect, | ||||
|               "(gccollect)", | ||||
|               "Run garbage collection. You should probably not call this manually.") { | ||||
|     (void) argv; | ||||
|     (void) argc; | ||||
|     janet_collect(); | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_gcsetinterval(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_gcsetinterval, | ||||
|               "(gcsetinterval interval)", | ||||
|               "Set an integer number of bytes to allocate before running garbage collection. " | ||||
|               "Low values for interval will be slower but use less memory. " | ||||
|               "High values will be faster but use more memory.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     size_t s = janet_getsize(argv, 0); | ||||
|     /* limit interval to 48 bits */ | ||||
| @@ -432,13 +504,33 @@ static Janet janet_core_gcsetinterval(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_gcinterval(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_gcinterval, | ||||
|               "(gcinterval)", | ||||
|               "Returns the integer number of bytes to allocate before running an iteration " | ||||
|               "of garbage collection.") { | ||||
|     (void) argv; | ||||
|     janet_fixarity(argc, 0); | ||||
|     return janet_wrap_number((double) janet_vm.gc_interval); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_type(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_type, | ||||
|               "(type x)", | ||||
|               "Returns the type of `x` as a keyword. `x` is one of:\n\n" | ||||
|               "* :nil\n\n" | ||||
|               "* :boolean\n\n" | ||||
|               "* :number\n\n" | ||||
|               "* :array\n\n" | ||||
|               "* :tuple\n\n" | ||||
|               "* :table\n\n" | ||||
|               "* :struct\n\n" | ||||
|               "* :string\n\n" | ||||
|               "* :buffer\n\n" | ||||
|               "* :symbol\n\n" | ||||
|               "* :keyword\n\n" | ||||
|               "* :function\n\n" | ||||
|               "* :cfunction\n\n" | ||||
|               "* :fiber\n\n" | ||||
|               "or another keyword for an abstract type.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetType t = janet_type(argv[0]); | ||||
|     if (t == JANET_ABSTRACT) { | ||||
| @@ -448,12 +540,21 @@ static Janet janet_core_type(int32_t argc, Janet *argv) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static Janet janet_core_hash(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_hash, | ||||
|               "(hash value)", | ||||
|               "Gets a hash for any value. The hash is an integer can be used " | ||||
|               "as a cheap hash function for all values. If two values are strictly equal, " | ||||
|               "then they will have the same hash value.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     return janet_wrap_number(janet_hash(argv[0])); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_getline(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_getline, | ||||
|               "(getline &opt prompt buf env)", | ||||
|               "Reads a line of input into a buffer, including the newline character, using a prompt. " | ||||
|               "An optional environment table can be provided for auto-complete. " | ||||
|               "Returns the modified buffer. " | ||||
|               "Use this function to implement a simple interface for a terminal program.") { | ||||
|     FILE *in = janet_dynfile("in", stdin); | ||||
|     FILE *out = janet_dynfile("out", stdout); | ||||
|     janet_arity(argc, 0, 3); | ||||
| @@ -478,21 +579,27 @@ static Janet janet_core_getline(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_buffer(buf); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_trace(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_trace, | ||||
|               "(trace func)", | ||||
|               "Enable tracing on a function. Returns the function.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetFunction *func = janet_getfunction(argv, 0); | ||||
|     func->gc.flags |= JANET_FUNCFLAG_TRACE; | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet janet_core_untrace(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_untrace, | ||||
|               "(untrace func)", | ||||
|               "Disables tracing on a function. Returns the function.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetFunction *func = janet_getfunction(argv, 0); | ||||
|     func->gc.flags &= ~JANET_FUNCFLAG_TRACE; | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet janet_core_check_int(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_check_int, | ||||
|               "(int? x)", | ||||
|               "Check if x can be exactly represented as a 32 bit signed two's complement integer.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     if (!janet_checktype(argv[0], JANET_NUMBER)) goto ret_false; | ||||
|     double num = janet_unwrap_number(argv[0]); | ||||
| @@ -501,7 +608,9 @@ ret_false: | ||||
|     return janet_wrap_false(); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_check_nat(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_check_nat, | ||||
|               "(nat? x)", | ||||
|               "Check if x can be exactly represented as a non-negative 32 bit signed two's complement integer.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     if (!janet_checktype(argv[0], JANET_NUMBER)) goto ret_false; | ||||
|     double num = janet_unwrap_number(argv[0]); | ||||
| @@ -510,7 +619,9 @@ ret_false: | ||||
|     return janet_wrap_false(); | ||||
| } | ||||
|  | ||||
| static Janet janet_core_signal(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_core_signal, | ||||
|               "(signal what x)", | ||||
|               "Raise a signal with payload x. ") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     int sig; | ||||
|     if (janet_checkint(argv[0])) { | ||||
| @@ -535,205 +646,6 @@ static Janet janet_core_signal(int32_t argc, Janet *argv) { | ||||
|     janet_signalv(sig, payload); | ||||
| } | ||||
|  | ||||
| static const JanetReg corelib_cfuns[] = { | ||||
|     { | ||||
|         "native", janet_core_native, | ||||
|         JDOC("(native path &opt env)\n\n" | ||||
|              "Load a native module from the given path. The path " | ||||
|              "must be an absolute or relative path on the file system, and is " | ||||
|              "usually a .so file on Unix systems, and a .dll file on Windows. " | ||||
|              "Returns an environment table that contains functions and other values " | ||||
|              "from the native module.") | ||||
|     }, | ||||
|     { | ||||
|         "describe", janet_core_describe, | ||||
|         JDOC("(describe x)\n\n" | ||||
|              "Returns a string that is a human-readable description of a value x.") | ||||
|     }, | ||||
|     { | ||||
|         "string", janet_core_string, | ||||
|         JDOC("(string & xs)\n\n" | ||||
|              "Creates a string by concatenating the elements of `xs` together. If an " | ||||
|              "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|              "Returns the new string.") | ||||
|     }, | ||||
|     { | ||||
|         "symbol", janet_core_symbol, | ||||
|         JDOC("(symbol & xs)\n\n" | ||||
|              "Creates a symbol by concatenating the elements of `xs` together. If an " | ||||
|              "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|              "Returns the new symbol.") | ||||
|     }, | ||||
|     { | ||||
|         "keyword", janet_core_keyword, | ||||
|         JDOC("(keyword & xs)\n\n" | ||||
|              "Creates a keyword by concatenating the elements of `xs` together. If an " | ||||
|              "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|              "Returns the new keyword.") | ||||
|     }, | ||||
|     { | ||||
|         "buffer", janet_core_buffer, | ||||
|         JDOC("(buffer & xs)\n\n" | ||||
|              "Creates a buffer by concatenating the elements of `xs` together. If an " | ||||
|              "element is not a byte sequence, it is converted to bytes via `describe`. " | ||||
|              "Returns the new buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "abstract?", janet_core_is_abstract, | ||||
|         JDOC("(abstract? x)\n\n" | ||||
|              "Check if x is an abstract type.") | ||||
|     }, | ||||
|     { | ||||
|         "table", janet_core_table, | ||||
|         JDOC("(table & kvs)\n\n" | ||||
|              "Creates a new table from a variadic number of keys and values. " | ||||
|              "kvs is a sequence k1, v1, k2, v2, k3, v3, ... If kvs has " | ||||
|              "an odd number of elements, an error will be thrown. Returns the " | ||||
|              "new table.") | ||||
|     }, | ||||
|     { | ||||
|         "array", janet_core_array, | ||||
|         JDOC("(array & items)\n\n" | ||||
|              "Create a new array that contains items. Returns the new array.") | ||||
|     }, | ||||
|     { | ||||
|         "scan-number", janet_core_scannumber, | ||||
|         JDOC("(scan-number str)\n\n" | ||||
|              "Parse a number from a byte sequence an return that number, either and integer " | ||||
|              "or a real. The number " | ||||
|              "must be in the same format as numbers in janet source code. Will return nil " | ||||
|              "on an invalid number.") | ||||
|     }, | ||||
|     { | ||||
|         "tuple", janet_core_tuple, | ||||
|         JDOC("(tuple & items)\n\n" | ||||
|              "Creates a new tuple that contains items. Returns the new tuple.") | ||||
|     }, | ||||
|     { | ||||
|         "struct", janet_core_struct, | ||||
|         JDOC("(struct & kvs)\n\n" | ||||
|              "Create a new struct from a sequence of key value pairs. " | ||||
|              "kvs is a sequence k1, v1, k2, v2, k3, v3, ... If kvs has " | ||||
|              "an odd number of elements, an error will be thrown. Returns the " | ||||
|              "new struct.") | ||||
|     }, | ||||
|     { | ||||
|         "gensym", janet_core_gensym, | ||||
|         JDOC("(gensym)\n\n" | ||||
|              "Returns a new symbol that is unique across the runtime. This means it " | ||||
|              "will not collide with any already created symbols during compilation, so " | ||||
|              "it can be used in macros to generate automatic bindings.") | ||||
|     }, | ||||
|     { | ||||
|         "gccollect", janet_core_gccollect, | ||||
|         JDOC("(gccollect)\n\n" | ||||
|              "Run garbage collection. You should probably not call this manually.") | ||||
|     }, | ||||
|     { | ||||
|         "gcsetinterval", janet_core_gcsetinterval, | ||||
|         JDOC("(gcsetinterval interval)\n\n" | ||||
|              "Set an integer number of bytes to allocate before running garbage collection. " | ||||
|              "Low values for interval will be slower but use less memory. " | ||||
|              "High values will be faster but use more memory.") | ||||
|     }, | ||||
|     { | ||||
|         "gcinterval", janet_core_gcinterval, | ||||
|         JDOC("(gcinterval)\n\n" | ||||
|              "Returns the integer number of bytes to allocate before running an iteration " | ||||
|              "of garbage collection.") | ||||
|     }, | ||||
|     { | ||||
|         "type", janet_core_type, | ||||
|         JDOC("(type x)\n\n" | ||||
|              "Returns the type of `x` as a keyword. `x` is one of:\n\n" | ||||
|              "* :nil\n\n" | ||||
|              "* :boolean\n\n" | ||||
|              "* :number\n\n" | ||||
|              "* :array\n\n" | ||||
|              "* :tuple\n\n" | ||||
|              "* :table\n\n" | ||||
|              "* :struct\n\n" | ||||
|              "* :string\n\n" | ||||
|              "* :buffer\n\n" | ||||
|              "* :symbol\n\n" | ||||
|              "* :keyword\n\n" | ||||
|              "* :function\n\n" | ||||
|              "* :cfunction\n\n" | ||||
|              "* :fiber\n\n" | ||||
|              "or another keyword for an abstract type.") | ||||
|     }, | ||||
|     { | ||||
|         "hash", janet_core_hash, | ||||
|         JDOC("(hash value)\n\n" | ||||
|              "Gets a hash for any value. The hash is an integer can be used " | ||||
|              "as a cheap hash function for all values. If two values are strictly equal, " | ||||
|              "then they will have the same hash value.") | ||||
|     }, | ||||
|     { | ||||
|         "getline", janet_core_getline, | ||||
|         JDOC("(getline &opt prompt buf env)\n\n" | ||||
|              "Reads a line of input into a buffer, including the newline character, using a prompt. " | ||||
|              "An optional environment table can be provided for auto-complete. " | ||||
|              "Returns the modified buffer. " | ||||
|              "Use this function to implement a simple interface for a terminal program.") | ||||
|     }, | ||||
|     { | ||||
|         "dyn", janet_core_dyn, | ||||
|         JDOC("(dyn key &opt default)\n\n" | ||||
|              "Get a dynamic binding. Returns the default value (or nil) if no binding found.") | ||||
|     }, | ||||
|     { | ||||
|         "setdyn", janet_core_setdyn, | ||||
|         JDOC("(setdyn key value)\n\n" | ||||
|              "Set a dynamic binding. Returns value.") | ||||
|     }, | ||||
|     { | ||||
|         "trace", janet_core_trace, | ||||
|         JDOC("(trace func)\n\n" | ||||
|              "Enable tracing on a function. Returns the function.") | ||||
|     }, | ||||
|     { | ||||
|         "untrace", janet_core_untrace, | ||||
|         JDOC("(untrace func)\n\n" | ||||
|              "Disables tracing on a function. Returns the function.") | ||||
|     }, | ||||
|     { | ||||
|         "module/expand-path", janet_core_expand_path, | ||||
|         JDOC("(module/expand-path path template)\n\n" | ||||
|              "Expands a path template as found in `module/paths` for `module/find`. " | ||||
|              "This takes in a path (the argument to require) and a template string, " | ||||
|              "to expand the path to a path that can be " | ||||
|              "used for importing files. The replacements are as follows:\n\n" | ||||
|              "* :all: -- the value of path verbatim\n\n" | ||||
|              "* :cur: -- the current file, or (dyn :current-file)\n\n" | ||||
|              "* :dir: -- the directory containing the current file\n\n" | ||||
|              "* :name: -- the name component of path, with extension if given\n\n" | ||||
|              "* :native: -- the extension used to load natives, .so or .dll\n\n" | ||||
|              "* :sys: -- the system path, or (dyn :syspath)") | ||||
|     }, | ||||
|     { | ||||
|         "int?", janet_core_check_int, | ||||
|         JDOC("(int? x)\n\n" | ||||
|              "Check if x can be exactly represented as a 32 bit signed two's complement integer.") | ||||
|     }, | ||||
|     { | ||||
|         "nat?", janet_core_check_nat, | ||||
|         JDOC("(nat? x)\n\n" | ||||
|              "Check if x can be exactly represented as a non-negative 32 bit signed two's complement integer.") | ||||
|     }, | ||||
|     { | ||||
|         "slice", janet_core_slice, | ||||
|         JDOC("(slice x &opt start end)\n\n" | ||||
|              "Extract a sub-range of an indexed data structure or byte sequence.") | ||||
|     }, | ||||
|     { | ||||
|         "signal", janet_core_signal, | ||||
|         JDOC("(signal what x)\n\n" | ||||
|              "Raise a signal with payload x. ") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| #ifdef JANET_BOOTSTRAP | ||||
|  | ||||
| /* Utility for inline assembly */ | ||||
| @@ -1006,7 +918,38 @@ static const uint32_t cmp_asm[] = { | ||||
|  */ | ||||
|  | ||||
| static void janet_load_libs(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, corelib_cfuns); | ||||
|     JanetRegExt corelib_cfuns[] = { | ||||
|         JANET_CORE_REG("native", janet_core_native), | ||||
|         JANET_CORE_REG("describe", janet_core_describe), | ||||
|         JANET_CORE_REG("string", janet_core_string), | ||||
|         JANET_CORE_REG("symbol", janet_core_symbol), | ||||
|         JANET_CORE_REG("keyword", janet_core_keyword), | ||||
|         JANET_CORE_REG("buffer", janet_core_buffer), | ||||
|         JANET_CORE_REG("abstract?", janet_core_is_abstract), | ||||
|         JANET_CORE_REG("table", janet_core_table), | ||||
|         JANET_CORE_REG("array", janet_core_array), | ||||
|         JANET_CORE_REG("scan-number", janet_core_scannumber), | ||||
|         JANET_CORE_REG("tuple", janet_core_tuple), | ||||
|         JANET_CORE_REG("struct", janet_core_struct), | ||||
|         JANET_CORE_REG("gensym", janet_core_gensym), | ||||
|         JANET_CORE_REG("gccollect", janet_core_gccollect), | ||||
|         JANET_CORE_REG("gcsetinterval", janet_core_gcsetinterval), | ||||
|         JANET_CORE_REG("gcinterval", janet_core_gcinterval), | ||||
|         JANET_CORE_REG("type", janet_core_type), | ||||
|         JANET_CORE_REG("hash", janet_core_hash), | ||||
|         JANET_CORE_REG("getline", janet_core_getline), | ||||
|         JANET_CORE_REG("dyn", janet_core_dyn), | ||||
|         JANET_CORE_REG("setdyn", janet_core_setdyn), | ||||
|         JANET_CORE_REG("trace", janet_core_trace), | ||||
|         JANET_CORE_REG("untrace", janet_core_untrace), | ||||
|         JANET_CORE_REG("module/expand-path", janet_core_expand_path), | ||||
|         JANET_CORE_REG("int?", janet_core_check_int), | ||||
|         JANET_CORE_REG("nat?", janet_core_check_nat), | ||||
|         JANET_CORE_REG("slice", janet_core_slice), | ||||
|         JANET_CORE_REG("signal", janet_core_signal), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|     janet_core_cfuns_ext(env, NULL, corelib_cfuns); | ||||
|     janet_lib_io(env); | ||||
|     janet_lib_math(env); | ||||
|     janet_lib_array(env); | ||||
|   | ||||
							
								
								
									
										157
									
								
								src/core/debug.c
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								src/core/debug.c
									
									
									
									
									
								
							| @@ -195,7 +195,13 @@ static void helper_find_fun(int32_t argc, Janet *argv, JanetFuncDef **def, int32 | ||||
|     *bytecode_offset = offset; | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_break(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_break, | ||||
|               "(debug/break source line col)", | ||||
|               "Sets a breakpoint in `source` at a given line and column. " | ||||
|               "Will throw an error if the breakpoint location " | ||||
|               "cannot be found. For example\n\n" | ||||
|               "\t(debug/break \"core.janet\" 10 4)\n\n" | ||||
|               "will set a breakpoint at line 10, 4th column of the file core.janet.") { | ||||
|     JanetFuncDef *def; | ||||
|     int32_t offset; | ||||
|     helper_find(argc, argv, &def, &offset); | ||||
| @@ -203,7 +209,11 @@ static Janet cfun_debug_break(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_unbreak, | ||||
|               "(debug/unbreak source line column)", | ||||
|               "Remove a breakpoint with a source key at a given line and column. " | ||||
|               "Will throw an error if the breakpoint " | ||||
|               "cannot be found.") { | ||||
|     JanetFuncDef *def; | ||||
|     int32_t offset = 0; | ||||
|     helper_find(argc, argv, &def, &offset); | ||||
| @@ -211,7 +221,11 @@ static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_fbreak, | ||||
|               "(debug/fbreak fun &opt pc)", | ||||
|               "Set a breakpoint in a given function. pc is an optional offset, which " | ||||
|               "is in bytecode instructions. fun is a function value. Will throw an error " | ||||
|               "if the offset is too large or negative.") { | ||||
|     JanetFuncDef *def; | ||||
|     int32_t offset = 0; | ||||
|     helper_find_fun(argc, argv, &def, &offset); | ||||
| @@ -219,7 +233,9 @@ static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_unfbreak, | ||||
|               "(debug/unfbreak fun &opt pc)", | ||||
|               "Unset a breakpoint set with debug/fbreak.") { | ||||
|     JanetFuncDef *def; | ||||
|     int32_t offset; | ||||
|     helper_find_fun(argc, argv, &def, &offset); | ||||
| @@ -227,7 +243,12 @@ static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_lineage(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_lineage, | ||||
|               "(debug/lineage fib)", | ||||
|               "Returns an array of all child fibers from a root fiber. This function " | ||||
|               "is useful when a fiber signals or errors to an ancestor fiber. Using this function, " | ||||
|               "the fiber handling the error can see which fiber raised the signal. This function should " | ||||
|               "be used mostly for debugging purposes.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     JanetArray *array = janet_array(0); | ||||
| @@ -284,7 +305,21 @@ static Janet doframe(JanetStackFrame *frame) { | ||||
|     return janet_wrap_table(t); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_stack(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_stack, | ||||
|               "(debug/stack fib)", | ||||
|               "Gets information about the stack as an array of tables. Each table " | ||||
|               "in the array contains information about a stack frame. The top-most, current " | ||||
|               "stack frame is the first table in the array, and the bottom-most stack frame " | ||||
|               "is the last value. Each stack frame contains some of the following attributes:\n\n" | ||||
|               "* :c - true if the stack frame is a c function invocation\n\n" | ||||
|               "* :column - the current source column of the stack frame\n\n" | ||||
|               "* :function - the function that the stack frame represents\n\n" | ||||
|               "* :line - the current source line of the stack frame\n\n" | ||||
|               "* :name - the human-friendly name of the function\n\n" | ||||
|               "* :pc - integer indicating the location of the program counter\n\n" | ||||
|               "* :source - string with the file path or other identifier for the source code\n\n" | ||||
|               "* :slots - array of all values in each slot\n\n" | ||||
|               "* :tail - boolean indicating a tail call") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     JanetArray *array = janet_array(0); | ||||
| @@ -300,7 +335,11 @@ static Janet cfun_debug_stack(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_stacktrace, | ||||
|               "(debug/stacktrace fiber &opt err)", | ||||
|               "Prints a nice looking stacktrace for a fiber. Can optionally provide " | ||||
|               "an error value to print the stack trace with. If `err` is nil or not " | ||||
|               "provided, will skip the error line. Returns the fiber.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     Janet x = argc == 1 ? janet_wrap_nil() : argv[1]; | ||||
| @@ -308,7 +347,11 @@ static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_argstack(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_argstack, | ||||
|               "(debug/arg-stack fiber)", | ||||
|               "Gets all values currently on the fiber's argument stack. Normally, " | ||||
|               "this should be empty unless the fiber signals while pushing arguments " | ||||
|               "to make a function call. Returns a new array.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     JanetArray *array = janet_array(fiber->stacktop - fiber->stackstart); | ||||
| @@ -317,7 +360,11 @@ static Janet cfun_debug_argstack(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Janet cfun_debug_step(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_debug_step, | ||||
|               "(debug/step fiber &opt x)", | ||||
|               "Run a fiber for one virtual instruction of the Janet machine. Can optionally " | ||||
|               "pass in a value that will be passed as the resuming value. Returns the signal value, " | ||||
|               "which will usually be nil, as breakpoints raise nil signals.") { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     Janet out = janet_wrap_nil(); | ||||
| @@ -325,85 +372,19 @@ static Janet cfun_debug_step(int32_t argc, Janet *argv) { | ||||
|     return out; | ||||
| } | ||||
|  | ||||
| static const JanetReg debug_cfuns[] = { | ||||
|     { | ||||
|         "debug/break", cfun_debug_break, | ||||
|         JDOC("(debug/break source line col)\n\n" | ||||
|              "Sets a breakpoint in `source` at a given line and column. " | ||||
|              "Will throw an error if the breakpoint location " | ||||
|              "cannot be found. For example\n\n" | ||||
|              "\t(debug/break \"core.janet\" 10 4)\n\n" | ||||
|              "will set a breakpoint at line 10, 4th column of the file core.janet.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/unbreak", cfun_debug_unbreak, | ||||
|         JDOC("(debug/unbreak source line column)\n\n" | ||||
|              "Remove a breakpoint with a source key at a given line and column. " | ||||
|              "Will throw an error if the breakpoint " | ||||
|              "cannot be found.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/fbreak", cfun_debug_fbreak, | ||||
|         JDOC("(debug/fbreak fun &opt pc)\n\n" | ||||
|              "Set a breakpoint in a given function. pc is an optional offset, which " | ||||
|              "is in bytecode instructions. fun is a function value. Will throw an error " | ||||
|              "if the offset is too large or negative.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/unfbreak", cfun_debug_unfbreak, | ||||
|         JDOC("(debug/unfbreak fun &opt pc)\n\n" | ||||
|              "Unset a breakpoint set with debug/fbreak.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/arg-stack", cfun_debug_argstack, | ||||
|         JDOC("(debug/arg-stack fiber)\n\n" | ||||
|              "Gets all values currently on the fiber's argument stack. Normally, " | ||||
|              "this should be empty unless the fiber signals while pushing arguments " | ||||
|              "to make a function call. Returns a new array.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/stack", cfun_debug_stack, | ||||
|         JDOC("(debug/stack fib)\n\n" | ||||
|              "Gets information about the stack as an array of tables. Each table " | ||||
|              "in the array contains information about a stack frame. The top-most, current " | ||||
|              "stack frame is the first table in the array, and the bottom-most stack frame " | ||||
|              "is the last value. Each stack frame contains some of the following attributes:\n\n" | ||||
|              "* :c - true if the stack frame is a c function invocation\n\n" | ||||
|              "* :column - the current source column of the stack frame\n\n" | ||||
|              "* :function - the function that the stack frame represents\n\n" | ||||
|              "* :line - the current source line of the stack frame\n\n" | ||||
|              "* :name - the human-friendly name of the function\n\n" | ||||
|              "* :pc - integer indicating the location of the program counter\n\n" | ||||
|              "* :source - string with the file path or other identifier for the source code\n\n" | ||||
|              "* :slots - array of all values in each slot\n\n" | ||||
|              "* :tail - boolean indicating a tail call") | ||||
|     }, | ||||
|     { | ||||
|         "debug/stacktrace", cfun_debug_stacktrace, | ||||
|         JDOC("(debug/stacktrace fiber &opt err)\n\n" | ||||
|              "Prints a nice looking stacktrace for a fiber. Can optionally provide " | ||||
|              "an error value to print the stack trace with. If `err` is nil or not " | ||||
|              "provided, will skip the error line. Returns the fiber.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/lineage", cfun_debug_lineage, | ||||
|         JDOC("(debug/lineage fib)\n\n" | ||||
|              "Returns an array of all child fibers from a root fiber. This function " | ||||
|              "is useful when a fiber signals or errors to an ancestor fiber. Using this function, " | ||||
|              "the fiber handling the error can see which fiber raised the signal. This function should " | ||||
|              "be used mostly for debugging purposes.") | ||||
|     }, | ||||
|     { | ||||
|         "debug/step", cfun_debug_step, | ||||
|         JDOC("(debug/step fiber &opt x)\n\n" | ||||
|              "Run a fiber for one virtual instruction of the Janet machine. Can optionally " | ||||
|              "pass in a value that will be passed as the resuming value. Returns the signal value, " | ||||
|              "which will usually be nil, as breakpoints raise nil signals.") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* Module entry point */ | ||||
| void janet_lib_debug(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, debug_cfuns); | ||||
|     JanetRegExt debug_cfuns[] = { | ||||
|         JANET_CORE_REG("debug/break", cfun_debug_break), | ||||
|         JANET_CORE_REG("debug/unbreak", cfun_debug_unbreak), | ||||
|         JANET_CORE_REG("debug/fbreak", cfun_debug_fbreak), | ||||
|         JANET_CORE_REG("debug/unfbreak", cfun_debug_unfbreak), | ||||
|         JANET_CORE_REG("debug/arg-stack", cfun_debug_argstack), | ||||
|         JANET_CORE_REG("debug/stack", cfun_debug_stack), | ||||
|         JANET_CORE_REG("debug/stacktrace", cfun_debug_stacktrace), | ||||
|         JANET_CORE_REG("debug/lineage", cfun_debug_lineage), | ||||
|         JANET_CORE_REG("debug/step", cfun_debug_step), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|     janet_core_cfuns_ext(env, NULL, debug_cfuns); | ||||
| } | ||||
|   | ||||
							
								
								
									
										257
									
								
								src/core/ev.c
									
									
									
									
									
								
							
							
						
						
									
										257
									
								
								src/core/ev.c
									
									
									
									
									
								
							| @@ -721,7 +721,10 @@ static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice) | ||||
|  | ||||
| /* Channel Methods */ | ||||
|  | ||||
| static Janet cfun_channel_push(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_push, | ||||
|         "(ev/give channel value)", | ||||
|         "Write a value to a channel, suspending the current fiber if the channel is full." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 2); | ||||
|     JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); | ||||
|     if (janet_channel_push(channel, argv[1], 0)) { | ||||
| @@ -730,7 +733,10 @@ static Janet cfun_channel_push(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_pop(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_pop,  | ||||
|         "(ev/take channel)", | ||||
|         "Read from a channel, suspending the current fiber if no value is available." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); | ||||
|     Janet item; | ||||
| @@ -740,7 +746,13 @@ static Janet cfun_channel_pop(int32_t argc, Janet *argv) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_choice(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_choice, | ||||
|         "(ev/select & clauses)", | ||||
|         "Block until the first of several channel operations occur. Returns a tuple of the form [:give chan] or [:take chan x], where " | ||||
|         "a :give tuple is the result of a write and :take tuple is the result of a write. Each clause must be either a channel (for " | ||||
|         "a channel take operation) or a tuple [channel x] for a channel give operation. Operations are tried in order, such that the first " | ||||
|         "clauses will take precedence over later clauses." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, -1); | ||||
|     int32_t len; | ||||
|     const Janet *data; | ||||
| @@ -782,19 +794,28 @@ static Janet cfun_channel_choice(int32_t argc, Janet *argv) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_full(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_full, | ||||
|         "(ev/full channel)", | ||||
|         "Check if a channel is full or not." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); | ||||
|     return janet_wrap_boolean(janet_q_count(&channel->items) >= channel->limit); | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_capacity(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_capacity, | ||||
|         "(ev/capacity channel)", | ||||
|         "Get the number of items a channel will store before blocking writers." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); | ||||
|     return janet_wrap_integer(channel->limit); | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_count(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_count, | ||||
|         "(ev/count channel)", | ||||
|         "Get the number of items currently waiting in a channel." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); | ||||
|     return janet_wrap_integer(janet_q_count(&channel->items)); | ||||
| @@ -810,12 +831,19 @@ static void fisher_yates_args(int32_t argc, Janet *argv) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_rchoice(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_rchoice, | ||||
|         "(ev/rselect & clauses)", | ||||
|         "Similar to ev/select, but will try clauses in a random order for fairness." | ||||
|         ) { | ||||
|     fisher_yates_args(argc, argv); | ||||
|     return cfun_channel_choice(argc, argv); | ||||
| } | ||||
|  | ||||
| static Janet cfun_channel_new(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_channel_new,  | ||||
|         "(ev/chan &opt capacity)",  | ||||
|         "Create a new channel. capacity is the number of values to queue before " | ||||
|         "blocking writers, defaults to 0 if not provided. Returns a new channel." | ||||
|         ) { | ||||
|     janet_arity(argc, 0, 1); | ||||
|     int32_t limit = janet_optnat(argv, argc, 0, 0); | ||||
|     JanetChannel *channel = janet_abstract(&ChannelAT, sizeof(JanetChannel)); | ||||
| @@ -2116,7 +2144,14 @@ error: | ||||
|  | ||||
| /* C functions */ | ||||
|  | ||||
| static Janet cfun_ev_go(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_go, | ||||
|         "(ev/go fiber &opt value supervisor)", | ||||
|         "Put a fiber on the event loop to be resumed later. Optionally pass " | ||||
|         "a value to resume with, otherwise resumes with nil. Returns the fiber. " | ||||
|         "An optional `core/channel` can be provided as well as a supervisor. When various " | ||||
|         "events occur in the newly scheduled fiber, an event will be pushed to the supervisor. " | ||||
|         "If not provided, the new fiber will inherit the current supervisor." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, 3); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     Janet value = argc >= 2 ? argv[1] : janet_wrap_nil(); | ||||
| @@ -2168,7 +2203,14 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { | ||||
|     return args; | ||||
| } | ||||
|  | ||||
| static Janet cfun_ev_thread(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_thread,  | ||||
|         "(ev/thread fiber &opt value flags)",  | ||||
|         "Resume a (copy of a) `fiber` in a new operating system thread, optionally passing `value` " | ||||
|         "to resume with. " | ||||
|         "Unlike `ev/go`, this function will suspend the current fiber until the thread is complete. " | ||||
|         "If you want to run the thread without waiting for a result, pass the `:n` flag to return nil immediately. " | ||||
|         "Otherwise, returns (a copy of) the final result from the fiber on the new thread." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, 3); | ||||
|     janet_getfiber(argv, 0); | ||||
|     Janet value = argc >= 2 ? argv[1] : janet_wrap_nil(); | ||||
| @@ -2200,7 +2242,12 @@ static Janet cfun_ev_thread(int32_t argc, Janet *argv) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static Janet cfun_ev_give_supervisor(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_give_supervisor,  | ||||
|         "(ev/give-supervisor tag & payload)",  | ||||
|         "Send a message to the current supervior channel if there is one. The message will be a " | ||||
|         "tuple of all of the arguments combined into a single message, where the first element is tag. " | ||||
|         "By convention, tag should be a keyword indicating the type of message. Returns nil." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, -1); | ||||
|     JanetChannel *chan = janet_vm.root_fiber->supervisor_channel; | ||||
|     if (NULL != chan) { | ||||
| @@ -2222,13 +2269,22 @@ JANET_NO_RETURN void janet_sleep_await(double sec) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| static Janet cfun_ev_sleep(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_sleep, | ||||
|         "(ev/sleep sec)",  | ||||
|         "Suspend the current fiber for sec seconds without blocking the event loop." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     double sec = janet_getnumber(argv, 0); | ||||
|     janet_sleep_await(sec); | ||||
| } | ||||
|  | ||||
| static Janet cfun_ev_deadline(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_deadline,  | ||||
|         "(ev/deadline sec &opt tocancel tocheck)", | ||||
|         "Set a deadline for a fiber `tocheck`. If `tocheck` is not finished after `sec` seconds, " | ||||
|         "`tocancel` will be canceled as with `ev/cancel`. " | ||||
|         "If `tocancel` and `tocheck` are not given, they default to `(fiber/root)` and " | ||||
|         "`(fiber/current)` respectively. Returns `tocancel`." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, 3); | ||||
|     double sec = janet_getnumber(argv, 0); | ||||
|     JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber); | ||||
| @@ -2243,7 +2299,10 @@ static Janet cfun_ev_deadline(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_fiber(tocancel); | ||||
| } | ||||
|  | ||||
| static Janet cfun_ev_cancel(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_ev_cancel, | ||||
|         "(ev/cancel fiber err)", | ||||
|         "Cancel a suspended fiber in the event loop. Differs from cancel in that it returns the canceled fiber immediately" | ||||
|         ) { | ||||
|     janet_fixarity(argc, 2); | ||||
|     JanetFiber *fiber = janet_getfiber(argv, 0); | ||||
|     Janet err = argv[1]; | ||||
| @@ -2251,14 +2310,25 @@ static Janet cfun_ev_cancel(int32_t argc, Janet *argv) { | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| Janet janet_cfun_stream_close(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_cfun_stream_close,  | ||||
|         "(ev/close stream)", | ||||
|         "Close a stream. This should be the same as calling (:close stream) for all streams." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type); | ||||
|     janet_stream_close(stream); | ||||
|     return argv[0]; | ||||
| } | ||||
|  | ||||
| Janet janet_cfun_stream_read(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_cfun_stream_read, | ||||
|         "(ev/read stream n &opt buffer timeout)", | ||||
|         "Read up to n bytes into a buffer asynchronously from a stream. `n` can also be the keyword " | ||||
|         "`:all` to read into the buffer until end of stream. " | ||||
|         "Optionally provide a buffer to write into " | ||||
|         "as well as a timeout in seconds after which to cancel the operation and raise an error. " | ||||
|         "Returns the buffer if the read was successful or nil if end-of-stream reached. Will raise an " | ||||
|         "error if there are problems with the IO operation." | ||||
|         ) { | ||||
|     janet_arity(argc, 2, 4); | ||||
|     JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type); | ||||
|     janet_stream_flags(stream, JANET_STREAM_READABLE); | ||||
| @@ -2275,7 +2345,11 @@ Janet janet_cfun_stream_read(int32_t argc, Janet *argv) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| Janet janet_cfun_stream_chunk(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_cfun_stream_chunk,  | ||||
|         "(ev/chunk stream n &opt buffer timeout)", | ||||
|         "Same as ev/read, but will not return early if less than n bytes are available. If an end of " | ||||
|         "stream is reached, will also return early with the collected bytes." | ||||
|         ) { | ||||
|     janet_arity(argc, 2, 4); | ||||
|     JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type); | ||||
|     janet_stream_flags(stream, JANET_STREAM_READABLE); | ||||
| @@ -2287,7 +2361,11 @@ Janet janet_cfun_stream_chunk(int32_t argc, Janet *argv) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| Janet janet_cfun_stream_write(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_cfun_stream_write,  | ||||
|         "(ev/write stream data &opt timeout)",  | ||||
|         "Write data to a stream, suspending the current fiber until the write " | ||||
|         "completes. Takes an optional timeout in seconds, after which will return nil. " | ||||
|         "Returns nil, or raises an error if the write failed.") { | ||||
|     janet_arity(argc, 2, 3); | ||||
|     JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type); | ||||
|     janet_stream_flags(stream, JANET_STREAM_WRITABLE); | ||||
| @@ -2303,127 +2381,30 @@ Janet janet_cfun_stream_write(int32_t argc, Janet *argv) { | ||||
|     janet_await(); | ||||
| } | ||||
|  | ||||
| static const JanetReg ev_cfuns[] = { | ||||
|     { | ||||
|         "ev/go", cfun_ev_go, | ||||
|         JDOC("(ev/go fiber &opt value supervisor)\n\n" | ||||
|              "Put a fiber on the event loop to be resumed later. Optionally pass " | ||||
|              "a value to resume with, otherwise resumes with nil. Returns the fiber. " | ||||
|              "An optional `core/channel` can be provided as well as a supervisor. When various " | ||||
|              "events occur in the newly scheduled fiber, an event will be pushed to the supervisor. " | ||||
|              "If not provided, the new fiber will inherit the current supervisor.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/thread", cfun_ev_thread, | ||||
|         JDOC("(ev/thread fiber &opt value flags)\n\n" | ||||
|              "Resume a (copy of a) `fiber` in a new operating system thread, optionally passing `value` " | ||||
|              "to resume with. " | ||||
|              "Unlike `ev/go`, this function will suspend the current fiber until the thread is complete. " | ||||
|              "If you want to run the thread without waiting for a result, pass the `:n` flag to return nil immediately. " | ||||
|              "Otherwise, returns (a copy of) the final result from the fiber on the new thread.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/give-supervisor", cfun_ev_give_supervisor, | ||||
|         JDOC("(ev/give-supervsior tag & payload)\n\n" | ||||
|              "Send a message to the current supervior channel if there is one. The message will be a " | ||||
|              "tuple of all of the arguments combined into a single message, where the first element is tag. " | ||||
|              "By convention, tag should be a keyword indicating the type of message. Returns nil.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/sleep", cfun_ev_sleep, | ||||
|         JDOC("(ev/sleep sec)\n\n" | ||||
|              "Suspend the current fiber for sec seconds without blocking the event loop.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/deadline", cfun_ev_deadline, | ||||
|         JDOC("(ev/deadline sec &opt tocancel tocheck)\n\n" | ||||
|              "Set a deadline for a fiber `tocheck`. If `tocheck` is not finished after `sec` seconds, " | ||||
|              "`tocancel` will be canceled as with `ev/cancel`. " | ||||
|              "If `tocancel` and `tocheck` are not given, they default to `(fiber/root)` and " | ||||
|              "`(fiber/current)` respectively. Returns `tocancel`.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/chan", cfun_channel_new, | ||||
|         JDOC("(ev/chan &opt capacity)\n\n" | ||||
|              "Create a new channel. capacity is the number of values to queue before " | ||||
|              "blocking writers, defaults to 0 if not provided. Returns a new channel.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/give", cfun_channel_push, | ||||
|         JDOC("(ev/give channel value)\n\n" | ||||
|              "Write a value to a channel, suspending the current fiber if the channel is full.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/take", cfun_channel_pop, | ||||
|         JDOC("(ev/take channel)\n\n" | ||||
|              "Read from a channel, suspending the current fiber if no value is available.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/full", cfun_channel_full, | ||||
|         JDOC("(ev/full channel)\n\n" | ||||
|              "Check if a channel is full or not.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/capacity", cfun_channel_capacity, | ||||
|         JDOC("(ev/capacity channel)\n\n" | ||||
|              "Get the number of items a channel will store before blocking writers.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/count", cfun_channel_count, | ||||
|         JDOC("(ev/count channel)\n\n" | ||||
|              "Get the number of items currently waiting in a channel.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/cancel", cfun_ev_cancel, | ||||
|         JDOC("(ev/cancel fiber err)\n\n" | ||||
|              "Cancel a suspended fiber in the event loop. Differs from cancel in that it returns the canceled fiber immediately") | ||||
|     }, | ||||
|     { | ||||
|         "ev/select", cfun_channel_choice, | ||||
|         JDOC("(ev/select & clauses)\n\n" | ||||
|              "Block until the first of several channel operations occur. Returns a tuple of the form [:give chan] or [:take chan x], where " | ||||
|              "a :give tuple is the result of a write and :take tuple is the result of a write. Each clause must be either a channel (for " | ||||
|              "a channel take operation) or a tuple [channel x] for a channel give operation. Operations are tried in order, such that the first " | ||||
|              "clauses will take precedence over later clauses.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/rselect", cfun_channel_rchoice, | ||||
|         JDOC("(ev/rselect & clauses)\n\n" | ||||
|              "Similar to ev/select, but will try clauses in a random order for fairness.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/close", janet_cfun_stream_close, | ||||
|         JDOC("(ev/close stream)\n\n" | ||||
|              "Close a stream. This should be the same as calling (:close stream) for all streams.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/read", janet_cfun_stream_read, | ||||
|         JDOC("(ev/read stream n &opt buffer timeout)\n\n" | ||||
|              "Read up to n bytes into a buffer asynchronously from a stream. `n` can also be the keyword " | ||||
|              "`:all` to read into the buffer until end of stream. " | ||||
|              "Optionally provide a buffer to write into " | ||||
|              "as well as a timeout in seconds after which to cancel the operation and raise an error. " | ||||
|              "Returns the buffer if the read was successful or nil if end-of-stream reached. Will raise an " | ||||
|              "error if there are problems with the IO operation.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/chunk", janet_cfun_stream_chunk, | ||||
|         JDOC("(ev/chunk stream n &opt buffer timeout)\n\n" | ||||
|              "Same as ev/read, but will not return early if less than n bytes are available. If an end of " | ||||
|              "stream is reached, will also return early with the collected bytes.") | ||||
|     }, | ||||
|     { | ||||
|         "ev/write", janet_cfun_stream_write, | ||||
|         JDOC("(ev/write stream data &opt timeout)\n\n" | ||||
|              "Write data to a stream, suspending the current fiber until the write " | ||||
|              "completes. Takes an optional timeout in seconds, after which will return nil. " | ||||
|              "Returns nil, or raises an error if the write failed.") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| void janet_lib_ev(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, ev_cfuns); | ||||
|     JanetRegExt ev_cfuns_ext[] = { | ||||
|         JANET_CORE_REG("ev/give", cfun_channel_push), | ||||
|         JANET_CORE_REG("ev/take", cfun_channel_pop), | ||||
|         JANET_CORE_REG("ev/full", cfun_channel_full), | ||||
|         JANET_CORE_REG("ev/capacity", cfun_channel_capacity), | ||||
|         JANET_CORE_REG("ev/count", cfun_channel_count), | ||||
|         JANET_CORE_REG("ev/select", cfun_channel_choice), | ||||
|         JANET_CORE_REG("ev/rselect", cfun_channel_rchoice), | ||||
|         JANET_CORE_REG("ev/chan", cfun_channel_new), | ||||
|         JANET_CORE_REG("ev/go", cfun_ev_go), | ||||
|         JANET_CORE_REG("ev/thread", cfun_ev_thread), | ||||
|         JANET_CORE_REG("ev/give-supervisor", cfun_ev_give_supervisor), | ||||
|         JANET_CORE_REG("ev/sleep", cfun_ev_sleep), | ||||
|         JANET_CORE_REG("ev/deadline", cfun_ev_deadline), | ||||
|         JANET_CORE_REG("ev/cancel", cfun_ev_cancel), | ||||
|         JANET_CORE_REG("ev/close", janet_cfun_stream_close), | ||||
|         JANET_CORE_REG("ev/read", janet_cfun_stream_read), | ||||
|         JANET_CORE_REG("ev/chunk", janet_cfun_stream_chunk), | ||||
|         JANET_CORE_REG("ev/write", janet_cfun_stream_write), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|  | ||||
|     janet_core_cfuns_ext(env, NULL, ev_cfuns_ext); | ||||
|     janet_register_abstract_type(&janet_stream_type); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										402
									
								
								src/core/math.c
									
									
									
									
									
								
							
							
						
						
									
										402
									
								
								src/core/math.c
									
									
									
									
									
								
							| @@ -117,7 +117,12 @@ double janet_rng_double(JanetRNG *rng) { | ||||
|     return ldexp((double)(big >> (64 - 52)), -52); | ||||
| } | ||||
|  | ||||
| static Janet cfun_rng_make(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_rng_make, | ||||
|         "(math/rng &opt seed)",  | ||||
|         "Creates a Psuedo-Random number generator, with an optional seed. " | ||||
|         "The seed should be an unsigned 32 bit integer or a buffer. " | ||||
|         "Do not use this for cryptography. Returns a core/rng abstract type." | ||||
|         ) { | ||||
|     janet_arity(argc, 0, 1); | ||||
|     JanetRNG *rng = janet_abstract(&janet_rng_type, sizeof(JanetRNG)); | ||||
|     if (argc == 1) { | ||||
| @@ -134,13 +139,21 @@ static Janet cfun_rng_make(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_abstract(rng); | ||||
| } | ||||
|  | ||||
| static Janet cfun_rng_uniform(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_rng_uniform, | ||||
|         "(math/rng-uniform rng)", | ||||
|         "Extract a random random integer in the range [0, max] from the RNG. If " | ||||
|         "no max is given, the default is 2^31 - 1." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type); | ||||
|     return janet_wrap_number(janet_rng_double(rng)); | ||||
| } | ||||
|  | ||||
| static Janet cfun_rng_int(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_rng_int,  | ||||
|         "(math/rng-int rng &opt max)",  | ||||
|         "Extract a random random integer in the range [0, max] from the RNG. If " | ||||
|         "no max is given, the default is 2^31 - 1." | ||||
|         ) { | ||||
|     janet_arity(argc, 1, 2); | ||||
|     JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type); | ||||
|     if (argc == 1) { | ||||
| @@ -168,7 +181,11 @@ static void rng_get_4bytes(JanetRNG *rng, uint8_t *buf) { | ||||
|     buf[3] = (word >> 24) & 0xFF; | ||||
| } | ||||
|  | ||||
| static Janet cfun_rng_buffer(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(cfun_rng_buffer,  | ||||
|         "(math/rng-buffer rng n &opt buf)",  | ||||
|         "Get n random bytes and put them in a buffer. Creates a new buffer if no buffer is " | ||||
|         "provided, otherwise appends to the given buffer. Returns the buffer." | ||||
|         ) { | ||||
|     janet_arity(argc, 2, 3); | ||||
|     JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type); | ||||
|     int32_t n = janet_getnat(argv, 1); | ||||
| @@ -213,14 +230,20 @@ static Janet janet_rng_next(void *p, Janet key) { | ||||
| } | ||||
|  | ||||
| /* Get a random number */ | ||||
| static Janet janet_rand(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_rand,  | ||||
|         "(math/random)",  | ||||
|         "Returns a uniformly distributed random number between 0 and 1") { | ||||
|     (void) argv; | ||||
|     janet_fixarity(argc, 0); | ||||
|     return janet_wrap_number(janet_rng_double(&janet_vm.rng)); | ||||
| } | ||||
|  | ||||
| /* Seed the random number generator */ | ||||
| static Janet janet_srand(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_srand,  | ||||
|         "(math/seedrandom seed)",  | ||||
|         "Set the seed for the random number generator. seed should be " | ||||
|         "an integer or a buffer." | ||||
|         ) { | ||||
|     janet_fixarity(argc, 1); | ||||
|     if (janet_checkint(argv[0])) { | ||||
|         uint32_t seed = (uint32_t)(janet_getinteger(argv, 0)); | ||||
| @@ -232,295 +255,130 @@ static Janet janet_srand(int32_t argc, Janet *argv) { | ||||
|     return janet_wrap_nil(); | ||||
| } | ||||
|  | ||||
| #define JANET_DEFINE_MATHOP(name, fop)\ | ||||
| static Janet janet_##name(int32_t argc, Janet *argv) {\ | ||||
| #define JANET_DEFINE_MATHOP(name, fop, doc)\ | ||||
| JANET_CORE_FN(janet_##name, "(math/" #name " x)", doc) {\ | ||||
|     janet_fixarity(argc, 1); \ | ||||
|     double x = janet_getnumber(argv, 0); \ | ||||
|     return janet_wrap_number(fop(x)); \ | ||||
| } | ||||
|  | ||||
| JANET_DEFINE_MATHOP(acos, acos) | ||||
| JANET_DEFINE_MATHOP(asin, asin) | ||||
| JANET_DEFINE_MATHOP(atan, atan) | ||||
| JANET_DEFINE_MATHOP(cos, cos) | ||||
| JANET_DEFINE_MATHOP(cosh, cosh) | ||||
| JANET_DEFINE_MATHOP(acosh, acosh) | ||||
| JANET_DEFINE_MATHOP(sin, sin) | ||||
| JANET_DEFINE_MATHOP(sinh, sinh) | ||||
| JANET_DEFINE_MATHOP(asinh, asinh) | ||||
| JANET_DEFINE_MATHOP(tan, tan) | ||||
| JANET_DEFINE_MATHOP(tanh, tanh) | ||||
| JANET_DEFINE_MATHOP(atanh, atanh) | ||||
| JANET_DEFINE_MATHOP(exp, exp) | ||||
| JANET_DEFINE_MATHOP(exp2, exp2) | ||||
| JANET_DEFINE_MATHOP(expm1, expm1) | ||||
| JANET_DEFINE_MATHOP(log, log) | ||||
| JANET_DEFINE_MATHOP(log10, log10) | ||||
| JANET_DEFINE_MATHOP(log2, log2) | ||||
| JANET_DEFINE_MATHOP(sqrt, sqrt) | ||||
| JANET_DEFINE_MATHOP(cbrt, cbrt) | ||||
| JANET_DEFINE_MATHOP(ceil, ceil) | ||||
| JANET_DEFINE_MATHOP(fabs, fabs) | ||||
| JANET_DEFINE_MATHOP(floor, floor) | ||||
| JANET_DEFINE_MATHOP(trunc, trunc) | ||||
| JANET_DEFINE_MATHOP(round, round) | ||||
| JANET_DEFINE_MATHOP(gamma, lgamma) | ||||
| JANET_DEFINE_MATHOP(log1p, log1p) | ||||
| JANET_DEFINE_MATHOP(erf, erf) | ||||
| JANET_DEFINE_MATHOP(erfc, erfc) | ||||
| JANET_DEFINE_MATHOP(acos, acos, "Returns the arccosize of x.") | ||||
| JANET_DEFINE_MATHOP(asin, asin, "Returns the arcsin of x.") | ||||
| JANET_DEFINE_MATHOP(atan, atan, "Returns the arctangent of x.") | ||||
| JANET_DEFINE_MATHOP(cos, cos, "Returns the cosine of x.") | ||||
| JANET_DEFINE_MATHOP(cosh, cosh, "Returns the hyperbolic cosine of x.") | ||||
| JANET_DEFINE_MATHOP(acosh, acosh, "Returns the hyperbolic arccosine of x.") | ||||
| JANET_DEFINE_MATHOP(sin, sin, "Returns the sine of x.") | ||||
| JANET_DEFINE_MATHOP(sinh, sinh, "Returns the hyperbolic sine of x.") | ||||
| JANET_DEFINE_MATHOP(asinh, asinh, "Returns the hypberbolic arcsine of x.") | ||||
| JANET_DEFINE_MATHOP(tan, tan, "Returns the tangent of x.") | ||||
| JANET_DEFINE_MATHOP(tanh, tanh, "Returns the hyperbolic tangent of x.") | ||||
| JANET_DEFINE_MATHOP(atanh, atanh, "Returns the hyperbolic arctangent of x.") | ||||
| JANET_DEFINE_MATHOP(exp, exp, "Returns e to the power of x.") | ||||
| JANET_DEFINE_MATHOP(exp2, exp2, "Returns 2 to the power of x.") | ||||
| JANET_DEFINE_MATHOP(expm1, expm1, "Returns e to the power of x minus 1.") | ||||
| JANET_DEFINE_MATHOP(log, log, "Returns the natural logarithm of x.") | ||||
| JANET_DEFINE_MATHOP(log10, log10, "Returns the log base 10 of x.") | ||||
| JANET_DEFINE_MATHOP(log2, log2, "Returns the log base 2 of x.") | ||||
| JANET_DEFINE_MATHOP(sqrt, sqrt, "Returns the square root of x.") | ||||
| JANET_DEFINE_MATHOP(cbrt, cbrt, "Returns the cube root of x.") | ||||
| JANET_DEFINE_MATHOP(ceil, ceil, "Returns the smallest integer value number that is not less than x.") | ||||
| JANET_DEFINE_MATHOP(fabs, fabs, "Return the absolute value of x.") | ||||
| JANET_DEFINE_MATHOP(floor, floor, "Returns the largest integer value number that is not greater than x.") | ||||
| JANET_DEFINE_MATHOP(trunc, trunc, "Returns the integer between x and 0 nearest to x.") | ||||
| JANET_DEFINE_MATHOP(round, round, "Returns the integer nearest to x.") | ||||
| JANET_DEFINE_MATHOP(gamma, lgamma, "Returns gamma(x).") | ||||
| JANET_DEFINE_MATHOP(log1p, log1p, "Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)") | ||||
| JANET_DEFINE_MATHOP(erf, erf, "Returns the error function of x.") | ||||
| JANET_DEFINE_MATHOP(erfc, erfc, "Returns the complementary error function of x.") | ||||
|  | ||||
| #define JANET_DEFINE_MATH2OP(name, fop)\ | ||||
| static Janet janet_##name(int32_t argc, Janet *argv) {\ | ||||
| #define JANET_DEFINE_MATH2OP(name, fop, signature, doc)\ | ||||
| JANET_CORE_FN(janet_##name, signature, doc) {\ | ||||
|     janet_fixarity(argc, 2); \ | ||||
|     double lhs = janet_getnumber(argv, 0); \ | ||||
|     double rhs = janet_getnumber(argv, 1); \ | ||||
|     return janet_wrap_number(fop(lhs, rhs)); \ | ||||
| }\ | ||||
| } | ||||
|  | ||||
| JANET_DEFINE_MATH2OP(atan2, atan2) | ||||
| JANET_DEFINE_MATH2OP(pow, pow) | ||||
| JANET_DEFINE_MATH2OP(hypot, hypot) | ||||
| JANET_DEFINE_MATH2OP(nextafter, nextafter) | ||||
| JANET_DEFINE_MATH2OP(atan2, atan2, "(math/atan2 y x)", "Returns the arctangent of y/x. Works even when x is 0.") | ||||
| JANET_DEFINE_MATH2OP(pow, pow, "(math/pow a x)", "Returns a to the power of x.") | ||||
| JANET_DEFINE_MATH2OP(hypot, hypot, "(math/hypot a b)", "Returns c from the equation c^2 = a^2 + b^2.") | ||||
| JANET_DEFINE_MATH2OP(nextafter, nextafter,  "(math/next x y)", "Returns the next representable floating point vaue after x in the direction of y.") | ||||
|  | ||||
| static Janet janet_not(int32_t argc, Janet *argv) { | ||||
| JANET_CORE_FN(janet_not, "(not x)", "Returns the boolean inverse of x.") { | ||||
|     janet_fixarity(argc, 1); | ||||
|     return janet_wrap_boolean(!janet_truthy(argv[0])); | ||||
| } | ||||
|  | ||||
| static const JanetReg math_cfuns[] = { | ||||
|     { | ||||
|         "not", janet_not, | ||||
|         JDOC("(not x)\n\nReturns the boolean inverse of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/random", janet_rand, | ||||
|         JDOC("(math/random)\n\n" | ||||
|              "Returns a uniformly distributed random number between 0 and 1.") | ||||
|     }, | ||||
|     { | ||||
|         "math/seedrandom", janet_srand, | ||||
|         JDOC("(math/seedrandom seed)\n\n" | ||||
|              "Set the seed for the random number generator. seed should be " | ||||
|              "an integer or a buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "math/cos", janet_cos, | ||||
|         JDOC("(math/cos x)\n\n" | ||||
|              "Returns the cosine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/sin", janet_sin, | ||||
|         JDOC("(math/sin x)\n\n" | ||||
|              "Returns the sine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/tan", janet_tan, | ||||
|         JDOC("(math/tan x)\n\n" | ||||
|              "Returns the tangent of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/acos", janet_acos, | ||||
|         JDOC("(math/acos x)\n\n" | ||||
|              "Returns the arccosine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/asin", janet_asin, | ||||
|         JDOC("(math/asin x)\n\n" | ||||
|              "Returns the arcsine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/atan", janet_atan, | ||||
|         JDOC("(math/atan x)\n\n" | ||||
|              "Returns the arctangent of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/exp", janet_exp, | ||||
|         JDOC("(math/exp x)\n\n" | ||||
|              "Returns e to the power of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/log", janet_log, | ||||
|         JDOC("(math/log x)\n\n" | ||||
|              "Returns log base natural number of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/log10", janet_log10, | ||||
|         JDOC("(math/log10 x)\n\n" | ||||
|              "Returns log base 10 of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/log2", janet_log2, | ||||
|         JDOC("(math/log2 x)\n\n" | ||||
|              "Returns log base 2 of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/sqrt", janet_sqrt, | ||||
|         JDOC("(math/sqrt x)\n\n" | ||||
|              "Returns the square root of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/cbrt", janet_cbrt, | ||||
|         JDOC("(math/cbrt x)\n\n" | ||||
|              "Returns the cube root of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/floor", janet_floor, | ||||
|         JDOC("(math/floor x)\n\n" | ||||
|              "Returns the largest integer value number that is not greater than x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/ceil", janet_ceil, | ||||
|         JDOC("(math/ceil x)\n\n" | ||||
|              "Returns the smallest integer value number that is not less than x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/pow", janet_pow, | ||||
|         JDOC("(math/pow a x)\n\n" | ||||
|              "Return a to the power of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/abs", janet_fabs, | ||||
|         JDOC("(math/abs x)\n\n" | ||||
|              "Return the absolute value of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/sinh", janet_sinh, | ||||
|         JDOC("(math/sinh x)\n\n" | ||||
|              "Return the hyperbolic sine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/cosh", janet_cosh, | ||||
|         JDOC("(math/cosh x)\n\n" | ||||
|              "Return the hyperbolic cosine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/tanh", janet_tanh, | ||||
|         JDOC("(math/tanh x)\n\n" | ||||
|              "Return the hyperbolic tangent of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/atanh", janet_atanh, | ||||
|         JDOC("(math/atanh x)\n\n" | ||||
|              "Return the hyperbolic arctangent of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/asinh", janet_asinh, | ||||
|         JDOC("(math/asinh x)\n\n" | ||||
|              "Return the hyperbolic arcsine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/acosh", janet_acosh, | ||||
|         JDOC("(math/acosh x)\n\n" | ||||
|              "Return the hyperbolic arccosine of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/atan2", janet_atan2, | ||||
|         JDOC("(math/atan2 y x)\n\n" | ||||
|              "Return the arctangent of y/x. Works even when x is 0.") | ||||
|     }, | ||||
|     { | ||||
|         "math/rng", cfun_rng_make, | ||||
|         JDOC("(math/rng &opt seed)\n\n" | ||||
|              "Creates a Psuedo-Random number generator, with an optional seed. " | ||||
|              "The seed should be an unsigned 32 bit integer or a buffer. " | ||||
|              "Do not use this for cryptography. Returns a core/rng abstract type.") | ||||
|     }, | ||||
|     { | ||||
|         "math/rng-uniform", cfun_rng_uniform, | ||||
|         JDOC("(math/rng-seed rng seed)\n\n" | ||||
|              "Extract a random number in the range [0, 1) from the RNG.") | ||||
|     }, | ||||
|     { | ||||
|         "math/rng-int", cfun_rng_int, | ||||
|         JDOC("(math/rng-int rng &opt max)\n\n" | ||||
|              "Extract a random random integer in the range [0, max] from the RNG. If " | ||||
|              "no max is given, the default is 2^31 - 1.") | ||||
|     }, | ||||
|     { | ||||
|         "math/rng-buffer", cfun_rng_buffer, | ||||
|         JDOC("(math/rng-buffer rng n &opt buf)\n\n" | ||||
|              "Get n random bytes and put them in a buffer. Creates a new buffer if no buffer is " | ||||
|              "provided, otherwise appends to the given buffer. Returns the buffer.") | ||||
|     }, | ||||
|     { | ||||
|         "math/hypot", janet_hypot, | ||||
|         JDOC("(math/hypot a b)\n\n" | ||||
|              "Returns the c from the equation c^2 = a^2 + b^2") | ||||
|     }, | ||||
|     { | ||||
|         "math/exp2", janet_exp2, | ||||
|         JDOC("(math/exp2 x)\n\n" | ||||
|              "Returns 2 to the power of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/log1p", janet_log1p, | ||||
|         JDOC("(math/log1p x)\n\n" | ||||
|              "Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)") | ||||
|     }, | ||||
|     { | ||||
|         "math/gamma", janet_gamma, | ||||
|         JDOC("(math/gamma x)\n\n" | ||||
|              "Returns gamma(x).") | ||||
|     }, | ||||
|     { | ||||
|         "math/erfc", janet_erfc, | ||||
|         JDOC("(math/erfc x)\n\n" | ||||
|              "Returns the complementary error function of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/erf", janet_erf, | ||||
|         JDOC("(math/erf x)\n\n" | ||||
|              "Returns the error function of x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/expm1", janet_expm1, | ||||
|         JDOC("(math/expm1 x)\n\n" | ||||
|              "Returns e to the power of x minus 1.") | ||||
|     }, | ||||
|     { | ||||
|         "math/trunc", janet_trunc, | ||||
|         JDOC("(math/trunc x)\n\n" | ||||
|              "Returns the integer between x and 0 nearest to x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/round", janet_round, | ||||
|         JDOC("(math/round x)\n\n" | ||||
|              "Returns the integer nearest to x.") | ||||
|     }, | ||||
|     { | ||||
|         "math/next", janet_nextafter, | ||||
|         JDOC("(math/next x y)\n\n" | ||||
|              "Returns the next representable floating point value after x in the direction of y.") | ||||
|     }, | ||||
|     {NULL, NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* Module entry point */ | ||||
| void janet_lib_math(JanetTable *env) { | ||||
|     janet_core_cfuns(env, NULL, math_cfuns); | ||||
|     JanetRegExt math_cfuns[] = { | ||||
|         JANET_CORE_REG("not", janet_not), | ||||
|         JANET_CORE_REG("math/random", janet_rand), | ||||
|         JANET_CORE_REG("math/seedrandom", janet_srand), | ||||
|         JANET_CORE_REG("math/cos", janet_cos), | ||||
|         JANET_CORE_REG("math/sin", janet_sin), | ||||
|         JANET_CORE_REG("math/tan", janet_tan), | ||||
|         JANET_CORE_REG("math/acos", janet_acos), | ||||
|         JANET_CORE_REG("math/asin", janet_asin), | ||||
|         JANET_CORE_REG("math/atan", janet_atan), | ||||
|         JANET_CORE_REG("math/exp", janet_exp), | ||||
|         JANET_CORE_REG("math/log", janet_log), | ||||
|         JANET_CORE_REG("math/log10", janet_log10), | ||||
|         JANET_CORE_REG("math/log2", janet_log2), | ||||
|         JANET_CORE_REG("math/sqrt", janet_sqrt), | ||||
|         JANET_CORE_REG("math/cbrt", janet_cbrt), | ||||
|         JANET_CORE_REG("math/floor", janet_floor), | ||||
|         JANET_CORE_REG("math/ceil", janet_ceil), | ||||
|         JANET_CORE_REG("math/pow", janet_pow), | ||||
|         JANET_CORE_REG("math/abs", janet_fabs), | ||||
|         JANET_CORE_REG("math/sinh", janet_sinh), | ||||
|         JANET_CORE_REG("math/cosh", janet_cosh), | ||||
|         JANET_CORE_REG("math/tanh", janet_tanh), | ||||
|         JANET_CORE_REG("math/atanh", janet_atanh), | ||||
|         JANET_CORE_REG("math/asinh", janet_asinh), | ||||
|         JANET_CORE_REG("math/acosh", janet_acosh), | ||||
|         JANET_CORE_REG("math/atan2", janet_atan2), | ||||
|         JANET_CORE_REG("math/rng", cfun_rng_make), | ||||
|         JANET_CORE_REG("math/rng-uniform", cfun_rng_uniform), | ||||
|         JANET_CORE_REG("math/rng-int", cfun_rng_int), | ||||
|         JANET_CORE_REG("math/rng-buffer", cfun_rng_buffer), | ||||
|         JANET_CORE_REG("math/hypot", janet_hypot), | ||||
|         JANET_CORE_REG("math/exp2", janet_exp2), | ||||
|         JANET_CORE_REG("math/log1p", janet_log1p), | ||||
|         JANET_CORE_REG("math/gamma", janet_gamma), | ||||
|         JANET_CORE_REG("math/erfc", janet_erfc), | ||||
|         JANET_CORE_REG("math/erf", janet_erf), | ||||
|         JANET_CORE_REG("math/expm1", janet_expm1), | ||||
|         JANET_CORE_REG("math/trunc", janet_trunc), | ||||
|         JANET_CORE_REG("math/round", janet_round), | ||||
|         JANET_CORE_REG("math/next", janet_nextafter), | ||||
|         JANET_REG_END | ||||
|     }; | ||||
|     janet_core_cfuns_ext(env, NULL, math_cfuns); | ||||
|     janet_register_abstract_type(&janet_rng_type); | ||||
| #ifdef JANET_BOOTSTRAP | ||||
|     janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931), | ||||
|               JDOC("The value pi.")); | ||||
|     janet_def(env, "math/e", janet_wrap_number(2.7182818284590451), | ||||
|               JDOC("The base of the natural log.")); | ||||
|     janet_def(env, "math/inf", janet_wrap_number(INFINITY), | ||||
|               JDOC("The number representing positive infinity")); | ||||
|     janet_def(env, "math/-inf", janet_wrap_number(-INFINITY), | ||||
|               JDOC("The number representing negative infinity")); | ||||
|     janet_def(env, "math/int32-min", janet_wrap_number(INT32_MIN), | ||||
|               JDOC("The minimum contiguous integer representable by a 32 bit signed integer")); | ||||
|     janet_def(env, "math/int32-max", janet_wrap_number(INT32_MAX), | ||||
|               JDOC("The maximum contiguous integer represtenable by a 32 bit signed integer")); | ||||
|     janet_def(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE), | ||||
|               JDOC("The minimum contiguous integer representable by a double (2^53)")); | ||||
|     janet_def(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE), | ||||
|               JDOC("The maximum contiguous integer represtenable by a double (-(2^53))")); | ||||
|     JANET_CORE_DEF(env, "math/pi", janet_wrap_number(3.1415926535897931), | ||||
|               "The value pi."); | ||||
|     JANET_CORE_DEF(env, "math/e", janet_wrap_number(2.7182818284590451), | ||||
|               "The base of the natural log."); | ||||
|     JANET_CORE_DEF(env, "math/inf", janet_wrap_number(INFINITY), | ||||
|               "The number representing positive infinity"); | ||||
|     JANET_CORE_DEF(env, "math/-inf", janet_wrap_number(-INFINITY), | ||||
|               "The number representing negative infinity"); | ||||
|     JANET_CORE_DEF(env, "math/int32-min", janet_wrap_number(INT32_MIN), | ||||
|               "The minimum contiguous integer representable by a 32 bit signed integer"); | ||||
|     JANET_CORE_DEF(env, "math/int32-max", janet_wrap_number(INT32_MAX), | ||||
|               "The maximum contiguous integer represtenable by a 32 bit signed integer"); | ||||
|     JANET_CORE_DEF(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE), | ||||
|               "The minimum contiguous integer representable by a double (2^53)"); | ||||
|     JANET_CORE_DEF(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE), | ||||
|               "The maximum contiguous integer represtenable by a double (-(2^53))"); | ||||
| #ifdef NAN | ||||
|     janet_def(env, "math/nan", janet_wrap_number(NAN), | ||||
|     JANET_CORE_DEF(env, "math/nan", janet_wrap_number(NAN), "Not a number (IEEE-754 NaN"); | ||||
| #else | ||||
|     janet_def(env, "math/nan", janet_wrap_number(0.0 / 0.0), | ||||
|     JANET_CORE_DEF(env, "math/nan", janet_wrap_number(0.0 / 0.0), "Not a number (IEEE-754 NaN)"); | ||||
| #endif | ||||
|               JDOC("Not a number (IEEE-754 NaN)")); | ||||
| #endif | ||||
| } | ||||
|   | ||||
| @@ -713,7 +713,6 @@ static const JanetMethod net_stream_methods[] = { | ||||
|     {"accept-loop", cfun_stream_accept_loop}, | ||||
|     {"send-to", cfun_stream_send_to}, | ||||
|     {"recv-from", cfun_stream_recv_from}, | ||||
|     {"recv-from", cfun_stream_recv_from}, | ||||
|     {"evread", janet_cfun_stream_read}, | ||||
|     {"evchunk", janet_cfun_stream_chunk}, | ||||
|     {"evwrite", janet_cfun_stream_write}, | ||||
|   | ||||
| @@ -92,6 +92,7 @@ Janet janet_next_impl(Janet ds, Janet key, int is_interpreter); | ||||
| #ifdef JANET_BOOTSTRAP | ||||
| #define JANET_CORE_REG JANET_REG | ||||
| #define JANET_CORE_FN JANET_FN | ||||
| #define JANET_CORE_DEF JANET_DEF | ||||
| #define janet_core_def janet_def | ||||
| #define janet_core_cfuns janet_cfuns | ||||
| #define janet_core_def_sm janet_def_sm | ||||
| @@ -99,6 +100,7 @@ Janet janet_next_impl(Janet ds, Janet key, int is_interpreter); | ||||
| #else | ||||
| #define JANET_CORE_REG JANET_REG_ | ||||
| #define JANET_CORE_FN JANET_FN_ | ||||
| #define JANET_CORE_DEF JANET_DEF_ | ||||
| void janet_core_def(JanetTable *env, const char *name, Janet x, const void *p); | ||||
| void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns); | ||||
| void janet_core_def_sm(JanetTable *env, const char *name, Janet x, const void *p, const void *sf, int32_t sl); | ||||
|   | ||||
| @@ -1765,40 +1765,53 @@ JANET_API Janet janet_resolve_core(const char *name); | ||||
| /* no docstrings or sourcemaps */ | ||||
| #define JANET_REG_(JNAME, CNAME) {JNAME, CNAME, NULL, NULL, 0} | ||||
| #define JANET_FN_(CNAME, USAGE, DOCSTRING) \ | ||||
|     static Janet CNAME (int32_t argc, Janet *argv) | ||||
|     Janet CNAME (int32_t argc, Janet *argv) | ||||
| #define JANET_DEF_(ENV, JNAME, VAL, DOC) \ | ||||
|     janet_def(ENV, JNAME, VAL, NULL) | ||||
|  | ||||
| /* sourcemaps only */ | ||||
| #define JANET_REG_S(JNAME, CNAME) {JNAME, CNAME, NULL, __FILE__, CNAME##_sourceline_} | ||||
| #define JANET_FN_S(CNAME, USAGE, DOCSTRING) \ | ||||
|     static int32_t CNAME##_sourceline_ = __LINE__; \ | ||||
|     static Janet CNAME (int32_t argc, Janet *argv) | ||||
|     Janet CNAME (int32_t argc, Janet *argv) | ||||
| #define JANET_DEF_S(ENV, JNAME, VAL, DOC) \ | ||||
|     janet_def_sm(ENV, JNAME, VAL, NULL, __FILE__, __LINE__) | ||||
|  | ||||
| /* docstring only */ | ||||
| #define JANET_REG_D(JNAME, CNAME) {JNAME, CNAME, CNAME##_docstring_, NULL, 0} | ||||
| #define JANET_FN_D(CNAME, USAGE, DOCSTRING) \ | ||||
|     static const char CNAME##_docstring_[] = USAGE "\n\n" DOCSTRING; \ | ||||
|     static Janet CNAME (int32_t argc, Janet *argv) | ||||
|     Janet CNAME (int32_t argc, Janet *argv) | ||||
| #define JANET_DEF_D(ENV, JNAME, VAL, DOC) \ | ||||
|     janet_def(ENV, JNAME, VAL, DOC) | ||||
|  | ||||
| /* sourcemaps and docstrings */ | ||||
| #define JANET_REG_SD(JNAME, CNAME) {JNAME, CNAME, CNAME##_docstring_, __FILE__, CNAME##_sourceline_} | ||||
| #define JANET_FN_SD(CNAME, USAGE, DOCSTRING) \ | ||||
|     static int32_t CNAME##_sourceline_ = __LINE__; \ | ||||
|     static const char CNAME##_docstring_[] = USAGE "\n\n" DOCSTRING; \ | ||||
|     static Janet CNAME (int32_t argc, Janet *argv) | ||||
|     Janet CNAME (int32_t argc, Janet *argv) | ||||
| #define JANET_DEF_SD(ENV, JNAME, VAL, DOC) \ | ||||
|     janet_def_sm(ENV, JNAME, VAL, DOC, __FILE__, __LINE__) | ||||
|  | ||||
|  | ||||
| /* Choose defaults for source mapping and docstring based on config defs */ | ||||
| #if defined(JANET_NO_SOURCEMAPS) && defined(JANET_NO_DOCSTRINGS) | ||||
| #define JANET_REG JANET_REG_ | ||||
| #define JANET_FN JANET_FN_ | ||||
| #define JANET_DEF JANET_DEF_ | ||||
| #elif defined(JANET_NO_SOURCEMAPS) && !defined(JANET_NO_DOCSTRINGS) | ||||
| #define JANET_REG JANET_REG_D | ||||
| #define JANET_FN JANET_FN_D | ||||
| #define JANET_DEF JANET_DEF_D | ||||
| #elif !defined(JANET_NO_SOURCEMAPS) && defined(JANET_NO_DOCSTRINGS) | ||||
| #define JANET_REG JANET_REG_S | ||||
| #define JANET_FN JANET_FN_S | ||||
| #define JANET_DEF JANET_DEF_S | ||||
| #elif !defined(JANET_NO_SOURCEMAPS) && !defined(JANET_NO_DOCSTRINGS) | ||||
| #define JANET_REG JANET_REG_SD | ||||
| #define JANET_FN JANET_FN_SD | ||||
| #define JANET_DEF JANET_DEF_SD | ||||
| #endif | ||||
|  | ||||
| /* Define things with source mapping information */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose