Browse Source

string

master
Martin Dørum 3 years ago
parent
commit
74d6840509
5 changed files with 98 additions and 21 deletions
  1. 7
    0
      include/lang2/bytecode.h
  2. 11
    2
      include/lang2/gen/gen.h
  3. 45
    7
      lib/gen/gen.c
  4. 5
    0
      lib/parse/parse.c
  5. 30
    12
      test/src/eval.t.c

+ 7
- 0
include/lang2/bytecode.h View File

@@ -52,6 +52,13 @@ enum l2_opcode {
*/
L2_OP_CALL,

/*
* Jump relative.
* Pop <word>
* Jump <word> words forwards
*/
L2_OP_RJMP,

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

+ 11
- 2
include/lang2/gen/gen.h View File

@@ -3,10 +3,18 @@

#include "../io.h"
#include "../strset.h"
#include "../bytecode.h"

struct l2_generator_string {
l2_word length;
l2_word pos;
};

struct l2_generator {
struct l2_strset atoms;
struct l2_strset strings;
struct l2_strset atomset;
struct l2_strset stringset;
struct l2_generator_string *strings;
l2_word pos;
struct l2_bufio_writer writer;
};

@@ -18,6 +26,7 @@ void l2_gen_halt(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_number(struct l2_generator *gen, double num);
void l2_gen_string(struct l2_generator *gen, char **str);
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident);

#endif

+ 45
- 7
lib/gen/gen.c View File

@@ -4,11 +4,14 @@

static void put(struct l2_generator *gen, l2_word word) {
l2_bufio_put_n(&gen->writer, &word, sizeof(word));
gen->pos += 1;
}

void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) {
l2_strset_init(&gen->atoms);
l2_strset_init(&gen->strings);
l2_strset_init(&gen->atomset);
l2_strset_init(&gen->stringset);
gen->strings = NULL;
gen->pos = 0;
l2_bufio_writer_init(&gen->writer, w);
}

@@ -17,8 +20,8 @@ void l2_gen_flush(struct l2_generator *gen) {
}

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

// Postconditions:
@@ -39,13 +42,12 @@ void l2_gen_stack_frame(struct l2_generator *gen) {
// * The namespace contains the new value under key 'ident'
// * Stack(0) is untouched
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->atomset, ident);
put(gen, L2_OP_PUSH);
put(gen, atom_id);
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) {
@@ -57,10 +59,46 @@ void l2_gen_number(struct l2_generator *gen, double num) {
put(gen, L2_OP_ALLOC_REAL_64);
}

void l2_gen_string(struct l2_generator *gen, char **str) {
size_t id = l2_strset_get(&gen->stringset, *str);
if (id == 0) {
size_t len = strlen(*str);
size_t aligned = len;
if (aligned % sizeof(l2_word) != 0) {
aligned += sizeof(l2_word) - (aligned % sizeof(l2_word));
}

put(gen, L2_OP_PUSH);
put(gen, aligned / sizeof(l2_word));
l2_word pos = gen->pos;

l2_bufio_put_n(&gen->writer, *str, len);
for (size_t i = len; i < aligned; ++i) {
l2_bufio_put(&gen->writer, '\0');
}

id = l2_strset_put(&gen->stringset, str);
gen->strings = realloc(gen->strings, id * sizeof(*gen->strings));
gen->strings[id - 1].length = len;
gen->strings[id - 1].pos = pos;

put(gen, L2_OP_PUSH_2);
put(gen, pos);
put(gen, len);
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
} else {
struct l2_generator_string *s = &gen->strings[id - 1];
put(gen, L2_OP_PUSH_2);
put(gen, s->pos);
put(gen, s->length);
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
}
}

// 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);
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP);

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

@@ -28,6 +28,11 @@ static int parse_expression(
l2_lexer_consume(lexer); // ident
l2_gen_namespace_lookup(gen, &ident);
return 0;
} else if (tok->kind == L2_TOK_STRING) {
char *str = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // string
l2_gen_string(gen, &str);
return 0;
}

l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s",

+ 30
- 12
test/src/eval.t.c View File

@@ -10,15 +10,14 @@ 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 atom_id = l2_strset_get(&gen.atomset, name);
l2_word id = l2_vm_namespace_get(&vm.values[vm.nstack[0]], atom_id);
return &vm.values[id];
}

static int eval(const char *str) {
static int eval_impl(const char *str, struct l2_parse_error *err) {
r.r.read = l2_io_mem_read;
r.idx = 0;
r.len = strlen(str);
@@ -30,7 +29,7 @@ static int eval(const char *str) {
w.mem = NULL;
l2_gen_init(&gen, (struct l2_io_writer *)&w);

if (l2_parse_program(&lex, &gen, &err) < 0) {
if (l2_parse_program(&lex, &gen, err) < 0) {
free(w.mem);
return -1;
}
@@ -42,24 +41,43 @@ static int eval(const char *str) {
return 0;
}

#define eval(str) do { \
snow_fail_update(); \
struct l2_parse_error err; \
if (eval_impl(str, &err) < 0) { \
snow_fail("Parsing failed: %i:%i: %s", err.line, err.ch, err.message); \
} \
} while (0)

describe(eval) {
test("eval assignment") {
test("assignment") {
eval("foo := 10");
defer(l2_vm_free(&vm));
defer(l2_gen_free(&gen));

assert(l2_vm_value_type(var_lookup("foo")) == L2_VAL_TYPE_REAL);
assert(var_lookup("foo")->real == 10);
asserteq(l2_vm_value_type(var_lookup("foo")), L2_VAL_TYPE_REAL);
asserteq(var_lookup("foo")->real, 10);
}

test("eval var deref assignment") {
test("var deref assignment") {
eval("foo := 10\nbar := foo");
defer(l2_vm_free(&vm));
defer(l2_gen_free(&gen));

assert(l2_vm_value_type(var_lookup("foo")) == L2_VAL_TYPE_REAL);
assert(var_lookup("foo")->real == 10);
assert(l2_vm_value_type(var_lookup("bar")) == L2_VAL_TYPE_REAL);
assert(var_lookup("bar")->real == 10);
asserteq(l2_vm_value_type(var_lookup("foo")), L2_VAL_TYPE_REAL);
asserteq(var_lookup("foo")->real, 10);
asserteq(l2_vm_value_type(var_lookup("bar")), L2_VAL_TYPE_REAL);
asserteq(var_lookup("bar")->real, 10);
}

test("string assignment") {
eval("foo := \"hello world\"");
defer(l2_vm_free(&vm));
defer(l2_gen_free(&gen));

asserteq(l2_vm_value_type(var_lookup("foo")), L2_VAL_TYPE_BUFFER);
struct l2_vm_buffer *buf = var_lookup("foo")->data;
asserteq(buf->len, 11);
assert(strncmp(buf->data, "hello world", 11) == 0);
}
}

Loading…
Cancel
Save