#ifndef APFL_H #define APFL_H #ifdef __cplusplus extern "C" { #endif #include #include #include 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; }; struct apfl_refcounted_string_data; typedef struct apfl_refcounted_string_data *apfl_refcounted_string; #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); struct apfl_string_view apfl_string_view_from_refcounted_string(apfl_refcounted_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, \ apfl_refcounted_string: apfl_string_view_from_refcounted_string, \ 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_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_string *dst, struct apfl_string_view src); struct apfl_string_builder { char *bytes; size_t len; size_t cap; }; void apfl_string_builder_init(struct apfl_string_builder *); 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); 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)))) apfl_refcounted_string apfl_string_move_into_new_refcounted(struct apfl_string *); /* Increases the reference of the refcounted string. * Returns the same apfl_refcounted_string value. */ apfl_refcounted_string apfl_refcounted_string_incref(apfl_refcounted_string); /* Unrefs the refcounted string. It is no longer allowed to use the pointer * after calling this function with it! */ void apfl_refcounted_string_unref(apfl_refcounted_string ); // 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_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_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, }; 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; }; void apfl_error_print(struct apfl_error, FILE *); 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, }; 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; }; struct apfl_expr_call { struct apfl_expr *callee; struct apfl_expr_list arguments; }; struct apfl_expr_body { struct apfl_expr *items; size_t len; }; 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; }; struct apfl_expr_param_list { struct apfl_expr_param *children; size_t len; }; enum apfl_expr_param_type { APFL_EXPR_PARAM_VAR, APFL_EXPR_PARAM_CONSTANT, APFL_EXPR_PARAM_PREDICATE, APFL_EXPR_PARAM_EXPAND, APFL_EXPR_PARAM_LIST, }; struct apfl_expr_params { struct apfl_expr_param *params; size_t len; }; 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_param *expand; struct apfl_expr_params list; }; }; 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; }; enum apfl_expr_assignable_type { APFL_EXPR_ASSIGNABLE_VAR, APFL_EXPR_ASSIGNABLE_CONSTANT, APFL_EXPR_ASSIGNABLE_PREDICATE, APFL_EXPR_ASSIGNABLE_EXPAND, APFL_EXPR_ASSIGNABLE_DOT, APFL_EXPR_ASSIGNABLE_AT, APFL_EXPR_ASSIGNABLE_LIST, }; struct apfl_expr_assignable_predicate { struct apfl_expr_assignable *lhs; struct apfl_expr *rhs; }; struct apfl_expr_assignable_dot { struct apfl_expr_assignable *lhs; struct apfl_string rhs; }; struct apfl_expr_assignable_at { struct apfl_expr_assignable *lhs; struct apfl_expr *rhs; }; struct apfl_expr_assignable_list { struct apfl_expr_assignable *children; size_t len; }; struct apfl_expr_assignable { enum apfl_expr_assignable_type type; union { struct apfl_string var; struct apfl_expr_const constant; struct apfl_expr_assignable_predicate predicate; struct apfl_expr_assignable *expand; struct apfl_expr_assignable_dot dot; struct apfl_expr_assignable_at at; struct apfl_expr_assignable_list list; }; }; 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; }; struct apfl_position position; }; void 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_expr *); void apfl_expr_list_deinit(struct apfl_expr_list *); void apfl_expr_list_item_deinit(struct apfl_expr_list_item *); void apfl_expr_dict_pair_deinit(struct apfl_expr_dict_pair *); void apfl_expr_dict_deinit(struct apfl_expr_dict *); void apfl_expr_call_deinit(struct apfl_expr_call *); void apfl_expr_body_deinit(struct apfl_expr_body *); void apfl_expr_const_deinit(struct apfl_expr_const *); void apfl_expr_param_predicate_deinit(struct apfl_expr_param_predicate *); void apfl_expr_param_list_deinit(struct apfl_expr_param_list *); void apfl_expr_params_deinit(struct apfl_expr_params *); void apfl_expr_param_deinit(struct apfl_expr_param *); void apfl_expr_subfunc_deinit(struct apfl_expr_subfunc *); void apfl_expr_complex_func_deinit(struct apfl_expr_complex_func *); void apfl_expr_assignable_predicate_deinit(struct apfl_expr_assignable_predicate *); void apfl_expr_assignable_dot_deinit(struct apfl_expr_assignable_dot *); void apfl_expr_assignable_at_deinit(struct apfl_expr_assignable_at *); void apfl_expr_assignable_list_deinit(struct apfl_expr_assignable_list *); void apfl_expr_assignable_deinit(struct apfl_expr_assignable *); void apfl_expr_assignment_deinit(struct apfl_expr_assignment *); void apfl_expr_dot_deinit(struct apfl_expr_dot *); void apfl_expr_at_deinit(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_param_list apfl_expr_param_list_move(struct apfl_expr_param_list *); 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_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; typedef bool (*apfl_source_reader_cb)(void *context, char *buf, size_t *len, bool need); apfl_tokenizer_ptr apfl_tokenizer_new(apfl_source_reader_cb, void *context); 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); /* An apfl_source_reader_cb implementation to have a string view as a source. * Use together with apfl_string_source_reader_new. */ bool apfl_string_source_reader(void *, char *, size_t *len, bool); void *apfl_string_source_reader_new(struct apfl_string_view); void apfl_string_source_reader_destroy(void *); 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_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; typedef unsigned apfl_refcount; struct apfl_list { // TODO: Not sure if it's a good idea to expose this struct? apfl_refcount refcount; struct apfl_value *items; size_t len; size_t cap; }; enum apfl_value_type { APFL_VALUE_NIL, APFL_VALUE_BOOLEAN, APFL_VALUE_NUMBER, APFL_VALUE_STRING, APFL_VALUE_LIST, APFL_VALUE_DICT, // TODO: functions/closures }; struct apfl_dict_data; typedef struct apfl_dict_data *apfl_dict; void apfl_dict_unref(apfl_dict); struct apfl_value { enum apfl_value_type type; union { bool boolean; apfl_number number; apfl_refcounted_string string; struct apfl_list *list; apfl_dict dict; }; }; bool apfl_value_eq(const struct apfl_value, const struct apfl_value); struct apfl_value apfl_value_move(struct apfl_value *src); bool apfl_value_copy(struct apfl_value *dst, struct apfl_value src); void apfl_value_print(struct apfl_value, FILE *); void apfl_value_deinit(struct apfl_value *); struct apfl_editable_dict_data; typedef struct apfl_editable_dict_data *apfl_editable_dict; apfl_editable_dict apfl_editable_dict_new(void); apfl_editable_dict apfl_editable_dict_new_from_dict(apfl_dict); bool apfl_editable_dict_set(apfl_editable_dict, struct apfl_value key, struct apfl_value value); void apfl_editable_dict_delete(apfl_editable_dict, struct apfl_value key); void apfl_editable_dict_destroy(apfl_editable_dict); /* Finalize the dictionary and return a non-editable dictionary. * This also destroys the editable dictionary object, so it's no longer safe to use it. * Returns NULL on failure */ apfl_dict apfl_editable_dict_finalize(apfl_editable_dict); enum apfl_result_type { APFL_RESULT_OK, APFL_RESULT_ERR, APFL_RESULT_ERR_FATAL, }; struct apfl_result { enum apfl_result_type type; struct apfl_value value; // 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_ctx apfl_ctx_new(void); void apfl_ctx_destroy(apfl_ctx); struct apfl_result apfl_eval(apfl_ctx, struct apfl_expr); #ifdef __cplusplus } #endif #endif