Add len() operator

This commit is contained in:
2025-08-08 23:07:16 +02:00
parent 208fcc008e
commit b2d3131cd4
6 changed files with 144 additions and 24 deletions
+61 -2
View File
@@ -351,6 +351,7 @@ typedef enum {
NODE_INCLUDE,
NODE_SELECT,
NODE_NESTED,
NODE_OPER_LEN,
NODE_OPER_POS,
NODE_OPER_NEG,
NODE_OPER_ASS,
@@ -459,6 +460,7 @@ typedef enum {
TOKEN_KWORD_TRUE,
TOKEN_KWORD_FALSE,
TOKEN_KWORD_INCLUDE,
TOKEN_KWORD_LEN,
TOKEN_VALUE_FLOAT,
TOKEN_VALUE_INT,
TOKEN_VALUE_STR,
@@ -550,6 +552,7 @@ String tok2str(Token token, char *buf, int max)
case TOKEN_KWORD_TRUE: return S("true");
case TOKEN_KWORD_FALSE: return S("false");
case TOKEN_KWORD_INCLUDE: return S("include");
case TOKEN_KWORD_LEN: return S("len");
case TOKEN_VALUE_FLOAT:
{
@@ -688,6 +691,7 @@ Token next_token(Parser *p)
if (streq(kword, S("true"))) return (Token) { .type=TOKEN_KWORD_TRUE };
if (streq(kword, S("false"))) return (Token) { .type=TOKEN_KWORD_FALSE };
if (streq(kword, S("include"))) return (Token) { .type=TOKEN_KWORD_INCLUDE };
if (streq(kword, S("len"))) return (Token) { .type=TOKEN_KWORD_LEN };
return (Token) { .type=TOKEN_IDENT, .sval=kword };
}
@@ -1249,6 +1253,23 @@ Node *parse_atom(Parser *p)
}
break;
case TOKEN_KWORD_LEN:
{
Node *child = parse_atom(p);
if (child == NULL)
return NULL;
Node *parent = alloc_node(p);
if (parent == NULL)
return NULL;
parent->type = NODE_OPER_LEN;
parent->left = child;
ret = parent;
}
break;
case TOKEN_IDENT:
{
Node *node = alloc_node(p);
@@ -2046,6 +2067,12 @@ void print_node(Node *node)
}
break;
case NODE_OPER_LEN:
printf("len(");
print_node(node->left);
printf(")");
break;
case NODE_OPER_POS:
printf("(");
printf("+");
@@ -2420,6 +2447,7 @@ enum {
OPCODE_FOR = 0x2E,
OPCODE_PUSHT = 0x2F,
OPCODE_PUSHFL = 0x30,
OPCODE_LEN = 0x31,
};
typedef struct {
@@ -2757,6 +2785,7 @@ bool is_expr(Node *node)
case NODE_SELECT:
case NODE_NESTED:
case NODE_FUNC_CALL:
case NODE_OPER_LEN:
case NODE_OPER_POS:
case NODE_OPER_NEG:
case NODE_OPER_ASS:
@@ -3002,6 +3031,20 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
}
break;
case NODE_OPER_LEN:
assemble_expr(a, node->left, 1);
append_u8(&a->out, OPCODE_LEN);
if (num_results == 0)
append_u8(&a->out, OPCODE_POP);
else if (num_results != -1 && num_results != 1) {
append_u8(&a->out, OPCODE_GROUP);
append_u8(&a->out, OPCODE_GTRUNC);
append_u32(&a->out, num_results-1);
append_u8(&a->out, OPCODE_GCOALESCE);
}
break;
case NODE_OPER_POS:
assemble_expr(a, node->left, num_results);
break;
@@ -5526,8 +5569,6 @@ int step(WL_State *state)
uint8_t var_2 = read_u8(state);
uint32_t end = read_u32(state);
printf("for end %u\n", end); // TODO
int base;
{
int group = state->frames[state->num_frames-1].group;
@@ -5576,6 +5617,24 @@ int step(WL_State *state)
}
break;
case OPCODE_LEN:
{
Value set = state->eval_stack[state->eval_depth-1];
Type type = type_of(set);
if (type != TYPE_ARRAY && type != TYPE_MAP) {
assert(0); // TODO
}
Value len = make_int(state->a, value_length(set));
if (len == VALUE_ERROR) {
assert(0); // TODO
}
state->eval_stack[state->eval_depth++] = len;
}
break;
default:
eval_report(state, "Invalid opcode (offset %d)", state->off-1);
return -1;
+15
View File
@@ -317,6 +317,7 @@ bool is_expr(Node *node)
case NODE_SELECT:
case NODE_NESTED:
case NODE_FUNC_CALL:
case NODE_OPER_LEN:
case NODE_OPER_POS:
case NODE_OPER_NEG:
case NODE_OPER_ASS:
@@ -562,6 +563,20 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
}
break;
case NODE_OPER_LEN:
assemble_expr(a, node->left, 1);
append_u8(&a->out, OPCODE_LEN);
if (num_results == 0)
append_u8(&a->out, OPCODE_POP);
else if (num_results != -1 && num_results != 1) {
append_u8(&a->out, OPCODE_GROUP);
append_u8(&a->out, OPCODE_GTRUNC);
append_u32(&a->out, num_results-1);
append_u8(&a->out, OPCODE_GCOALESCE);
}
break;
case NODE_OPER_POS:
assemble_expr(a, node->left, num_results);
break;
+1
View File
@@ -49,6 +49,7 @@ enum {
OPCODE_FOR = 0x2E,
OPCODE_PUSHT = 0x2F,
OPCODE_PUSHFL = 0x30,
OPCODE_LEN = 0x31,
};
typedef struct {
+18
View File
@@ -934,6 +934,24 @@ int step(WL_State *state)
}
break;
case OPCODE_LEN:
{
Value set = state->eval_stack[state->eval_depth-1];
Type type = type_of(set);
if (type != TYPE_ARRAY && type != TYPE_MAP) {
assert(0); // TODO
}
Value len = make_int(state->a, value_length(set));
if (len == VALUE_ERROR) {
assert(0); // TODO
}
state->eval_stack[state->eval_depth++] = len;
}
break;
default:
eval_report(state, "Invalid opcode (offset %d)", state->off-1);
return -1;
+26
View File
@@ -25,6 +25,7 @@ typedef enum {
TOKEN_KWORD_TRUE,
TOKEN_KWORD_FALSE,
TOKEN_KWORD_INCLUDE,
TOKEN_KWORD_LEN,
TOKEN_VALUE_FLOAT,
TOKEN_VALUE_INT,
TOKEN_VALUE_STR,
@@ -116,6 +117,7 @@ String tok2str(Token token, char *buf, int max)
case TOKEN_KWORD_TRUE: return S("true");
case TOKEN_KWORD_FALSE: return S("false");
case TOKEN_KWORD_INCLUDE: return S("include");
case TOKEN_KWORD_LEN: return S("len");
case TOKEN_VALUE_FLOAT:
{
@@ -254,6 +256,7 @@ Token next_token(Parser *p)
if (streq(kword, S("true"))) return (Token) { .type=TOKEN_KWORD_TRUE };
if (streq(kword, S("false"))) return (Token) { .type=TOKEN_KWORD_FALSE };
if (streq(kword, S("include"))) return (Token) { .type=TOKEN_KWORD_INCLUDE };
if (streq(kword, S("len"))) return (Token) { .type=TOKEN_KWORD_LEN };
return (Token) { .type=TOKEN_IDENT, .sval=kword };
}
@@ -815,6 +818,23 @@ Node *parse_atom(Parser *p)
}
break;
case TOKEN_KWORD_LEN:
{
Node *child = parse_atom(p);
if (child == NULL)
return NULL;
Node *parent = alloc_node(p);
if (parent == NULL)
return NULL;
parent->type = NODE_OPER_LEN;
parent->left = child;
ret = parent;
}
break;
case TOKEN_IDENT:
{
Node *node = alloc_node(p);
@@ -1612,6 +1632,12 @@ void print_node(Node *node)
}
break;
case NODE_OPER_LEN:
printf("len(");
print_node(node->left);
printf(")");
break;
case NODE_OPER_POS:
printf("(");
printf("+");
+1
View File
@@ -20,6 +20,7 @@ typedef enum {
NODE_INCLUDE,
NODE_SELECT,
NODE_NESTED,
NODE_OPER_LEN,
NODE_OPER_POS,
NODE_OPER_NEG,
NODE_OPER_ASS,