✨ str arithmetic operators.
parent
caf6b3b47c
commit
5b8748b843
|
@ -121,6 +121,17 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
|||
{
|
||||
op = OP_USUB;
|
||||
}
|
||||
else if (node->type == NODE_ADD
|
||||
&& node_find_first(node, NODE_STR))
|
||||
{
|
||||
op = OP_STRCAT;
|
||||
}
|
||||
else if (node->type == NODE_MUL
|
||||
&& node_find_first(node, NODE_STR)
|
||||
&& node_find_first(node, NODE_NUM))
|
||||
{
|
||||
op = OP_STRDUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (node->type)
|
||||
|
|
22
lib/node.c
22
lib/node.c
|
@ -97,3 +97,25 @@ size_t node_str(node_t* node, char* buffer, size_t size)
|
|||
|
||||
return sz;
|
||||
}
|
||||
|
||||
node_t* node_find_first(node_t* node, NodeType type)
|
||||
{
|
||||
assert(node);
|
||||
|
||||
if (node->type == type)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
node_t* child = node_find_first((node_t*) node->children.data[i], type);
|
||||
|
||||
if (child)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -34,5 +34,6 @@ void node_add_new_child(node_t* node, node_t* child);
|
|||
node_t* node_child(node_t* node, size_t index);
|
||||
|
||||
size_t node_str(node_t* node, char* buffer, size_t size);
|
||||
node_t* node_find_first(node_t* node, NodeType type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), \
|
||||
G(OP_MODULO), G(OP_POW), G(OP_USUB), \
|
||||
G(OP_AND), G(OP_OR), G(OP_NOT), \
|
||||
G(OP_BRF), G(OP_BRT), G(OP_BR)
|
||||
G(OP_BRF), G(OP_BRT), G(OP_BR), \
|
||||
G(OP_STRCAT), G(OP_STRDUP)
|
||||
|
||||
|
||||
RZ_ENUM_H(Opcode, OPCODES);
|
||||
|
|
71
lib/vm.c
71
lib/vm.c
|
@ -21,7 +21,7 @@ void vm_free(vm_t* vm)
|
|||
assert(vm);
|
||||
}
|
||||
|
||||
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value)
|
||||
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value)
|
||||
{
|
||||
assert(vm);
|
||||
assert(value);
|
||||
|
@ -146,7 +146,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
: (!same_type || !eq)),
|
||||
rhs->line);
|
||||
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -176,7 +176,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
}
|
||||
|
||||
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -210,7 +210,63 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
}
|
||||
|
||||
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
||||
case OP_STRCAT: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_STR);
|
||||
vm_ensure_type(vm, rhs, TYPE_STR);
|
||||
|
||||
str_t res;
|
||||
str_init(&res);
|
||||
str_append(&res, lhs->value.str);
|
||||
str_append(&res, rhs->value.str);
|
||||
|
||||
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||
str_free(&res);
|
||||
|
||||
vm_push_new_value(vm, mod, value);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
||||
case OP_STRDUP: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
|
||||
if (lhs->type->kind != TYPE_NUM)
|
||||
{
|
||||
value_t* tmp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = tmp;
|
||||
}
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_NUM);
|
||||
vm_ensure_type(vm, rhs, TYPE_STR);
|
||||
|
||||
str_t res;
|
||||
str_init(&res);
|
||||
|
||||
for (int i=0; i<(int) lhs->value.num; i++)
|
||||
{
|
||||
str_append(&res, rhs->value.str);
|
||||
}
|
||||
|
||||
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||
str_free(&res);
|
||||
|
||||
vm_push_new_value(vm, mod, value);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -236,7 +292,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
}
|
||||
|
||||
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -251,7 +307,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
double val = -lhs->value.num;
|
||||
|
||||
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -264,7 +320,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
int val = !lhs->value.bool;
|
||||
|
||||
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||
vm_push_value(vm, mod, res);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
|
||||
vm->pc++;
|
||||
} break;
|
||||
|
@ -320,5 +376,6 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want)
|
|||
TypeKindStr[got] + strlen("TYPE_"));
|
||||
|
||||
err_fatal(vm->err, msg, line);
|
||||
err_dump(vm->err);
|
||||
}
|
||||
}
|
||||
|
|
2
lib/vm.h
2
lib/vm.h
|
@ -20,7 +20,7 @@ typedef struct {
|
|||
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err);
|
||||
void vm_free(vm_t* vm);
|
||||
|
||||
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value);
|
||||
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value);
|
||||
void vm_push(vm_t* vm, param_t param);
|
||||
param_t vm_pop(vm_t* vm);
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# STRING OPERATIONS
|
||||
# =================
|
||||
|
||||
# concatenation with +
|
||||
assert "hel" + "lo" == "hello"
|
||||
assert "hello" + " " + "world" == "hello world"
|
||||
|
||||
# duplication with *
|
||||
assert "a" * 3 == "aaa"
|
||||
assert 4 * "!" == "!!!!"
|
||||
|
||||
# bonus
|
||||
assert ("a" * 2) + "b" == "aab"
|
||||
assert 4 * ("a" + "b") == "abababab"
|
|
@ -152,5 +152,4 @@ Test(lexer, bool_arith) {
|
|||
"AND",
|
||||
"OR",
|
||||
"NOT");
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue