✨ assert-eqv! function.
parent
7847fe4c5d
commit
0bb1512fc4
|
@ -2,6 +2,7 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "moka.h"
|
||||||
|
|
||||||
void register_builtins(struct moka* moka)
|
void register_builtins(struct moka* moka)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +10,7 @@ void register_builtins(struct moka* moka)
|
||||||
moka_decl_native(moka, "println", mk_println);
|
moka_decl_native(moka, "println", mk_println);
|
||||||
moka_decl_native(moka, "define", mk_define);
|
moka_decl_native(moka, "define", mk_define);
|
||||||
moka_decl_native(moka, "array", mk_array);
|
moka_decl_native(moka, "array", mk_array);
|
||||||
|
moka_decl_native(moka, "assert-eqv!", mk_assert_eqv_mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOKA mk_println(struct moka* moka, struct vec* args)
|
MOKA mk_println(struct moka* moka, struct vec* args)
|
||||||
|
@ -64,3 +66,30 @@ MOKA mk_array(struct moka* moka, struct vec* args)
|
||||||
|
|
||||||
return moka_top(moka);
|
return moka_top(moka);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOKA mk_assert_eqv_mut(struct moka* moka, struct vec* args)
|
||||||
|
{
|
||||||
|
assert(moka);
|
||||||
|
assert(args);
|
||||||
|
|
||||||
|
MOKA lhs = MK_EVAL((MOKA) args->data[0]);
|
||||||
|
MOKA rhs = MK_EVAL((MOKA) args->data[1]);
|
||||||
|
int line = moka_line(moka, lhs);
|
||||||
|
|
||||||
|
char lhs_buf[MK_STRLEN];
|
||||||
|
moka_str(moka, lhs, lhs_buf, MK_STRLEN);
|
||||||
|
|
||||||
|
char rhs_buf[MK_STRLEN];
|
||||||
|
moka_str(moka, rhs, rhs_buf, MK_STRLEN);
|
||||||
|
|
||||||
|
if (!moka_is_eqv(moka, lhs, rhs))
|
||||||
|
{
|
||||||
|
status_push(moka->status, STATUS_ERROR, line,
|
||||||
|
"assertion failed\nlhs = %s\nrhs = %s",
|
||||||
|
lhs_buf, rhs_buf);
|
||||||
|
|
||||||
|
return moka_push_bool(moka, false, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return moka_push_bool(moka, true, line);
|
||||||
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@ void register_builtins(struct moka* moka);
|
||||||
MOKA mk_println(struct moka* moka, struct vec* args);
|
MOKA mk_println(struct moka* moka, struct vec* args);
|
||||||
MOKA mk_define(struct moka* moka, struct vec* args);
|
MOKA mk_define(struct moka* moka, struct vec* args);
|
||||||
MOKA mk_array(struct moka* moka, struct vec* args);
|
MOKA mk_array(struct moka* moka, struct vec* args);
|
||||||
|
MOKA mk_assert_eqv_mut(struct moka* moka, struct vec* args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -244,9 +244,6 @@ void compiler_quote(struct compiler* self,
|
||||||
|
|
||||||
switch (node->kind)
|
switch (node->kind)
|
||||||
{
|
{
|
||||||
case NODE_INT: {
|
|
||||||
compiler_compile(self, node, prog, moka);
|
|
||||||
} break;
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
node->kind = NODE_SYMBOL;
|
node->kind = NODE_SYMBOL;
|
||||||
compiler_compile(self, node, prog, moka);
|
compiler_compile(self, node, prog, moka);
|
||||||
|
@ -262,9 +259,7 @@ void compiler_quote(struct compiler* self,
|
||||||
node->children.size);
|
node->children.size);
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "cannot quote node <%s>\n",
|
compiler_compile(self, node, prog, moka);
|
||||||
NodeKindStr[node->kind]);
|
|
||||||
abort();
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
lib/exec.c
11
lib/exec.c
|
@ -1,4 +1,5 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
void exec_init(struct exec* self)
|
void exec_init(struct exec* self)
|
||||||
{
|
{
|
||||||
|
@ -24,6 +25,11 @@ void exec_prog(struct exec* self,
|
||||||
moka,
|
moka,
|
||||||
prog,
|
prog,
|
||||||
prog->instructions.data[self->pc]);
|
prog->instructions.data[self->pc]);
|
||||||
|
|
||||||
|
if (!status_is_ok(moka->status))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +50,11 @@ void exec_instr(struct exec* self,
|
||||||
|
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
moka_call(moka, param);
|
moka_call(moka, param);
|
||||||
|
if (!status_is_ok(moka->status))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ void lexer_init(struct lexer* self,
|
||||||
str_push(&self->separators, ')');
|
str_push(&self->separators, ')');
|
||||||
str_push(&self->separators, '[');
|
str_push(&self->separators, '[');
|
||||||
str_push(&self->separators, ']');
|
str_push(&self->separators, ']');
|
||||||
|
str_push(&self->separators, '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_free(struct lexer* self)
|
void lexer_free(struct lexer* self)
|
||||||
|
@ -425,14 +426,8 @@ bool lexer_is_ident(struct lexer* self, size_t index)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char c = self->source[index];
|
|
||||||
|
|
||||||
return isalnum(c)
|
return !lexer_is_sep(self, index);
|
||||||
|| c == '_'
|
|
||||||
|| c == '!'
|
|
||||||
|| c == '?'
|
|
||||||
|| c == '-'
|
|
||||||
|| c == ':';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct token* lexer_try_new_text(struct lexer* self,
|
struct token* lexer_try_new_text(struct lexer* self,
|
||||||
|
|
|
@ -109,6 +109,10 @@ int module_load_from_str(struct module* self, char const* source)
|
||||||
exec_init(&exec);
|
exec_init(&exec);
|
||||||
|
|
||||||
exec_prog(&exec, &self->moka, &self->prog);
|
exec_prog(&exec, &self->moka, &self->prog);
|
||||||
|
if (!status_is_ok(self->moka.status))
|
||||||
|
{
|
||||||
|
status_dump(self->moka.status);
|
||||||
|
}
|
||||||
exec_free(&exec);
|
exec_free(&exec);
|
||||||
|
|
||||||
free_compiler:
|
free_compiler:
|
||||||
|
|
45
lib/moka.c
45
lib/moka.c
|
@ -229,6 +229,49 @@ MOKA moka_pop(struct moka* self)
|
||||||
vec_pop(&frame->stack);
|
vec_pop(&frame->stack);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int moka_line(struct moka* self, MOKA value)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
struct frame* frame = moka_frame(self);
|
||||||
|
struct value const* val = frame->local_values.data[value];
|
||||||
|
return val->line;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t moka_str(struct moka* self, MOKA value,
|
||||||
|
char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct frame* frame = moka_frame(self);
|
||||||
|
struct value* val = frame->local_values.data[value];
|
||||||
|
|
||||||
|
if (moka_is(self, value, TY_REF))
|
||||||
|
{
|
||||||
|
val = self->global_values.data[val->data.ref];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_str(val, buffer, size, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool moka_is_eqv(struct moka* self, MOKA mk_lhs, MOKA mk_rhs)
|
||||||
|
{
|
||||||
|
struct frame* frame = moka_frame(self);
|
||||||
|
struct value* lhs = frame->local_values.data[mk_lhs];
|
||||||
|
struct value* rhs = frame->local_values.data[mk_rhs];
|
||||||
|
|
||||||
|
if (lhs->type != rhs->type)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moka_is(self, mk_lhs, TY_REF))
|
||||||
|
{
|
||||||
|
lhs = self->global_values.data[lhs->data.ref];
|
||||||
|
rhs = self->global_values.data[rhs->data.ref];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_is_eqv(lhs, rhs, self);
|
||||||
|
}
|
||||||
|
|
||||||
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
||||||
{
|
{
|
||||||
return moka_type_of(self, value) == type;
|
return moka_type_of(self, value) == type;
|
||||||
|
@ -264,7 +307,7 @@ void moka_dump(struct moka* self, MOKA value)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char buffer[MK_STRLEN];
|
char buffer[MK_STRLEN];
|
||||||
value_str(val, buffer, MK_STRLEN);
|
value_str(val, buffer, MK_STRLEN, self);
|
||||||
|
|
||||||
printf("%s", buffer);
|
printf("%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,11 @@ bool moka_has_top(struct moka* self);
|
||||||
MOKA moka_top(struct moka* self);
|
MOKA moka_top(struct moka* self);
|
||||||
MOKA moka_pop(struct moka* self);
|
MOKA moka_pop(struct moka* self);
|
||||||
|
|
||||||
|
int moka_line(struct moka* self, MOKA value);
|
||||||
|
size_t moka_str(struct moka* self, MOKA value,
|
||||||
|
char* buffer, size_t size);
|
||||||
|
bool moka_is_eqv(struct moka* self, MOKA mk_lhs, MOKA mk_rhs);
|
||||||
|
|
||||||
bool moka_is(struct moka* self, MOKA value, TypeKind type);
|
bool moka_is(struct moka* self, MOKA value, TypeKind type);
|
||||||
TypeKind moka_type_of(struct moka* self, MOKA value);
|
TypeKind moka_type_of(struct moka* self, MOKA value);
|
||||||
|
|
||||||
|
|
109
lib/value.c
109
lib/value.c
|
@ -1,5 +1,6 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "moka.h"
|
||||||
|
|
||||||
MK_ENUM_C(TypeKind, TYPE_KIND);
|
MK_ENUM_C(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -88,11 +89,14 @@ void value_init_array(struct value* self, struct vec* new_values, int line)
|
||||||
self->line = line;
|
self->line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t value_str(struct value* self, char* buffer, size_t size)
|
size_t value_str(struct value* self,
|
||||||
|
char* buffer,
|
||||||
|
size_t size,
|
||||||
|
struct moka* moka)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(buffer);
|
assert(buffer);
|
||||||
|
|
||||||
switch (self->type)
|
switch (self->type)
|
||||||
{
|
{
|
||||||
case TY_INT: {
|
case TY_INT: {
|
||||||
|
@ -104,7 +108,7 @@ size_t value_str(struct value* self, char* buffer, size_t size)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TY_BOOL: {
|
case TY_BOOL: {
|
||||||
return snprintf(buffer, size, "%s",
|
return snprintf(buffer, size, "%s",
|
||||||
self->data.boolean ? "true" : "false");
|
self->data.boolean ? "true" : "false");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -123,16 +127,27 @@ size_t value_str(struct value* self, char* buffer, size_t size)
|
||||||
case TY_NATIVE: {
|
case TY_NATIVE: {
|
||||||
return snprintf(buffer, size, "<native: %p>", self->data.native);
|
return snprintf(buffer, size, "<native: %p>", self->data.native);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TY_LAZY: {
|
case TY_LAZY: {
|
||||||
return snprintf(buffer, size, "<lazy:%s>",
|
return snprintf(buffer, size, "<lazy:%s>",
|
||||||
NodeKindStr[self->data.lazy->kind]
|
NodeKindStr[self->data.lazy->kind]
|
||||||
+ strlen("NODE_"));
|
+ strlen("NODE_"));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TY_ARRAY: {
|
case TY_ARRAY: {
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
sz += snprintf(buffer + sz, size - sz, "[array]");
|
sz += snprintf(buffer + sz, size - sz, "[");
|
||||||
|
for (size_t i=0; i<self->data.array->values.size; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
MOKA val = (MOKA) self->data.array->values.data[i];
|
||||||
|
sz += moka_str(moka, val, buffer + sz, size - sz);
|
||||||
|
}
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "]");
|
||||||
return sz;
|
return sz;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -142,16 +157,77 @@ size_t value_str(struct value* self, char* buffer, size_t size)
|
||||||
abort();
|
abort();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// void value_init_int(struct value* self, int value, int line);
|
bool value_is_eqv(struct value* self,
|
||||||
// void value_init_float(struct value* self, float value, int line);
|
struct value* rhs,
|
||||||
// void value_init_bool(struct value* self, bool value, int line);
|
struct moka* moka)
|
||||||
// void value_init_string(struct value* self, char const* value, int line);
|
{
|
||||||
// void value_init_symbol(struct value* self, char const* value, int line);
|
if (self->type != rhs->type)
|
||||||
// void value_init_ref(struct value* self, size_t value, int line);
|
{
|
||||||
// void value_init_native(struct value* self, struct native* value, int line);
|
return false;
|
||||||
// void value_init_lazy(struct value* self, struct node* value, int line);
|
}
|
||||||
// void value_init_array(struct value* self, struct vec* new_values, int line);
|
|
||||||
|
switch (self->type)
|
||||||
|
{
|
||||||
|
case TY_INT: {
|
||||||
|
return self->data.integer == rhs->data.integer;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_FLOAT: {
|
||||||
|
return self->data.real == rhs->data.real;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_BOOL: {
|
||||||
|
return self->data.boolean == rhs->data.boolean;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_STRING: {
|
||||||
|
return strcmp(self->data.str, rhs->data.str) == 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_SYMBOL: {
|
||||||
|
return strcmp(self->data.sym, rhs->data.sym) == 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_REF: {
|
||||||
|
return self->data.ref == rhs->data.ref;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_ARRAY: {
|
||||||
|
if (self->data.array->values.size
|
||||||
|
!= rhs->data.array->values.size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->data.array->values.size; i++)
|
||||||
|
{
|
||||||
|
MOKA first = (MOKA) self->data.array->values.data[i];
|
||||||
|
MOKA second = (MOKA) rhs->data.array->values.data[i];
|
||||||
|
if (!moka_is_eqv(moka, first, second))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_NATIVE: {
|
||||||
|
return false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_LAZY: {
|
||||||
|
return true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "cannot test eqv on type <%s>\n",
|
||||||
|
TypeKindStr[self->type]);
|
||||||
|
abort();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void value_free(struct value* self)
|
void value_free(struct value* self)
|
||||||
|
@ -180,3 +256,6 @@ void value_free(struct value* self)
|
||||||
free(self->data.array);
|
free(self->data.array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,14 @@ void value_init_native(struct value* self, struct native* value, int line);
|
||||||
void value_init_lazy(struct value* self, struct node* value, int line);
|
void value_init_lazy(struct value* self, struct node* value, int line);
|
||||||
void value_init_array(struct value* self, struct vec* new_values, int line);
|
void value_init_array(struct value* self, struct vec* new_values, int line);
|
||||||
|
|
||||||
size_t value_str(struct value* self, char* buffer, size_t size);
|
size_t value_str(struct value* self,
|
||||||
|
char* buffer,
|
||||||
|
size_t size,
|
||||||
|
struct moka* moka);
|
||||||
|
|
||||||
|
bool value_is_eqv(struct value* self,
|
||||||
|
struct value* rhs,
|
||||||
|
struct moka* moka);
|
||||||
|
|
||||||
void value_free(struct value* self);
|
void value_free(struct value* self);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue