Parcourir la source

add test cases, and fix bugs in the process

master
Martin Dørum il y a 3 ans
Parent
révision
d5974171e3

+ 2
- 1
include/lang2/parse/lex.h Voir le fichier

@@ -59,9 +59,10 @@ struct l2_token {

#define l2_token_get_kind(tok) ((enum l2_token_kind)((tok)->v.flags & ~(1 << 7)))
#define l2_token_get_name(tok) (l2_token_kind_name(l2_token_get_kind(tok)))
#define l2_token_is_small(tok) ((tok)->v.flags & (1 << 7))
#define l2_token_is_small(tok) ((tok)->v.flags & L2_TOK_SMALL)
void l2_token_free(struct l2_token *tok);
struct l2_token_value l2_token_extract_val(struct l2_token *tok);
const char *l2_token_get_str(struct l2_token *tok);
void l2_token_print(struct l2_token *tok, struct l2_io_writer *w);

struct l2_lexer {

+ 8
- 0
lib/parse/lex.c Voir le fichier

@@ -90,6 +90,14 @@ struct l2_token_value l2_token_extract_val(struct l2_token *tok) {
return v;
}

const char *l2_token_get_str(struct l2_token *tok) {
if (l2_token_is_small(tok)) {
return tok->v.strbuf;
} else {
return tok->v.str;
}
}

void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) {
lexer->toks[0].v.flags = L2_TOK_EOF,
lexer->tokidx = 0;

+ 22
- 36
lib/parse/parse.c Voir le fichier

@@ -13,12 +13,7 @@ static int tok_is_end(struct l2_token *tok) {

static int tok_is_infix(struct l2_token *tok) {
if (l2_token_get_kind(tok) != L2_TOK_IDENT) return 0;
char *str;
if (l2_token_is_small(tok)) {
str = tok->v.strbuf;
} else {
str = tok->v.str;
}
const char *str = l2_token_get_str(tok);

return
(str[0] == '$' && str[1] != '\0') ||
@@ -58,7 +53,7 @@ static int parse_object_literal(
return -1;
}

l2_trace("key: '%s'", tok->v.str);
l2_trace("key: '%s'", l2_token_get_str(tok));
struct l2_token_value key = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident

@@ -258,11 +253,7 @@ static int parse_arg_level_expression_base(
l2_lexer_consume(lexer); // ')'
} else if (l2_token_get_kind(tok) == L2_TOK_IDENT) {
l2_trace_scope("ident");
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
l2_trace("ident '%s'", l2_token_get_str(tok));
struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident

@@ -280,7 +271,7 @@ static int parse_arg_level_expression_base(
l2_gen_number(gen, number);
} else if (l2_token_get_kind(tok) == L2_TOK_STRING) {
l2_trace_scope("string literal");
l2_trace("string '%s'", tok->v.str);
l2_trace("string '%s'", l2_token_get_str(tok));
struct l2_token_value str = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // string

@@ -293,7 +284,7 @@ static int parse_arg_level_expression_base(
l2_token_get_kind(tok) == L2_TOK_QUOT &&
l2_token_get_kind(tok2) == L2_TOK_IDENT) {
l2_trace_scope("atom literal");
l2_trace("atom '%s'", tok->v.str);
l2_trace("atom '%s'", l2_token_get_str(tok2));
struct l2_token_value ident = l2_token_extract_val(tok2);
l2_lexer_consume(lexer); // "'"
l2_lexer_consume(lexer); // ident
@@ -334,10 +325,18 @@ static int parse_func_call_after_base(
// so we need to parse the operator, then the rhs

// Operator
if (parse_arg_level_expression(lexer, gen, err) < 0) {
int ret = parse_arg_level_expression(lexer, gen, err);
if (ret < 0) {
return -1;
}

// If the operator wasn't just the one base expression,
// abort; we're not doing the infix call
if (ret == 1) {
argc += 1;
break;
}

// RHS
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
@@ -377,6 +376,7 @@ static int parse_arg_level_expression(
return -1;
}

int ret = 0;
while (1) {
struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2);
@@ -407,11 +407,7 @@ static int parse_arg_level_expression(
l2_token_get_kind(tok2) == L2_TOK_IDENT &&
l2_token_get_kind(tok3) == L2_TOK_EQUALS) {
l2_trace_scope("namespace assign");
if (l2_token_is_small(tok2)) {
l2_trace("ident '%s'", tok2->v.strbuf);
} else {
l2_trace("ident '%s'", tok2->v.str);
}
l2_trace("ident '%s'", l2_token_get_str(tok2));
struct l2_token_value ident = l2_token_extract_val(tok2);
l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident
@@ -432,11 +428,7 @@ static int parse_arg_level_expression(
l2_token_get_kind(tok) == L2_TOK_PERIOD &&
l2_token_get_kind(tok2) == L2_TOK_IDENT) {
l2_trace_scope("namespace lookup");
if (l2_token_is_small(tok2)) {
l2_trace("ident '%s'", tok2->v.strbuf);
} else {
l2_trace("ident '%s'", tok2->v.str);
}
l2_trace("ident '%s'", l2_token_get_str(tok2));
struct l2_token_value ident = l2_token_extract_val(tok2);
l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident
@@ -498,9 +490,11 @@ static int parse_arg_level_expression(
} else {
break;
}

ret = 1;
}

return 0;
return ret;
}

static int parse_expression(
@@ -513,11 +507,7 @@ static int parse_expression(
l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_COLON_EQ) {
l2_trace_scope("assign expression");
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
l2_trace("ident '%s'", l2_token_get_str(tok));
struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // :=
@@ -536,11 +526,7 @@ static int parse_expression(
l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_EQUALS) {
l2_trace_scope("replacement assign expression");
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
l2_trace("ident '%s'", l2_token_get_str(tok));
struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // =

+ 32
- 106
lib/vm/builtins.c Voir le fichier

@@ -66,113 +66,39 @@ static void print_val(struct l2_vm *vm, struct l2_io_writer *out, struct l2_vm_v
}
}

l2_word l2_builtin_add(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 1) {
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = 0;
return id;
}

struct l2_vm_value *val = &vm->values[argv[0]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

double sum = val->real;
for (l2_word i = 1; i < argc; ++i) {
val = &vm->values[argv[i]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

sum += val->real;
}

l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = sum;
return id;
}

l2_word l2_builtin_sub(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 1) {
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = 0;
return id;
}

struct l2_vm_value *val = &vm->values[argv[0]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

double sum = val->real;
for (l2_word i = 1; i < argc; ++i) {
val = &vm->values[argv[i]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

sum -= val->real;
}

l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = sum;
return id;
}

l2_word l2_builtin_mul(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 1) {
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = 1;
return id;
}

struct l2_vm_value *val = &vm->values[argv[0]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

double sum = val->real;
for (l2_word i = 1; i < argc; ++i) {
val = &vm->values[argv[i]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

sum *= val->real;
}

l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = sum;
return id;
}

l2_word l2_builtin_div(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 1) {
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = 1;
return id;
}

struct l2_vm_value *val = &vm->values[argv[0]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

double sum = val->real;
for (l2_word i = 1; i < argc; ++i) {
val = &vm->values[argv[i]];
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) {
return l2_vm_type_error(vm, val);
}

sum /= val->real;
}

l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
vm->values[id].real = sum;
return id;
#define X(name, identity, op) \
l2_word name(struct l2_vm *vm, l2_word argc, l2_word *argv) { \
if (argc == 0) { \
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \
vm->values[id].real = identity; \
return id; \
} \
struct l2_vm_value *first = &vm->values[argv[0]]; \
if (l2_value_get_type(first) != L2_VAL_TYPE_REAL) { \
return l2_vm_type_error(vm, first); \
} \
if (argc == 1) { \
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \
vm->values[id].real = identity op first->real; \
return id; \
} \
double sum = first->real; \
for (l2_word i = 1; i < argc; ++i) { \
struct l2_vm_value *val = &vm->values[argv[i]]; \
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { \
return l2_vm_type_error(vm, val); \
} \
sum = sum op val->real; \
} \
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \
vm->values[id].real = sum; \
return id; \
}
X(l2_builtin_add, 0, +)
X(l2_builtin_sub, 0, -)
X(l2_builtin_mul, 1, *)
X(l2_builtin_div, 1, /)
#undef X

l2_word l2_builtin_eq(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 2) {

+ 73
- 0
test/examples/builtins.l2 Voir le fichier

@@ -0,0 +1,73 @@
print "+"
print +()
print +(10)
print 10 + 20
print (+ 10 20 30)

print "\n-"
print -() -(10)
print 10 - 20
print (- 10 20 30)

print "\n/"
print /() /(10)
print 10 / 2
print (/ 10 2 2)

print "\n*"
print *() *(10)
print 10 * 2
print (* 10 20 30)

print "\n=="
print ==() ==(10)
print 10 == 10 20 == 10
print (== 10 20 30)
print (== 'a 'a 'a)

print "\n!="
print !=() !=(10)
print 10 != 10 20 != 10
print (!= 10 20 30)
print (!= 'a 'a 'a)

print "\n>"
print 10 > 20
print 20 > 10
print 10 > 10
print (> 1 10 100 200)

print "\n>="
print 10 >= 20
print 20 >= 10
print 10 >= 10
print (>= 1 10 100 200)

print "\n<"
print 10 < 20
print 20 < 10
print 10 < 10
print (< 1 10 100 200)

print "\n<="
print 10 <= 20
print 20 <= 10
print 10 <= 10
print (<= 1 10 100 200)

print "\nprint"
print none
print 'true 'false 'hello
print 100
print 100.5
print 0xff
print "Hello World"
print [none 'true 'false 'hello 100.1 "Nope" {} {0}]
print {} {a: 10}

print "\nlen"
print (len 10)
print (len [])
print (len [10 20])
print (len "Hello")
print (len {a: 10; b: 20; c: 30})

+ 73
- 0
test/examples/builtins.l2.expected Voir le fichier

@@ -0,0 +1,73 @@
+
0
10
30
60

-
0 -10
-10
-40

/
1 0.1
5
2.5

*
1 10
20
6000

==
(true) (true)
(true) (false)
(false)
(true)

!=
(false) (false)
(false) (true)
(true)
(false)

>
(false)
(true)
(false)
(false)

>=
(false)
(true)
(true)
(false)

<
(true)
(false)
(false)
(true)

<=
(true)
(false)
(true)
(true)

print
(none)
(true) (false) (atom 20)
100
100.5
255
Hello World
[(none) (true) (false) (atom 20) 100.1 Nope (namespace) (function)]
(namespace) (namespace)

len
0
0
2
5
3

+ 1
- 0
test/src/examples.t.c Voir le fichier

@@ -131,6 +131,7 @@ describe(exaples) {
check("arrays.l2");
check("functions.l2");
check("dynamic-lookups.l2");
check("builtins.l2");

if (error_message != NULL) {
free(error_message);

Chargement…
Annuler
Enregistrer