Add len() operator
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -49,6 +49,7 @@ enum {
|
||||
OPCODE_FOR = 0x2E,
|
||||
OPCODE_PUSHT = 0x2F,
|
||||
OPCODE_PUSHFL = 0x30,
|
||||
OPCODE_LEN = 0x31,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
+18
@@ -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
@@ -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("+");
|
||||
|
||||
@@ -20,6 +20,7 @@ typedef enum {
|
||||
NODE_INCLUDE,
|
||||
NODE_SELECT,
|
||||
NODE_NESTED,
|
||||
NODE_OPER_LEN,
|
||||
NODE_OPER_POS,
|
||||
NODE_OPER_NEG,
|
||||
NODE_OPER_ASS,
|
||||
|
||||
Reference in New Issue
Block a user