move non essential opcodes to primitives and add userdata
This commit is contained in:
parent
e654143a90
commit
45e2c0d406
17 changed files with 234 additions and 37 deletions
|
|
@ -1,12 +1,12 @@
|
||||||
#load("std.grr")
|
#load("std.grr")
|
||||||
|
|
||||||
def fizzbuzz? { [3 % 0 =] [5 % 0 =] bi or }
|
def fizzbuzz? { [3 % 0 =] [5 % 0 =] bi or }
|
||||||
def fizz { when: 3 % 0 = ["Fizz" type]; }
|
def fizz { when: 3 % 0 = ["Fizz" print]; }
|
||||||
def buzz { when: 5 % 0 = ["Buzz" type]; }
|
def buzz { when: 5 % 0 = ["Buzz" print]; }
|
||||||
|
|
||||||
def fizzbuzz1 {
|
def fizzbuzz1 {
|
||||||
if: fizzbuzz?
|
if: fizzbuzz?
|
||||||
[ [fizz] keep buzz "\n" type ]
|
[ [fizz] keep buzz nl ]
|
||||||
[ . ];
|
[ . ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,14 @@ sources = [
|
||||||
'src/compile.c',
|
'src/compile.c',
|
||||||
'src/debug.c',
|
'src/debug.c',
|
||||||
'src/dictionary.c',
|
'src/dictionary.c',
|
||||||
|
'src/file.c',
|
||||||
'src/object.c',
|
'src/object.c',
|
||||||
'src/gc.c',
|
'src/gc.c',
|
||||||
'src/parser.c',
|
'src/parser.c',
|
||||||
|
'src/primitive.c',
|
||||||
'src/print.c',
|
'src/print.c',
|
||||||
'src/string.c',
|
'src/string.c',
|
||||||
|
'src/userdata.c',
|
||||||
'src/vm.c',
|
'src/vm.c',
|
||||||
'src/vendor/linenoise.c',
|
'src/vendor/linenoise.c',
|
||||||
'src/vendor/mpc.c',
|
'src/vendor/mpc.c',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef COMMON_H
|
#ifndef COMMON_H
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "src/primitive.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
|
@ -50,10 +51,7 @@ struct {
|
||||||
{">=", {OP_GTE, 0}},
|
{">=", {OP_GTE, 0}},
|
||||||
{"and", {OP_AND, 0}},
|
{"and", {OP_AND, 0}},
|
||||||
{"or", {OP_OR, 0}},
|
{"or", {OP_OR, 0}},
|
||||||
{"type", {OP_TYPE, 0}},
|
|
||||||
{"^", {OP_CONCAT, 0}},
|
{"^", {OP_CONCAT, 0}},
|
||||||
{".", {OP_PPRINT, 0}},
|
|
||||||
{".s", {OP_PRINTSTACK, 0}},
|
|
||||||
{NULL, {0}},
|
{NULL, {0}},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -146,6 +144,14 @@ static I compile_call(Cm *cm, const char *name, I line, I col) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
I prim_idx = prim_find(name);
|
||||||
|
if (prim_idx != -1) {
|
||||||
|
chunk_emit_byte_with_line(cm->chunk, OP_PRIM, line, col);
|
||||||
|
chunk_emit_sleb128(cm->chunk, prim_idx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Dt *word = upsert(cm->dictionary, name, NULL);
|
Dt *word = upsert(cm->dictionary, name, NULL);
|
||||||
if (!word) {
|
if (!word) {
|
||||||
fprintf(stderr, "compiler error at %ld:%ld: undefined word '%s'\n",
|
fprintf(stderr, "compiler error at %ld:%ld: undefined word '%s'\n",
|
||||||
|
|
|
||||||
15
src/debug.c
15
src/debug.c
|
|
@ -4,6 +4,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "dictionary.h"
|
#include "dictionary.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "src/primitive.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
static I decode_sleb128(U8 *ptr, Z *bytes_read) {
|
static I decode_sleb128(U8 *ptr, Z *bytes_read) {
|
||||||
|
|
@ -94,7 +95,7 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
|
||||||
Z bytes_read;
|
Z bytes_read;
|
||||||
I idx = decode_sleb128(&chunk->items[offset], &bytes_read);
|
I idx = decode_sleb128(&chunk->items[offset], &bytes_read);
|
||||||
Dt *word = chunk->symbols.items[idx].resolved;
|
Dt *word = chunk->symbols.items[idx].resolved;
|
||||||
printf("DOWORD %s\n", word->name);
|
printf("DOWORD \"%s\"\n", word->name);
|
||||||
return offset + bytes_read;
|
return offset + bytes_read;
|
||||||
}
|
}
|
||||||
SIMPLE(CALL);
|
SIMPLE(CALL);
|
||||||
|
|
@ -102,10 +103,17 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
|
||||||
Z bytes_read;
|
Z bytes_read;
|
||||||
I idx = decode_sleb128(&chunk->items[offset], &bytes_read);
|
I idx = decode_sleb128(&chunk->items[offset], &bytes_read);
|
||||||
Dt *word = chunk->symbols.items[idx].resolved;
|
Dt *word = chunk->symbols.items[idx].resolved;
|
||||||
printf("TAIL_DOWORD %s\n", word->name);
|
printf("TAIL_DOWORD \"%s\"\n", word->name);
|
||||||
return offset + bytes_read;
|
return offset + bytes_read;
|
||||||
}
|
}
|
||||||
SIMPLE(TAIL_CALL);
|
SIMPLE(TAIL_CALL);
|
||||||
|
CASE(PRIM) {
|
||||||
|
Z bytes_read;
|
||||||
|
I idx = decode_sleb128(&chunk->items[offset], &bytes_read);
|
||||||
|
Pr prim = primitives_table[idx];
|
||||||
|
printf("PRIM \"%s\"\n", prim.name);
|
||||||
|
return offset + bytes_read;
|
||||||
|
}
|
||||||
SIMPLE(RETURN);
|
SIMPLE(RETURN);
|
||||||
SIMPLE(CHOOSE);
|
SIMPLE(CHOOSE);
|
||||||
SIMPLE(ADD);
|
SIMPLE(ADD);
|
||||||
|
|
@ -125,10 +133,7 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
|
||||||
SIMPLE(GTE);
|
SIMPLE(GTE);
|
||||||
SIMPLE(AND);
|
SIMPLE(AND);
|
||||||
SIMPLE(OR);
|
SIMPLE(OR);
|
||||||
SIMPLE(TYPE);
|
|
||||||
SIMPLE(CONCAT);
|
SIMPLE(CONCAT);
|
||||||
SIMPLE(PPRINT);
|
|
||||||
SIMPLE(PRINTSTACK);
|
|
||||||
default:
|
default:
|
||||||
printf("??? (%d)\n", opcode);
|
printf("??? (%d)\n", opcode);
|
||||||
return offset;
|
return offset;
|
||||||
|
|
|
||||||
56
src/file.c
Normal file
56
src/file.c
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "userdata.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
static V finalizer(V *data);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
Ut userdata_file = {
|
||||||
|
.name = "file",
|
||||||
|
.finalizer = finalizer
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
I prim_file_stdout(Vm *vm) {
|
||||||
|
static O stdout_object = NIL;
|
||||||
|
if (stdout_object == NIL)
|
||||||
|
stdout_object = userdata_make(vm, (void *)stdout, &userdata_file);
|
||||||
|
vm_push(vm, stdout_object);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
I prim_file_stderr(Vm *vm) {
|
||||||
|
static O stderr_object = NIL;
|
||||||
|
if (stderr_object == NIL)
|
||||||
|
stderr_object = userdata_make(vm, (void *)stderr, &userdata_file);
|
||||||
|
vm_push(vm, stderr_object);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
I prim_file_fprint(Vm *vm) {
|
||||||
|
O file_obj = vm_pop(vm);
|
||||||
|
O string_obj = vm_pop(vm);
|
||||||
|
|
||||||
|
Ud *file_ud = userdata_unwrap(file_obj, &userdata_file);
|
||||||
|
if (file_ud == NULL) {
|
||||||
|
fprintf(stderr, "expected file object");
|
||||||
|
return VM_ERR_TYPE;
|
||||||
|
};
|
||||||
|
|
||||||
|
Str *str = string_unwrap(string_obj);
|
||||||
|
if (str == NULL) {
|
||||||
|
fprintf(stderr, "expected string");
|
||||||
|
return VM_ERR_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(str->data, sizeof(char), str->len, (FILE *)file_ud->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static V finalizer(V *data) {
|
||||||
|
FILE *f = (FILE *)data;
|
||||||
|
if (f && f != stdin && f != stdout && f != stderr)
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
7
src/file.h
Normal file
7
src/file.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "userdata.h"
|
||||||
|
|
||||||
|
extern Ut userdata_file;
|
||||||
|
|
||||||
|
I prim_file_stdout(Vm *);
|
||||||
|
I prim_file_stderr(Vm *);
|
||||||
|
I prim_file_fprint(Vm *);
|
||||||
9
src/gc.c
9
src/gc.c
|
|
@ -6,6 +6,7 @@
|
||||||
#include "chunk.h"
|
#include "chunk.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "userdata.h"
|
||||||
#include "vendor/yar.h"
|
#include "vendor/yar.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
|
@ -110,6 +111,8 @@ V gc_collect(Vm *vm) {
|
||||||
chunk->constants.items[i] = forward(gc, chunk->constants.items[i]);
|
chunk->constants.items[i] = forward(gc, chunk->constants.items[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OBJ_USERDATA:
|
||||||
|
break;
|
||||||
case OBJ_FWD:
|
case OBJ_FWD:
|
||||||
fprintf(stderr, "fatal GC error: forwarding pointer in to-space\n");
|
fprintf(stderr, "fatal GC error: forwarding pointer in to-space\n");
|
||||||
abort();
|
abort();
|
||||||
|
|
@ -129,6 +132,12 @@ V gc_collect(Vm *vm) {
|
||||||
chunk_release(*chunk_ptr);
|
chunk_release(*chunk_ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OBJ_USERDATA: {
|
||||||
|
Ud *ud = (Ud *)(hdr + 1);
|
||||||
|
if (ud->kind->finalizer != NULL)
|
||||||
|
ud->kind->finalizer(ud->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ enum {
|
||||||
OBJ_FWD = 2,
|
OBJ_FWD = 2,
|
||||||
OBJ_QUOT,
|
OBJ_QUOT,
|
||||||
OBJ_STR,
|
OBJ_STR,
|
||||||
|
OBJ_USERDATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -22,6 +23,7 @@ enum {
|
||||||
TYPE_FWD = OBJ_FWD,
|
TYPE_FWD = OBJ_FWD,
|
||||||
TYPE_QUOT = OBJ_QUOT,
|
TYPE_QUOT = OBJ_QUOT,
|
||||||
TYPE_STR = OBJ_STR,
|
TYPE_STR = OBJ_STR,
|
||||||
|
TYPE_USERDATA = OBJ_USERDATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uintptr_t O;
|
typedef uintptr_t O;
|
||||||
|
|
|
||||||
44
src/primitive.c
Normal file
44
src/primitive.c
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "primitive.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
// Pretty-printing primitives
|
||||||
|
static I prim_pprint(Vm *vm) {
|
||||||
|
println(vm_pop(vm));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static I prim_printstack(Vm *vm) {
|
||||||
|
printf("Stk:");
|
||||||
|
for (O *p = vm->stack; p < vm->sp; p++) {
|
||||||
|
putchar(' ');
|
||||||
|
print(*p);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
Pr primitives_table[] = {
|
||||||
|
{".", prim_pprint},
|
||||||
|
{".s", prim_printstack},
|
||||||
|
{"stdout", prim_file_stdout},
|
||||||
|
{"stderr", prim_file_stderr},
|
||||||
|
{"fprint", prim_file_fprint},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
I prim_find(const char *name) {
|
||||||
|
for (Z i = 0; primitives_table[i].name != NULL; i++) {
|
||||||
|
if (strcmp(primitives_table[i].name, name) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
15
src/primitive.h
Normal file
15
src/primitive.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef PRIMITIVE_H
|
||||||
|
#define PRIMITIVE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
typedef struct Pr {
|
||||||
|
const char *name;
|
||||||
|
I (*fn)(Vm *);
|
||||||
|
} Pr;
|
||||||
|
|
||||||
|
extern Pr primitives_table[];
|
||||||
|
I prim_find(const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include "userdata.h"
|
||||||
#include "vendor/mpc.h"
|
#include "vendor/mpc.h"
|
||||||
|
|
||||||
V print(O o) {
|
V print(O o) {
|
||||||
|
|
@ -29,8 +30,13 @@ V print(O o) {
|
||||||
free(escaped);
|
free(escaped);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OBJ_USERDATA: {
|
||||||
|
Ud *ud = (Ud *)(hdr + 1);
|
||||||
|
printf("<#userdata %s@%p>", ud->kind->name, ud->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
printf("<obj type=%ld ptr=%p>", type(o), (void *)o);
|
printf("<#obj type=%ld ptr=%p>", type(o), (void *)o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
src/userdata.c
Normal file
24
src/userdata.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#include "userdata.h"
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
|
O userdata_make(Vm *vm, V *data, Ut *kind) {
|
||||||
|
Z size = sizeof(Hd) + sizeof(Ud);
|
||||||
|
Hd *hdr = gc_alloc(vm, size);
|
||||||
|
hdr->type = OBJ_USERDATA;
|
||||||
|
Ud *ud = (Ud *)(hdr + 1);
|
||||||
|
ud->kind = kind;
|
||||||
|
ud->data = data;
|
||||||
|
return BOX(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ud *userdata_unwrap(O o, Ut *kind) {
|
||||||
|
if (o == NIL || IMM(o))
|
||||||
|
return NULL;
|
||||||
|
Hd *hdr = UNBOX(o);
|
||||||
|
if (hdr->type != OBJ_USERDATA)
|
||||||
|
return NULL;
|
||||||
|
Ud *ud = (Ud *)(hdr + 1);
|
||||||
|
if (ud->kind != kind)
|
||||||
|
return NULL;
|
||||||
|
return ud;
|
||||||
|
}
|
||||||
21
src/userdata.h
Normal file
21
src/userdata.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef USERDATA_H
|
||||||
|
#define USERDATA_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
typedef struct Ut {
|
||||||
|
const char *name;
|
||||||
|
V (*finalizer)(V *);
|
||||||
|
} Ut;
|
||||||
|
|
||||||
|
typedef struct Ud {
|
||||||
|
Ut *kind;
|
||||||
|
V *data;
|
||||||
|
} Ud;
|
||||||
|
|
||||||
|
O userdata_make(Vm *, V *, Ut *);
|
||||||
|
Ud *userdata_unwrap(O, Ut *);
|
||||||
|
|
||||||
|
#endif
|
||||||
30
src/vm.c
30
src/vm.c
|
|
@ -8,6 +8,7 @@
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "src/primitive.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
|
@ -271,6 +272,14 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_PRIM: {
|
||||||
|
I idx = decode_sleb128(&vm->ip);
|
||||||
|
Pr prim = primitives_table[idx];
|
||||||
|
I err = prim.fn(vm);
|
||||||
|
if (err != 0)
|
||||||
|
vm_error(vm, err, "primitive call failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_RETURN:
|
case OP_RETURN:
|
||||||
if (vm->rsp != vm->rstack) {
|
if (vm->rsp != vm->rstack) {
|
||||||
Fr frame = vm_rpop(vm);
|
Fr frame = vm_rpop(vm);
|
||||||
|
|
@ -356,27 +365,6 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
|
||||||
vm_push(vm, string_concat(vm, a, b));
|
vm_push(vm, string_concat(vm, a, b));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_TYPE: {
|
|
||||||
Str *s = string_unwrap(vm_pop(vm));
|
|
||||||
if (s == NULL)
|
|
||||||
vm_error(vm, VM_ERR_TYPE, "expected string");
|
|
||||||
printf("%.*s", (int)s->len, s->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_PPRINT: {
|
|
||||||
O obj = vm_pop(vm);
|
|
||||||
println(obj);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_PRINTSTACK: {
|
|
||||||
printf("Stk:");
|
|
||||||
for (O *p = vm->stack; p < vm->sp; p++) {
|
|
||||||
putchar(' ');
|
|
||||||
print(*p);
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
vm_error(vm, VM_ERR_RUNTIME, "unknown opcode");
|
vm_error(vm, VM_ERR_RUNTIME, "unknown opcode");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/vm.h
10
src/vm.h
|
|
@ -28,6 +28,7 @@ enum {
|
||||||
OP_CALL,
|
OP_CALL,
|
||||||
OP_TAIL_DOWORD, // Tail call to dictionary word (reuses current frame)
|
OP_TAIL_DOWORD, // Tail call to dictionary word (reuses current frame)
|
||||||
OP_TAIL_CALL, // Tail call to quotation (reuses current frame)
|
OP_TAIL_CALL, // Tail call to quotation (reuses current frame)
|
||||||
|
OP_PRIM,
|
||||||
OP_RETURN,
|
OP_RETURN,
|
||||||
OP_CHOOSE,
|
OP_CHOOSE,
|
||||||
OP_ADD,
|
OP_ADD,
|
||||||
|
|
@ -47,10 +48,7 @@ enum {
|
||||||
OP_GTE,
|
OP_GTE,
|
||||||
OP_AND,
|
OP_AND,
|
||||||
OP_OR,
|
OP_OR,
|
||||||
OP_TYPE,
|
|
||||||
OP_CONCAT,
|
OP_CONCAT,
|
||||||
OP_PPRINT,
|
|
||||||
OP_PRINTSTACK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define STACK_SIZE 256
|
#define STACK_SIZE 256
|
||||||
|
|
@ -82,4 +80,10 @@ enum {
|
||||||
V vm_init(Vm *);
|
V vm_init(Vm *);
|
||||||
V vm_deinit(Vm *);
|
V vm_deinit(Vm *);
|
||||||
I vm_run(Vm *, Bc *, I);
|
I vm_run(Vm *, Bc *, I);
|
||||||
|
|
||||||
|
V vm_push(Vm *, O);
|
||||||
|
O vm_pop(Vm *);
|
||||||
|
V vm_tpush(Vm *, O);
|
||||||
|
O vm_tpop(Vm *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
7
std.grr
7
std.grr
|
|
@ -1,3 +1,10 @@
|
||||||
|
def print { stdout fprint }
|
||||||
|
def println { stdout fprint "\n" stdout fprint }
|
||||||
|
def nl { "\n" stdout fprint }
|
||||||
|
|
||||||
|
def eprint { stderr fprint }
|
||||||
|
def eprintln { stderr fprint "\n" stderr fprint }
|
||||||
|
|
||||||
def when { [] if }
|
def when { [] if }
|
||||||
def unless { swap when }
|
def unless { swap when }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue