apflc: Use an apfl_ctx for compilation

We'll soon need the full apfl_ctx, where we previously only needed the
gc. apflc was the only place manually constructing a struct gc without
an apfl_ctx, so lets change that.
This commit is contained in:
Laria 2023-11-23 20:29:38 +01:00
parent aa6346eafa
commit 0361000e7c
13 changed files with 161 additions and 237 deletions

View file

@ -13,7 +13,9 @@ set(commonfiles
alloc.c
bytecode.c
compile.c
context.c
encode.c
eval.c
error.c
expr.c
format.c
@ -21,12 +23,16 @@ set(commonfiles
hashmap.c
io.c
messages.c
modules.c
numparse.c
parser.c
position.c
registry.c
resizable.c
scope.c
source_readers.c
strings.c
symbols.c
token.c
tokenizer.c
value.c
@ -34,14 +40,8 @@ set(commonfiles
add_library(apfl
${commonfiles}
builtins.c
context.c
eval.c
modules.c
globals.c
re.c
registry.c
scope.c
symbols.c
mod_globals.c
mod_re.c

View file

@ -860,6 +860,8 @@ void apfl_error_decorate_with_backtrace(apfl_ctx ctx, void *ignored);
void apfl_load(apfl_ctx, struct apfl_source_reader, apfl_stackidx name);
void apfl_bytecode_save(apfl_ctx, struct apfl_io_writer, apfl_stackidx func);
void apfl_registry_set(apfl_ctx, void *key_major, size_t key_minor, apfl_stackidx);
void apfl_registry_delete(apfl_ctx, void *key_major, size_t key_minor);
bool apfl_registry_try_get(apfl_ctx, void *key_major, size_t key_minor);

View file

@ -83,23 +83,6 @@ c_source_epilogue(struct apfl_io_writer w, const char *function_name)
);
}
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)
{
@ -132,48 +115,24 @@ closefile(FILE *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;
}
struct protected_compiling_data {
const char *name;
struct apfl_io_reader *r;
struct apfl_io_writer *w;
};
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;
}
static void
protected_compiling(apfl_ctx ctx, void *opaque)
{
struct protected_compiling_data *data = opaque;
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;
apfl_push_const_string(ctx, data->name);
apfl_load(ctx, apfl_io_reader_as_source_reader(data->r), -1);
apfl_bytecode_save(ctx, *data->w, -1);
}
#define MAIN_TRY_FMT(x) if (!(x)) { goto error; }
int
main(int argc, const char *argv[])
{
@ -187,7 +146,7 @@ main(int argc, const char *argv[])
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;
goto error_before_ctx;
}
}
@ -197,7 +156,7 @@ main(int argc, const char *argv[])
(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;
goto error_before_ctx;
}
int rv = 1;
@ -206,40 +165,18 @@ main(int argc, const char *argv[])
(in = openfile(argv[0], name_in, "rb")) == NULL
|| (out = openfile(argv[0], name_out, "wb")) == NULL
) {
goto error_before_gc;
goto error_before_ctx;
}
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;
goto error_before_ctx;
}
struct apfl_io_writer w_err = apfl_io_file_writer(stderr);
struct apfl_io_writer bytecode_writer = w_raw;
struct c_writer_data c_writer_data = {
.w = w_raw,
@ -252,12 +189,40 @@ main(int argc, const char *argv[])
};
}
if (!apfl_bytecode_serialize(
gc.allocator,
bytecode_writer,
roots.ilist
)) {
fprintf(stderr, "%s: Could not serialize bytecode\n", argv[0]);
apfl_ctx ctx = apfl_ctx_new((struct apfl_config) {
.allocator = apfl_allocator_default(),
.output_writer = apfl_io_file_writer(stdout),
.no_standard_modules = true,
});
if (ctx == NULL) {
fprintf(stderr, "Could not init context\n");
goto error;
}
struct protected_compiling_data data = {
.name = name_in,
.r = &r,
.w = &bytecode_writer,
};
switch (apfl_do_protected(ctx, protected_compiling, &data, NULL)) {
case APFL_RESULT_OK :
break;
case APFL_RESULT_ERR:
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Error occurred during compilation:\n"));
if (apfl_get_type(ctx, -1) == APFL_VALUE_STRING) {
MAIN_TRY_FMT(apfl_io_write_string(w_err, apfl_get_string(ctx, -1)));
} else {
MAIN_TRY_FMT(apfl_debug_print_val(ctx, -1, w_err));
}
MAIN_TRY_FMT(apfl_io_write_byte(w_err, '\n'));
break;
case APFL_RESULT_ERRERR:
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Error occurred during error handling.\n"));
break;
case APFL_RESULT_ERR_ALLOC:
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Fatal: Could not allocate memory.\n"));
goto error;
}
@ -268,8 +233,8 @@ main(int argc, const char *argv[])
rv = 0;
error:
apfl_gc_deinit(&gc);
error_before_gc:
apfl_ctx_destroy(ctx);
error_before_ctx:
closefile(in);
closefile(out);
return rv;

View file

@ -4,6 +4,7 @@
#include "alloc.h"
#include "bytecode.h"
#include "context.h"
#include "encode.h"
#include "format.h"
#include "gc.h"
@ -1014,39 +1015,6 @@ bytecode_serialize_inner(
return true;
}
bool
apfl_bytecode_serialize(
struct apfl_allocator allocator,
struct apfl_io_writer w,
struct instruction_list *ilist
) {
struct serializer serializer = {
.allocator = allocator,
.w = w,
.next_string_index = 0,
};
if (!apfl_hashmap_init(
&serializer.string_lookup,
allocator,
(struct apfl_hashmap_callbacks) {
.opaque = NULL,
.keys_eq = serializer_strings_eq,
.calc_hash = serializer_strings_hash,
},
sizeof(struct apfl_string *),
sizeof(uint_least64_t)
)) {
return false;
}
bool out = bytecode_serialize_inner(&serializer, ilist);
apfl_hashmap_deinit(&serializer.string_lookup);
return out;
}
static bool
set_ilist_root(
struct unserializer *unserializer,
@ -1102,3 +1070,45 @@ apfl_bytecode_unserialize(
return out;
}
void
apfl_bytecode_save(apfl_ctx ctx, struct apfl_io_writer w, apfl_stackidx func)
{
struct apfl_value val = apfl_stack_must_get(ctx, func);
if (val.type != VALUE_FUNC) {
apfl_raise_const_error(ctx, "Can only dump apfl functions");
}
if (val.func->subfunctions_len != 1) {
apfl_raise_const_error(ctx, "Can only dump functions with exactly one subfunction");
}
struct apfl_allocator allocator = apfl_get_allocator(ctx);
struct serializer serializer = {
.allocator = allocator,
.w = w,
.next_string_index = 0,
};
if (!apfl_hashmap_init(
&serializer.string_lookup,
allocator,
(struct apfl_hashmap_callbacks) {
.opaque = NULL,
.keys_eq = serializer_strings_eq,
.calc_hash = serializer_strings_hash,
},
sizeof(struct apfl_string *),
sizeof(uint_least64_t)
)) {
apfl_raise_alloc_error(ctx);
}
bool ok = bytecode_serialize_inner(&serializer, val.func->subfunctions[0].body);
apfl_hashmap_deinit(&serializer.string_lookup);
if (!ok) {
apfl_raise_const_error(ctx, apfl_messages.io_error);
}
}

View file

@ -107,12 +107,6 @@ void apfl_matcher_instructions_deinit(struct apfl_allocator, struct matcher_inst
bool apfl_bytecode_dump_matcher(unsigned indent, struct apfl_io_writer w, struct matcher_instruction_list *milist);
bool apfl_bytecode_dump(unsigned indent, struct apfl_io_writer w, struct instruction_list *ilist);
bool apfl_bytecode_serialize(
struct apfl_allocator,
struct apfl_io_writer,
struct instruction_list *
);
struct instruction_list *apfl_bytecode_unserialize(
struct gc *gc,
struct apfl_io_reader r

View file

@ -6,10 +6,10 @@
#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 "registry.h"
@ -846,8 +846,7 @@ init_globals_protected(apfl_ctx ctx, void *opaque)
{
(void)opaque;
apfl_builtins(ctx);
apfl_build_native_and_bytecode_combined_module(ctx, -1, apfl_mod_globals());
apfl_globals(ctx);
struct apfl_value val = apfl_stack_must_get(ctx, -1);
if (val.type != VALUE_DICT) {

View file

@ -1,5 +1,5 @@
#ifndef APFL_CONTEXT_H
#define APFL_CONTEXT_H
#ifndef APFL_ENCODE_H
#define APFL_ENCODE_H
#ifdef __cplusplus
extern "C" {

View file

@ -30,8 +30,6 @@
raise := C.raise
symbol := C.symbol
splice := C.splice
-serialize-bytecode := C.-serialize-bytecode
-unserialize-bytecode := C.-unserialize-bytecode
Some := (C.getsym-Some)
@ -394,8 +392,6 @@
'load-file -> load-file
'load-string -> load-string
'run-file -> run-file
'-serialize-bytecode -> -serialize-bytecode
'-unserialize-bytecode -> -unserialize-bytecode
'& -> &
'substr -> substr
'strsearch -> strsearch

View file

@ -6,9 +6,9 @@
#include "apfl.h"
#include "alloc.h"
#include "builtins.h"
#include "bytecode.h"
#include "context.h"
#include "globals.h"
#include "modules.h"
#include "parsing.h"
#include "scope.h"
@ -602,41 +602,6 @@ loadstring(apfl_ctx ctx)
apfl_drop(ctx, -2);
}
static void
serialize_bytecode(apfl_ctx ctx)
{
apfl_get_list_member_by_index(ctx, 0, 0);
struct apfl_value value = apfl_stack_must_get(ctx, -1);
if (value.type == VALUE_CFUNC) {
apfl_raise_const_error(ctx, "-serialize-bytecode needs a apfl function, got a native function instead");
} else if (value.type != VALUE_FUNC) {
apfl_raise_errorfmt(ctx, "-serialize-bytecode needs a apfl function, got value of type {value:type} instead", value);
}
apfl_get_list_member_by_index(ctx, 0, 1);
FILE **fh = apfl_get_native_object(ctx, &file_object, -1);
struct apfl_io_writer w = apfl_io_file_writer(*fh);
if (!apfl_bytecode_serialize(ctx->gc.allocator, w, value.func->subfunctions[0].body)) {
apfl_raise_const_error(ctx, "Could not serialize function");
}
apfl_push_nil(ctx);
}
static void
unserialize_bytecode(apfl_ctx ctx)
{
apfl_get_list_member_by_index(ctx, 0, 0);
apfl_drop(ctx, -2);
FILE **fh = apfl_get_native_object(ctx, &file_object, -1);
struct apfl_io_reader r = apfl_io_file_reader(*fh);
apfl_load_bytecode(ctx, r);
}
static void
set_func_name(apfl_ctx ctx)
{
@ -860,19 +825,11 @@ add_builtin(apfl_ctx ctx, const char *name, apfl_cfunc func)
apfl_dict_set(ctx, -3, -2, -1);
}
static int cmod_searcher_registry_key;
static void
cmod_searcher(apfl_ctx ctx)
{
ONE_ARG(ctx, "cmod-searcher");
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
apfl_drop(ctx, -1);
apfl_push_nil(ctx);
return;
}
if (apfl_get_member_if_exists(ctx, -1, -2)) {
if (apfl_modules_query(ctx, -1)) {
apfl_sym_some(ctx);
apfl_push_pair(ctx, -1, -2);
} else {
@ -881,22 +838,7 @@ cmod_searcher(apfl_ctx ctx)
}
void
apfl_modules_register(apfl_ctx ctx, const char *name, apfl_stackidx modloader)
{
apfl_move_to_top_of_stack(ctx, modloader);
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
apfl_dict_create(ctx);
}
apfl_push_const_string(ctx, name);
apfl_dict_set(ctx, -2, -1, -3);
apfl_registry_set(ctx, &cmod_searcher_registry_key, 0, -1);
}
void
apfl_builtins(apfl_ctx ctx)
apfl_globals(apfl_ctx ctx)
{
apfl_dict_create(ctx);
@ -928,8 +870,6 @@ apfl_builtins(apfl_ctx ctx)
add_builtin(ctx, "fclose", impl_fclose);
add_builtin(ctx, "load-file", loadfile);
add_builtin(ctx, "load-string", loadstring);
add_builtin(ctx, "-serialize-bytecode", serialize_bytecode);
add_builtin(ctx, "-unserialize-bytecode", unserialize_bytecode);
add_builtin(ctx, "set-func-name", set_func_name);
add_builtin(ctx, "substring", substring);
add_builtin(ctx, "stringsearch", stringsearch);
@ -942,4 +882,6 @@ apfl_builtins(apfl_ctx ctx)
add_builtin(ctx, "cmod-searcher", cmod_searcher);
add_builtin(ctx, "tonumber", tonumber);
add_builtin(ctx, "splice", splice);
apfl_build_native_and_bytecode_combined_module(ctx, -1, apfl_mod_globals());
}

View file

@ -1,5 +1,5 @@
#ifndef APFL_BUILTINS_H
#define APFL_BUILTINS_H
#ifndef APFL_GLOBALS_H
#define APFL_GLOBALS_H
#ifdef __cplusplus
extern "C" {
@ -7,7 +7,7 @@ extern "C" {
#include "apfl.h"
void apfl_builtins(apfl_ctx);
void apfl_globals(apfl_ctx);
#ifdef __cplusplus
}

View file

@ -19,3 +19,33 @@ apfl_build_native_and_bytecode_combined_module(
apfl_list_append(ctx, -1, -3);
apfl_call(ctx, -2, -1);
}
static int cmod_searcher_registry_key;
bool
apfl_modules_query(apfl_ctx ctx, apfl_stackidx modname)
{
apfl_move_to_top_of_stack(ctx, modname);
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
apfl_drop(ctx, -1);
return false;
}
return apfl_get_member_if_exists(ctx, -1, -2);
}
void
apfl_modules_register(apfl_ctx ctx, const char *name, apfl_stackidx modloader)
{
apfl_move_to_top_of_stack(ctx, modloader);
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
apfl_dict_create(ctx);
}
apfl_push_const_string(ctx, name);
apfl_dict_set(ctx, -2, -1, -3);
apfl_registry_set(ctx, &cmod_searcher_registry_key, 0, -1);
}

View file

@ -14,6 +14,8 @@ apfl_build_native_and_bytecode_combined_module(
struct apfl_string_view bytecode
);
bool apfl_modules_query(apfl_ctx, apfl_stackidx modname);
struct apfl_string_view apfl_mod_globals(void);
struct apfl_string_view apfl_mod_re(void);

View file

@ -1,32 +1,16 @@
#include <assert.h>
#include <stdbool.h>
#include "context.h"
#include "scope.h"
#include "apfl.h"
#include "globals.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 MODULE_STUB(name) \
void \
name(apfl_ctx ctx) \
{ \
(void)ctx; \
apfl_dict_create(ctx); \
}
#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 *)
MODULE_STUB(apfl_globals)
MODULE_STUB(apfl_module_re)