Skip to content

Commit

Permalink
external functions: Ability to pass arguments to functions
Browse files Browse the repository at this point in the history
  • Loading branch information
obiwac committed Sep 13, 2024
1 parent dea6e98 commit 60d121e
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 48 deletions.
32 changes: 1 addition & 31 deletions flamingo/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,34 +29,4 @@ static inline int parse_assignment(flamingo_t* flamingo, TSNode node);
static inline int parse_import(flamingo_t* flamingo, TSNode node);
static inline int parse_function_declaration(flamingo_t* flamingo, TSNode node, flamingo_fn_kind_t kind);

__attribute__((format(printf, 2, 3))) static inline int error(flamingo_t* flamingo, char const* fmt, ...) {
va_list args;
va_start(args, fmt);

// TODO validate the size of the program name

// format caller's error message

char formatted[sizeof flamingo->err];
size_t res = vsnprintf(formatted, sizeof formatted, fmt, args);
assert(res < sizeof formatted);

// format the new error message and concatenate to the previous one if there were still errors outstanding
// TODO truncate the number of errors that we show at once (just do this by seeing how much longer we have)

if (flamingo->errors_outstanding) {
size_t const prev_len = strlen(flamingo->err);
res = snprintf(flamingo->err + prev_len, sizeof flamingo->err - prev_len, ", %s:%d:%d: %s", flamingo->progname, 0, 0, formatted);
}

else {
res = snprintf(flamingo->err, sizeof flamingo->err, "%s:%d:%d: %s", flamingo->progname, 0, 0, formatted);
}

assert(res < sizeof flamingo->err);

va_end(args);
flamingo->errors_outstanding = true;

return -1;
}
#define error(...) (flamingo_raise_error(__VA_ARGS__))
32 changes: 32 additions & 0 deletions flamingo/flamingo.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,38 @@ typedef struct {

extern TSLanguage const* tree_sitter_flamingo(void);

__attribute__((format(printf, 2, 3))) int flamingo_raise_error(flamingo_t* flamingo, char const* fmt, ...) {
va_list args;
va_start(args, fmt);

// TODO validate the size of the program name

// format caller's error message

char formatted[sizeof flamingo->err];
size_t res = vsnprintf(formatted, sizeof formatted, fmt, args);
assert(res < sizeof formatted);

// format the new error message and concatenate to the previous one if there were still errors outstanding
// TODO truncate the number of errors that we show at once (just do this by seeing how much longer we have)

if (flamingo->errors_outstanding) {
size_t const prev_len = strlen(flamingo->err);
res = snprintf(flamingo->err + prev_len, sizeof flamingo->err - prev_len, ", %s:%d:%d: %s", flamingo->progname, 0, 0, formatted);
}

else {
res = snprintf(flamingo->err, sizeof flamingo->err, "%s:%d:%d: %s", flamingo->progname, 0, 0, formatted);
}

assert(res < sizeof flamingo->err);

va_end(args);
flamingo->errors_outstanding = true;

return -1;
}

int flamingo_create(flamingo_t* flamingo, char const* progname, char* src, size_t src_size) {
flamingo->consistent = false;

Expand Down
25 changes: 24 additions & 1 deletion flamingo/flamingo.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

typedef struct flamingo_t flamingo_t;
typedef struct flamingo_val_t flamingo_val_t;
typedef struct flamingo_var_t flamingo_var_t;
typedef struct flamingo_scope_t flamingo_scope_t;
typedef struct flamingo_arg_list_t flamingo_arg_list_t;

typedef int (*flamingo_external_fn_cb_t)(flamingo_t* flamingo, size_t name_size, char* name, void* data, size_t arg_count, flamingo_val_t** args, flamingo_val_t** rv);
typedef int (*flamingo_external_fn_cb_t)(flamingo_t* flamingo, size_t name_size, char* name, void* data, flamingo_arg_list_t* args, flamingo_val_t** rv);

typedef enum {
FLAMINGO_VAL_KIND_NONE,
Expand Down Expand Up @@ -94,6 +96,11 @@ struct flamingo_scope_t {
bool class_scope;
};

struct flamingo_arg_list_t {
size_t count;
flamingo_val_t** args;
};

struct flamingo_t {
char const* progname;
bool consistent; // Set if we managed to create the instance, so we know whether or not it still needs freeing.
Expand Down Expand Up @@ -129,6 +136,8 @@ struct flamingo_t {
flamingo_val_t* cur_fn_rv;
};

__attribute__((format(printf, 2, 3))) int flamingo_raise_error(flamingo_t* flamingo, char const* fmt, ...);

int flamingo_create(flamingo_t* flamingo, char const* progname, char* src, size_t src_size);
void flamingo_destroy(flamingo_t* flamingo);

Expand All @@ -144,3 +153,17 @@ flamingo_val_t* flamingo_val_make_int(int64_t integer);
flamingo_val_t* flamingo_val_make_str(size_t size, char* str);
flamingo_val_t* flamingo_val_make_cstr(char* str);
flamingo_val_t* flamingo_val_make_bool(bool boolean);

flamingo_val_t* flamingo_val_find_arg(flamingo_arg_list_t* args, char const* name);

static inline int flamingo_strcmp(char* a, char* b, size_t a_size, size_t b_size) {
if (a_size != b_size) {
return -1; // XXX Not right but whatever.
}

return memcmp(a, b, a_size);
}

static inline int flamingo_cstrcmp(char* str, char* cstr, size_t str_size) {
return flamingo_strcmp(str, cstr, str_size, strlen(cstr));
}
30 changes: 27 additions & 3 deletions flamingo/grammar/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,37 @@ static int parse_call(flamingo_t* flamingo, TSNode node, flamingo_val_t** val) {
return error(flamingo, "cannot call external function without a external function callback being set");
}

size_t arg_count = 0;
flamingo_val_t** args = NULL;
// Create arg list.

flamingo_scope_t* const arg_scope = flamingo->scope_stack[flamingo->scope_stack_size - 1];

size_t const arg_count = arg_scope->vars_size;
flamingo_val_t** const args = malloc(arg_count * sizeof *args);
assert(args != NULL);

for (size_t i = 0; i < arg_count; i++) {
args[i] = arg_scope->vars[i].val;

// TODO Should I have to do this?

args[i]->name_size = arg_scope->vars[i].key_size;
args[i]->name = arg_scope->vars[i].key;
}

flamingo_arg_list_t arg_list = {
.count = arg_count,
.args = args,
};

// Actually call the external function callback.

assert(flamingo->cur_fn_rv == NULL);

if (flamingo->external_fn_cb(flamingo, callable->name_size, callable->name, flamingo->external_fn_cb_data, arg_count, args, &flamingo->cur_fn_rv) < 0) {
if (flamingo->external_fn_cb(flamingo, callable->name_size, callable->name, flamingo->external_fn_cb_data, &arg_list, &flamingo->cur_fn_rv) < 0) {
return -1;
}

free(args);
}

else if (parse_block(flamingo, *body, is_class ? &inner_scope : NULL) < 0) {
Expand Down
12 changes: 12 additions & 0 deletions flamingo/val.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,15 @@ flamingo_val_t* flamingo_val_make_bool(bool boolean) {

return val;
}

flamingo_val_t* flamingo_val_find_arg(flamingo_arg_list_t* args, char const* name) {
for (size_t i = 0; i < args->count; i++) {
flamingo_val_t* const arg = args->args[i];

if (flamingo_cstrcmp(arg->name, (char*) name, arg->name_size) == 0) {
return arg;
}
}

return NULL;
}
42 changes: 34 additions & 8 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,55 @@ static void usage(void) {
exit(EXIT_FAILURE);
}

static int external_fn_cb(flamingo_t* flamingo, size_t name_size, char* name, void* data, size_t arg_count, flamingo_val_t** args, flamingo_val_t** rv) {
if (memcmp(name, "test_return_number", name_size) == 0) {
static int external_fn_cb(flamingo_t* flamingo, size_t name_size, char* name, void* data, flamingo_arg_list_t* args, flamingo_val_t** rv) {
if (flamingo_cstrcmp(name, "test_return_number", name_size) == 0) {
*rv = flamingo_val_make_int(420);
}

else if (memcmp(name, "test_return_bool", name_size) == 0) {
else if (flamingo_cstrcmp(name, "test_return_bool", name_size) == 0) {
*rv = flamingo_val_make_bool(true);
}

else if (memcmp(name, "test_return_str", name_size) == 0) {
else if (flamingo_cstrcmp(name, "test_return_str", name_size) == 0) {
*rv = flamingo_val_make_cstr("zonnebloemgranen");
}

else if (memcmp(name, "test_return_none", name_size) == 0) {
else if (flamingo_cstrcmp(name, "test_return_none", name_size) == 0) {
*rv = flamingo_val_make_none();
}

else if (memcmp(name, "test_do_literally_nothing", name_size) == 0) {
else if (flamingo_cstrcmp(name, "test_do_literally_nothing", name_size) == 0) {
}

else if (flamingo_cstrcmp(name, "test_sub", name_size) == 0) {
if (args->count != 2) {
return flamingo_raise_error(flamingo, "test_sub: expected 2 arguments, got %zu", args->count);
}

flamingo_val_t* const a = flamingo_val_find_arg(args, "a");
flamingo_val_t* const b = flamingo_val_find_arg(args, "b");

if (a == NULL) {
return flamingo_raise_error(flamingo, "test_sub: argument 'a' doesn't exist");
}

if (b == NULL) {
return flamingo_raise_error(flamingo, "test_sub: argument 'b' doesn't exist");
}

if (a->kind != FLAMINGO_VAL_KIND_INT) {
return flamingo_raise_error(flamingo, "test_sub: expected 'a' to be an integer");
}

if (b->kind != FLAMINGO_VAL_KIND_INT) {
return flamingo_raise_error(flamingo, "test_sub: expected 'b' to be an integer");
}

*rv = flamingo_val_make_int(a->integer.integer - b->integer.integer);
}

else {
printf("Runtime does not support the '%.*s' external function call (%zu args)\n", (int) name_size, name, arg_count);
return -1;
return flamingo_raise_error(flamingo, "runtime does not support the '%.*s' external function call (%zu arguments passed)", (int) name_size, name, args->count);
}

return 0;
Expand Down
17 changes: 12 additions & 5 deletions tests/proto.fl
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
proto test_do_literally_nothing
# Test external function returns.

proto test_do_literally_nothing -> none
assert test_do_literally_nothing() == none

proto test_return_number
proto test_return_number -> int
assert test_return_number() == 420

proto test_return_bool
proto test_return_bool -> bool
assert test_return_bool() == true

proto test_return_str
proto test_return_str -> str
assert test_return_str() == "zonnebloemgranen"

proto test_return_none
proto test_return_none -> none
assert test_return_none() == none

# Test external function arguments.

proto test_sub(a: int, b: int) -> int
assert test_sub(420, 69) == 420 - 69

0 comments on commit 60d121e

Please sign in to comment.