parser+expr: Handle blank identifier (_)
This commit is contained in:
parent
50cd2c18d2
commit
ae45aeebe2
6 changed files with 82 additions and 4 deletions
|
|
@ -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;
|
||||
|
|
|
|||
11
src/error.c
11
src/error.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
33
src/expr.c
33
src/expr.c
|
|
@ -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(¶m->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(¶m->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);
|
||||
|
|
|
|||
25
src/parser.c
25
src/parser.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue