apfl/src/apfl.h
Laria Carolin Chabowski b29219af25 Make strings in apfl_value refcounted
This avoids copying the string every time we pass it around. Not too
important right now, but will become important onve we're able to evaluate
more complex expressions.
2022-01-02 17:55:44 +01:00

572 lines
16 KiB
C

#ifndef APFL_H
#define APFL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
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 {
unsigned refcount;
struct apfl_string 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(struct 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, \
struct 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))))
struct apfl_refcounted_string *apfl_string_move_into_new_refcounted(struct apfl_string *);
struct apfl_refcounted_string *apfl_refcounted_string_copy(struct 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(struct 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,
// TODO: dict, functions/closures
};
struct apfl_value {
enum apfl_value_type type;
union {
bool boolean;
apfl_number number;
struct apfl_refcounted_string *string;
struct apfl_list *list;
};
};
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 *);
enum apfl_function_response_type {
APFL_FUNCTION_RESPONSE_OK,
APFL_FUNCTION_RESPONSE_ERROR,
};
struct apfl_function_response {
enum apfl_function_response_type type;
struct apfl_value value;
};
typedef struct apfl_function_response (*apfl_user_function_cb)(apfl_ctx, struct apfl_list arguments, void *);
struct apfl_user_function {
apfl_user_function_cb cb;
void *opaque;
};
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