Browse Source

parsing/codegen, plus vm work

master
Martin Dørum 3 years ago
parent
commit
48be0c18b1

+ 3
- 76
cmd/main.c View File

#include "vm/vm.h" #include "vm/vm.h"
#include "vm/print.h"
#include "bitset.h" #include "bitset.h"


#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>


void print_var(struct l2_vm_value *val) {
switch (val->flags & 0x0f) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
break;

case L2_VAL_TYPE_INTEGER:
printf("INTEGER %zi\n", val->integer);
break;

case L2_VAL_TYPE_REAL:
printf("REAL %f\n", val->real);
break;

case L2_VAL_TYPE_ARRAY:
{
if (val->data == NULL) {
printf("ARRAY, empty\n");
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
printf("ARRAY, len %zu\n", arr->len);
for (size_t i = 0; i < arr->len; ++i) {
printf(" %zu: %u\n", i, arr->data[i]);
}
}
break;

case L2_VAL_TYPE_BUFFER:
{
if (val->data == NULL) {
printf("BUFFER, empty\n");
return;
}

struct l2_vm_buffer *buf = (struct l2_vm_buffer *)val->data;
printf("BUFFER, len %zu\n", buf->len);
for (size_t i = 0; i < buf->len; ++i) {
printf(" %zu: %c\n", i, buf->data[i]);
}
}
break;

case L2_VAL_TYPE_NAMESPACE:
{
if (val->data == NULL) {
printf("NAMESPACE, empty\n");
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
printf("NAMESPACE, len %zu\n", ns->len);
}
break;
}
}

int main() { int main() {
l2_word ops[] = { l2_word ops[] = {
L2_OP_PUSH, 100, L2_OP_PUSH, 100,


l2_vm_run(&vm); l2_vm_run(&vm);


printf("Stack:\n");
for (l2_word i = 0; i < vm.sptr; ++i) {
printf(" %i: %i\n", i, vm.stack[i]);
}

printf("Heap:\n");
for (l2_word i = 0; i < vm.valuessize; ++i) {
if (l2_bitset_get(&vm.valueset, i)) {
printf(" %u: ", i);
print_var(&vm.values[i]);
}
}
l2_vm_print_state(&vm);


l2_vm_gc(&vm); l2_vm_gc(&vm);


printf("Heap:\n"); printf("Heap:\n");
for (l2_word i = 0; i < vm.valuessize; ++i) {
if (l2_bitset_get(&vm.valueset, i)) {
printf(" %u: ", i);
print_var(&vm.values[i]);
}
}
l2_vm_print_stack(&vm);


l2_vm_free(&vm); l2_vm_free(&vm);
} }

+ 28
- 5
include/lang2/bytecode.h View File

*/ */
L2_OP_CALL, L2_OP_CALL,


/*
* Generate a stack frame.
* Alloc namespace <var>
* NSPush <var>
*/
L2_OP_GEN_STACK_FRAME,

/*
* Look up a value from the current stack frame.
* Pop <word>
* Find <val> in stack frame using <word>
* Push <val>
*/
L2_OP_STACK_FRAME_LOOKUP,

/*
* Set a value in the current stack frame.
* Pop <key>
* Read <val>
* Assign <val> to stack frame
*/
L2_OP_STACK_FRAME_SET,

/* /*
* Return from a function. * Return from a function.
* NSPop
* Pop <word> * Pop <word>
* Jump to <word> * Jump to <word>
*/ */


/* /*
* Allocate a real from two words. * Allocate a real from two words.
* Pop <word1>
* Pop <word2>
* Alloc real <var> from <word1> << 32 | <word2>
* Pop <high>
* Pop <low>
* Alloc real <var> from <high> << 32 | <low>
* Push <var> * Push <var>
*/ */
L2_OP_ALLOC_REAL_64, L2_OP_ALLOC_REAL_64,
/* /*
* Set a namespace's name to a value. * Set a namespace's name to a value.
* Pop <key> * Pop <key>
* Pop <val>
* Read <val>
* Read <ns> * Read <ns>
* Assign <val> to <ns[<key>]> * Assign <val> to <ns[<key>]>
* Push <val>
*/ */
L2_OP_NAMESPACE_SET, L2_OP_NAMESPACE_SET,



+ 5
- 1
include/lang2/gen/gen.h View File

struct l2_bufio_writer writer; struct l2_bufio_writer writer;
}; };


void l2_gen_init(struct l2_generator *gen);
void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w);
void l2_gen_flush(struct l2_generator *gen);
void l2_gen_free(struct l2_generator *gen); void l2_gen_free(struct l2_generator *gen);

void l2_gen_halt(struct l2_generator *gen);
void l2_gen_stack_frame(struct l2_generator *gen); void l2_gen_stack_frame(struct l2_generator *gen);
void l2_gen_assignment(struct l2_generator *gen, char **ident); void l2_gen_assignment(struct l2_generator *gen, char **ident);
void l2_gen_number(struct l2_generator *gen, double num); void l2_gen_number(struct l2_generator *gen, double num);
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident);


#endif #endif

+ 2
- 2
include/lang2/parse/lex.h View File

}; };


void l2_token_free(struct l2_token *tok); void l2_token_free(struct l2_token *tok);
struct l2_token l2_token_move(struct l2_token *tok);
char *l2_token_extract_str(struct l2_token *tok);
void l2_token_print(struct l2_token *tok, struct l2_io_writer *w); void l2_token_print(struct l2_token *tok, struct l2_io_writer *w);


struct l2_lexer { struct l2_lexer {
struct l2_token currtok; struct l2_token currtok;
struct l2_token toks[2];
struct l2_token toks[4];
int tokidx; int tokidx;
int line; int line;
int ch; int ch;

+ 11
- 1
include/lang2/parse/parse.h View File

#include "lex.h" #include "lex.h"
#include "gen/gen.h" #include "gen/gen.h"


int l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen);
struct l2_parse_error {
int line;
int ch;
char *message;
};

void l2_parse_err(struct l2_parse_error *err, struct l2_token *tok, const char *fmt, ...);
void l2_parse_error_free(struct l2_parse_error *err);

int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err);


#endif #endif

+ 15
- 0
include/lang2/vm/print.h View File

#ifndef L2_VM_PRINT_H
#define L2_VM_PRINT_H

#include "vm.h"

void l2_vm_print_val(struct l2_vm_value *val);
void l2_vm_print_state(struct l2_vm *vm);
void l2_vm_print_heap(struct l2_vm *vm);
void l2_vm_print_stack(struct l2_vm *vm);
void l2_vm_print_nstack(struct l2_vm *vm);

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr);
void l2_vm_print_bytecode(l2_word *ops, size_t opcount);

#endif

+ 6
- 2
include/lang2/vm/vm.h View File

}; };
}; };


#define l2_vm_value_type(val) ((val).flags & 0x0f)

struct l2_vm_buffer { struct l2_vm_buffer {
size_t len; size_t len;
char data[]; char data[];
struct l2_vm { struct l2_vm {
l2_word *ops; l2_word *ops;
size_t opcount; size_t opcount;
l2_word iptr;


struct l2_vm_value *values; struct l2_vm_value *values;
size_t valuessize; size_t valuessize;
struct l2_bitset valueset; struct l2_bitset valueset;


l2_word stack[1024]; l2_word stack[1024];
unsigned char stackflags[1024];
l2_word iptr;
l2_word sptr; l2_word sptr;

l2_word nstack[1024];
l2_word nsptr;
}; };


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

+ 34
- 4
lib/gen/gen.c View File

l2_bufio_put_n(&gen->writer, &word, sizeof(word)); l2_bufio_put_n(&gen->writer, &word, sizeof(word));
} }


void l2_gen_init(struct l2_generator *gen) {
void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) {
l2_strset_init(&gen->atoms); l2_strset_init(&gen->atoms);
l2_strset_init(&gen->strings); l2_strset_init(&gen->strings);
l2_bufio_writer_init(&gen->writer, w);
}

void l2_gen_flush(struct l2_generator *gen) {
l2_bufio_flush(&gen->writer);
} }


void l2_gen_free(struct l2_generator *gen) { void l2_gen_free(struct l2_generator *gen) {
l2_strset_free(&gen->strings); l2_strset_free(&gen->strings);
} }


// Postconditions:
// * Execution is halted
void l2_gen_halt(struct l2_generator *gen) {
put(gen, L2_OP_HALT);
}

// Postconditions:
// * NStack(0) is a namespace value
void l2_gen_stack_frame(struct l2_generator *gen) { void l2_gen_stack_frame(struct l2_generator *gen) {
put(gen, L2_OP_ALLOC_NAMESPACE);
put(gen, L2_OP_GEN_STACK_FRAME);
} }


// Preconditions:
// * Stack(0) is any value
// Postconditions:
// * The namespace contains the new value under key 'ident'
// * Stack(0) is untouched
void l2_gen_assignment(struct l2_generator *gen, char **ident) { void l2_gen_assignment(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atoms, ident); size_t atom_id = l2_strset_put(&gen->atoms, ident);
put(gen, L2_OP_PUSH); put(gen, L2_OP_PUSH);
put(gen, atom_id); put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_SET);
put(gen, L2_OP_STACK_FRAME_SET);
} }



// Postconditions;
// * Stack(0) is changed to a number value
void l2_gen_number(struct l2_generator *gen, double num) { void l2_gen_number(struct l2_generator *gen, double num) {
uint64_t n; uint64_t n;
memcpy(&n, &num, sizeof(num)); memcpy(&n, &num, sizeof(num));
put(gen, L2_OP_PUSH_2); put(gen, L2_OP_PUSH_2);
put(gen, n >> 32);
put(gen, n); put(gen, n);
put(gen, n >> 32);
put(gen, L2_OP_ALLOC_REAL_64); put(gen, L2_OP_ALLOC_REAL_64);
} }

// Postconditions:
// * Stack(0) is any value
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atoms, ident);
put(gen, L2_OP_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP);
}

+ 36
- 0
lib/parse/error.c View File

#include "parse/parse.h"

#include <stdio.h>
#include <stdarg.h>

void l2_parse_err(struct l2_parse_error *err, struct l2_token *tok, const char *fmt, ...) {
err->line = tok->line;
err->ch = tok->ch;
char buf[256];

va_list va;
va_start(va, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, va);

if (n < 0) {
const char *message = "Failed to generate error message!";
err->message = malloc(strlen(message) + 1);
strcpy(err->message, message);
va_end(va);
return;
} else if (n + 1 < sizeof(buf)) {
err->message = malloc(n + 1);
strcpy(err->message, buf);
va_end(va);
return;
}

// Need to allocate for this one
err->message = malloc(n + 1);
vsnprintf(err->message, n + 1, fmt, va);
va_end(va);
}

void l2_parse_error_free(struct l2_parse_error *err) {
free(err->message);
}

+ 42
- 8
lib/parse/lex.c View File



#include <stdlib.h> #include <stdlib.h>


static int parse_number(const char *str, double *num) {
size_t len = strlen(str);
*num = 0;
int power = 1;
for (int i = (int)len - 1; i >= 0; --i) {
char ch = str[i];
if (ch >= '0' && ch <= '9') {
*num += (ch - '0') * power;
power *= 10;
} else {
return -1;
}
}

return 0;
}

const char *l2_token_kind_name(enum l2_token_kind kind) { const char *l2_token_kind_name(enum l2_token_kind kind) {
switch (kind) { switch (kind) {
case L2_TOK_OPEN_PAREN: case L2_TOK_OPEN_PAREN:
} }
} }


struct l2_token l2_token_move(struct l2_token *tok) {
struct l2_token dup = *tok;
if (tok->kind == L2_TOK_STRING) {
tok->v.str = NULL;
}

return dup;
char *l2_token_extract_str(struct l2_token *tok) {
char *str = tok->v.str;
tok->v.str = NULL;
return str;
} }


void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) { void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) {
tok->line = lexer->line; tok->line = lexer->line;
tok->ch = lexer->ch; tok->ch = lexer->ch;


int ch = read_ch(lexer);
int ch = peek_ch(lexer);
switch (ch) { switch (ch) {
case '(': case '(':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_PAREN; tok->kind = L2_TOK_OPEN_PAREN;
break; break;


case ')': case ')':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_PAREN; tok->kind = L2_TOK_CLOSE_PAREN;
break; break;


case '{': case '{':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_BRACE; tok->kind = L2_TOK_OPEN_BRACE;
break; break;


case '}': case '}':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_BRACE; tok->kind = L2_TOK_CLOSE_BRACE;
break; break;


case '[': case '[':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_BRACKET; tok->kind = L2_TOK_OPEN_BRACKET;
break; break;


case ']': case ']':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_BRACKET; tok->kind = L2_TOK_CLOSE_BRACKET;
break; break;


case ',': case ',':
read_ch(lexer);
tok->kind = L2_TOK_COMMA; tok->kind = L2_TOK_COMMA;
break; break;


case '.': case '.':
read_ch(lexer);
tok->kind = L2_TOK_PERIOD; tok->kind = L2_TOK_PERIOD;
break; break;


case ':': case ':':
read_ch(lexer);
{ {
ch = read_ch(lexer); ch = read_ch(lexer);
switch (ch) { switch (ch) {
break; break;


case '"': case '"':
read_ch(lexer);
read_string(lexer, tok); read_string(lexer, tok);
break; break;


default: default:
read_ident(lexer, tok); read_ident(lexer, tok);
if (tok->kind != L2_TOK_IDENT) {
break;
}

double num;
if (parse_number(tok->v.str, &num) >= 0) {
free(tok->v.str);
tok->kind = L2_TOK_NUMBER;
tok->v.num = num;
}
break; break;
} }
} }

+ 27
- 5
lib/parse/parse.c View File



#include "gen/gen.h" #include "gen/gen.h"


static int parse_expression(struct l2_lexer *lexer, struct l2_generator *gen) {
static int parse_expression(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
struct l2_token *tok = l2_lexer_peek(lexer, 1); struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); struct l2_token *tok2 = l2_lexer_peek(lexer, 2);


if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) {
parse_expression(lexer, gen);
l2_gen_assignment(gen, &tok->v.str);
char *ident = l2_token_extract_str(tok);
l2_lexer_get(lexer); // ident
l2_lexer_get(lexer); // :=

if (parse_expression(lexer, gen, err) < 0) {
free(ident);
return -1;
}

l2_gen_assignment(gen, &ident);
return 0; return 0;
} else if (tok->kind == L2_TOK_NUMBER) { } else if (tok->kind == L2_TOK_NUMBER) {
l2_gen_number(gen, tok->v.num); l2_gen_number(gen, tok->v.num);
l2_lexer_get(lexer); // number
return 0;
} else if (tok->kind == L2_TOK_IDENT) {
char *ident = l2_token_extract_str(tok);
l2_lexer_get(lexer); // ident
l2_gen_namespace_lookup(gen, &ident);
return 0; return 0;
} }


l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s",
l2_token_kind_name(tok->kind), l2_token_kind_name(tok2->kind));
return -1; return -1;
} }


int l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen) {
int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_gen_stack_frame(gen); l2_gen_stack_frame(gen);


while (1) { while (1) {
break; break;
} }


if (parse_expression(lexer, gen) < 0) {
if (parse_expression(lexer, gen, err) < 0) {
l2_gen_halt(gen);
l2_gen_flush(gen);
return -1; return -1;
} }
} }


l2_gen_halt(gen);
l2_gen_flush(gen);
return 0; return 0;
} }

+ 202
- 0
lib/vm/print.c View File

#include "vm/print.h"

#include <stdio.h>

void l2_vm_print_val(struct l2_vm_value *val) {
switch (val->flags & 0x0f) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
break;

case L2_VAL_TYPE_INTEGER:
printf("INTEGER %zi\n", val->integer);
break;

case L2_VAL_TYPE_REAL:
printf("REAL %f\n", val->real);
break;

case L2_VAL_TYPE_ARRAY:
{
if (val->data == NULL) {
printf("ARRAY, empty\n");
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
printf("ARRAY, len %zu\n", arr->len);
for (size_t i = 0; i < arr->len; ++i) {
printf(" %zu: %u\n", i, arr->data[i]);
}
}
break;

case L2_VAL_TYPE_BUFFER:
{
if (val->data == NULL) {
printf("BUFFER, empty\n");
return;
}

struct l2_vm_buffer *buf = (struct l2_vm_buffer *)val->data;
printf("BUFFER, len %zu\n", buf->len);
for (size_t i = 0; i < buf->len; ++i) {
printf(" %zu: %c\n", i, buf->data[i]);
}
}
break;

case L2_VAL_TYPE_NAMESPACE:
{
if (val->data == NULL) {
printf("NAMESPACE, empty\n");
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
printf("NAMESPACE, len %zu\n", ns->len);
}
break;
}
}

void l2_vm_print_state(struct l2_vm *vm) {
printf("Stack:\n");
l2_vm_print_stack(vm);
printf("Heap:\n");
l2_vm_print_heap(vm);
printf("NStack:\n");
l2_vm_print_nstack(vm);
}

void l2_vm_print_heap(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->valuessize; ++i) {
if (l2_bitset_get(&vm->valueset, i)) {
printf(" %u: ", i);
l2_vm_print_val(&vm->values[i]);
}
}
}

void l2_vm_print_stack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->sptr; ++i) {
printf(" %i: %i\n", i, vm->stack[i]);
}
}

void l2_vm_print_nstack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->nsptr; ++i) {
printf(" %i: %i\n", i, vm->nstack[i]);
}
}

static void print_op_num(l2_word *ops, size_t opcount, size_t ptr) {
if (ptr >= opcount) {
printf("<EOF>");
} else {
printf("%i", ops[ptr]);
}
}

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++];

switch (opcode) {
case L2_OP_NOP:
printf("NOP\n");
break;

case L2_OP_PUSH:
printf("PUSH ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
break;

case L2_OP_PUSH_2:
printf("PUSH2 ");
print_op_num(ops, opcount, (*ptr)++);
printf(" ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
break;

case L2_OP_POP:
printf("POP\n");
break;

case L2_OP_DUP:
printf("DUP\n");
break;

case L2_OP_ADD:
printf("ADD\n");
break;

case L2_OP_CALL:
printf("CALL\n");
break;

case L2_OP_GEN_STACK_FRAME:
printf("GEN_STACK_FRAME\n");
break;

case L2_OP_STACK_FRAME_LOOKUP:
printf("STACK_FRAME_LOOKUP\n");
break;

case L2_OP_STACK_FRAME_SET:
printf("STACK_FRAME_SET\n");
break;

case L2_OP_RET:
printf("RET\n");
break;

case L2_OP_ALLOC_INTEGER_32:
printf("ALLOC_INTEGER_32\n");
break;

case L2_OP_ALLOC_INTEGER_64:
printf("ALLOC_INTEGER_64\n");
break;

case L2_OP_ALLOC_REAL_32:
printf("ALLOC_REAL_32\n");
break;

case L2_OP_ALLOC_REAL_64:
printf("ALLOC_REAL_64\n");
break;

case L2_OP_ALLOC_BUFFER_STATIC:
printf("ALLOC_BUFFER_STATIC\n");
break;

case L2_OP_ALLOC_BUFFER_ZERO:
printf("ALLOC_BUFFER_ZERO\n");
break;

case L2_OP_ALLOC_ARRAY:
printf("ALLOC_ARRAY\n");
break;

case L2_OP_ALLOC_NAMESPACE:
printf("ALLOC_NAMESPACE\n");
break;

case L2_OP_NAMESPACE_SET:
printf("NAMESPACE_SET\n");
break;

case L2_OP_HALT:
printf("HALT\n");
break;
}
}

void l2_vm_print_bytecode(l2_word *ops, size_t opcount) {
size_t ptr = 0;
while (ptr < opcount) {
l2_vm_print_op(ops, opcount, &ptr);
}
}

+ 64
- 38
lib/vm/vm.c View File

return d; return d;
} }


static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val);
static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val);

static void gc_mark(struct l2_vm *vm, l2_word id) { static void gc_mark(struct l2_vm *vm, l2_word id) {
printf("GC MARK %i\n", id); printf("GC MARK %i\n", id);
struct l2_vm_value *val = &vm->values[id]; struct l2_vm_value *val = &vm->values[id];
val->flags |= L2_VAL_MARKED; val->flags |= L2_VAL_MARKED;


int typ = val->flags & 0x0f;
int typ = l2_vm_value_type(*val);
if (typ == L2_VAL_TYPE_ARRAY) { if (typ == L2_VAL_TYPE_ARRAY) {
if (val->data == NULL) {
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
for (size_t i = 0; i < arr->len; ++i) {
gc_mark(vm, arr->data[i]);
}
gc_mark_array(vm, val);
} else if (typ == L2_VAL_TYPE_NAMESPACE) { } else if (typ == L2_VAL_TYPE_NAMESPACE) {
if (val->data == NULL) {
return;
}
gc_mark_namespace(vm, val);
}
}


struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
if (key == 0 || key == ~(l2_word)0) {
continue;
}
static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
return;
}


gc_mark(vm, ns->data[ns->size + i]);
struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
for (size_t i = 0; i < arr->len; ++i) {
gc_mark(vm, arr->data[i]);
}
}

static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
if (key == 0 || key == ~(l2_word)0) {
continue;
} }

gc_mark(vm, ns->data[ns->size + i]);
} }
} }


struct l2_vm_value *val = &vm->values[id]; struct l2_vm_value *val = &vm->values[id];
l2_bitset_unset(&vm->valueset, id); l2_bitset_unset(&vm->valueset, id);


int typ = val->flags & 0x0f;
int typ = l2_vm_value_type(*val);
if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) { if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
free(val->data); free(val->data);
// Don't need to do anything more; the next round of GC will free // Don't need to do anything more; the next round of GC will free
vm->opcount = opcount; vm->opcount = opcount;
vm->iptr = 0; vm->iptr = 0;
vm->sptr = 0; vm->sptr = 0;
vm->nsptr = 0;


vm->values = NULL; vm->values = NULL;
vm->valuessize = 0; vm->valuessize = 0;
} }


size_t l2_vm_gc(struct l2_vm *vm) { size_t l2_vm_gc(struct l2_vm *vm) {
for (l2_word sptr = 0; sptr < vm->sptr; ++sptr) {
if (vm->stackflags[sptr]) {
gc_mark(vm, vm->stack[sptr]);
}
for (l2_word nsptr = 0; nsptr < vm->nsptr; ++nsptr) {
struct l2_vm_value *val = &vm->values[vm->nstack[nsptr]];
val->flags |= L2_VAL_MARKED;
gc_mark_namespace(vm, val);
} }


return gc_sweep(vm); return gc_sweep(vm);


case L2_OP_PUSH: case L2_OP_PUSH:
vm->stack[vm->sptr] = vm->ops[vm->iptr]; vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->stackflags[vm->sptr] = 0;
vm->sptr += 1; vm->sptr += 1;
vm->iptr += 1; vm->iptr += 1;
break; break;
case L2_OP_PUSH_2: case L2_OP_PUSH_2:
vm->stack[vm->sptr] = vm->ops[vm->iptr]; vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1]; vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1];
vm->stackflags[vm->sptr] = 0;
vm->stackflags[vm->sptr + 1] = 0;
vm->sptr += 2; vm->sptr += 2;
vm->iptr += 2; vm->iptr += 2;
break; break;


case L2_OP_DUP: case L2_OP_DUP:
vm->stack[vm->sptr] = vm->ops[vm->sptr - 1]; vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
vm->stackflags[vm->sptr] = 0;
vm->sptr += 1; vm->sptr += 1;
break; break;


case L2_OP_ADD: case L2_OP_ADD:
vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1]; vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
vm->stackflags[vm->sptr - 2] = 0;
vm->sptr -= 1; vm->sptr -= 1;
break; break;


case L2_OP_CALL: case L2_OP_CALL:
word = vm->stack[vm->sptr - 1]; word = vm->stack[vm->sptr - 1];
vm->stack[vm->sptr - 1] = vm->iptr + 1; vm->stack[vm->sptr - 1] = vm->iptr + 1;
vm->stackflags[vm->sptr - 1] = 0;
vm->iptr = word; vm->iptr = word;
break; break;


case L2_OP_GEN_STACK_FRAME:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->nstack[vm->nsptr] = word;
vm->nsptr += 1;
break;

case L2_OP_STACK_FRAME_LOOKUP:
{
l2_word key = vm->stack[vm->sptr - 1];
struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
vm->stack[vm->sptr - 1] = l2_vm_namespace_get(ns, key);
}
break;

case L2_OP_STACK_FRAME_SET:
{
l2_word key = vm->stack[vm->sptr - 1];
l2_word val = vm->stack[vm->sptr - 2];
struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
l2_vm_namespace_set(ns, key, val);
vm->sptr -= 1;
}
break;

case L2_OP_RET: case L2_OP_RET:
vm->nsptr -= 1;
vm->iptr = vm->stack[vm->sptr - 1]; vm->iptr = vm->stack[vm->sptr - 1];
vm->sptr -= 1; vm->sptr -= 1;
vm->nsptr -= 1;
break; break;


case L2_OP_ALLOC_INTEGER_32: case L2_OP_ALLOC_INTEGER_32:
vm->values[word].flags = L2_VAL_TYPE_INTEGER; vm->values[word].flags = L2_VAL_TYPE_INTEGER;
vm->values[word].integer = vm->stack[--vm->sptr]; vm->values[word].integer = vm->stack[--vm->sptr];
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;


(uint64_t)vm->stack[vm->sptr - 2]); (uint64_t)vm->stack[vm->sptr - 2]);
vm->sptr -= 2; vm->sptr -= 2;
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;


vm->values[word].flags = L2_VAL_TYPE_REAL; vm->values[word].flags = L2_VAL_TYPE_REAL;
vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]); vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]);
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;


vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]); vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
vm->sptr -= 2; vm->sptr -= 2;
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;


(unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer), (unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
vm->ops + offset, length); vm->ops + offset, length);
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
} }
break; break;
vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length); vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
((struct l2_vm_buffer *)vm->values[word].data)->len = length; ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
} }
break; break;
vm->values[word].flags = L2_VAL_TYPE_ARRAY; vm->values[word].flags = L2_VAL_TYPE_ARRAY;
vm->values[word].data = NULL; // Will be allocated on first insert vm->values[word].data = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;


vm->values[word].flags = L2_VAL_TYPE_NAMESPACE; vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[word].data = NULL; // Will be allocated on first insert vm->values[word].data = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word; vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1; vm->sptr += 1;
break; break;



+ 2
- 2
test/build.bx View File

files := src ../lib files := src ../lib
includes := snow ../include/lang2 includes := snow ../include/lang2
defines := SNOW_ENABLED defines := SNOW_ENABLED
sanitizers := address
cflags := -g -O3
#sanitizers := address undefined
cflags := -g

+ 50
- 0
test/src/eval.t.c View File

#include "parse/parse.h"
#include "vm/vm.h"
#include "vm/print.h"

#include <stdio.h>
#include <snow/snow.h>

static struct l2_lexer lex;
static struct l2_io_mem_reader r;
static struct l2_generator gen;
static struct l2_io_mem_writer w;
static struct l2_vm vm;
static struct l2_parse_error err;

static struct l2_vm_value *var_lookup(const char *name) {
l2_word atom_id = l2_strset_get(&gen.atoms, name);
l2_word id = l2_vm_namespace_get(&vm.values[vm.nstack[0]], atom_id);
return &vm.values[id];
}

static void init(const char *str) {
r.r.read = l2_io_mem_read;
r.idx = 0;
r.len = strlen(str);
r.mem = str;
l2_lexer_init(&lex, &r.r);

w.w.write = l2_io_mem_write;
w.len = 0;
w.mem = NULL;
l2_gen_init(&gen, (struct l2_io_writer *)&w);
}

static void done() {
l2_gen_free(&gen);
free(w.mem);
}

describe(parse) {
test("parse program") {
init("foo := 10");
defer(done());
assert(l2_parse_program(&lex, &gen, &err) >= 0);

l2_vm_init(&vm, (l2_word *)w.mem, w.len / sizeof(l2_word));
l2_vm_run(&vm);
assert(l2_vm_value_type(*var_lookup("foo")) == L2_VAL_TYPE_REAL);
assert(var_lookup("foo")->real == 10);
}
}

Loading…
Cancel
Save