@@ -21,6 +21,8 @@ struct l2_bufio_reader { | |||
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_shift(struct l2_bufio_reader *b); | |||
int l2_bufio_shift_peek(struct l2_bufio_reader *b, size_t count); |
@@ -5,6 +5,7 @@ | |||
#include "../bytecode.h" | |||
#include "../bitset.h" | |||
#include "../io.h" | |||
struct l2_vm; | |||
struct l2_vm_array; | |||
@@ -83,6 +84,9 @@ struct l2_vm { | |||
size_t opcount; | |||
l2_word iptr; | |||
struct l2_io_writer *std_output; | |||
struct l2_io_writer *std_error; | |||
struct l2_vm_value *values; | |||
size_t valuessize; | |||
struct l2_bitset valueset; |
@@ -1,6 +1,43 @@ | |||
#include "io.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) { | |||
b->r = r; |
@@ -2,50 +2,50 @@ | |||
#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)) { | |||
case L2_VAL_TYPE_NONE: | |||
printf("(none)"); | |||
l2_io_printf(out, "(none)"); | |||
break; | |||
case L2_VAL_TYPE_ATOM: | |||
printf("(atom %u)", val->atom); | |||
l2_io_printf(out, "(atom %u)", val->atom); | |||
break; | |||
case L2_VAL_TYPE_REAL: | |||
printf("%g", val->real); | |||
l2_io_printf(out, "%g", val->real); | |||
break; | |||
case L2_VAL_TYPE_BUFFER: | |||
if (val->buffer != NULL) { | |||
fwrite(val->buffer->data, 1, val->buffer->len, stdout); | |||
out->write(out, val->buffer->data, val->buffer->len); | |||
} | |||
break; | |||
case L2_VAL_TYPE_ARRAY: | |||
if (val->array == NULL) { | |||
printf("[]"); | |||
out->write(out, "[]", 2); | |||
break; | |||
} | |||
putchar('['); | |||
out->write(out, "[", 1); | |||
for (size_t i = 0; i < val->array->len; ++i) { | |||
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; | |||
case L2_VAL_TYPE_NAMESPACE: | |||
printf("(namespace)"); | |||
l2_io_printf(out, "(namespace)"); | |||
break; | |||
case L2_VAL_TYPE_FUNCTION: | |||
case L2_VAL_TYPE_CFUNCTION: | |||
printf("(function)"); | |||
l2_io_printf(out, "(function)"); | |||
break; | |||
} | |||
} | |||
@@ -81,14 +81,14 @@ l2_word l2_builtin_div(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) { | |||
if (i != 0) { | |||
putchar(' '); | |||
vm->std_output->write(vm->std_output, " ", 1); | |||
} | |||
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; | |||
} | |||
@@ -5,6 +5,10 @@ | |||
#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) { | |||
size_t id = l2_bitset_set_next(&vm->valueset); | |||
if (id >= vm->valuessize) { | |||
@@ -123,6 +127,17 @@ static size_t gc_sweep(struct l2_vm *vm) { | |||
} | |||
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->opcount = opcount; | |||
vm->iptr = 0; |