char buf[L2_IO_BUFSIZ]; | char buf[L2_IO_BUFSIZ]; | ||||
}; | }; | ||||
int l2_io_printf(struct l2_io_writer *w, const char *fmt, ...); | |||||
void l2_bufio_reader_init(struct l2_bufio_reader *b, struct l2_io_reader *r); | void l2_bufio_reader_init(struct l2_bufio_reader *b, struct l2_io_reader *r); | ||||
void l2_bufio_shift(struct l2_bufio_reader *b); | void l2_bufio_shift(struct l2_bufio_reader *b); | ||||
int l2_bufio_shift_peek(struct l2_bufio_reader *b, size_t count); | int l2_bufio_shift_peek(struct l2_bufio_reader *b, size_t count); |
#include "../bytecode.h" | #include "../bytecode.h" | ||||
#include "../bitset.h" | #include "../bitset.h" | ||||
#include "../io.h" | |||||
struct l2_vm; | struct l2_vm; | ||||
struct l2_vm_array; | struct l2_vm_array; | ||||
size_t opcount; | size_t opcount; | ||||
l2_word iptr; | l2_word iptr; | ||||
struct l2_io_writer *std_output; | |||||
struct l2_io_writer *std_error; | |||||
struct l2_vm_value *values; | struct l2_vm_value *values; | ||||
size_t valuessize; | size_t valuessize; | ||||
struct l2_bitset valueset; | struct l2_bitset valueset; |
#include "io.h" | #include "io.h" | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdarg.h> | |||||
int l2_io_printf(struct l2_io_writer *w, const char *fmt, ...) { | |||||
char buf[256]; | |||||
va_list va; | |||||
va_start(va, fmt); | |||||
int n = vsnprintf(buf, sizeof(buf), fmt, va); | |||||
if (n < 0) { | |||||
va_end(va); | |||||
return n; | |||||
} else if (n + 1 < sizeof(buf)) { | |||||
w->write(w, buf, n); | |||||
va_end(va); | |||||
return n; | |||||
} | |||||
// Yeah, this is slower, but it's just a fallback for when | |||||
// the output of printf is stupidly long. That shouldn't happen much. | |||||
char *buf2 = malloc(n + 1); | |||||
if (buf2 == NULL) { | |||||
va_end(va); | |||||
return -1; | |||||
} | |||||
n = vsnprintf(buf2, n + 1, fmt, va); | |||||
if (n < 0) { | |||||
va_end(va); | |||||
free(buf2); | |||||
return -1; | |||||
} | |||||
w->write(w, buf2, n); | |||||
va_end(va); | |||||
free(buf2); | |||||
return n; | |||||
} | |||||
void l2_bufio_reader_init(struct l2_bufio_reader *b, struct l2_io_reader *r) { | void l2_bufio_reader_init(struct l2_bufio_reader *b, struct l2_io_reader *r) { | ||||
b->r = r; | b->r = r; |
#include <stdio.h> | #include <stdio.h> | ||||
static void print_val(struct l2_vm *vm, struct l2_vm_value *val) { | |||||
static void print_val(struct l2_vm *vm, struct l2_io_writer *out, struct l2_vm_value *val) { | |||||
switch (l2_vm_value_type(val)) { | switch (l2_vm_value_type(val)) { | ||||
case L2_VAL_TYPE_NONE: | case L2_VAL_TYPE_NONE: | ||||
printf("(none)"); | |||||
l2_io_printf(out, "(none)"); | |||||
break; | break; | ||||
case L2_VAL_TYPE_ATOM: | case L2_VAL_TYPE_ATOM: | ||||
printf("(atom %u)", val->atom); | |||||
l2_io_printf(out, "(atom %u)", val->atom); | |||||
break; | break; | ||||
case L2_VAL_TYPE_REAL: | case L2_VAL_TYPE_REAL: | ||||
printf("%g", val->real); | |||||
l2_io_printf(out, "%g", val->real); | |||||
break; | break; | ||||
case L2_VAL_TYPE_BUFFER: | case L2_VAL_TYPE_BUFFER: | ||||
if (val->buffer != NULL) { | if (val->buffer != NULL) { | ||||
fwrite(val->buffer->data, 1, val->buffer->len, stdout); | |||||
out->write(out, val->buffer->data, val->buffer->len); | |||||
} | } | ||||
break; | break; | ||||
case L2_VAL_TYPE_ARRAY: | case L2_VAL_TYPE_ARRAY: | ||||
if (val->array == NULL) { | if (val->array == NULL) { | ||||
printf("[]"); | |||||
out->write(out, "[]", 2); | |||||
break; | break; | ||||
} | } | ||||
putchar('['); | |||||
out->write(out, "[", 1); | |||||
for (size_t i = 0; i < val->array->len; ++i) { | for (size_t i = 0; i < val->array->len; ++i) { | ||||
if (i != 0) { | if (i != 0) { | ||||
putchar(' '); | |||||
out->write(out, " ", 1); | |||||
} | } | ||||
print_val(vm, &vm->values[val->array->data[i]]); | |||||
print_val(vm, out, &vm->values[val->array->data[i]]); | |||||
} | } | ||||
putchar(']'); | |||||
out->write(out, "]", 1); | |||||
break; | break; | ||||
case L2_VAL_TYPE_NAMESPACE: | case L2_VAL_TYPE_NAMESPACE: | ||||
printf("(namespace)"); | |||||
l2_io_printf(out, "(namespace)"); | |||||
break; | break; | ||||
case L2_VAL_TYPE_FUNCTION: | case L2_VAL_TYPE_FUNCTION: | ||||
case L2_VAL_TYPE_CFUNCTION: | case L2_VAL_TYPE_CFUNCTION: | ||||
printf("(function)"); | |||||
l2_io_printf(out, "(function)"); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
l2_word l2_builtin_print(struct l2_vm *vm, struct l2_vm_array *args) { | l2_word l2_builtin_print(struct l2_vm *vm, struct l2_vm_array *args) { | ||||
for (size_t i = 0; i < args->len; ++i) { | for (size_t i = 0; i < args->len; ++i) { | ||||
if (i != 0) { | if (i != 0) { | ||||
putchar(' '); | |||||
vm->std_output->write(vm->std_output, " ", 1); | |||||
} | } | ||||
struct l2_vm_value *val = &vm->values[args->data[i]]; | struct l2_vm_value *val = &vm->values[args->data[i]]; | ||||
print_val(vm, val); | |||||
print_val(vm, vm->std_output, val); | |||||
} | } | ||||
putchar('\n'); | |||||
vm->std_output->write(vm->std_output, "\n", 1); | |||||
return 0; | return 0; | ||||
} | } | ||||
#include "vm/builtins.h" | #include "vm/builtins.h" | ||||
static int stdio_inited = 0; | |||||
static struct l2_io_file_writer std_output; | |||||
static struct l2_io_file_writer std_error; | |||||
static l2_word alloc_val(struct l2_vm *vm) { | static l2_word alloc_val(struct l2_vm *vm) { | ||||
size_t id = l2_bitset_set_next(&vm->valueset); | size_t id = l2_bitset_set_next(&vm->valueset); | ||||
if (id >= vm->valuessize) { | if (id >= vm->valuessize) { | ||||
} | } | ||||
void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) { | void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) { | ||||
if (!stdio_inited) { | |||||
std_output.w.write = l2_io_file_write; | |||||
std_output.f = stdout; | |||||
std_error.w.write = l2_io_file_write; | |||||
std_error.f = stderr; | |||||
stdio_inited = 1; | |||||
} | |||||
vm->std_output = &std_output.w; | |||||
vm->std_error = &std_error.w; | |||||
vm->ops = ops; | vm->ops = ops; | ||||
vm->opcount = opcount; | vm->opcount = opcount; | ||||
vm->iptr = 0; | vm->iptr = 0; |