Browse Source

support setting the VM's stdout

master
Martin Dørum 3 years ago
parent
commit
fc8bdb9df1
5 changed files with 73 additions and 15 deletions
  1. 2
    0
      include/lang2/io.h
  2. 4
    0
      include/lang2/vm/vm.h
  3. 37
    0
      lib/io.c
  4. 15
    15
      lib/vm/builtins.c
  5. 15
    0
      lib/vm/vm.c

+ 2
- 0
include/lang2/io.h View File

@@ -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);

+ 4
- 0
include/lang2/vm/vm.h View File

@@ -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;

+ 37
- 0
lib/io.c View File

@@ -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;

+ 15
- 15
lib/vm/builtins.c View File

@@ -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;
}


+ 15
- 0
lib/vm/vm.c View File

@@ -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;

Loading…
Cancel
Save