diff --git a/subprojects/vinumc/ast.c b/subprojects/vinumc/ast.c index 33b455f..4b2ddf2 100644 --- a/subprojects/vinumc/ast.c +++ b/subprojects/vinumc/ast.c @@ -4,6 +4,7 @@ #include #include "ast.h" +#include "vinumc.h" struct ast_node ast_node_new(const int type, char *text) { struct ast_node ret = { diff --git a/subprojects/vinumc/complib.c b/subprojects/vinumc/complib.c new file mode 100644 index 0000000..338a0e6 --- /dev/null +++ b/subprojects/vinumc/complib.c @@ -0,0 +1,21 @@ +#include + +#include "complib.h" + +struct compiler_ctx compiler_ctx; + +void yyerror(char *s, ...) { + va_list ap; + va_start(ap, s); + + fprintf(stderr, "[ERROR]:"); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +void init_comp_env() { + compiler_ctx.ast = ast_new(); + compiler_ctx.eval_ctx = eval_ctx_new(); +} diff --git a/subprojects/vinumc/complib.h b/subprojects/vinumc/complib.h new file mode 100644 index 0000000..e234cc8 --- /dev/null +++ b/subprojects/vinumc/complib.h @@ -0,0 +1,19 @@ +#ifndef __COMLIB_H__ +#define __COMLIB_H__ + +#include "ast.h" +#include "eval.h" + +struct compiler_ctx { + struct ast ast; + struct eval_ctx eval_ctx; + struct str_vec libraries; +}; + +extern struct compiler_ctx compiler_ctx; +void yyerror(char *s, ...); +int yyparse(); + +void init_comp_env(); + +#endif // __COMLIB_H__ diff --git a/subprojects/vinumc/dry_bison.y b/subprojects/vinumc/dry_bison.y index 6a51f14..d16d41b 100644 --- a/subprojects/vinumc/dry_bison.y +++ b/subprojects/vinumc/dry_bison.y @@ -26,10 +26,10 @@ int yylex(); program: { struct ast_node node = ast_node_new_nvl(PROGRAM); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } | program block { - struct ast_node *node = &VUT_VEC_AT(&ctx.ast.nodes, $1); + struct ast_node *node = &VUT_VEC_AT(&compiler_ctx.ast.nodes, $1); ast_node_add_child(node, $2); $$ = $1; @@ -43,7 +43,7 @@ block: ast_node_add_child(&node, $2); ast_node_add_child(&node, $4); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } | '[' symbol args ']' { struct ast_node node = ast_node_new_nvl(CALL); @@ -51,14 +51,14 @@ block: ast_node_add_child(&node, $2); ast_node_add_child(&node, $3); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } | '[' symbol ']' { struct ast_node node = ast_node_new_nvl(CALL); ast_node_add_child(&node, $2); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } ; @@ -67,10 +67,10 @@ args: struct ast_node node = ast_node_new_nvl(ARGS); ast_node_add_child(&node, $1); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } | args args_child { - struct ast_node *node = &VUT_VEC_AT(&ctx.ast.nodes, $1); + struct ast_node *node = &VUT_VEC_AT(&compiler_ctx.ast.nodes, $1); ast_node_add_child(node, $2); @@ -87,7 +87,7 @@ args_child: symbol: SYMBOL { // making so our symbols are case insensitive by making the whole string lowercase - char *text = VUT_VEC_AT(&ctx.ast.nodes, $1).text; + char *text = VUT_VEC_AT(&compiler_ctx.ast.nodes, $1).text; size_t len = strlen(text); // we need to convert from multi-byte to wide-character string @@ -110,7 +110,7 @@ symbol: SYMBOL { ast_node_add_child(&node, $1); - $$ = ast_add_node(&ctx.ast, node); + $$ = ast_add_node(&compiler_ctx.ast, node); } ; %% diff --git a/subprojects/vinumc/dry_flex.l b/subprojects/vinumc/dry_flex.l index 47efab2..cbb7b76 100644 --- a/subprojects/vinumc/dry_flex.l +++ b/subprojects/vinumc/dry_flex.l @@ -13,7 +13,7 @@ #include "dry_bison.h" -#include "vinumc.h" +#include "complib.h" /* * Disables input() and unput() function definitions from the generated .c @@ -39,7 +39,7 @@ BEFORE_TEXT_END ("["|"]"|"$*"|"{#") [ \t\r\n]+ ; [^\[\] \t\r\n]+ { struct ast_node node = ast_node_new(TEXT, strdup(yytext)); - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); return TEXT; } @@ -58,7 +58,7 @@ BEFORE_TEXT_END ("["|"]"|"$*"|"{#") [ \t\r\n]+ ; [^\[\]: \t\r\n]+ { struct ast_node node = ast_node_new(SYMBOL, strdup(yytext)); - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); replace_state(HAS_CALL_NAME); @@ -69,7 +69,7 @@ BEFORE_TEXT_END ("["|"]"|"$*"|"{#") "$*" { struct ast_node node = ast_node_new_nvl(ARG_REF_ALL_ARGS); - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); return ARG_REF_ALL_ARGS; } @@ -77,7 +77,7 @@ BEFORE_TEXT_END ("["|"]"|"$*"|"{#") "{#" { yy_push_state(IN_LITERAL); } "#}" { struct ast_node node = ast_node_new(LITERAL, strndup(yytext, yyleng - 2)); - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); yy_pop_state(); return LITERAL; @@ -89,7 +89,7 @@ BEFORE_TEXT_END ("["|"]"|"$*"|"{#") // the next token is eof, so we yield the // contents buffered so far struct ast_node node = ast_node_new(LITERAL, strndup(yytext, yyleng)); - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); yy_pop_state(); return LITERAL; } @@ -137,6 +137,6 @@ static int yield_text_node(void) { struct ast_node node = ast_node_new(TEXT, text_buffer.base); // transfers the string to the ast node text_buffer = (struct vut_str){}; - yylval = ast_add_node(&ctx.ast, node); + yylval = ast_add_node(&compiler_ctx.ast, node); return TEXT; } diff --git a/subprojects/vinumc/eval.c b/subprojects/vinumc/eval.c index d45e823..a19956c 100644 --- a/subprojects/vinumc/eval.c +++ b/subprojects/vinumc/eval.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -59,6 +60,21 @@ static struct namespace_entry *find_symbol_on_scopes(const struct eval_ctx_scope return NULL; } +static ssize_t find_scope_by_ast_node_id(const struct eval_ctx_scopes_t *scope_array, size_t ast_node_id) { + for (size_t i = 0; i < scope_array->len; i++) { + struct scope *s = &VUT_VEC_AT(scope_array, i); + if (s->node == ast_node_id) + return i; + } + + return -1; +} + +struct namespace_entry *eval_find_symbol_on_scopes(const struct eval_ctx *ctx, size_t curr_scope, const char *name) { + struct scope *sp = &VUT_VEC_AT(&ctx->scopes, curr_scope); + return find_symbol_on_scopes(&ctx->scopes, sp, name); +} + static int find_scope_child_by_node(const struct eval_ctx_scopes_t *scopes, size_t scope_id, size_t ast_node_id) { const struct scope *curr_scope = &VUT_VEC_AT(scopes, scope_id); @@ -255,10 +271,49 @@ DO_CALLS_FUNC_SIGNATURE(do_calls_call) { struct scope *curr_scope = &VUT_VEC_AT(&ctx->scopes, 0); struct namespace_entry *symbol_info = find_symbol_on_scopes(&ctx->scopes, curr_scope, symbol_node->text); + ssize_t curr_scope_id = find_scope_by_ast_node_id(&ctx->scopes, ast_node_id); + + assert(curr_scope_id != -1); // expose context to external function - struct _call_ctx cctx = { .text = tmp_out.base }; + struct _call_ctx cctx = { + .text = tmp_out.base, + .status = false, + .scope_id = curr_scope_id, + .ast_node_id = ast_node_id, + .compiler_ctx = &compiler_ctx, + }; + struct return_value call_return = symbol_info->as.func(&cctx); + if (call_return.status == false) { + size_t node; + const struct ast_node *args_node = &VUT_VEC_AT(&ast->nodes, args_id); + size_t len = cctx.args_req.len; + for (size_t i = 0; i < len; i++) { + node = VUT_VEC_AT(&args_node->childs, VUT_VEC_POP(&cctx.args_req)); + const struct ast_node *arg_node = &VUT_VEC_AT(&ast->nodes, node); + if (arg_node->type == ASSIGNMENT) { + node = VUT_VEC_AT(&arg_node->childs, 1); + } + struct vut_str arg_out = {}; + VUT_VEC_PUT(&arg_out, '\0'); + do_calls(ctx, ast, &arg_out, node, flags); + VUT_VEC_PUT(&cctx.args, arg_out.base); + } + len = cctx.names_req.len; + for (size_t i = 0; i < len; i++) { + struct namespace_entry symbol = *find_symbol_on_scopes( + &ctx->scopes, curr_scope, VUT_VEC_POP(&cctx.names_req)); + node = symbol.as.ast_node_id; + struct vut_str name_out = {}; + VUT_VEC_PUT(&name_out, '\0'); + do_calls(ctx, ast, &name_out, node, flags); + VUT_VEC_PUT(&cctx.names, name_out.base); + } + + cctx.status = true; + call_return = symbol_info->as.func(&cctx); + } // put the extern function call return on the out str diff --git a/subprojects/vinumc/eval.h b/subprojects/vinumc/eval.h index 8a8235c..d27869c 100644 --- a/subprojects/vinumc/eval.h +++ b/subprojects/vinumc/eval.h @@ -49,4 +49,6 @@ void eval(struct eval_ctx *ctx, struct ast *ast, FILE *out, struct str_vec *libr void eval_dot(const struct eval_ctx *ctx, FILE *stream); +struct namespace_entry *eval_find_symbol_on_scopes(const struct eval_ctx *ctx, size_t curr_scope, const char *name); + #endif // __EVAL_H__ diff --git a/subprojects/vinumc/include/vinumc/extern_library.h b/subprojects/vinumc/include/vinumc/extern_library.h index f80e3b8..05e200c 100644 --- a/subprojects/vinumc/include/vinumc/extern_library.h +++ b/subprojects/vinumc/include/vinumc/extern_library.h @@ -24,5 +24,8 @@ struct loaded_lib { }; struct return_value ctx_get_text(call_ctx ctx); +struct return_value ctx_call(call_ctx ctx); +struct return_value ctx_get_index(call_ctx ctx, int index); +struct return_value ctx_get_symbol_by_name(call_ctx ctx, const char* name); #endif //__EXTERN_LIBRARY_H__ diff --git a/subprojects/vinumc/meson.build b/subprojects/vinumc/meson.build index ab03437..6ec9e0c 100644 --- a/subprojects/vinumc/meson.build +++ b/subprojects/vinumc/meson.build @@ -23,13 +23,14 @@ parse = generator(bison, common_srcs = [ 'ast.c', - parse.process('dry_bison.y'), - lex.process('dry_flex.l'), + 'complib.c', 'eval.c', 'library_loader.c', + parse.process('dry_bison.y'), + lex.process('dry_flex.l'), ] -vinumc_srcs = common_srcs + [ +vinumc_srcs = [ 'vinumc.c', ] @@ -51,10 +52,16 @@ install_subdir( install_dir: 'include', ) +vutils_dep = dependency('vutils', fallback : ['vutils', 'vutils_dep']) + extern_library = library( 'extern_library', - 'v_lib.c', + ['v_lib.c'] + common_srcs, include_directories: local_inc, + dependencies: [ + dl_dep, + vutils_dep, + ], install: true ) @@ -63,7 +70,10 @@ extern_library_dep = declare_dependency( include_directories: external_inc, ) -vutils_dep = dependency('vutils', fallback : ['vutils', 'vutils_dep']) +extern_library_dep_priv = declare_dependency( + link_with: extern_library, + include_directories: [external_inc, extern_library.private_dir_include()], +) vinumc = executable( 'vinumc', @@ -71,8 +81,8 @@ vinumc = executable( include_directories : local_inc, install : true, dependencies: [ - dl_dep, vutils_dep, + extern_library_dep_priv, ], ) @@ -87,8 +97,8 @@ if get_option('build_vin2dot') include_directories : local_inc, install : true, dependencies: [ - dl_dep, vutils_dep, + extern_library_dep_priv, ], ) endif diff --git a/subprojects/vinumc/tests/library_test.c b/subprojects/vinumc/tests/library_test.c index 595c161..a7312e9 100644 --- a/subprojects/vinumc/tests/library_test.c +++ b/subprojects/vinumc/tests/library_test.c @@ -3,17 +3,38 @@ void test_call(struct vunit_test_ctx *ctx) { char *out = NULL; - vunit_run_vinumc_ok(ctx, "[return_arg test]\n", &out, "--with", + vunit_run_vinumc_ok(ctx, "[return_text test]\n", &out, "--with", "subprojects/vinumc/tests/libtestlib.so", NULL); VUNIT_ASSERT_STREQ(ctx, out, "test"); } +void test_arg_call(struct vunit_test_ctx *ctx) { + char *out = NULL; + + vunit_run_vinumc_ok(ctx, + "[hello: world!]\n" + "[return_text hello]\n" + "[return_call hello]\n", + &out, "--with", "subprojects/vinumc/tests/libtestlib.so", NULL); + + VUNIT_ASSERT_STREQ(ctx, out, "helloworld!"); +} + +void test_arg_by_index(struct vunit_test_ctx *ctx) { + char *out = NULL; + + vunit_run_vinumc_ok(ctx, "[invert [a:2][b:1]]\n", &out, "--with", + "subprojects/vinumc/tests/libtestlib.so", NULL); + + VUNIT_ASSERT_STREQ(ctx, out, "1 2"); +} + void test_nested_call(struct vunit_test_ctx *ctx) { char *out = NULL; vunit_run_vinumc_ok(ctx, - "[a: This is a [return_arg Test!]!]\n" + "[a: This is a [return_text Test!]!]\n" "[a]\n", &out, "--with", "subprojects/vinumc/tests/libtestlib.so", NULL); @@ -23,7 +44,7 @@ void test_nested_call(struct vunit_test_ctx *ctx) { void test_empty_nested_call(struct vunit_test_ctx *ctx) { char *out = NULL; - vunit_run_vinumc_ok(ctx, "[return_arg [return_arg [return_arg]]]", &out, "--with", + vunit_run_vinumc_ok(ctx, "[return_text [return_text [return_text]]]", &out, "--with", "subprojects/vinumc/tests/libtestlib.so", NULL); VUNIT_ASSERT_STREQ(ctx, out, ""); @@ -40,6 +61,8 @@ void test_call_no_args(struct vunit_test_ctx *ctx) { struct vunit_test tests[] = { { .name = "Test extern library call", .test_func = test_call }, + { .name = "Test extern library get by index", .test_func = test_arg_by_index }, + { .name = "Test extern library call get text and get arg", .test_func = test_arg_call }, { .name = "Test extern library call inside call", .test_func = test_nested_call }, { .name = "Test nested empty library calls", .test_func = test_empty_nested_call }, { diff --git a/subprojects/vinumc/tests/testlib.c b/subprojects/vinumc/tests/testlib.c index c333c78..576f5c7 100644 --- a/subprojects/vinumc/tests/testlib.c +++ b/subprojects/vinumc/tests/testlib.c @@ -1,12 +1,29 @@ +#include #include #include #include -struct return_value return_arg(call_ctx ctx) { +struct return_value return_text(call_ctx ctx) { return ctx_get_text(ctx); } +struct return_value return_call(call_ctx ctx) { + return ctx_call(ctx); +} + +struct return_value invert(call_ctx ctx) { + struct return_value ret = {}; + ret = ctx_get_symbol_by_name(ctx, "a"); + char *a = ret.ptr; + ret = ctx_get_symbol_by_name(ctx, "b"); + char *b = ret.ptr; + if (ret.status) { + sprintf(ret.ptr, "%s %s", b, a); + } + return ret; +} + struct return_value parenthesize(call_ctx ctx) { struct return_value ret = ctx_get_text(ctx); if (!ret.status) { @@ -26,8 +43,10 @@ struct return_value parenthesize(call_ctx ctx) { } struct extern_function *expose_library() { - static struct extern_function lib[] = { { "return_arg", return_arg }, + static struct extern_function lib[] = { { "return_text", return_text }, + { "return_call", return_call }, { "parenthesize", parenthesize }, + { "invert", invert }, {} }; return lib; } diff --git a/subprojects/vinumc/v_lib.c b/subprojects/vinumc/v_lib.c index ee33984..be8463e 100644 --- a/subprojects/vinumc/v_lib.c +++ b/subprojects/vinumc/v_lib.c @@ -1,6 +1,40 @@ #include "v_lib.h" +#include "eval.h" #include "extern_library.h" struct return_value ctx_get_text(call_ctx ctx) { return (struct return_value){ .ptr = ctx->text, .status = true }; } + +struct return_value ctx_call(call_ctx ctx) { + if (ctx->status == true) { + return (struct return_value){ .ptr = VUT_VEC_POP(&ctx->names), .status = true }; + } + struct return_value ret = { .status = false }; + VUT_VEC_PUT(&ctx->names_req, ctx->text); + return ret; +} + +struct return_value ctx_get_index(call_ctx ctx, int index) { + if (ctx->status == true) { + return (struct return_value){ .ptr = VUT_VEC_POP(&ctx->args), .status = true }; + } + struct return_value ret = { .status = false }; + VUT_VEC_PUT(&ctx->args_req, index); + return ret; +} + +struct return_value ctx_get_symbol_by_name(call_ctx ctx, const char* name) { + struct compiler_ctx *comp_ctx = ctx->compiler_ctx; + struct namespace_entry *symbol_info = eval_find_symbol_on_scopes(&comp_ctx->eval_ctx, ctx->scope_id, name); + if (symbol_info->type == ENTRY_INTERNAL) { + struct ast_node node = VUT_VEC_AT(&comp_ctx->ast.nodes, symbol_info->as.ast_node_id); + if (node.type == TEXT) + return (struct return_value) { + .ptr = node.text, + .status = true, + }; + } + + return (struct return_value) {}; +} diff --git a/subprojects/vinumc/v_lib.h b/subprojects/vinumc/v_lib.h index a11714c..eacacad 100644 --- a/subprojects/vinumc/v_lib.h +++ b/subprojects/vinumc/v_lib.h @@ -1,8 +1,25 @@ #ifndef __V_LIB_H__ #define __V_LIB_H__ +#include +#include + +#include "complib.h" + +struct v_str_vec VUT_VEC_DEF(char *); +struct arg_vec VUT_VEC_DEF(int); +struct name_vec VUT_VEC_DEF(char *); + struct _call_ctx { char *text; + struct v_str_vec args; + struct v_str_vec names; + struct arg_vec args_req; + struct name_vec names_req; + struct compiler_ctx *compiler_ctx; + size_t scope_id; + size_t ast_node_id; + bool status; }; #endif //__V_LIB_H__ diff --git a/subprojects/vinumc/vin2dot.c b/subprojects/vinumc/vin2dot.c index 9d2ea30..bfc24d4 100644 --- a/subprojects/vinumc/vin2dot.c +++ b/subprojects/vinumc/vin2dot.c @@ -4,29 +4,16 @@ #include #include "vinumc.h" +#include "complib.h" struct ctx ctx; struct ctx ctx_new() { - struct ctx ret = { - .ast = ast_new(), - .eval_ctx = eval_ctx_new(), - }; + struct ctx ret = { }; return ret; } -void yyerror(char *s, ...) { - va_list ap; - va_start(ap, s); - - fprintf(stderr, "[ERROR]:"); - vfprintf(stderr, s, ap); - fprintf(stderr, "\n"); - - va_end(ap); -} - enum command { CMD_AST, CMD_AST_AFTER, @@ -142,19 +129,19 @@ int main(int argc, char *argv[]) { switch (cmd) { case CMD_AST: - ast_dot(&ctx.ast, stdout); + ast_dot(&compiler_ctx.ast, stdout); return EXIT_SUCCESS; case CMD_AST_AFTER: - eval(&ctx.eval_ctx, &ctx.ast, stderr, &ctx.libraries); - ast_dot(&ctx.ast, stdout); + eval(&compiler_ctx.eval_ctx, &compiler_ctx.ast, stderr, &compiler_ctx.libraries); + ast_dot(&compiler_ctx.ast, stdout); return EXIT_SUCCESS; case CMD_AST_AND_SCOPES: - eval(&ctx.eval_ctx, &ctx.ast, stderr, &ctx.libraries); - dot_ast_and_scopes(&ctx.ast.nodes, &ctx.eval_ctx.scopes, stdout); + eval(&compiler_ctx.eval_ctx, &compiler_ctx.ast, stderr, &compiler_ctx.libraries); + dot_ast_and_scopes(&compiler_ctx.ast.nodes, &compiler_ctx.eval_ctx.scopes, stdout); return EXIT_SUCCESS; case CMD_SCOPES: - eval(&ctx.eval_ctx, &ctx.ast, stderr, &ctx.libraries); - eval_dot(&ctx.eval_ctx, stdout); + eval(&compiler_ctx.eval_ctx, &compiler_ctx.ast, stderr, &compiler_ctx.libraries); + eval_dot(&compiler_ctx.eval_ctx, stdout); return EXIT_SUCCESS; default: assert(0 && "unreachable"); // This should never happen diff --git a/subprojects/vinumc/vinumc.c b/subprojects/vinumc/vinumc.c index d146ffa..5a15340 100644 --- a/subprojects/vinumc/vinumc.c +++ b/subprojects/vinumc/vinumc.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -14,25 +13,10 @@ struct ctx ctx; struct ctx ctx_new() { - struct ctx ret = { - .ast = ast_new(), - .eval_ctx = eval_ctx_new(), - }; - + struct ctx ret = { }; return ret; } -void yyerror(char *s, ...) { - va_list ap; - va_start(ap, s); - - fprintf(stderr, "[ERROR]:"); - vfprintf(stderr, s, ap); - fprintf(stderr, "\n"); - - va_end(ap); -} - extern FILE *yyin; enum flag_kind { @@ -171,6 +155,7 @@ static struct flag *print_help(const char *prg_name, struct flag *flags, size_t } int main(int argc, char **argv) { + init_comp_env(); setlocale(LC_ALL, ""); struct flag vinumc_flags[] = { @@ -195,7 +180,7 @@ int main(int argc, char **argv) { .help_desc = "Set a library to be loaded", .placeholder_name = "libraries", .kind = FLAG_MULTI_ARGUMENTS, - .ref_as.str_vec = &ctx.libraries, + .ref_as.str_vec = &compiler_ctx.libraries, }, }; @@ -217,7 +202,7 @@ int main(int argc, char **argv) { yyparse(); - eval(&ctx.eval_ctx, &ctx.ast, out, &ctx.libraries); + eval(&compiler_ctx.eval_ctx, &compiler_ctx.ast, out, &compiler_ctx.libraries); exit: free_flags(vinumc_flags, ARRAY_SIZE(vinumc_flags)); diff --git a/subprojects/vinumc/vinumc.h b/subprojects/vinumc/vinumc.h index 0b4165d..c1e3e49 100644 --- a/subprojects/vinumc/vinumc.h +++ b/subprojects/vinumc/vinumc.h @@ -1,8 +1,7 @@ #ifndef __VINUMC_H__ #define __VINUMC_H__ -#include "ast.h" -#include "eval.h" +#include "complib.h" #include @@ -10,17 +9,10 @@ struct ctx { char *input_path; char *output_path; bool show_help; - - struct ast ast; - struct eval_ctx eval_ctx; - struct str_vec libraries; }; extern struct ctx ctx; struct ctx ctx_new(); -void yyerror(char *s, ...); -int yyparse(); - #endif // __VINUMC_H__ diff --git a/subprojects/vutils/include/vutils/vec.h b/subprojects/vutils/include/vutils/vec.h index 1a28182..520abce 100644 --- a/subprojects/vutils/include/vutils/vec.h +++ b/subprojects/vutils/include/vutils/vec.h @@ -67,13 +67,8 @@ (vec)->capacity = 0; \ } while (0) -/// Decrements the length of the vector by one. -#define VUT_VEC_POP(arr) \ - do { \ - if ((arr)->len > 0) { \ - (arr)->len--; \ - } \ - } while (0) +/// Returns the last element and decrements the length of the vector by one. +#define VUT_VEC_POP(arr) ((arr)->len > 0 ? (arr)->base[--(arr)->len] : (arr)->base[0]) /// Will append `from_size` elements from `from` to `to`. /// It will reserve enough space for `from_size + 1` elements in `to`. diff --git a/subprojects/vutils_tests/vec_macros.c b/subprojects/vutils_tests/vec_macros.c index b9f1a8c..62150d7 100644 --- a/subprojects/vutils_tests/vec_macros.c +++ b/subprojects/vutils_tests/vec_macros.c @@ -86,10 +86,16 @@ void test_vec_pop(struct vunit_test_ctx *ctx) { VUNIT_ASSERT_EQ(ctx, vec.len, 3); VUNIT_ASSERT_EQ(ctx, VUT_VEC_AT(&vec, 2), 3); - VUT_VEC_POP(&vec); + int popped = VUT_VEC_POP(&vec); + VUNIT_ASSERT_EQ(ctx, popped, 3); VUNIT_ASSERT_EQ(ctx, vec.len, 2); VUNIT_ASSERT_EQ(ctx, VUT_VEC_AT(&vec, 1), 2); + popped = VUT_VEC_POP(&vec); + VUNIT_ASSERT_EQ(ctx, popped, 2); + popped = VUT_VEC_POP(&vec); + VUNIT_ASSERT_EQ(ctx, popped, 1); + VUT_VEC_FREE(&vec); }