Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assert: Messages #6

Merged
merged 4 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading