diff --git a/devices/wasm/wasm/lib.c b/devices/wasm/wasm/lib.c index a3f541e..00605ea 100644 --- a/devices/wasm/wasm/lib.c +++ b/devices/wasm/wasm/lib.c @@ -62,6 +62,11 @@ static void print_flush(bool is_error) { fprintf(is_error ? stderr : stdout, "\n"); } +/** Browser only: EV3/desktop use runner.c’s get_time_ms + clock_gettime. */ +static uint64_t wasm_get_time_ms(void) { + return (uint64_t)emscripten_get_now(); +} + EMSCRIPTEN_KEEPALIVE void siwasm_alloc_heap(size_t size) { if (heap) { @@ -93,6 +98,7 @@ void siwasm_run(unsigned char *code, size_t code_size) { sinter_printer_integer = print_integer; sinter_printer_string = print_string; sinter_printer_flush = print_flush; + sinter_get_time_ms = wasm_get_time_ms; sinter_value_t result; sinter_fault_t fault = (uint8_t) sinter_run(code, code_size, &result); diff --git a/runner/src/runner.c b/runner/src/runner.c index f5a94de..e3cbba1 100644 --- a/runner/src/runner.c +++ b/runner/src/runner.c @@ -1,3 +1,5 @@ +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -8,10 +10,17 @@ #include #include +#include #include #define eprintf(...) fprintf(stderr, __VA_ARGS__) +static uint64_t get_time_ms(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * 1000u + (uint64_t) ts.tv_nsec / 1000000u; +} + static const char *fault_names[] = { "no fault", "out of memory", @@ -94,9 +103,17 @@ int main(int argc, char *argv[]) { sinter_printer_string = print_string; sinter_printer_integer = print_integer; sinter_printer_flush = print_flush; + sinter_get_time_ms = get_time_ms; setup_internals(); + void *heap = malloc(0x100000); // 1MB + if (!heap) { + eprintf("Failed to allocate heap\n"); + return 1; + } + sinter_setup_heap(heap, 0x100000); + sinter_value_t result = { 0 }; sinter_fault_t fault = sinter_run(program, size, &result); diff --git a/vm/include/sinter.h b/vm/include/sinter.h index a5f145c..767d2be 100644 --- a/vm/include/sinter.h +++ b/vm/include/sinter.h @@ -105,6 +105,8 @@ extern sinter_printfn_integer sinter_printer_integer; extern sinter_printfn_float sinter_printer_float; extern sinter_printfn_flush sinter_printer_flush; +extern uint64_t (*sinter_get_time_ms)(void); + #ifdef __cplusplus } #endif diff --git a/vm/src/primitives.c b/vm/src/primitives.c index 5bbab9c..724fc58 100644 --- a/vm/src/primitives.c +++ b/vm/src/primitives.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -1596,6 +1597,70 @@ static sinanbox_t sivmfn_prim_noop(uint8_t argc, sinanbox_t *argv) { return NANBOX_OFUNDEF(); } +uint64_t (*sinter_get_time_ms)(void) = NULL; + +static sinanbox_t sivmfn_prim_parse_int(uint8_t argc, sinanbox_t *argv) { + CHECK_ARGC(2); + + if (!NANBOX_ISPTR(argv[0]) || !siheap_is_string(SIHEAP_NANBOXTOPTR(argv[0]))) { + sifault(sinter_fault_type); + return NANBOX_OFEMPTY(); + } + + int32_t radix = 0; + if (NANBOX_ISINT(argv[1])) { + radix = NANBOX_INT(argv[1]); + } else if (NANBOX_ISFLOAT(argv[1])) { + float fv = NANBOX_FLOAT(argv[1]); + if (!isfinite(fv) || truncf(fv) != fv) { + sifault(sinter_fault_type); + return NANBOX_OFEMPTY(); + } + radix = (int32_t) fv; + } else { + sifault(sinter_fault_type); + return NANBOX_OFEMPTY(); + } + + if (radix < 2 || radix > 36) { + sifault(sinter_fault_type); + return NANBOX_OFEMPTY(); + } + + const char *str = sistrobj_tocharptr(SIHEAP_NANBOXTOPTR(argv[0])); + char *endptr = NULL; + errno = 0; + long result = strtol(str, &endptr, radix); + + if (endptr == str) { + return NANBOX_CANONICAL_NAN; + } + + if (errno == ERANGE) { + // strtol overflowed, return as float instead + return NANBOX_OFFLOAT((float) result); + } + + if (result >= NANBOX_INTMIN && result <= NANBOX_INTMAX) { + return NANBOX_OFINT((int32_t) result); + } else { + return NANBOX_OFFLOAT((float) result); + } +} + +static sinanbox_t sivmfn_prim_runtime(uint8_t argc, sinanbox_t *argv) { + (void) argc; (void) argv; + if (sinter_get_time_ms) { + uint64_t t = sinter_get_time_ms(); + if (t <= (uint64_t) NANBOX_INTMAX) { + return NANBOX_OFINT((int32_t) t); + } + return NANBOX_OFFLOAT((float) t); + } + return NANBOX_OFINT(0); +} + + sivmfnptr_t sivmfn_primitives[] = { sivmfn_prim_accumulate, sivmfn_prim_append, @@ -1666,11 +1731,11 @@ sivmfnptr_t sivmfn_primitives[] = { sivmfn_prim_math_trunc, sivmfn_prim_member, sivmfn_prim_pair, - /* parse_int */ sivmfn_prim_unimpl, // TODO: doesn't make sense without the ability to take input (prompt) + /* parse_int */ sivmfn_prim_parse_int, sivmfn_prim_remove, sivmfn_prim_remove_all, sivmfn_prim_reverse, - /* runtime */ sivmfn_prim_unimpl, // TODO: need to get time from host + /* runtime */ sivmfn_prim_runtime, sivmfn_prim_set_head, sivmfn_prim_set_tail, sivmfn_prim_stream,