Use formatter for expr printing
This commit is contained in:
parent
b4a7dfe1f6
commit
a4fd3acfac
7 changed files with 259 additions and 184 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
49
src/error.c
49
src/error.c
|
|
@ -65,15 +65,6 @@ apfl_error_type_name(enum apfl_error_type type)
|
|||
return "<unknown error>";
|
||||
}
|
||||
|
||||
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"));
|
||||
|
|
|
|||
351
src/expr.c
351
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
|
||||
|
|
|
|||
32
src/format.c
32
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue