diff --git a/CMakeLists.txt b/CMakeLists.txt index 481a930..6a30b62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) project(apfl VERSION 0.0.1 LANGUAGES C) enable_testing() add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb66ed9..e7575ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,37 +4,56 @@ set(CMAKE_C_EXTENSIONS OFF) option(BUILD_SHARED_LIBS "Build dynamic / shared libraries" ON) option(TEST_WITH_VALGRIND_MEMCHECK "Also run tests with valgrind / memcheck" ON) -add_library(apfl +set(commonfiles alloc.c bytecode.c compile.c encode.c - context.c error.c - eval.c expr.c format.c gc.c hashmap.c io.c - globals.c messages.c parser.c position.c resizable.c source_readers.c - scope.c strings.c token.c tokenizer.c value.c ) +add_library(apfl + ${commonfiles} + builtins.c + context.c + eval.c + scope.c + + mod_globals.c +) target_link_libraries(apfl PUBLIC m) add_executable(apfl-bin main.c) target_link_libraries(apfl-bin PUBLIC apfl) +if(CMAKE_CROSSCOMPILING) + find_package(ApflApflcNative) +else() + add_executable(apflc apflc.c ${commonfiles} stubs_for_apflc.c) + target_link_libraries(apflc PUBLIC m) + export(TARGETS apflc FILE "${CMAKE_BINARY_DIR}/ApflApflcNativeConfig.cmake") +endif() + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mod_globals.c" + COMMAND apflc -c apfl_mod_globals "${CMAKE_CURRENT_SOURCE_DIR}/globals.apfl" "${CMAKE_CURRENT_BINARY_DIR}/mod_globals.c" + DEPENDS apflc "${CMAKE_CURRENT_SOURCE_DIR}/globals.apfl" +) + add_executable(functional-test-runner functional-test-runner.c) target_link_libraries(functional-test-runner PUBLIC apfl) diff --git a/src/apfl.h b/src/apfl.h index 1f30c4b..9bad5cd 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -732,6 +732,9 @@ int apfl_cmp(apfl_ctx, apfl_stackidx a, apfl_stackidx b); // Push a C function onto the stack with nslots slots (initialized to nil) void apfl_push_cfunc(apfl_ctx, apfl_cfunc, size_t nslots); +// Set the name of a function. name is dropped, func will be on the top of the stack afterwards +void apfl_set_func_name(apfl_ctx, apfl_stackidx func, apfl_stackidx name); + void apfl_cfunc_getslot(apfl_ctx, apfl_stackidx cfunc, apfl_slotidx); void apfl_cfunc_self_getslot(apfl_ctx, apfl_slotidx); void apfl_cfunc_setslot(apfl_ctx, apfl_stackidx cfunc, apfl_slotidx, apfl_stackidx value); diff --git a/src/apflc.c b/src/apflc.c new file mode 100644 index 0000000..5297246 --- /dev/null +++ b/src/apflc.c @@ -0,0 +1,276 @@ +#include +#include +#include +#include + +#include "apfl.h" +#include "bytecode.h" +#include "compile.h" +#include "format.h" +#include "gc.h" +#include "strings.h" + +struct c_writer_data { + struct apfl_io_writer w; + size_t written_len; +}; + +static const unsigned char hex[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', +}; + +static bool +write_as_c_source(void *opaque, const unsigned char *buf, size_t len) +{ + struct c_writer_data *data = opaque; + for (size_t i = 0; i < len; i++) { + if (data->written_len % 16 == 0) { + if (!apfl_io_write_byte(data->w, '\n')) { + return false; + } + } + + unsigned char out[] = {'0', 'x', hex[(buf[i] >> 4) & 0x0F], hex[buf[i] & 0x0F], ','}; + + if (!apfl_io_write_string_view( + data->w, + (struct apfl_string_view) { .bytes = out, .len = sizeof(out), } + )) { + return false; + } + + (data->written_len)++; + } + + return true; +} + +static bool +c_source_prelude(struct apfl_io_writer w) +{ + return apfl_io_write_string( + w, + "#include \n" + // TODO: This is a bit hackish, the generated C code should include + // apfl.h instead of declaring the string view struct itself. However, + // since the code is generated, it does not live in the same directory + // as apfl.h, so our usual `#include "apfl.h"` doesn't work. + "struct apfl_string_view {\n" + " const unsigned char *bytes;\n" + " size_t len;\n" + "};\n" + "static const unsigned char bytecode[] = {" + ); +} + +static bool +c_source_epilogue(struct apfl_io_writer w, const char *function_name) +{ + return apfl_io_write_string(w, + "\n};\n" + "struct apfl_string_view\n" + ) + && apfl_io_write_string(w, function_name) + && apfl_io_write_string(w, + "(void)\n" + "{\n" + " return (struct apfl_string_view) {\n" + " .bytes = bytecode,\n" + " .len = sizeof(bytecode),\n" + " };\n" + "}\n" + ); +} + +struct roots { + struct instruction_list *ilist; + struct apfl_string *name; +}; + +static void +getroots(void *own_opaque, gc_visitor visitor, void *visitor_opaque) +{ + struct roots *roots = own_opaque; + if (roots->ilist != NULL) { + visitor(visitor_opaque, GC_OBJECT_FROM(roots->ilist, GC_TYPE_INSTRUCTIONS)); + } + if (roots->name != NULL) { + visitor(visitor_opaque, GC_OBJECT_FROM(roots->name, GC_TYPE_STRING)); + } +} + +static const char * +get_next_string_from_arg(const char *progname, const char ***argpp) +{ + if (**argpp == NULL) { + fprintf(stderr, "Usage: %s [-c function_name] input output\n", progname); + return NULL; + } + + const char *filename = **argpp; + (*argpp)++; + return filename; +} + +static FILE * +openfile(const char *progname, const char *filename, const char *mode) +{ + FILE *f = fopen(filename, mode); + if (f == NULL) { + fprintf(stderr, "%s: Could not open %s: %s\n", progname, filename, strerror(errno)); + return NULL; + } + return f; +} + +static void +closefile(FILE *f) +{ + if (f != NULL) { + fclose(f); + } +} + +static bool +compile( + const char *progname, + struct gc *gc, + struct apfl_io_reader r, + struct instruction_list *ilist +) { + apfl_tokenizer_ptr tokenizer = apfl_tokenizer_new(gc->allocator, apfl_io_reader_as_source_reader(&r)); + if (tokenizer == NULL) { + return false; + } + + apfl_parser_ptr parser = apfl_parser_new( + gc->allocator, + apfl_tokenizer_as_token_source(tokenizer) + ); + if (parser == NULL) { + apfl_tokenizer_destroy(tokenizer); + fprintf(stderr, "%s: Failed to init parser\n", progname); + return false; + } + + struct apfl_error error; + if (!apfl_compile_whole_file( + gc, + parser, + &error, + ilist + )) { + fprintf(stderr, "%s: Could not compile file:\n", progname); + apfl_error_print(error, stderr); + + apfl_parser_destroy(parser); + apfl_tokenizer_destroy(tokenizer); + return false; + } + + apfl_parser_destroy(parser); + apfl_tokenizer_destroy(tokenizer); + return true; +} + +int +main(int argc, const char *argv[]) +{ + (void)argc; + const char **argp = argv+1; + + FILE *in = NULL; + FILE *out = NULL; + + const char *c_function_name = NULL; + if (*argp != NULL && apfl_string_eq(*argp, "-c")) { + argp++; + if ((c_function_name = get_next_string_from_arg(argv[0], &argp)) == NULL) { + goto error_before_gc; + } + } + + const char *name_in = NULL; + const char *name_out = NULL; + if ( + (name_in = get_next_string_from_arg(argv[0], &argp)) == NULL + || (name_out = get_next_string_from_arg(argv[0], &argp)) == NULL + ) { + goto error_before_gc; + } + + int rv = 1; + + if ( + (in = openfile(argv[0], name_in, "rb")) == NULL + || (out = openfile(argv[0], name_out, "wb")) == NULL + ) { + goto error_before_gc; + } + + struct apfl_io_reader r = apfl_io_file_reader(in); + struct apfl_io_writer w_raw = apfl_io_file_writer(out); + + struct roots roots = { + .ilist = NULL, + .name = NULL, + }; + + struct gc gc; + apfl_gc_init(&gc, apfl_allocator_default(), getroots, &roots); + + if ((roots.name = apfl_string_copy_to_new_gc_string( + &gc, + apfl_string_view_from(name_in) + )) == NULL) { + goto error; + } + + if ((roots.ilist = apfl_instructions_new(&gc, 1, roots.name)) == NULL) { + goto error; + } + + if (!compile(argv[0], &gc, r, roots.ilist)) { + goto error; + } + + if (c_function_name != NULL && !c_source_prelude(w_raw)) { + fprintf(stderr, "%s: IO error\n", argv[0]); + goto error; + } + + struct apfl_io_writer bytecode_writer = w_raw; + struct c_writer_data c_writer_data = { + .w = w_raw, + .written_len = 0, + }; + if (c_function_name != NULL) { + bytecode_writer = (struct apfl_io_writer) { + .opaque = &c_writer_data, + .write = write_as_c_source, + }; + } + + if (!apfl_bytecode_serialize( + gc.allocator, + bytecode_writer, + roots.ilist + )) { + fprintf(stderr, "%s: Could not serialize bytecode\n", argv[0]); + goto error; + } + + if (c_function_name != NULL && !c_source_epilogue(w_raw, c_function_name)) { + fprintf(stderr, "%s: IO error\n", argv[0]); + goto error; + } + + rv = 0; +error: + apfl_gc_deinit(&gc); +error_before_gc: + closefile(in); + closefile(out); + return rv; +} diff --git a/src/globals.c b/src/builtins.c similarity index 90% rename from src/globals.c rename to src/builtins.c index 3d2c2ef..d1607ac 100644 --- a/src/globals.c +++ b/src/builtins.c @@ -6,9 +6,10 @@ #include "apfl.h" #include "alloc.h" +#include "builtins.h" #include "bytecode.h" #include "context.h" -#include "globals.h" +#include "modules.h" #include "scope.h" #define TRY_FORMAT(ctx, x) \ @@ -583,42 +584,62 @@ unserialize_bytecode(apfl_ctx ctx) apfl_load_bytecode(ctx, r); } -static const struct global_def globals[] = { - {"if", impl_if}, - {"==", impl_eq}, - {">", impl_gt}, - {"<", impl_lt}, - {">=", impl_ge}, - {"<=", impl_le}, - {"+", impl_plus}, - {"-", impl_minus}, - {"*", impl_mult}, - {"/", impl_div}, - {"&", impl_concat}, - {"join", impl_join}, - {"print", print}, - {"dump", dump}, - {"disasm", disasm}, - {"tostring", tostring}, - {"not", not}, - {"len", len}, - {"type", type}, - {"while", impl_while}, - {"gc", impl_gc}, - {"backtrace", impl_backtrace}, - {"fopen", impl_fopen}, - {"fread", impl_fread}, - {"fwrite", impl_fwrite}, - {"fclose", impl_fclose}, - {"loadfile", loadfile}, - {"loadstring", loadstring}, - {"-serialize-bytecode", serialize_bytecode}, - {"-unserialize-bytecode", unserialize_bytecode}, - {NULL, NULL}, -}; - -const struct global_def * -apfl_globals(void) +static void +set_func_name(apfl_ctx ctx) { - return globals; + size_t argc = apfl_len(ctx, 0); + if (argc != 2) { + apfl_raise_const_error(ctx, "set-func-name needs exactly 2 arguments"); + } + apfl_get_list_member_by_index(ctx, 0, 0); + apfl_get_list_member_by_index(ctx, 0, 1); + apfl_set_func_name(ctx, -2, -1); +} + +static void +add_builtin(apfl_ctx ctx, const char *name, apfl_cfunc func) +{ + apfl_push_const_string(ctx, name); + apfl_push_cfunc(ctx, func, 0); + apfl_push_const_string(ctx, name); + apfl_set_func_name(ctx, -2, -1); + apfl_dict_set(ctx, -3, -2, -1); +} + +void +apfl_builtins(apfl_ctx ctx) +{ + apfl_dict_create(ctx); + + add_builtin(ctx, "if", impl_if); + add_builtin(ctx, "==", impl_eq); + add_builtin(ctx, ">", impl_gt); + add_builtin(ctx, "<", impl_lt); + add_builtin(ctx, ">=", impl_ge); + add_builtin(ctx, "<=", impl_le); + add_builtin(ctx, "+", impl_plus); + add_builtin(ctx, "-", impl_minus); + add_builtin(ctx, "*", impl_mult); + add_builtin(ctx, "/", impl_div); + add_builtin(ctx, "&", impl_concat); + add_builtin(ctx, "join", impl_join); + add_builtin(ctx, "print", print); + add_builtin(ctx, "dump", dump); + add_builtin(ctx, "disasm", disasm); + add_builtin(ctx, "tostring", tostring); + add_builtin(ctx, "not", not); + add_builtin(ctx, "len", len); + add_builtin(ctx, "type", type); + add_builtin(ctx, "while", impl_while); + add_builtin(ctx, "gc", impl_gc); + add_builtin(ctx, "backtrace", impl_backtrace); + add_builtin(ctx, "fopen", impl_fopen); + add_builtin(ctx, "fread", impl_fread); + add_builtin(ctx, "fwrite", impl_fwrite); + add_builtin(ctx, "fclose", impl_fclose); + add_builtin(ctx, "loadfile", loadfile); + add_builtin(ctx, "loadstring", loadstring); + add_builtin(ctx, "-serialize-bytecode", serialize_bytecode); + add_builtin(ctx, "-unserialize-bytecode", unserialize_bytecode); + add_builtin(ctx, "set-func-name", set_func_name); } diff --git a/src/builtins.h b/src/builtins.h new file mode 100644 index 0000000..ee8983e --- /dev/null +++ b/src/builtins.h @@ -0,0 +1,16 @@ +#ifndef APFL_BUILTINS_H +#define APFL_BUILTINS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "apfl.h" + +void apfl_builtins(apfl_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/compile.c b/src/compile.c index 5b47a99..084a90b 100644 --- a/src/compile.c +++ b/src/compile.c @@ -952,3 +952,33 @@ apfl_compile(struct gc *gc, struct apfl_expr expr, struct apfl_error *error_out, } return ok; } + +bool +apfl_compile_whole_file( + struct gc *gc, + struct apfl_parser *parser, + struct apfl_error *error, + struct instruction_list *out +) { + for (;;) { + switch (apfl_parser_next(parser)) { + case APFL_PARSE_OK: { + if (!apfl_compile( + gc, + apfl_parser_get_expr(parser), + error, + out + )) { + return false; + } + + break; + } + case APFL_PARSE_ERROR: + *error = apfl_parser_get_error(parser); + return false; + case APFL_PARSE_EOF: + return true; + } + } +} diff --git a/src/compile.h b/src/compile.h index 5ba7ac5..5179de4 100644 --- a/src/compile.h +++ b/src/compile.h @@ -11,6 +11,12 @@ extern "C" { #include "gc.h" bool apfl_compile(struct gc *, struct apfl_expr, struct apfl_error *, struct instruction_list *); +bool apfl_compile_whole_file( + struct gc *gc, + struct apfl_parser *parser, + struct apfl_error *error, + struct instruction_list *out +); #ifdef __cplusplus } diff --git a/src/context.c b/src/context.c index 5b7f831..3083c81 100644 --- a/src/context.c +++ b/src/context.c @@ -6,18 +6,18 @@ #include "apfl.h" #include "alloc.h" +#include "builtins.h" #include "compile.h" #include "context.h" #include "gc.h" -#include "globals.h" #include "hashmap.h" +#include "modules.h" #include "resizable.h" #include "strings.h" #include "value.h" static bool try_push_const_string(apfl_ctx ctx, const char *string); static bool current_stack_move_to_top(apfl_ctx, apfl_stackidx); -static struct apfl_string *new_copied_string(struct gc *, struct apfl_string_view); noreturn static void panic(apfl_ctx ctx, enum apfl_result result) @@ -809,54 +809,45 @@ iterative_runners_list_new(void) }; } +static void +init_globals_protected(apfl_ctx ctx, void *opaque) +{ + (void)opaque; + + struct apfl_io_string_reader_data reader = apfl_io_string_reader_create(apfl_mod_globals()); + struct apfl_io_reader r = apfl_io_string_reader(&reader); + apfl_load_bytecode(ctx, r); + apfl_list_create(ctx, 0); + apfl_call(ctx, -2, -1); + apfl_list_create(ctx, 1); + apfl_builtins(ctx); + apfl_list_append(ctx, -2, -1); + apfl_call(ctx, -2, -1); + + struct apfl_value val = apfl_stack_must_get(ctx, -1); + if (val.type != VALUE_DICT) { + apfl_raise_const_error(ctx, "Globals didn't return a dict"); + } + + HASHMAP_EACH(&val.dict->map, cur) { + struct apfl_value *k = apfl_hashmap_cursor_peek_key(cur); + apfl_stack_must_push(ctx, *k); + struct apfl_string *name = apfl_to_dynamic_string(ctx, -1); + + struct apfl_value *v = apfl_hashmap_cursor_peek_value(cur); + + if (!apfl_scope_set(&ctx->gc, ctx->globals, name, *v)) { + apfl_raise_alloc_error(ctx); + } + + apfl_drop(ctx, -1); + } +} + static bool init_globals(apfl_ctx ctx) { - struct gc *gc = &ctx->gc; - - size_t tmproots = apfl_gc_tmproots_begin(gc); - - for ( - const struct global_def *global = apfl_globals(); - global->name != NULL && global->func != NULL; - global++ - ) { - struct cfunction *cfunc = apfl_cfunc_new(gc, global->func, 0); - if (cfunc == NULL) { - goto error; - } - - if (!apfl_gc_tmproot_add(gc, GC_OBJECT_FROM(cfunc, GC_TYPE_CFUNC))) { - goto error; - } - - struct apfl_string *name = new_copied_string(gc, apfl_string_view_from(global->name)); - if (name == NULL) { - goto error; - } - - if (!apfl_gc_tmproot_add(gc, GC_OBJECT_FROM(name, GC_TYPE_STRING))) { - goto error; - } - - // TODO: There should also be an API for setting the name of a cfunc - cfunc->name = name; - - if (!apfl_scope_set(gc, ctx->globals, name, (struct apfl_value) { - .type = VALUE_CFUNC, - .cfunc = cfunc, - })) { - goto error; - } - - apfl_gc_tmproots_restore(gc, tmproots); - } - - return true; - -error: - apfl_gc_tmproots_restore(gc, tmproots); - return false; + return apfl_do_protected(ctx, init_globals_protected, NULL, NULL) == APFL_RESULT_OK; } apfl_ctx @@ -1061,23 +1052,6 @@ apfl_push_number(apfl_ctx ctx, apfl_number num) }); } -static struct apfl_string * -new_copied_string(struct gc *gc, struct apfl_string_view sv) -{ - struct apfl_string s = apfl_string_blank(); - if (!apfl_string_copy(gc->allocator, &s, sv)) { - return NULL; - } - - struct apfl_string *out = apfl_string_move_into_new_gc_string(gc, &s); - if (out == NULL) { - apfl_string_deinit(gc->allocator, &s); - return NULL; - } - - return out; -} - void apfl_push_string_view_copy(apfl_ctx ctx, struct apfl_string_view sv) { @@ -1085,7 +1059,7 @@ apfl_push_string_view_copy(apfl_ctx ctx, struct apfl_string_view sv) ctx, VALUE_STRING, string, - new_copied_string(&ctx->gc, sv) + apfl_string_copy_to_new_gc_string(&ctx->gc, sv) ) } @@ -1697,6 +1671,29 @@ apfl_push_cfunc(apfl_ctx ctx, apfl_cfunc cfunc, size_t nslots) ) } +void +apfl_set_func_name(apfl_ctx ctx, apfl_stackidx func_index, apfl_stackidx name_index) +{ + apfl_multi_move_to_top_of_stack(ctx, 2, (apfl_stackidx []) {func_index, name_index}); + if (apfl_get_type(ctx, -1) != APFL_VALUE_STRING) { + apfl_raise_errorfmt(ctx, "Expected string, got {stack:type}", -1); + } + struct apfl_value func = apfl_stack_must_get(ctx, -2); + struct apfl_string *name = apfl_to_dynamic_string(ctx, -1); + switch (func.type) { + case VALUE_FUNC: + func.func->name = name; + break; + case VALUE_CFUNC: + func.cfunc->name = name; + break; + default: + apfl_raise_errorfmt(ctx, "Expected function, got {value:type}", func); + } + + apfl_drop(ctx, -1); +} + static noreturn void raise_no_cfunc(apfl_ctx ctx) { @@ -2136,35 +2133,17 @@ apfl_load(apfl_ctx ctx, struct apfl_source_reader reader, apfl_stackidx name) apfl_raise_alloc_error(ctx); } - for (;;) { - switch (apfl_parser_next(parser)) { - case APFL_PARSE_OK: { - struct apfl_error err; - if (!apfl_compile( - &ctx->gc, - apfl_parser_get_expr(parser), - &err, - ilist - )) { - apfl_drop(ctx, -1); - apfl_parser_destroy(parser); - apfl_tokenizer_destroy(tokenizer); - apfl_raise_error_object(ctx, err); - } - - break; - } - case APFL_PARSE_ERROR: - apfl_drop(ctx, -1); - apfl_parser_destroy(parser); - apfl_tokenizer_destroy(tokenizer); - apfl_raise_error_object(ctx, apfl_parser_get_error(parser)); - break; - case APFL_PARSE_EOF: - apfl_parser_destroy(parser); - apfl_tokenizer_destroy(tokenizer); - return; - } + struct apfl_error err; + if (!apfl_compile_whole_file( + &ctx->gc, + parser, + &err, + ilist + )) { + apfl_drop(ctx, -1); + apfl_parser_destroy(parser); + apfl_tokenizer_destroy(tokenizer); + apfl_raise_error_object(ctx, err); } } diff --git a/src/globals.apfl b/src/globals.apfl new file mode 100644 index 0000000..079a68e --- /dev/null +++ b/src/globals.apfl @@ -0,0 +1,101 @@ +{builtins -> + if := builtins.if + == := builtins.== + > := builtins.> + < := builtins.< + >= := builtins.>= + <= := builtins.<= + + := builtins.+ + - := builtins.- + * := builtins.* + / := builtins./ + join := builtins.join + print := builtins.print + dump := builtins.dump + disasm := builtins.disasm + tostring := builtins.tostring + not := builtins.not + len := builtins.len + type := builtins.type + while := builtins.while + gc := builtins.gc + backtrace := builtins.backtrace + fopen := builtins.fopen + fread := builtins.fread + fwrite := builtins.fwrite + fclose := builtins.fclose + loadfile := builtins.loadfile + loadstring := builtins.loadstring + -serialize-bytecode := builtins.-serialize-bytecode + -unserialize-bytecode := builtins.-unserialize-bytecode + + -named := { name f -> + builtins.set-func-name f name + } + + & := { ~strings -> + join "" strings + } + + partial := { f ~a1 -> + { ~a2 -> + f ~a1 ~a2 + } + } + + compose := { + f -> f + f ~fs -> + fs-composed := compose ~fs + { ~args -> + f (fs-composed ~args) + } + } + + != := -named '!= (compose not ==) + !> := -named '!> (compose not >) + !< := -named '!< (compose not <) + !>= := -named '!>= (compose not >=) + !<= := -named '!<= (compose not <=) + + # Dictionary of exported functions + [ + 'if -> if + '== -> == + '> -> > + '< -> < + '>= -> >= + '<= -> <= + '+ -> + + '- -> - + '* -> * + '/ -> / + 'join -> join + 'print -> print + 'dump -> dump + 'disasm -> disasm + 'tostring -> tostring + 'not -> not + 'len -> len + 'type -> type + 'while -> while + 'gc -> gc + 'backtrace -> backtrace + 'fopen -> fopen + 'fread -> fread + 'fwrite -> fwrite + 'fclose -> fclose + 'loadfile -> loadfile + 'loadstring -> loadstring + '-serialize-bytecode -> -serialize-bytecode + '-unserialize-bytecode -> -unserialize-bytecode + '& -> & + 'partial -> partial + 'compose -> compose + '!= -> != + '!> -> !> + '!< -> !< + '!>= -> !>= + '!<= -> !<= + ] +} diff --git a/src/globals.h b/src/globals.h deleted file mode 100644 index 4d8a242..0000000 --- a/src/globals.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef APFL_GLOBALS_H -#define APFL_GLOBALS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "apfl.h" - -struct global_def { - const char *name; - apfl_cfunc func; -}; - -const struct global_def *apfl_globals(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/modules.h b/src/modules.h new file mode 100644 index 0000000..9d36dc1 --- /dev/null +++ b/src/modules.h @@ -0,0 +1,16 @@ +#ifndef APFL_MODULES_H +#define APFL_MODULES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "apfl.h" + +struct apfl_string_view apfl_mod_globals(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/strings.c b/src/strings.c index 73c028a..0abd0f9 100644 --- a/src/strings.c +++ b/src/strings.c @@ -183,6 +183,24 @@ apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in) return str; } +struct apfl_string * +apfl_string_copy_to_new_gc_string(struct gc *gc, struct apfl_string_view sv) +{ + struct apfl_string s = apfl_string_blank(); + if (!apfl_string_copy(gc->allocator, &s, sv)) { + return NULL; + } + + struct apfl_string *out = apfl_string_move_into_new_gc_string(gc, &s); + if (out == NULL) { + apfl_string_deinit(gc->allocator, &s); + return NULL; + } + + return out; +} + + struct apfl_string_view apfl_string_view_offset(struct apfl_string_view sv, size_t off) { diff --git a/src/strings.h b/src/strings.h index a53f8fb..e0eae8d 100644 --- a/src/strings.h +++ b/src/strings.h @@ -9,6 +9,7 @@ extern "C" { #include "gc.h" struct apfl_string *apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in); +struct apfl_string *apfl_string_copy_to_new_gc_string(struct gc *gc, struct apfl_string_view sv); #ifdef __cplusplus } diff --git a/src/stubs_for_apflc.c b/src/stubs_for_apflc.c new file mode 100644 index 0000000..089df65 --- /dev/null +++ b/src/stubs_for_apflc.c @@ -0,0 +1,32 @@ +#include +#include + +#include "context.h" +#include "scope.h" + +#define GC_TRAVERSE_STUB(name, T) \ + void \ + name(T arg, gc_visitor visitor, void *opaque) \ + { \ + (void)arg; \ + (void)visitor; \ + (void)opaque; \ + \ + assert(false && "Stub " #name " called"); \ + } + +#define GC_DEINIT_STUB(name, T) \ + void name(struct apfl_allocator allocator, T arg) \ + { \ + (void)allocator; \ + (void)arg; \ + \ + assert(false && "Stub " #name " called"); \ + } + +GC_TRAVERSE_STUB(apfl_gc_var_traverse, struct apfl_value *) +GC_TRAVERSE_STUB(apfl_gc_scope_traverse, struct scope *) +GC_TRAVERSE_STUB(apfl_gc_matcher_traverse, struct matcher *) + +GC_DEINIT_STUB(apfl_scope_deinit, struct scope *) +GC_DEINIT_STUB(apfl_matcher_deinit, struct matcher *) diff --git a/webpage/.gitignore b/webpage/.gitignore new file mode 100644 index 0000000..0aa5503 --- /dev/null +++ b/webpage/.gitignore @@ -0,0 +1,2 @@ +build/ +build-native/ diff --git a/webpage/build.sh b/webpage/build.sh index c0c5b77..3786509 100755 --- a/webpage/build.sh +++ b/webpage/build.sh @@ -1,10 +1,16 @@ #!/bin/sh set -e cd playground +rm -rf build-native +mkdir build-native +cd build-native +cmake ../../../CMakeLists.txt +make -j"$(nproc)" apflc +cd .. rm -rf build mkdir build cd build -emcmake cmake -DCMAKE_C_FLAGS="-O2" ../../../CMakeLists.txt +emcmake cmake -DCMAKE_C_FLAGS="-O2" -DBUILD_SHARED_LIBS=NO -DApflApflcNative_DIR="$(pwd)/../build-native/" ../../../CMakeLists.txt emmake make -j"$(nproc)" apfl cd .. emcc -sASYNCIFY -O3 -oplayground.js playground.c build/src/libapfl.a