diff --git a/src/apfl.h b/src/apfl.h index 165f2b8..4c54e56 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -404,7 +404,7 @@ struct apfl_expr { struct apfl_position position; }; -void apfl_expr_print(struct apfl_expr, FILE *); +bool apfl_expr_print(struct apfl_expr, FILE *); bool apfl_expr_eq(struct apfl_expr, struct apfl_expr); diff --git a/src/error.c b/src/error.c index f8040cd..9a6582e 100644 --- a/src/error.c +++ b/src/error.c @@ -65,15 +65,6 @@ apfl_error_type_name(enum apfl_error_type type) return ""; } -static bool -format_pos(struct apfl_format_writer w, struct apfl_position pos) -{ - TRY(apfl_format_put_int(w, pos.line)); - TRY(apfl_format_put_string(w, ":")); - TRY(apfl_format_put_int(w, pos.col)); - return true; -} - static bool format_error(struct apfl_format_writer w, struct apfl_error error) { @@ -86,7 +77,7 @@ format_error(struct apfl_format_writer w, struct apfl_error error) return apfl_format_put_string(w, "Unexpected end of file"); case APFL_ERR_EXPECTED_EQ_AFTER_COLON: TRY(apfl_format_put_string(w, "Expected '=' after ':' at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_BYTE: TRY(apfl_format_put_string(w, "Unexpected byte '")); @@ -94,89 +85,89 @@ format_error(struct apfl_format_writer w, struct apfl_error error) TRY(apfl_format_put_string(w, "' (0x")); TRY(apfl_format_put_hexbyte(w, (unsigned char)error.byte)); TRY(apfl_format_put_string(w, ") at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER: TRY(apfl_format_put_string(w, "Unexpected byte '")); TRY(apfl_format_put_char(w, error.byte)); TRY(apfl_format_put_string(w, "' while parsing number at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_EXPECTED_DIGIT: TRY(apfl_format_put_string(w, "Expected a digit at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE: TRY(apfl_format_put_string(w, "Expected a hex-digit in hex escape at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_INVALID_ESCAPE_SEQUENCE: TRY(apfl_format_put_string(w, "Invalid escape sequence \\")); TRY(apfl_format_put_char(w, error.byte)); TRY(apfl_format_put_string(w, " at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE: TRY(apfl_format_put_string(w, "No line break (after optional comments) after \\ at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_TOKEN: TRY(apfl_format_put_string(w, "Unexpected `")); TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type))); TRY(apfl_format_put_string(w, "` token at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_MISMATCHING_CLOSING_BRACKET: TRY(apfl_format_put_string(w, "Closing `")); TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type))); TRY(apfl_format_put_string(w, "` token at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); TRY(apfl_format_put_string(w, "Does not match opening `")); TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type2))); TRY(apfl_format_put_string(w, "` at ")); - TRY(format_pos(w, error.position2)); + TRY(apfl_format_put_pos(w, error.position2)); return true; case APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN: TRY(apfl_format_put_string(w, "Unexpected end of file after `")); TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type))); TRY(apfl_format_put_string(w, "` token at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_STATEMENTS_BEFORE_PARAMETERS: TRY(apfl_format_put_string(w, "Unexpected statements before parameters near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS: TRY(apfl_format_put_string(w, "Unexpected empty assignment before parameters near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_EXPRESSION: TRY(apfl_format_put_string(w, "Unexpected expression near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_INVALID_ASSIGNMENT_LHS: TRY(apfl_format_put_string(w, "Invalid left hand side of assignment near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_EMPTY_ASSIGNMENT: TRY(apfl_format_put_string(w, "Empty assignment at ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED: TRY(apfl_format_put_string(w, "Only one expansion (~) is allowed per level, near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS: TRY(apfl_format_put_string(w, "Unexpected constant in member access near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS: TRY(apfl_format_put_string(w, "Unexpected expression in member access near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS: TRY(apfl_format_put_string(w, "Unexpected blank (\"_\") in member access near ")); - TRY(format_pos(w, error.position)); + TRY(apfl_format_put_pos(w, error.position)); return true; case APFL_ERR_NOT_IMPLEMENTED: TRY(apfl_format_put_string(w, "Feature not implemented")); diff --git a/src/expr.c b/src/expr.c index 3a52721..4e9da57 100644 --- a/src/expr.c +++ b/src/expr.c @@ -5,8 +5,11 @@ #include "apfl.h" #include "alloc.h" +#include "format.h" #include "internal.h" +#define TRY(x) do { if (!(x)) return false; } while (0) + void apfl_expr_deinit(struct apfl_allocator allocator, struct apfl_expr *expr) { @@ -529,260 +532,306 @@ apfl_expr_at_move(struct apfl_expr_at *in) return out; } -#define POSFMT "%d:%d" -#define POSARGS(p) (p).line, (p).col +static bool +format_expr_headline(struct apfl_format_writer w, const char *name, struct apfl_position pos, unsigned indent) +{ + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, name)); + TRY(apfl_format_put_string(w, " @ ")); + TRY(apfl_format_put_pos(w, pos)); + TRY(apfl_format_put_string(w, "\n")); + return true; +} -static void print_expr(struct apfl_expr *expr, unsigned indent, FILE *f); +static bool +format_simple_headline(struct apfl_format_writer w, const char *headline, unsigned indent) +{ + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, headline)); + TRY(apfl_format_put_string(w, "\n")); + return true; +} -static void -print_expr_list(struct apfl_expr_list *list, unsigned indent, FILE *f) +static bool format_expr(struct apfl_format_writer, struct apfl_expr *, unsigned indent); + +static bool +format_expr_list(struct apfl_format_writer w, struct apfl_expr_list *list, unsigned indent) { for (size_t i = 0; i < list->len; i++) { unsigned item_indent = indent; if (list->items[i].expand) { - apfl_print_indented(indent, f, "Expand\n"); + TRY(format_simple_headline(w, "Expand", indent)); item_indent++; } - print_expr(list->items[i].expr, item_indent, f); + TRY(format_expr(w, list->items[i].expr, item_indent)); } + + return true; } -static void -print_body(struct apfl_expr_body *body, unsigned indent, FILE *f) +static bool +format_body(struct apfl_format_writer w, struct apfl_expr_body *body, unsigned indent) { for (size_t i = 0; i < body->len; i++) { - print_expr(&body->items[i], indent, f); + TRY(format_expr(w, &body->items[i], indent)); } + + return true; } -static void -print_constant_with_pos(struct apfl_expr_const constant, struct apfl_position pos, unsigned indent, FILE *f) +static bool +format_constant_with_pos(struct apfl_format_writer w, struct apfl_expr_const constant, struct apfl_position pos, unsigned indent) { - struct apfl_string_view sv; - switch (constant.type) { case APFL_EXPR_CONST_NIL: - apfl_print_indented(indent, f, "Const (nil) @ " POSFMT "\n", POSARGS(pos)); - break; + return format_expr_headline(w, "Const (nil)", pos, indent); case APFL_EXPR_CONST_BOOLEAN: - apfl_print_indented(indent, f, "Const (%s) @ " POSFMT "\n", constant.boolean ? "true" : "false", POSARGS(pos)); - break; + return format_expr_headline(w, constant.boolean ? "Const (true)" : "Const (false", pos, indent); case APFL_EXPR_CONST_STRING: - sv = apfl_string_view_from(constant.string); - apfl_print_indented(indent, f, "Const (" APFL_STR_FMT ") @ " POSFMT "\n", APFL_STR_FMT_ARGS(sv), POSARGS(pos)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Const (")); + TRY(apfl_format_put_string(w, constant.string)); + TRY(apfl_format_put_string(w, ") @ ")); + TRY(apfl_format_put_pos(w, pos)); + TRY(apfl_format_put_string(w, "\n")); + return true; case APFL_EXPR_CONST_NUMBER: - apfl_print_indented(indent, f, "Const (%f) @ " POSFMT "\n", constant.number, POSARGS(pos)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Number (")); + TRY(apfl_format_put_number(w, constant.number)); + TRY(apfl_format_put_string(w, ") @ ")); + TRY(apfl_format_put_pos(w, pos)); + TRY(apfl_format_put_string(w, "\n")); + return true; } + + assert(false); + return false; } -static void -print_constant(struct apfl_expr_const constant, unsigned indent, FILE *f) +static bool +format_constant(struct apfl_format_writer w, struct apfl_expr_const constant, unsigned indent) { - struct apfl_string_view sv; - switch (constant.type) { case APFL_EXPR_CONST_NIL: - apfl_print_indented(indent, f, "Const (nil)\n"); - break; + return format_simple_headline(w, "Const (nil)", indent); case APFL_EXPR_CONST_BOOLEAN: - apfl_print_indented(indent, f, "Const (%s)\n", constant.boolean ? "true" : "false"); - break; + return format_simple_headline(w, constant.boolean ? "Const (true)" : "Const (false", indent); case APFL_EXPR_CONST_STRING: - sv = apfl_string_view_from(constant.string); - apfl_print_indented(indent, f, "Const (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(sv)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Const (")); + TRY(apfl_format_put_string(w, constant.string)); + TRY(apfl_format_put_string(w, ")\n")); + return true; case APFL_EXPR_CONST_NUMBER: - apfl_print_indented(indent, f, "Const (%f)\n", constant.number); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Number (")); + TRY(apfl_format_put_number(w, constant.number)); + TRY(apfl_format_put_string(w, ")\n")); + return true; } + + assert(false); + return false; } -static void print_param(struct apfl_expr_param *, unsigned, FILE *); +static bool format_param(struct apfl_format_writer w, struct apfl_expr_param *, unsigned); -static void -print_params_item(struct apfl_expr_params_item *item, unsigned indent, FILE *f) +static bool +format_params_item(struct apfl_format_writer w, struct apfl_expr_params_item *item, unsigned indent) { if (item->expand) { - apfl_print_indented(indent, f, "Expand\n"); + TRY(format_simple_headline(w, "Expand", indent)); indent++; } - print_param(&item->param, indent, f); + return format_param(w, &item->param, indent); } -static void -print_param(struct apfl_expr_param *param, unsigned indent, FILE *f) +static bool +format_param(struct apfl_format_writer w, struct apfl_expr_param *param, unsigned indent) { - struct apfl_string_view sv; - switch (param->type) { case APFL_EXPR_PARAM_VAR: - sv = apfl_string_view_from(param->var); - apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(sv)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Var (")); + TRY(apfl_format_put_string(w, param->var)); + TRY(apfl_format_put_string(w, ")\n")); + return true; case APFL_EXPR_PARAM_CONSTANT: - print_constant(param->constant, indent, f); - break; + return format_constant(w, param->constant, indent); case APFL_EXPR_PARAM_PREDICATE: - apfl_print_indented(indent, f, "Predicate\n"); - apfl_print_indented(indent+1, f, "LHS\n"); - print_param(param->predicate.lhs, indent+2, f); - apfl_print_indented(indent+1, f, "RHS\n"); - print_expr(param->predicate.rhs, indent+2, f); - break; + TRY(format_simple_headline(w, "Predicate", indent)); + TRY(format_simple_headline(w, "LHS", indent+1)); + TRY(format_param(w, param->predicate.lhs, indent+2)); + TRY(format_simple_headline(w, "RHS", indent+1)); + TRY(format_expr(w, param->predicate.rhs, indent+2)); + return true; case APFL_EXPR_PARAM_LIST: - apfl_print_indented(indent, f, "List\n"); + TRY(format_simple_headline(w, "List", indent)); for (size_t i = 0; i < param->list.len; i++) { - print_params_item(¶m->list.params[i], indent+1, f); + TRY(format_params_item(w, ¶m->list.params[i], indent+1)); } - break; + return true; case APFL_EXPR_PARAM_BLANK: - apfl_print_indented(indent, f, "Blank (_)\n"); - break; + return format_simple_headline(w, "Blank (_)", indent); } + + assert(false); + return false; } -static void -print_assignable_var_or_member(struct apfl_expr_assignable_var_or_member var_or_member, unsigned indent, FILE *f) +static bool +format_assignable_var_or_member(struct apfl_format_writer w, struct apfl_expr_assignable_var_or_member var_or_member, unsigned indent) { - struct apfl_string_view sv; - switch (var_or_member.type) { case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR: - sv = apfl_string_view_from(var_or_member.var); - apfl_print_indented(indent, f, "Variable (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(sv)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Var (")); + TRY(apfl_format_put_string(w, var_or_member.var)); + TRY(apfl_format_put_string(w, ")\n")); + return true; case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT: - sv = apfl_string_view_from(var_or_member.dot.rhs); - apfl_print_indented(indent, f, "Dot (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(sv)); - print_assignable_var_or_member(*var_or_member.dot.lhs, indent+1, f); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Dot (")); + TRY(apfl_format_put_string(w, var_or_member.dot.rhs)); + TRY(apfl_format_put_string(w, ")\n")); + TRY(format_assignable_var_or_member(w, *var_or_member.dot.lhs, indent+1)); + return true; case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT: - apfl_print_indented(indent, f, "At\n"); - apfl_print_indented(indent+1, f, "LHS\n"); - print_assignable_var_or_member(*var_or_member.at.lhs, indent+2, f); - apfl_print_indented(indent+1, f, "RHS\n"); - print_expr(var_or_member.at.rhs, indent+2, f); - break; + TRY(format_simple_headline(w, "At", indent)); + TRY(format_simple_headline(w, "LHS", indent+1)); + TRY(format_assignable_var_or_member(w, *var_or_member.at.lhs, indent+2)); + TRY(format_simple_headline(w, "RHS", indent+1)); + TRY(format_expr(w, var_or_member.at.rhs, indent+2)); + return true; } + + assert(false); + return false; } -static void -print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE *f) +static bool +format_assignable(struct apfl_format_writer w, struct apfl_expr_assignable assignable, unsigned indent) { switch(assignable.type) { case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER: - print_assignable_var_or_member(assignable.var_or_member, indent, f); - break; + return format_assignable_var_or_member(w, assignable.var_or_member, indent); case APFL_EXPR_ASSIGNABLE_CONSTANT: - print_constant(assignable.constant, indent, f); - break; + return format_constant(w, assignable.constant, indent); case APFL_EXPR_ASSIGNABLE_PREDICATE: - apfl_print_indented(indent, f, "Predicate\n"); - apfl_print_indented(indent+1, f, "LHS\n"); - print_assignable(*assignable.predicate.lhs, indent+2, f); - apfl_print_indented(indent+1, f, "RHS\n"); - print_expr(assignable.predicate.rhs, indent+2, f); - break; + TRY(format_simple_headline(w, "Predicate", indent)); + TRY(format_simple_headline(w, "LHS", indent+1)); + TRY(format_assignable(w, *assignable.predicate.lhs, indent+2)); + TRY(format_simple_headline(w, "RHS", indent+1)); + TRY(format_expr(w, assignable.predicate.rhs, indent+2)); + return true; case APFL_EXPR_ASSIGNABLE_LIST: - apfl_print_indented(indent, f, "List\n"); + TRY(format_simple_headline(w, "List", indent)); for (size_t i = 0; i < assignable.list.len; i++) { struct apfl_expr_assignable_list_item *item = &assignable.list.items[i]; unsigned indent_item = indent+1; if (item->expand) { - apfl_print_indented(indent_item, f, "Expand\n"); + TRY(format_simple_headline(w, "Expand", indent_item)); indent_item++; } - print_assignable(item->assignable, indent_item, f); + TRY(format_assignable(w, item->assignable, indent_item)); } - break; + return true; case APFL_EXPR_ASSIGNABLE_BLANK: - apfl_print_indented(indent, f, "Blank (_)\n"); - break; + return format_simple_headline(w, "Blank (_)", indent); } + + assert(false); + return false; } -static void -print_expr(struct apfl_expr *expr, unsigned indent, FILE *f) +static bool +format_expr(struct apfl_format_writer w, struct apfl_expr *expr, unsigned indent) { - struct apfl_string_view sv; - switch (expr->type) { case APFL_EXPR_LIST: - apfl_print_indented(indent, f, "List @ " POSFMT "\n", POSARGS(expr->position)); - print_expr_list(&expr->list, indent+1, f); - break; + TRY(format_expr_headline(w, "List", expr->position, indent)); + TRY(format_expr_list(w, &expr->list, indent+1)); + return true; case APFL_EXPR_DICT: - apfl_print_indented(indent, f, "Dict @ " POSFMT "\n", POSARGS(expr->position)); + TRY(format_expr_headline(w, "Dict", expr->position, indent)); for (size_t i = 0; i < expr->dict.len; i++) { - apfl_print_indented(indent+1, f, "Dict item\n"); - apfl_print_indented(indent+2, f, "Key\n"); - print_expr(expr->dict.items[i].k, indent+3, f); - apfl_print_indented(indent+2, f, "Value\n"); - print_expr(expr->dict.items[i].v, indent+3, f); + TRY(format_simple_headline(w, "Dict item", indent+1)); + TRY(format_simple_headline(w, "Key", indent+2)); + TRY(format_expr(w, expr->dict.items[i].k, indent+3)); + TRY(format_simple_headline(w, "Value", indent+2)); + TRY(format_expr(w, expr->dict.items[i].v, indent+3)); } - break; + return true; case APFL_EXPR_CALL: - apfl_print_indented(indent, f, "Call @ " POSFMT "\n", POSARGS(expr->position)); - apfl_print_indented(indent+1, f, "Callee\n"); - print_expr(expr->call.callee, indent+2, f); - apfl_print_indented(indent+1, f, "Args\n"); - print_expr_list(&expr->call.arguments, indent+2, f); - break; + TRY(format_expr_headline(w, "Call", expr->position, indent)); + TRY(format_simple_headline(w, "Callee", indent+1)); + TRY(format_expr(w, expr->call.callee, indent+2)); + TRY(format_simple_headline(w, "Args", indent+1)); + TRY(format_expr_list(w, &expr->call.arguments, indent+2)); + return true; case APFL_EXPR_SIMPLE_FUNC: - apfl_print_indented(indent, f, "Simple function @ " POSFMT "\n", POSARGS(expr->position)); - print_body(&expr->simple_func, indent+1, f); - break; + TRY(format_expr_headline(w, "Simple function", expr->position, indent)); + TRY(format_body(w, &expr->simple_func, indent+1)); + return true; case APFL_EXPR_COMPLEX_FUNC: - apfl_print_indented(indent, f, "Complex function @ " POSFMT "\n", POSARGS(expr->position)); + TRY(format_expr_headline(w, "Complex function", expr->position, indent)); for (size_t i = 0; i < expr->complex_func.len; i++) { - apfl_print_indented(indent+1, f, "Subfunction\n"); + TRY(format_simple_headline(w, "Subfunction", indent+1)); struct apfl_expr_subfunc *sub = &expr->complex_func.subfuncs[i]; - apfl_print_indented(indent+2, f, "Parameters\n"); + TRY(format_simple_headline(w, "Parameters", indent+2)); for (size_t j = 0; j < sub->params.len; j++) { - print_params_item(&sub->params.params[j], indent+3, f); + TRY(format_params_item(w, &sub->params.params[j], indent+3)); } - apfl_print_indented(indent+2, f, "Body\n"); - print_body(&sub->body, indent+3, f); + TRY(format_simple_headline(w, "Body", indent+2)); + TRY(format_body(w, &sub->body, indent+3)); } - break; + return true; case APFL_EXPR_ASSIGNMENT: - apfl_print_indented(indent, f, "Assignment\n"); - apfl_print_indented(indent+1, f, "LHS\n"); - print_assignable(expr->assignment.lhs, indent+2, f); - apfl_print_indented(indent+1, f, "RHS\n"); - print_expr(expr->assignment.rhs, indent+2, f); - break; + TRY(format_expr_headline(w, "Assignment", expr->position, indent)); + TRY(format_simple_headline(w, "LHS", indent+1)); + TRY(format_assignable(w, expr->assignment.lhs, indent+2)); + TRY(format_simple_headline(w, "RHS", indent+1)); + TRY(format_expr(w, expr->assignment.rhs, indent+2)); + return true; case APFL_EXPR_DOT: - sv = apfl_string_view_from(expr->dot.rhs); - apfl_print_indented(indent, f, "Dot (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(sv)); - print_expr(expr->dot.lhs, indent+1, f); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Dot (")); + TRY(apfl_format_put_string(w, expr->dot.rhs)); + TRY(apfl_format_put_string(w, ") @ ")); + TRY(apfl_format_put_pos(w, expr->position)); + TRY(apfl_format_put_string(w, "\n")); + TRY(format_expr(w, expr->dot.lhs, indent+1)); + return true; case APFL_EXPR_AT: - apfl_print_indented(indent, f, "At\n"); - apfl_print_indented(indent+1, f, "LHS\n"); - print_expr(expr->at.lhs, indent+2, f); - apfl_print_indented(indent+1, f, "RHS\n"); - print_expr(expr->at.rhs, indent+2, f); - break; + TRY(format_expr_headline(w, "At", expr->position, indent)); + TRY(format_simple_headline(w, "LHS", indent+1)); + TRY(format_expr(w, expr->at.lhs, indent+2)); + TRY(format_simple_headline(w, "RHS", indent+1)); + TRY(format_expr(w, expr->at.rhs, indent+2)); + return true; case APFL_EXPR_CONSTANT: - print_constant_with_pos(expr->constant, expr->position, indent, f); - break; + return format_constant_with_pos(w, expr->constant, expr->position, indent); case APFL_EXPR_VAR: - sv = apfl_string_view_from(expr->var); - apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ") @ " POSFMT "\n", APFL_STR_FMT_ARGS(sv), POSARGS(expr->position)); - break; + TRY(apfl_format_put_indent(w, indent)); + TRY(apfl_format_put_string(w, "Var (")); + TRY(apfl_format_put_string(w, expr->var)); + TRY(apfl_format_put_string(w, ") @ ")); + TRY(apfl_format_put_pos(w, expr->position)); + TRY(apfl_format_put_string(w, "\n")); + return true; case APFL_EXPR_BLANK: - apfl_print_indented(indent, f, "Blank (_)\n"); - break; + return format_expr_headline(w, "Blank (_)", expr->position, indent); } + + assert(false); + return false; } -void +bool apfl_expr_print(struct apfl_expr expr, FILE *f) { - print_expr(&expr, 0, f); + return format_expr(apfl_format_file_writer(f), &expr, 0); } static bool diff --git a/src/format.c b/src/format.c index ecb2470..b5a2384 100644 --- a/src/format.c +++ b/src/format.c @@ -75,3 +75,35 @@ apfl_format_put_hexbyte(struct apfl_format_writer w, unsigned char c) assert(len < PUT_HEXBYTE_BUFSIZE); return WRITE(w, buf, len); } + +bool +apfl_format_put_pos(struct apfl_format_writer w, struct apfl_position pos) +{ + TRY(apfl_format_put_int(w, pos.line)); + TRY(apfl_format_put_string(w, ":")); + TRY(apfl_format_put_int(w, pos.col)); + return true; +} + +bool +apfl_format_put_indent(struct apfl_format_writer w, unsigned indent) +{ + while (indent--) { + TRY(apfl_format_put_string(w, " ")); + } + return true; +} + +#define PUT_NUMBER_BUFSIZE 100 // Arbitrarily chosen ¯\_(ツ)_/¯ + +bool +apfl_format_put_number(struct apfl_format_writer w, apfl_number number) +{ + char buf[PUT_NUMBER_BUFSIZE]; + size_t len = snprintf(buf, PUT_NUMBER_BUFSIZE, "%f", number); + TRY(WRITE(w, buf, len)); + if (len >= PUT_NUMBER_BUFSIZE) { + TRY(apfl_format_put_string(w, "[...]")); + } + return true; +} diff --git a/src/format.h b/src/format.h index 8e5c05e..30146ee 100644 --- a/src/format.h +++ b/src/format.h @@ -25,6 +25,9 @@ bool apfl_format_put_string_view(struct apfl_format_writer, struct apfl_string_v 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); #ifdef __cplusplus } diff --git a/src/main.c b/src/main.c index 5d0bb5c..0129899 100644 --- a/src/main.c +++ b/src/main.c @@ -82,7 +82,7 @@ repl_parser(struct apfl_allocator allocator, apfl_parser_ptr parser) switch (apfl_parser_next(parser)) { case APFL_PARSE_OK: expr = apfl_parser_get_expr(parser); - apfl_expr_print(expr, stdout); + assert(apfl_expr_print(expr, stdout)); apfl_expr_deinit(allocator, &expr); break; case APFL_PARSE_EOF: diff --git a/src/parser_test.c b/src/parser_test.c index e5e36b4..5a69899 100644 --- a/src/parser_test.c +++ b/src/parser_test.c @@ -75,9 +75,9 @@ expect_expr(struct parser_test *pt, struct apfl_expr expected) if (!apfl_expr_eq(expr, expected)) { test_failf(pt->t, "Expected expression differs from actual expression"); test_failf(pt->t, "Expected:"); - apfl_expr_print(expected, stderr); + assert(apfl_expr_print(expected, stderr)); test_failf(pt->t, "Have:"); - apfl_expr_print(expr, stderr); + assert(apfl_expr_print(expr, stderr)); } apfl_expr_deinit(pt->allocator, &expr); apfl_expr_deinit(pt->allocator, &expected);