2021-04-09 00:41:55 +02:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cmath>
|
|
|
|
|
2021-03-24 02:21:27 +01:00
|
|
|
#include "cs_gen.hh"
|
2016-08-14 17:14:10 +02:00
|
|
|
|
2021-04-09 00:41:55 +02:00
|
|
|
#include "cs_bcode.hh"
|
|
|
|
#include "cs_ident.hh"
|
|
|
|
#include "cs_parser.hh"
|
|
|
|
|
2021-03-23 23:32:25 +01:00
|
|
|
namespace cubescript {
|
2016-08-14 17:14:10 +02:00
|
|
|
|
2021-04-09 00:41:55 +02:00
|
|
|
void gen_state::gen_val_null() {
|
|
|
|
code.push_back(BC_INST_VAL_INT | BC_RET_NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_integer(integer_type v) {
|
|
|
|
if (v >= -0x800000 && v <= 0x7FFFFF) {
|
|
|
|
code.push_back(BC_INST_VAL_INT | BC_RET_INT | (v << 8));
|
|
|
|
} else {
|
|
|
|
std::uint32_t u[bc_store_size<integer_type>] = {0};
|
|
|
|
std::memcpy(u, &v, sizeof(v));
|
|
|
|
code.push_back(BC_INST_VAL | BC_RET_INT);
|
|
|
|
code.append(u, u + bc_store_size<integer_type>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_integer(std::string_view v) {
|
|
|
|
gen_val_integer(parse_int(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_float(float_type v) {
|
|
|
|
if (std::floor(v) == v && v >= -0x800000 && v <= 0x7FFFFF) {
|
|
|
|
code.push_back(
|
|
|
|
BC_INST_VAL_INT | BC_RET_FLOAT | (integer_type(std::floor(v)) << 8)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
std::uint32_t u[bc_store_size<float_type>] = {0};
|
|
|
|
std::memcpy(u, &v, sizeof(v));
|
|
|
|
code.push_back(BC_INST_VAL | BC_RET_FLOAT);
|
|
|
|
code.append(u, u + bc_store_size<float_type>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_float(std::string_view v) {
|
|
|
|
gen_val_float(parse_float(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_string(std::string_view v) {
|
|
|
|
auto vsz = v.size();
|
|
|
|
if (vsz <= 3) {
|
|
|
|
std::uint32_t op = BC_INST_VAL_INT | BC_RET_STRING;
|
|
|
|
for (size_t i = 0; i < vsz; ++i) {
|
|
|
|
auto c = static_cast<unsigned char>(v[i]);
|
|
|
|
op |= std::uint32_t(c) << ((i + 1) * 8);
|
|
|
|
}
|
|
|
|
code.push_back(op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
code.push_back(BC_INST_VAL | BC_RET_STRING | std::uint32_t(vsz << 8));
|
|
|
|
auto it = reinterpret_cast<std::uint32_t const *>(v.data());
|
|
|
|
code.append(it, it + (v.size() / sizeof(std::uint32_t)));
|
|
|
|
std::size_t esz = v.size() % sizeof(std::uint32_t);
|
|
|
|
char c[sizeof(std::uint32_t)] = {0};
|
|
|
|
std::memcpy(c, v.data() + v.size() - esz, esz);
|
|
|
|
std::uint32_t u;
|
|
|
|
std::memcpy(&u, c, sizeof(u));
|
|
|
|
code.push_back(u);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_ident() {
|
|
|
|
gen_val_ident(*ts.istate->id_dummy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_ident(ident &i) {
|
|
|
|
code.push_back(BC_INST_IDENT | (i.get_index() << 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val_ident(std::string_view v) {
|
|
|
|
gen_val_ident(ts.istate->new_ident(*ts.pstate, v, IDENT_FLAG_UNKNOWN));
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_val(
|
|
|
|
int val_type, std::string_view v, std::size_t line
|
|
|
|
) {
|
|
|
|
switch (val_type) {
|
|
|
|
case VAL_ANY:
|
|
|
|
if (!v.empty()) {
|
|
|
|
gen_val_string(v);
|
|
|
|
} else {
|
|
|
|
gen_val_null();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VAL_STRING:
|
|
|
|
gen_val_string(v);
|
|
|
|
break;
|
|
|
|
case VAL_FLOAT:
|
|
|
|
gen_val_float(v);
|
|
|
|
break;
|
|
|
|
case VAL_INT:
|
|
|
|
gen_val_integer(v);
|
|
|
|
break;
|
|
|
|
case VAL_COND:
|
|
|
|
if (!v.empty()) {
|
|
|
|
gen_block(v, line);
|
|
|
|
} else {
|
|
|
|
gen_val_null();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VAL_CODE:
|
|
|
|
gen_block(v, line);
|
|
|
|
break;
|
|
|
|
case VAL_IDENT:
|
|
|
|
gen_val_ident(v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_state::gen_block() {
|
|
|
|
code.push_back(BC_INST_EMPTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<std::size_t, std::string_view> gen_state::gen_block(
|
|
|
|
std::string_view v, std::size_t line, int ret_type, int term
|
|
|
|
) {
|
|
|
|
auto csz = code.size();
|
|
|
|
code.push_back(BC_INST_BLOCK);
|
|
|
|
/* encodes the offset from the start of the bytecode block
|
|
|
|
* this is used for refcounting (subtract the offset, get to
|
|
|
|
* the start of the original allocation, i.e. BC_INST_START)
|
|
|
|
*/
|
|
|
|
code.push_back(BC_INST_OFFSET | std::uint32_t((csz + 2) << 8));
|
|
|
|
auto ret_line = line;
|
|
|
|
if (!v.empty()) {
|
|
|
|
parser_state ps{ts, *this};
|
|
|
|
ps.source = v.data();
|
|
|
|
ps.send = v.data() + v.size();
|
|
|
|
ps.current_line = line;
|
|
|
|
ps.parse_block(VAL_ANY, term);
|
|
|
|
v = std::string_view{ps.source, ps.send};
|
|
|
|
ret_line = ps.current_line;
|
|
|
|
}
|
|
|
|
if (code.size() > (csz + 2)) {
|
|
|
|
code.push_back(BC_INST_EXIT | ret_type);
|
|
|
|
/* encode the block size in BC_INST_BLOCK */
|
|
|
|
code[csz] |= (std::uint32_t(code.size() - csz - 1) << 8);
|
|
|
|
} else {
|
|
|
|
/* empty code */
|
|
|
|
code.resize(csz);
|
|
|
|
code.push_back(BC_INST_EMPTY | ret_type);
|
|
|
|
}
|
|
|
|
return std::make_pair(ret_line, v);
|
|
|
|
}
|
|
|
|
|
2021-04-08 23:33:00 +02:00
|
|
|
} /* namespace cubescript */
|