parser+expr: Handle blank identifier (_)

This commit is contained in:
Laria 2022-01-08 23:20:29 +01:00
parent 50cd2c18d2
commit ae45aeebe2
6 changed files with 82 additions and 4 deletions

View file

@ -159,6 +159,7 @@ enum apfl_error_type {
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);
@ -192,6 +193,7 @@ enum apfl_expr_type {
APFL_EXPR_AT,
APFL_EXPR_CONSTANT,
APFL_EXPR_VAR,
APFL_EXPR_BLANK,
};
struct apfl_expr_list_item {
@ -257,6 +259,7 @@ enum apfl_expr_param_type {
APFL_EXPR_PARAM_CONSTANT,
APFL_EXPR_PARAM_PREDICATE,
APFL_EXPR_PARAM_LIST,
APFL_EXPR_PARAM_BLANK,
};
struct apfl_expr_params {
@ -295,6 +298,8 @@ enum apfl_expr_assignable_type {
APFL_EXPR_ASSIGNABLE_CONSTANT,
APFL_EXPR_ASSIGNABLE_PREDICATE,
APFL_EXPR_ASSIGNABLE_LIST,
APFL_EXPR_ASSIGNABLE_BLANK,
};
enum apfl_expr_assignable_var_or_member_type {
@ -377,6 +382,7 @@ struct apfl_expr {
struct apfl_expr_at at;
struct apfl_expr_const constant;
struct apfl_string var;
// blank has no further data
};
struct apfl_position position;

View file

@ -1,4 +1,4 @@
#include <stdio.h>
#include <stdio.h>
#include "apfl.h"
@ -52,6 +52,8 @@ apfl_error_type_name(enum apfl_error_type type)
return "APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS";
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
return "APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS";
case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS:
return "APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS";
}
return "<unknown error>";
@ -168,6 +170,13 @@ apfl_error_print(struct apfl_error error, FILE *file)
POSARGS
);
break;
case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS:
fprintf(
file,
"Unexpected blank (\"_\") in member access near " POSFMT "\n",
POSARGS
);
break;
}
fprintf(file, "Unknown error %d\n", (int)error.type);

View file

@ -437,7 +437,6 @@ static struct apfl_result
evaluate_assignment(apfl_ctx ctx, struct apfl_expr_assignment *assignment)
{
// TODO: Use assignment->local flag. Sonce we don't hev functions yet, it's not yet relevant.
// TODO: Handle special variable _. Maybe the parser should already generate a different assignment type for it?
if (
assignment->lhs.type != APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER
@ -508,6 +507,13 @@ evaluate(apfl_ctx ctx, struct apfl_expr *expr)
return evaluate_assignment(ctx, &expr->assignment);
case APFL_EXPR_VAR:
return evaluate_var(ctx, &expr->var);
case APFL_EXPR_BLANK:
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_NIL,
},
};
case APFL_EXPR_CALL:
case APFL_EXPR_SIMPLE_FUNC:
case APFL_EXPR_COMPLEX_FUNC:

View file

@ -41,6 +41,9 @@ apfl_expr_deinit(struct apfl_expr *expr)
case APFL_EXPR_VAR:
apfl_string_deinit(&expr->var);
break;
case APFL_EXPR_BLANK:
// nop
break;
}
}
@ -143,6 +146,9 @@ apfl_expr_param_deinit(struct apfl_expr_param *param)
case APFL_EXPR_PARAM_LIST:
apfl_expr_params_deinit(&param->list);
break;
case APFL_EXPR_PARAM_BLANK:
// nop
break;
}
}
@ -224,6 +230,9 @@ apfl_expr_assignable_deinit(struct apfl_expr_assignable *a)
case APFL_EXPR_ASSIGNABLE_LIST:
apfl_expr_assignable_list_deinit(&a->list);
break;
case APFL_EXPR_ASSIGNABLE_BLANK:
// nop
break;
}
}
@ -284,6 +293,9 @@ apfl_expr_move(struct apfl_expr *in)
case APFL_EXPR_VAR:
out.var = apfl_string_move(&in->var);
break;
case APFL_EXPR_BLANK:
// nop
break;
}
return out;
}
@ -412,6 +424,9 @@ apfl_expr_param_move(struct apfl_expr_param *in)
case APFL_EXPR_PARAM_LIST:
out.list = apfl_expr_params_move(&in->list);
break;
case APFL_EXPR_PARAM_BLANK:
// nop
break;
}
return out;
}
@ -487,6 +502,9 @@ apfl_expr_assignable_move(struct apfl_expr_assignable *in)
case APFL_EXPR_ASSIGNABLE_LIST:
out.list = apfl_expr_assignable_list_move(&in->list);
break;
case APFL_EXPR_ASSIGNABLE_BLANK:
// nop
break;
}
return out;
}
@ -616,6 +634,9 @@ print_param(struct apfl_expr_param *param, unsigned indent, FILE *f)
print_params_item(&param->list.params[i], indent+1, f);
}
break;
case APFL_EXPR_PARAM_BLANK:
apfl_print_indented(indent, f, "Blank (_)\n");
break;
}
}
@ -669,6 +690,9 @@ print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE *
print_assignable(item->assignable, indent_item, f);
}
break;
case APFL_EXPR_ASSIGNABLE_BLANK:
apfl_print_indented(indent, f, "Blank (_)\n");
break;
}
}
@ -738,6 +762,9 @@ print_expr(struct apfl_expr *expr, unsigned indent, FILE *f)
case APFL_EXPR_VAR:
apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ") @ " POSFMT "\n", APFL_STR_FMT_ARGS(expr->var), POSARGS(expr->position));
break;
case APFL_EXPR_BLANK:
apfl_print_indented(indent, f, "Blank (_)\n");
break;
}
}
@ -840,6 +867,8 @@ param_eq(struct apfl_expr_param a, struct apfl_expr_param b)
&& apfl_expr_eq(*a.predicate.rhs, *b.predicate.rhs);
case APFL_EXPR_PARAM_LIST:
return params_eq(a.list, b.list);
case APFL_EXPR_PARAM_BLANK:
return true;
}
assert(false);
@ -896,6 +925,8 @@ assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b)
}
}
return true;
case APFL_EXPR_ASSIGNABLE_BLANK:
return true;
}
assert(false);
@ -961,6 +992,8 @@ apfl_expr_eq(struct apfl_expr a, struct apfl_expr b)
return const_eq(a.constant, b.constant);
case APFL_EXPR_VAR:
return apfl_string_eq(a.var, b.var);
case APFL_EXPR_BLANK:
return true;
}
assert(false);

View file

@ -41,6 +41,7 @@ enum fragment_type {
FRAG_PREDICATE,
FRAG_EXPR,
FRAG_LIST,
FRAG_BLANK,
};
struct fragment_dot {
@ -148,6 +149,9 @@ fragment_deinit(struct fragment *fragment)
case FRAG_LIST:
fragment_list_deinit(&fragment->list);
break;
case FRAG_BLANK:
// nop
break;
}
}
@ -209,6 +213,9 @@ fragment_move(struct fragment *in)
case FRAG_LIST:
out.list = fragment_list_move(&in->list);
break;
case FRAG_BLANK:
// nop
break;
}
return out;
@ -630,6 +637,10 @@ fragment_to_expr_inner(apfl_parser_ptr p, struct fragment *fragment, struct apfl
out->list.len++;
}
return true;
case FRAG_BLANK:
out->type = APFL_EXPR_BLANK;
out->position = fragment->position;
return true;
}
assert(false);
@ -1054,6 +1065,9 @@ fragment_to_param_inner(
case FRAG_LIST:
out->type = APFL_EXPR_PARAM_LIST;
return fragments_to_params(p, fragment_list_move(&fragment->list), &out->list);
case FRAG_BLANK:
out->type = APFL_EXPR_PARAM_BLANK;
return true;
}
assert(false);
@ -1213,6 +1227,12 @@ static bool fragment_to_assignable_var_or_member(
case FRAG_LIST:
p->error = err_unexpected_token(APFL_TOK_LBRACKET, fragment->position);
return false;
case FRAG_BLANK:
p->error = (struct apfl_error) {
.type = APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS,
.position = fragment->position,
};
return false;
}
assert(false);
@ -1327,6 +1347,9 @@ fragment_to_assignable_inner(
out->list.len++;
}
return true;
case FRAG_BLANK:
out->type = APFL_EXPR_ASSIGNABLE_BLANK;
return true;
}
@ -1895,6 +1918,8 @@ parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum par
.type = APFL_EXPR_CONST_BOOLEAN,
.boolean = false,
};
} else if (apfl_string_eq(p->token.text, "_")) {
fragment->type = FRAG_BLANK;
} else {
fragment->type = FRAG_NAME;
fragment->name = apfl_string_move(&p->token.text);

View file

@ -635,8 +635,7 @@ TEST(map, t) {
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "_"),
.type = APFL_EXPR_PARAM_BLANK,
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_LIST,