#ifndef APFL_H #define APFL_H #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef __GNUC__ # define APFL_NORETURN __attribute__((noreturn)) #else # define APFL_NORETURN #endif // Allocator // apfl_allocator_cb is called to (re)allocate and free memory. // // If called with newsize = 0, the memory of oldsize bytes pointed to by // oldptr should be freed. If the NULL-pointer is freed, nothing should // happen. A freeing must return the NULL-pointer and is not allowed to // fail. // // If oldptr = NULL and oldsize = 0, memory of size newsize should be // allocated and the pointer to it returned. If the allocation fails, NULL // should be returned. // // Reallocation is done by calling with the old pointer, old size and new // size. On success the new pointer should be returned and the old pointer // (unless they're the same) no longer used. On failure, NULL should be // returned and the oldptr should stay valid. typedef void * (*apfl_allocator_cb) (void *opaque, void *oldptr, size_t oldsize, size_t newsize); struct apfl_allocator { void *opaque; apfl_allocator_cb alloc; }; struct apfl_allocator apfl_allocator_default(void); struct apfl_allocator apfl_allocator_wrap_verifying(struct apfl_allocator *wrapped); typedef double apfl_number; struct apfl_position { int line; int col; }; bool apfl_position_eq(struct apfl_position, struct apfl_position); // Strings struct apfl_string_view { const char *bytes; size_t len; }; struct apfl_string { char *bytes; size_t len; // TODO: Not sure, if it's a good idea to expose this. We now need the actual // size of the underlying allocation though. Maybe we should better // shrink the cap to len wen we're done building a string? size_t cap; }; #define APFL_STR_FMT "%.*s" #define APFL_STR_FMT_ARGS(s) (int)(s).len,(s).bytes struct apfl_string_view apfl_string_view_from_view(struct apfl_string_view); struct apfl_string_view apfl_string_view_from_cstr(char *); struct apfl_string_view apfl_string_view_from_const_cstr(const char *); struct apfl_string_view apfl_string_view_from_string(struct apfl_string); #define apfl_string_view_from(s) _Generic((s), \ struct apfl_string: apfl_string_view_from_string, \ struct apfl_string_view: apfl_string_view_from_view, \ char *: apfl_string_view_from_cstr, \ const char *: apfl_string_view_from_const_cstr \ )(s) int apfl_string_view_cmp(struct apfl_string_view, struct apfl_string_view); #define apfl_string_cmp(a, b) apfl_string_view_cmp(apfl_string_view_from(a), apfl_string_view_from(b)) #define apfl_string_eq(a, b) (apfl_string_cmp((a), (b)) == 0) struct apfl_string apfl_string_blank(void); void apfl_string_deinit(struct apfl_allocator allocator, struct apfl_string *); struct apfl_string apfl_string_move(struct apfl_string *src); /** * Copies a string from src to dst. dst must point to a blank string. * Returns true on success, false otherwise (if the necessary memory could not * be allocated). */ bool apfl_string_copy(struct apfl_allocator allocator, struct apfl_string *dst, struct apfl_string_view src); struct apfl_string_builder { struct apfl_allocator allocator; char *bytes; size_t len; size_t cap; }; struct apfl_string_builder apfl_string_builder_init(struct apfl_allocator allocator); void apfl_string_builder_deinit(struct apfl_string_builder *); bool apfl_string_builder_append(struct apfl_string_builder *, struct apfl_string_view); bool apfl_string_builder_append_byte(struct apfl_string_builder *, char byte); bool apfl_string_builder_append_bytes(struct apfl_string_builder *, const char *bytes, size_t len); struct apfl_string apfl_string_builder_move_string(struct apfl_string_builder *); #define apfl_string_builder_append_cstr(builder, cstr) (apfl_string_builder_append((builder), apfl_string_view_from_cstr((cstr)))) struct apfl_string_view apfl_string_view_offset(struct apfl_string_view sv, size_t off); struct apfl_string_view apfl_string_view_trunc(struct apfl_string_view sv, size_t newlen); struct apfl_string_view apfl_string_view_substr(struct apfl_string_view sv, size_t off, size_t newlen); ptrdiff_t apfl_string_view_search(struct apfl_string_view haystack, struct apfl_string_view needle); struct apfl_string_view apfl_string_view_ltrim(struct apfl_string_view sv); struct apfl_string_view apfl_string_view_rtrim(struct apfl_string_view sv); struct apfl_string_view apfl_string_view_trim(struct apfl_string_view sv); struct apfl_format_writer { bool (*write)(void *, const char *buf, size_t len); void *opaque; }; struct apfl_format_writer apfl_format_file_writer(FILE *f); struct apfl_format_writer apfl_format_string_writer(struct apfl_string_builder *sb); bool apfl_format_put_string_view(struct apfl_format_writer, struct apfl_string_view); #define apfl_format_put_string(w, s) apfl_format_put_string_view((w), apfl_string_view_from(s)) bool apfl_format_put_int(struct apfl_format_writer, int); bool apfl_format_put_char(struct apfl_format_writer, char); bool apfl_format_put_hexbyte(struct apfl_format_writer, unsigned char); bool apfl_format_put_pos(struct apfl_format_writer, struct apfl_position); bool apfl_format_put_indent(struct apfl_format_writer, unsigned); bool apfl_format_put_number(struct apfl_format_writer, apfl_number); bool apfl_format_put_poiner(struct apfl_format_writer, void *); // Tokens enum apfl_token_type { APFL_TOK_LPAREN, APFL_TOK_RPAREN, APFL_TOK_LBRACKET, APFL_TOK_RBRACKET, APFL_TOK_LBRACE, APFL_TOK_RBRACE, APFL_TOK_MAPSTO, APFL_TOK_EXPAND, APFL_TOK_DOT, APFL_TOK_AT, APFL_TOK_SEMICOLON, APFL_TOK_LINEBREAK, APFL_TOK_CONTINUE_LINE, APFL_TOK_COMMENT, APFL_TOK_COMMA, APFL_TOK_QUESTION_MARK, APFL_TOK_STRINGIFY, APFL_TOK_ASSIGN, APFL_TOK_LOCAL_ASSIGN, APFL_TOK_NUMBER, APFL_TOK_NAME, APFL_TOK_STRING, }; struct apfl_token { enum apfl_token_type type; struct apfl_position position; union { struct apfl_string text; apfl_number number; }; }; void apfl_token_deinit(struct apfl_allocator allocator, struct apfl_token *); const char *apfl_token_type_name(enum apfl_token_type); void apfl_token_print(struct apfl_token, FILE *); // Errors enum apfl_error_type { APFL_ERR_MALLOC_FAILED, APFL_ERR_INPUT_ERROR, APFL_ERR_UNEXPECTED_EOF, APFL_ERR_EXPECTED_EQ_AFTER_COLON, APFL_ERR_UNEXPECTED_BYTE, APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER, APFL_ERR_EXPECTED_DIGIT, APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE, APFL_ERR_INVALID_ESCAPE_SEQUENCE, APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE, APFL_ERR_UNEXPECTED_TOKEN, APFL_ERR_MISMATCHING_CLOSING_BRACKET, APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN, APFL_ERR_STATEMENTS_BEFORE_PARAMETERS, APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS, APFL_ERR_UNEXPECTED_EXPRESSION, APFL_ERR_INVALID_ASSIGNMENT_LHS, APFL_ERR_EMPTY_ASSIGNMENT, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED, APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS, APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS, APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS, }; const char *apfl_error_type_name(enum apfl_error_type); struct apfl_error { enum apfl_error_type type; // Optional data struct apfl_position position; struct apfl_position position2; enum apfl_token_type token_type; enum apfl_token_type token_type2; char byte; }; bool apfl_error_print(struct apfl_error, FILE *); bool apfl_error_as_string(struct apfl_error, struct apfl_allocator, struct apfl_string *out); // Get a constant string for the error, if available (returns NULL otherwise) const char *apfl_error_as_const_string(struct apfl_error error); struct apfl_error apfl_error_simple(enum apfl_error_type); bool apfl_error_is_fatal_type(enum apfl_error_type); #define APFL_ERROR_IS_FATAL(err) (apfl_error_is_fatal_type((err).type)) enum apfl_expr_type { APFL_EXPR_LIST, APFL_EXPR_DICT, APFL_EXPR_CALL, APFL_EXPR_SIMPLE_FUNC, APFL_EXPR_COMPLEX_FUNC, APFL_EXPR_ASSIGNMENT, APFL_EXPR_DOT, APFL_EXPR_AT, APFL_EXPR_CONSTANT, APFL_EXPR_VAR, APFL_EXPR_BLANK, }; struct apfl_expr_list_item { struct apfl_expr *expr; bool expand; }; struct apfl_expr_list { struct apfl_expr_list_item *items; size_t len; }; struct apfl_expr_dict_pair { struct apfl_expr *k; struct apfl_expr *v; }; struct apfl_expr_dict { struct apfl_expr_dict_pair *items; size_t len; size_t cap; }; struct apfl_expr_call { struct apfl_expr *callee; struct apfl_expr_list arguments; }; struct apfl_expr_body { struct apfl_expr *items; size_t len; size_t cap; }; enum apfl_expr_const_type { APFL_EXPR_CONST_NIL, APFL_EXPR_CONST_BOOLEAN, APFL_EXPR_CONST_STRING, APFL_EXPR_CONST_NUMBER, }; struct apfl_expr_const { enum apfl_expr_const_type type; union { // variant nil is without data bool boolean; struct apfl_string string; apfl_number number; }; }; struct apfl_expr_param_predicate { struct apfl_expr_param *lhs; struct apfl_expr *rhs; }; enum apfl_expr_param_type { APFL_EXPR_PARAM_VAR, APFL_EXPR_PARAM_CONSTANT, APFL_EXPR_PARAM_PREDICATE, APFL_EXPR_PARAM_LIST, APFL_EXPR_PARAM_BLANK, }; struct apfl_expr_params { struct apfl_expr_params_item *params; size_t len; size_t cap; }; struct apfl_expr_param { enum apfl_expr_param_type type; union { struct apfl_string var; struct apfl_expr_const constant; struct apfl_expr_param_predicate predicate; struct apfl_expr_params list; }; }; struct apfl_expr_params_item { bool expand; struct apfl_expr_param param; }; struct apfl_expr_subfunc { struct apfl_expr_params params; struct apfl_expr_body body; }; struct apfl_expr_complex_func { struct apfl_expr_subfunc *subfuncs; size_t len; size_t cap; }; enum apfl_expr_assignable_type { APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER, APFL_EXPR_ASSIGNABLE_CONSTANT, APFL_EXPR_ASSIGNABLE_PREDICATE, APFL_EXPR_ASSIGNABLE_LIST, APFL_EXPR_ASSIGNABLE_BLANK, }; enum apfl_expr_assignable_var_or_member_type { APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR, APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT, APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT, }; struct apfl_expr_assignable_var_or_member_dot { struct apfl_expr_assignable_var_or_member *lhs; struct apfl_string rhs; }; struct apfl_expr_assignable_var_or_member_at { struct apfl_expr_assignable_var_or_member *lhs; struct apfl_expr *rhs; }; struct apfl_expr_assignable_var_or_member { enum apfl_expr_assignable_var_or_member_type type; union { struct apfl_string var; struct apfl_expr_assignable_var_or_member_dot dot; struct apfl_expr_assignable_var_or_member_at at; }; }; struct apfl_expr_assignable_predicate { struct apfl_expr_assignable *lhs; struct apfl_expr *rhs; }; struct apfl_expr_assignable_list { struct apfl_expr_assignable_list_item *items; size_t len; }; struct apfl_expr_assignable { enum apfl_expr_assignable_type type; union { struct apfl_expr_assignable_var_or_member var_or_member; struct apfl_expr_const constant; struct apfl_expr_assignable_predicate predicate; struct apfl_expr_assignable_list list; }; }; struct apfl_expr_assignable_list_item { struct apfl_expr_assignable assignable; bool expand; }; struct apfl_expr_assignment { bool local; struct apfl_expr_assignable lhs; struct apfl_expr *rhs; }; struct apfl_expr_dot { struct apfl_expr *lhs; struct apfl_string rhs; }; struct apfl_expr_at { struct apfl_expr *lhs; struct apfl_expr *rhs; }; struct apfl_expr { enum apfl_expr_type type; union { struct apfl_expr_list list; struct apfl_expr_dict dict; struct apfl_expr_call call; struct apfl_expr_body simple_func; struct apfl_expr_complex_func complex_func; struct apfl_expr_assignment assignment; struct apfl_expr_dot dot; struct apfl_expr_at at; struct apfl_expr_const constant; struct apfl_string var; // blank has no further data }; struct apfl_position position; }; bool apfl_expr_print(struct apfl_expr, FILE *); bool apfl_expr_eq(struct apfl_expr, struct apfl_expr); // Begin deinit functions void apfl_expr_deinit(struct apfl_allocator allocator, struct apfl_expr *); void apfl_expr_list_deinit(struct apfl_allocator allocator, struct apfl_expr_list *); void apfl_expr_list_item_deinit(struct apfl_allocator allocator, struct apfl_expr_list_item *); void apfl_expr_dict_pair_deinit(struct apfl_allocator allocator, struct apfl_expr_dict_pair *); void apfl_expr_dict_deinit(struct apfl_allocator allocator, struct apfl_expr_dict *); void apfl_expr_call_deinit(struct apfl_allocator allocator, struct apfl_expr_call *); void apfl_expr_body_deinit(struct apfl_allocator allocator, struct apfl_expr_body *); void apfl_expr_const_deinit(struct apfl_allocator allocator, struct apfl_expr_const *); void apfl_expr_param_predicate_deinit(struct apfl_allocator allocator, struct apfl_expr_param_predicate *); void apfl_expr_params_deinit(struct apfl_allocator allocator, struct apfl_expr_params *); void apfl_expr_params_item_deinit(struct apfl_allocator allocator, struct apfl_expr_params_item *); void apfl_expr_param_deinit(struct apfl_allocator allocator, struct apfl_expr_param *); void apfl_expr_subfunc_deinit(struct apfl_allocator allocator, struct apfl_expr_subfunc *); void apfl_expr_complex_func_deinit(struct apfl_allocator allocator, struct apfl_expr_complex_func *); void apfl_expr_assignable_predicate_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_predicate *); void apfl_expr_assignable_list_item_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_list_item *); void apfl_expr_assignable_list_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_list *); void apfl_expr_assignable_var_or_member_dot_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_var_or_member_dot *); void apfl_expr_assignable_var_or_member_at_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_var_or_member_at *); void apfl_expr_assignable_var_or_member_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable_var_or_member *); void apfl_expr_assignable_deinit(struct apfl_allocator allocator, struct apfl_expr_assignable *); void apfl_expr_assignment_deinit(struct apfl_allocator allocator, struct apfl_expr_assignment *); void apfl_expr_dot_deinit(struct apfl_allocator allocator, struct apfl_expr_dot *); void apfl_expr_at_deinit(struct apfl_allocator allocator, struct apfl_expr_at *); // End deinit functions // Begin move functions struct apfl_expr apfl_expr_move(struct apfl_expr *); struct apfl_expr_list apfl_expr_list_move(struct apfl_expr_list *); struct apfl_expr_list_item apfl_expr_list_item_move(struct apfl_expr_list_item *); struct apfl_expr_dict_pair apfl_expr_dict_pair_move(struct apfl_expr_dict_pair *); struct apfl_expr_dict apfl_expr_dict_move(struct apfl_expr_dict *); struct apfl_expr_call apfl_expr_call_move(struct apfl_expr_call *); struct apfl_expr_body apfl_expr_body_move(struct apfl_expr_body *); struct apfl_expr_const apfl_expr_const_move(struct apfl_expr_const *); struct apfl_expr_param_predicate apfl_expr_param_predicate_move(struct apfl_expr_param_predicate *); struct apfl_expr_params apfl_expr_params_move(struct apfl_expr_params *); struct apfl_expr_param apfl_expr_param_move(struct apfl_expr_param *); struct apfl_expr_subfunc apfl_expr_subfunc_move(struct apfl_expr_subfunc *); struct apfl_expr_complex_func apfl_expr_complex_func_move(struct apfl_expr_complex_func *); struct apfl_expr_assignable_var_or_member apfl_expr_assignable_var_or_member_move(struct apfl_expr_assignable_var_or_member *); struct apfl_expr_assignable_predicate apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *); struct apfl_expr_assignable_dot apfl_expr_assignable_dot_move(struct apfl_expr_assignable_dot *); struct apfl_expr_assignable_at apfl_expr_assignable_at_move(struct apfl_expr_assignable_at *); struct apfl_expr_assignable_list apfl_expr_assignable_list_move(struct apfl_expr_assignable_list *); struct apfl_expr_assignable apfl_expr_assignable_move(struct apfl_expr_assignable *); struct apfl_expr_assignment apfl_expr_assignment_move(struct apfl_expr_assignment *); struct apfl_expr_dot apfl_expr_dot_move(struct apfl_expr_dot *); struct apfl_expr_at apfl_expr_at_move(struct apfl_expr_at *); // End move functions enum apfl_parse_result { APFL_PARSE_OK, APFL_PARSE_EOF, APFL_PARSE_ERROR, }; struct apfl_tokenizer; typedef struct apfl_tokenizer *apfl_tokenizer_ptr; /* An apfl_source_reader is used to read source code for parsing / evaluation. */ struct apfl_source_reader { /* callback gets called repeatedly to get the source code. * buf points to a buffer to fill that has a size of *len. * The callback must set len to the number of read bytes and return true * on success and false on failure. * * Setting len to 0 indicates and end of file. * * need is true if more input is required for parsing, this is useful for * implementing a reader for a REPL to indicate to the user if they need * to type more code (e.g. by changing the prompt). */ bool (*callback)(void *opaque, char *buf, size_t *len, bool need); void *opaque; }; apfl_tokenizer_ptr apfl_tokenizer_new(struct apfl_allocator allocator, struct apfl_source_reader); void apfl_tokenizer_destroy(apfl_tokenizer_ptr); enum apfl_parse_result apfl_tokenizer_next(apfl_tokenizer_ptr, bool need); /* Get the current token. * Return value is undefined when the last call to apfl_tokenizer_next did not * return APFL_PARSE_OK. */ struct apfl_token apfl_tokenizer_get_token(apfl_tokenizer_ptr); /* Get the current error. * Return value is undefined when the last call to apfl_tokenizer_next did not * return APFL_PARSE_ERROR. */ struct apfl_error apfl_tokenizer_get_error(apfl_tokenizer_ptr); /* apfl_string_source_reader_* implements an apfl_source_reader that reads * source code from a string view. */ struct apfl_string_source_reader_data { struct apfl_string_view sv; size_t off; }; struct apfl_string_source_reader_data apfl_string_source_reader_create(struct apfl_string_view); /* Creates a source reader for apfl_string_source_reader_data. * The pointed to apfl_string_source_reader_data and the underlying string view * must be alive while the reader is in use. */ struct apfl_source_reader apfl_string_source_reader(struct apfl_string_source_reader_data *); struct apfl_parser_token_source { enum apfl_parse_result (*next)(void *, bool need); struct apfl_token (*get_token)(void *); struct apfl_error (*get_error)(void *); void *opaque; }; struct apfl_parser_token_source apfl_tokenizer_as_token_source(apfl_tokenizer_ptr); struct apfl_parser; typedef struct apfl_parser *apfl_parser_ptr; apfl_parser_ptr apfl_parser_new(struct apfl_allocator allocator, struct apfl_parser_token_source); /* Destroys the parser. * Note that if the token source needs it's own destruction, you'll have to do * that yourself after destroying the parser. */ void apfl_parser_destroy(apfl_parser_ptr); enum apfl_parse_result apfl_parser_next(apfl_parser_ptr); /* Get the current error. * Return value is undefined when the last call to apfl_parser_next did not * return APFL_PARSE_ERROR. */ struct apfl_error apfl_parser_get_error(apfl_parser_ptr); /* Get the current expression. * Return value is undefined when the last call to apfl_parser_next did not * return APFL_PARSE_OK. */ struct apfl_expr apfl_parser_get_expr(apfl_parser_ptr); struct apfl_ctx_data; typedef struct apfl_ctx_data *apfl_ctx; enum apfl_value_type { APFL_VALUE_NIL, APFL_VALUE_BOOLEAN, APFL_VALUE_NUMBER, APFL_VALUE_STRING, APFL_VALUE_LIST, APFL_VALUE_DICT, APFL_VALUE_FUNC, APFL_VALUE_USERDATA, }; typedef int apfl_stackidx; typedef size_t apfl_slotidx; enum apfl_result { APFL_RESULT_OK, // Evaluation succeeded, value is on the stack // TODO: No further details are yet provided on (fatal) error. Not quite // sure what to return / how errors/exceptions should work. Maybe a // value + a backtrace? APFL_RESULT_ERR, APFL_RESULT_ERR_FATAL, }; struct apfl_config { struct apfl_allocator allocator; struct apfl_format_writer output_writer; }; apfl_ctx apfl_ctx_new(struct apfl_config); void apfl_ctx_destroy(apfl_ctx); typedef void (*apfl_panic_callback)(apfl_ctx, bool with_error_on_stack, void *); void apfl_ctx_set_panic_callback(apfl_ctx, apfl_panic_callback, void *); typedef struct apfl_iterative_runner_data *apfl_iterative_runner; apfl_iterative_runner apfl_iterative_runner_new(apfl_ctx, struct apfl_source_reader); bool apfl_iterative_runner_next(apfl_iterative_runner); enum apfl_result apfl_iterative_runner_get_result(apfl_iterative_runner); bool apfl_iterative_runner_has_error_on_stack(apfl_iterative_runner); void apfl_iterative_runner_destroy(apfl_iterative_runner); typedef void (*apfl_cfunc)(apfl_ctx); // Get the type of a value on the stack enum apfl_value_type apfl_get_type(apfl_ctx, apfl_stackidx); // Drop a value from the stack void apfl_drop(apfl_ctx, apfl_stackidx); // Move a value to the top of the stack void apfl_move_to_top_of_stack(apfl_ctx, apfl_stackidx); // Copy a value to the top of the stack void apfl_copy(apfl_ctx ctx, apfl_stackidx index); // Push a nil onto the stack void apfl_push_nil(apfl_ctx); // Push a boolean onto the stack void apfl_push_bool(apfl_ctx, bool); // Push a number onto the stack void apfl_push_number(apfl_ctx, apfl_number); // Push a string onto the stack void apfl_push_string_view_copy(apfl_ctx, struct apfl_string_view); // Push a constant string. void apfl_push_const_string(apfl_ctx, const char *); // Create a new empty list on the stack void apfl_list_create(apfl_ctx, size_t initial_capacity); // Append a value to a list. The value will be dropped. void apfl_list_append(apfl_ctx, apfl_stackidx list, apfl_stackidx value); // Append a list to another list. The second list will be dropped. void apfl_list_append_list(apfl_ctx, apfl_stackidx a, apfl_stackidx b); // Create a new empty dict on the stack void apfl_dict_create(apfl_ctx); // Set a value in a dictionary. k and v will be dropped. void apfl_dict_set(apfl_ctx, apfl_stackidx dict, apfl_stackidx k, apfl_stackidx v); // Get a value from a container (list or dict) and push it on the stack. container and k will be dropped. void apfl_get_member(apfl_ctx, apfl_stackidx container, apfl_stackidx k); // Get a value from a container (list or dict) and push it on the stack, if it exists. container and k will be dropped. bool apfl_get_member_if_exists(apfl_ctx, apfl_stackidx container, apfl_stackidx k); // Get a value from a list and push it on the stack. The list will stay on the stack. void apfl_get_list_member_by_index(apfl_ctx, apfl_stackidx list, size_t index_in_list); // Get the length of a string/list/dict. The value stays on the stack, size_t apfl_len(apfl_ctx, apfl_stackidx); // Get a string view into a APFL_VALUE_STRING value. The value stays on the stack. // The returned string view is only guaranteed to be valid, as long as the value is on the stack. struct apfl_string_view apfl_get_string(apfl_ctx, apfl_stackidx); // Pops a value off the stack and turns it into a string. void apfl_tostring(apfl_ctx, apfl_stackidx); // Pops a value from the stack and returns whether is was truthy. All values except false and nil are truthy. bool apfl_is_truthy(apfl_ctx, apfl_stackidx); // Pops a number from the stack and returns it. apfl_number apfl_get_number(apfl_ctx, apfl_stackidx); // Pops two values from the stack and returns whether they are equal. bool apfl_eq(apfl_ctx, apfl_stackidx, apfl_stackidx); // Push a C function onto the stack with nslots slots (initialized to nil) void apfl_push_cfunc(apfl_ctx, apfl_cfunc, size_t nslots); 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); void apfl_cfunc_self_setslot(apfl_ctx, apfl_slotidx, apfl_stackidx value); void apfl_push_userdata(apfl_ctx, void *); void *apfl_get_userdata(apfl_ctx, apfl_stackidx); void apfl_call(apfl_ctx, apfl_stackidx func, apfl_stackidx args); enum apfl_result apfl_call_protected(apfl_ctx, apfl_stackidx func, apfl_stackidx args, bool *with_error_on_stack); bool apfl_debug_print_val(apfl_ctx, apfl_stackidx, struct apfl_format_writer); // Raise an error with a value from the stack as the message. APFL_NORETURN void apfl_raise_error_with_type(apfl_ctx, apfl_stackidx, enum apfl_result type); // Raise an error with a constant string as the message. APFL_NORETURN void apfl_raise_const_error(apfl_ctx, enum apfl_result type, const char *message); // Raise a memory allocation error. APFL_NORETURN void apfl_raise_alloc_error(apfl_ctx); // Raise an error for invalid stack indices. APFL_NORETURN void apfl_raise_invalid_stackidx(apfl_ctx); // Raise an error with a message derived from an struct apfl_error. APFL_NORETURN void apfl_raise_error_object(apfl_ctx, struct apfl_error); struct apfl_messages { const char *invalid_stack_index; const char *could_not_alloc_mem; const char *input_error_while_parsing; const char *unexpected_end_of_file; const char *corrupted_bytecode; const char *not_a_list; const char *not_a_dict; const char *key_doesnt_exist; const char *value_is_not_a_container; const char *wrong_key_type; const char *variable_doesnt_exist; const char *not_a_c_function; const char *invalid_slotidx; const char *not_a_function; const char *wrong_type; const char *io_error; const char *value_doesnt_match; const char *invalid_matcher_state; const char *no_matching_subfunction; }; extern const struct apfl_messages apfl_messages; #ifdef __cplusplus } #endif #endif