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

*/ */
L2_OP_CALL, L2_OP_CALL,


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

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

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



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

struct l2_generator_string {
l2_word length;
l2_word pos;
};


struct l2_generator { 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; struct l2_bufio_writer writer;
}; };


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_string(struct l2_generator *gen, char **str);
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident);


#endif #endif

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



static void put(struct l2_generator *gen, l2_word word) { static void put(struct l2_generator *gen, l2_word word) {
l2_bufio_put_n(&gen->writer, &word, sizeof(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) { 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); l2_bufio_writer_init(&gen->writer, w);
} }


} }


void l2_gen_free(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: // Postconditions:
// * The namespace contains the new value under key 'ident' // * The namespace contains the new value under key 'ident'
// * Stack(0) is untouched // * 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->atomset, ident);
put(gen, L2_OP_PUSH); put(gen, L2_OP_PUSH);
put(gen, atom_id); put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_SET); put(gen, L2_OP_STACK_FRAME_SET);
} }



// Postconditions; // Postconditions;
// * Stack(0) is changed to a number value // * 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) {
put(gen, L2_OP_ALLOC_REAL_64); 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: // Postconditions:
// * Stack(0) is any value // * Stack(0) is any value
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { 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, L2_OP_PUSH);
put(gen, atom_id); put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP); put(gen, L2_OP_STACK_FRAME_LOOKUP);

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

l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_gen_namespace_lookup(gen, &ident); l2_gen_namespace_lookup(gen, &ident);
return 0; 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", l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s",

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

static struct l2_generator gen; static struct l2_generator gen;
static struct l2_io_mem_writer w; static struct l2_io_mem_writer w;
static struct l2_vm vm; static struct l2_vm vm;
static struct l2_parse_error err;


static struct l2_vm_value *var_lookup(const char *name) { 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); l2_word id = l2_vm_namespace_get(&vm.values[vm.nstack[0]], atom_id);
return &vm.values[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.r.read = l2_io_mem_read;
r.idx = 0; r.idx = 0;
r.len = strlen(str); r.len = strlen(str);
w.mem = NULL; w.mem = NULL;
l2_gen_init(&gen, (struct l2_io_writer *)&w); 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); free(w.mem);
return -1; return -1;
} }
return 0; 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) { describe(eval) {
test("eval assignment") {
test("assignment") {
eval("foo := 10"); eval("foo := 10");
defer(l2_vm_free(&vm)); defer(l2_vm_free(&vm));
defer(l2_gen_free(&gen)); 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"); eval("foo := 10\nbar := foo");
defer(l2_vm_free(&vm)); defer(l2_vm_free(&vm));
defer(l2_gen_free(&gen)); 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