Skip to content

Commit

Permalink
Merge pull request #6 from inobulles/feature/assert-message
Browse files Browse the repository at this point in the history
assert: Messages
  • Loading branch information
obiwac authored Dec 21, 2024
2 parents c1d882a + f3b1510 commit 2274ab3
Show file tree
Hide file tree
Showing 6 changed files with 4,946 additions and 4,716 deletions.
4 changes: 4 additions & 0 deletions flamingo/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,8 @@ static inline int call(
flamingo_arg_list_t* args
);

// Representation prototypes.

static inline int repr(flamingo_t* flamingo, flamingo_val_t* val, char** res);

#define error(...) (flamingo_raise_error(__VA_ARGS__))
64 changes: 59 additions & 5 deletions flamingo/grammar/assert.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
#include "../val.h"

static int parse_assert(flamingo_t* flamingo, TSNode node) {
assert(ts_node_child_count(node) == 2);
size_t const child_count = ts_node_named_child_count(node);
assert(child_count == 1 || child_count == 2);

// Get test expression.

TSNode const test_node = ts_node_child_by_field_name(node, "test", 4);
char const* const type = ts_node_type(test_node);
Expand All @@ -18,6 +21,21 @@ static int parse_assert(flamingo_t* flamingo, TSNode node) {
return error(flamingo, "expected expression for test, got %s", type);
}

// Get message.

TSNode const msg_node = ts_node_child_by_field_name(node, "msg", 3);
bool const has_msg = !ts_node_is_null(msg_node);

if (has_msg) {
char const* const msg_type = ts_node_type(msg_node);

if (strcmp(msg_type, "expression") != 0) {
return error(flamingo, "expected expression for message, got %s", msg_type);
}
}

// Evaluate the test expression.

flamingo_val_t* val = NULL;

if (parse_expr(flamingo, test_node, &val, NULL) < 0) {
Expand All @@ -28,16 +46,52 @@ static int parse_assert(flamingo_t* flamingo, TSNode node) {
return error(flamingo, "expected boolean value for test, got %s", val_type_str(val));
}

// If the test succeeded, exit now.

if (val->boolean.boolean) {
val_decref(val);
return 0;
}

// Otherwise, start by getting a string for the test expression.

size_t const start = ts_node_start_byte(test_node);
size_t const end = ts_node_end_byte(test_node);

char const* const test_str = flamingo->src + start;
size_t const test_size = end - start;

if (!val->boolean.boolean) {
return error(flamingo, "assertion test '%.*s' failed", (int) test_size, test_str);
// If we have a message, evaluate it and include it in the error message.

if (has_msg) {
flamingo_val_t* msg_val = NULL;

if (parse_expr(flamingo, msg_node, &msg_val, NULL) < 0) {
val_decref(val);
return error(flamingo, "assertion test '%.*s' failed, and failed to parse message expression in doing so", (int) test_size, test_str);
}

char* msg_repr = NULL;

if (repr(flamingo, msg_val, &msg_repr) < 0) {
val_decref(val);
val_decref(msg_val);

return error(flamingo, "assertion test '%.*s' failed, and failed to represent message expression in doing so", (int) test_size, test_str);
}

val_decref(val);
val_decref(msg_val);

// Finally, actually error.

int const rv = error(flamingo, "assertion test '%.*s' failed: %s", (int) test_size, test_str, msg_repr);
free(msg_repr);

return rv;
}

val_decref(val);
return 0;
// Otherwise, just spit out something generic.

return error(flamingo, "assertion test '%.*s' failed", (int) test_size, test_str);
}
116 changes: 2 additions & 114 deletions flamingo/grammar/print.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,121 +6,9 @@
#include "expr.h"

#include "../common.h"
#include "../repr.h"
#include "../val.h"

#include <inttypes.h>

static int repr(flamingo_t* flamingo, flamingo_val_t* val, char** res, bool inner) {
char* buf;

switch (val->kind) {
case FLAMINGO_VAL_KIND_NONE:
*res = strdup("<none>");
break;
case FLAMINGO_VAL_KIND_BOOL:
*res = strdup(val->boolean.boolean ? "true" : "false");
break;
case FLAMINGO_VAL_KIND_INT:
asprintf(res, "%" PRId64, val->integer.integer);
break;
case FLAMINGO_VAL_KIND_STR:
if (inner) {
asprintf(res, "\"%.*s\"", (int) val->str.size, val->str.str);
}

else {
asprintf(res, "%.*s", (int) val->str.size, val->str.str);
}

break;
case FLAMINGO_VAL_KIND_VEC:
*res = strdup("[");
assert(*res != NULL);

for (size_t i = 0; i < val->vec.count; i++) {
flamingo_val_t* const elem = val->vec.elems[i];
char* elem_repr;

if (repr(flamingo, elem, &elem_repr, true) < 0) {
free(res);
return -1;
}

buf = strdup(*res);
assert(buf != NULL);
asprintf(res, "%s%s%s", buf, i == 0 ? "" : ", ", elem_repr);
assert(*res != NULL);

free(buf);
free(elem_repr);
}

buf = strdup(*res);
assert(buf != NULL);
asprintf(res, "%s]", buf);
free(buf);

break;
case FLAMINGO_VAL_KIND_MAP:
*res = strdup("{");
assert(*res != NULL);

for (size_t i = 0; i < val->map.count; i++) {
flamingo_val_t* const k = val->map.keys[i];
flamingo_val_t* const v = val->map.vals[i];

char* key_repr;

if (repr(flamingo, k, &key_repr, true) < 0) {
free(res);
return -1;
}

char* val_repr;

if (repr(flamingo, v, &val_repr, true) < 0) {
free(key_repr);
free(res);
return -1;
}

buf = strdup(*res);
assert(buf != NULL);
asprintf(res, "%s%s%s: %s", buf, i == 0 ? "" : ", ", key_repr, val_repr);
assert(*res != NULL);
free(key_repr);
free(val_repr);
free(buf);
}

buf = strdup(*res);
assert(buf != NULL);
asprintf(res, "%s}", buf);
free(buf);

break;
case FLAMINGO_VAL_KIND_FN:
if (val->name_size == 0) {
*res = strdup("<anonymous function>");
break;
}

asprintf(res, "<%s %.*s>", val_type_str(val), (int) val->name_size, val->name);
break;
case FLAMINGO_VAL_KIND_INST:;
flamingo_val_t* const class = val->inst.class;
assert(class != NULL);

asprintf(res, "<instance of %.*s>", (int) class->name_size, class->name);
break;
default:
return error(flamingo, "can't print expression kind: %s (%d)", val_type_str(val), val->kind);
}

assert(*res != NULL);
return 0;
}

static int parse_print(flamingo_t* flamingo, TSNode node) {
assert(ts_node_child_count(node) == 2);

Expand All @@ -140,7 +28,7 @@ static int parse_print(flamingo_t* flamingo, TSNode node) {
// XXX Don't forget to decrement reference at the end!

char* to_print = NULL;
int rv = repr(flamingo, val, &to_print, false);
int rv = repr(flamingo, val, &to_print);

if (rv == 0) {
assert(to_print != NULL);
Expand Down
Loading

0 comments on commit 2274ab3

Please sign in to comment.