An embeddable, thread-safe implementation of the cubescript language
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

926 lines
33 KiB

4 years ago
3 months ago
3 months ago
3 months ago
5 months ago
3 months ago
5 months ago
5 years ago
5 years ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
5 months ago
4 months ago
4 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 years ago
5 years ago
5 years ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. #include <cubescript/cubescript.hh>
  2. #include "cs_vm.hh"
  3. #include "cs_std.hh"
  4. #include "cs_parser.hh"
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <limits>
  8. namespace cubescript {
  9. static inline void push_alias(thread_state &ts, ident &id, ident_stack &st) {
  10. if (id.type() != ident_type::ALIAS) {
  11. return;
  12. }
  13. if (!static_cast<alias &>(id).is_arg()) {
  14. auto *aimp = static_cast<alias_impl *>(&id);
  15. auto ast = ts.get_astack(aimp);
  16. ast.push(st);
  17. ast.flags &= ~IDENT_FLAG_UNKNOWN;
  18. }
  19. }
  20. static inline void pop_alias(thread_state &ts, ident &id) {
  21. if (id.type() != ident_type::ALIAS) {
  22. return;
  23. }
  24. if (!static_cast<alias &>(id).is_arg()) {
  25. ts.get_astack(static_cast<alias *>(&id)).pop();
  26. }
  27. }
  28. static inline void force_arg(state &cs, any_value &v, int type) {
  29. switch (type) {
  30. case BC_RET_STRING:
  31. if (v.type() != value_type::STRING) {
  32. v.force_string(cs);
  33. }
  34. break;
  35. case BC_RET_INT:
  36. if (v.type() != value_type::INTEGER) {
  37. v.force_integer();
  38. }
  39. break;
  40. case BC_RET_FLOAT:
  41. if (v.type() != value_type::FLOAT) {
  42. v.force_float();
  43. }
  44. break;
  45. }
  46. }
  47. void exec_command(
  48. thread_state &ts, command_impl *id, ident *self, any_value *args,
  49. any_value &res, std::size_t nargs, bool lookup
  50. ) {
  51. int i = -1, fakeargs = 0, numargs = int(nargs);
  52. bool rep = false;
  53. auto fmt = id->args();
  54. auto set_fake = [&i, &fakeargs, &rep, args, numargs]() {
  55. if (++i >= numargs) {
  56. if (rep) {
  57. return false;
  58. }
  59. args[i].set_none();
  60. ++fakeargs;
  61. return false;
  62. }
  63. return true;
  64. };
  65. for (auto it = fmt.begin(); it != fmt.end(); ++it) {
  66. switch (*it) {
  67. case 'i':
  68. if (set_fake()) {
  69. args[i].force_integer();
  70. }
  71. break;
  72. case 'f':
  73. if (set_fake()) {
  74. args[i].force_float();
  75. }
  76. break;
  77. case 's':
  78. if (set_fake()) {
  79. args[i].force_string(*ts.pstate);
  80. }
  81. break;
  82. case 'a':
  83. set_fake();
  84. break;
  85. case 'c':
  86. if (set_fake()) {
  87. if (args[i].type() == value_type::STRING) {
  88. auto str = args[i].get_string(*ts.pstate);
  89. if (str.empty()) {
  90. args[i].set_integer(0);
  91. } else {
  92. args[i].force_code(*ts.pstate);
  93. }
  94. }
  95. }
  96. break;
  97. case 'b':
  98. if (set_fake()) {
  99. args[i].force_code(*ts.pstate);
  100. }
  101. break;
  102. case 'v':
  103. if (set_fake()) {
  104. args[i].force_ident(*ts.pstate);
  105. }
  106. break;
  107. case '$':
  108. i += 1;
  109. args[i].set_ident(*self);
  110. break;
  111. case '#':
  112. i += 1;
  113. args[i].set_integer(integer_type(lookup ? -1 : i - fakeargs));
  114. break;
  115. case '.':
  116. i = std::max(i + 1, numargs);
  117. id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
  118. return;
  119. case '1':
  120. case '2':
  121. case '3':
  122. case '4':
  123. if (i + 1 < numargs) {
  124. it -= *it - '0' + 1;
  125. rep = true;
  126. }
  127. break;
  128. }
  129. }
  130. ++i;
  131. id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
  132. res.force_plain();
  133. }
  134. bool exec_alias(
  135. thread_state &ts, alias *a, any_value *args, any_value &result,
  136. std::size_t callargs, std::size_t &nargs,
  137. std::size_t offset, std::size_t skip, std::uint32_t op, bool ncheck
  138. ) {
  139. auto &aast = ts.get_astack(a);
  140. if (ncheck) {
  141. if (aast.node->val_s.type() == value_type::NONE) {
  142. return false;
  143. }
  144. } else if (aast.flags & IDENT_FLAG_UNKNOWN) {
  145. throw error {
  146. *ts.pstate, "unknown command: %s", a->name().data()
  147. };
  148. }
  149. /* excess arguments get ignored (make error maybe?) */
  150. callargs = std::min(callargs, MAX_ARGUMENTS);
  151. builtin_var *anargs = ts.istate->ivar_numargs;
  152. argset uargs{};
  153. std::size_t noff = ts.idstack.size();
  154. for(std::size_t i = 0; i < callargs; i++) {
  155. auto &ast = ts.get_astack(
  156. static_cast<alias *>(ts.istate->identmap[i])
  157. );
  158. auto &st = ts.idstack.emplace_back();
  159. ast.push(st);
  160. st.val_s = std::move(args[offset + i]);
  161. uargs[i] = true;
  162. }
  163. auto oldargs = anargs->value();
  164. auto oldflags = ts.ident_flags;
  165. ts.ident_flags = aast.flags;
  166. any_value cv;
  167. cv.set_integer(callargs);
  168. anargs->set_raw_value(*ts.pstate, std::move(cv));
  169. ident_link aliaslink = {a, ts.callstack, uargs};
  170. ts.callstack = &aliaslink;
  171. if (!aast.node->code) {
  172. gen_state gs{ts};
  173. gs.gen_main(aast.node->val_s.get_string(*ts.pstate));
  174. aast.node->code = gs.steal_ref();
  175. }
  176. bcode_ref coderef = aast.node->code;
  177. auto cleanup = [&]() {
  178. ts.callstack = aliaslink.next;
  179. ts.ident_flags = oldflags;
  180. auto amask = aliaslink.usedargs;
  181. for (std::size_t i = 0; i < callargs; i++) {
  182. ts.get_astack(
  183. static_cast<alias *>(ts.istate->identmap[i])
  184. ).pop();
  185. amask[i] = false;
  186. }
  187. for (; amask.any(); ++callargs) {
  188. if (amask[callargs]) {
  189. ts.get_astack(
  190. static_cast<alias *>(ts.istate->identmap[callargs])
  191. ).pop();
  192. amask[callargs] = false;
  193. }
  194. }
  195. ts.idstack.resize(noff);
  196. force_arg(*ts.pstate, result, op & BC_INST_RET_MASK);
  197. anargs->set_raw_value(*ts.pstate, std::move(oldargs));
  198. nargs = offset - skip;
  199. };
  200. try {
  201. vm_exec(ts, bcode_p{coderef}.get()->raw(), result);
  202. } catch (...) {
  203. cleanup();
  204. throw;
  205. }
  206. cleanup();
  207. return true;
  208. }
  209. call_depth_guard::call_depth_guard(thread_state &ts): tsp(&ts) {
  210. if (ts.max_call_depth && (ts.call_depth >= ts.max_call_depth)) {
  211. throw error{*ts.pstate, "exceeded recursion limit"};
  212. }
  213. ++ts.call_depth;
  214. }
  215. call_depth_guard::~call_depth_guard() { --tsp->call_depth; }
  216. static inline alias *get_lookup_id(
  217. thread_state &ts, std::uint32_t op, alias_stack *&ast
  218. ) {
  219. ident *id = ts.istate->identmap[op >> 8];
  220. auto *a = static_cast<alias_impl *>(id);
  221. if (a->is_arg()) {
  222. if (!ident_is_used_arg(id, ts)) {
  223. return nullptr;
  224. }
  225. ast = &ts.get_astack(static_cast<alias *>(id));
  226. } else {
  227. ast = &ts.get_astack(static_cast<alias *>(id));
  228. if (ast->flags & IDENT_FLAG_UNKNOWN) {
  229. throw error{
  230. *ts.pstate, "unknown alias lookup: %s", id->name().data()
  231. };
  232. }
  233. }
  234. return static_cast<alias *>(id);
  235. }
  236. std::uint32_t *vm_exec(
  237. thread_state &ts, std::uint32_t *code, any_value &result
  238. ) {
  239. result.set_none();
  240. auto &cs = *ts.pstate;
  241. call_depth_guard level{ts}; /* incr and decr on scope exit */
  242. stack_guard guard{ts}; /* resize back to original */
  243. auto &args = ts.vmstack;
  244. auto &chook = cs.call_hook();
  245. if (chook) {
  246. chook(cs);
  247. }
  248. for (;;) {
  249. std::uint32_t op = *code++;
  250. switch (op & 0xFF) {
  251. case BC_INST_START:
  252. case BC_INST_OFFSET:
  253. continue;
  254. case BC_INST_NULL | BC_RET_NULL:
  255. result.set_none();
  256. continue;
  257. case BC_INST_NULL | BC_RET_STRING:
  258. result.set_string("", cs);
  259. continue;
  260. case BC_INST_NULL | BC_RET_INT:
  261. result.set_integer(0);
  262. continue;
  263. case BC_INST_NULL | BC_RET_FLOAT:
  264. result.set_float(0.0f);
  265. continue;
  266. case BC_INST_FALSE | BC_RET_STRING:
  267. result.set_string("0", cs);
  268. continue;
  269. case BC_INST_FALSE | BC_RET_NULL:
  270. case BC_INST_FALSE | BC_RET_INT:
  271. result.set_integer(0);
  272. continue;
  273. case BC_INST_FALSE | BC_RET_FLOAT:
  274. result.set_float(0.0f);
  275. continue;
  276. case BC_INST_TRUE | BC_RET_STRING:
  277. result.set_string("1", cs);
  278. continue;
  279. case BC_INST_TRUE | BC_RET_NULL:
  280. case BC_INST_TRUE | BC_RET_INT:
  281. result.set_integer(1);
  282. continue;
  283. case BC_INST_TRUE | BC_RET_FLOAT:
  284. result.set_float(1.0f);
  285. continue;
  286. case BC_INST_NOT | BC_RET_STRING:
  287. result.set_string(args.back().get_bool() ? "0" : "1", cs);
  288. args.pop_back();
  289. continue;
  290. case BC_INST_NOT | BC_RET_NULL:
  291. case BC_INST_NOT | BC_RET_INT:
  292. result.set_integer(!args.back().get_bool());
  293. args.pop_back();
  294. continue;
  295. case BC_INST_NOT | BC_RET_FLOAT:
  296. result.set_float(float_type(!args.back().get_bool()));
  297. args.pop_back();
  298. continue;
  299. case BC_INST_POP:
  300. args.pop_back();
  301. continue;
  302. case BC_INST_ENTER:
  303. code = vm_exec(ts, code, args.emplace_back());
  304. continue;
  305. case BC_INST_ENTER_RESULT:
  306. code = vm_exec(ts, code, result);
  307. continue;
  308. case BC_INST_EXIT | BC_RET_STRING:
  309. case BC_INST_EXIT | BC_RET_INT:
  310. case BC_INST_EXIT | BC_RET_FLOAT:
  311. force_arg(cs, result, op & BC_INST_RET_MASK);
  312. /* fallthrough */
  313. case BC_INST_EXIT | BC_RET_NULL:
  314. return code;
  315. case BC_INST_RESULT | BC_RET_NULL:
  316. result = std::move(args.back());
  317. args.pop_back();
  318. continue;
  319. case BC_INST_RESULT | BC_RET_STRING:
  320. case BC_INST_RESULT | BC_RET_INT:
  321. case BC_INST_RESULT | BC_RET_FLOAT:
  322. result = std::move(args.back());
  323. args.pop_back();
  324. force_arg(cs, result, op & BC_INST_RET_MASK);
  325. continue;
  326. case BC_INST_RESULT_ARG | BC_RET_STRING:
  327. case BC_INST_RESULT_ARG | BC_RET_INT:
  328. case BC_INST_RESULT_ARG | BC_RET_FLOAT:
  329. force_arg(cs, result, op & BC_INST_RET_MASK);
  330. /* fallthrough */
  331. case BC_INST_RESULT_ARG | BC_RET_NULL:
  332. args.emplace_back(std::move(result));
  333. continue;
  334. case BC_INST_FORCE | BC_RET_STRING:
  335. args.back().force_string(cs);
  336. continue;
  337. case BC_INST_FORCE | BC_RET_INT:
  338. args.back().force_integer();
  339. continue;
  340. case BC_INST_FORCE | BC_RET_FLOAT:
  341. args.back().force_float();
  342. continue;
  343. case BC_INST_DUP | BC_RET_NULL: {
  344. auto &v = args.back();
  345. args.emplace_back() = v.get_plain();
  346. continue;
  347. }
  348. case BC_INST_DUP | BC_RET_INT: {
  349. auto &v = args.back();
  350. args.emplace_back().set_integer(v.get_integer());
  351. continue;
  352. }
  353. case BC_INST_DUP | BC_RET_FLOAT: {
  354. auto &v = args.back();
  355. args.emplace_back().set_float(v.get_float());
  356. continue;
  357. }
  358. case BC_INST_DUP | BC_RET_STRING: {
  359. auto &v = args.back();
  360. auto &nv = args.emplace_back();
  361. nv = v;
  362. nv.force_string(cs);
  363. continue;
  364. }
  365. case BC_INST_VAL | BC_RET_STRING: {
  366. std::uint32_t len = op >> 8;
  367. args.emplace_back().set_string(std::string_view{
  368. reinterpret_cast<char const *>(code), len
  369. }, cs);
  370. code += len / sizeof(std::uint32_t) + 1;
  371. continue;
  372. }
  373. case BC_INST_VAL_INT | BC_RET_STRING: {
  374. char s[4] = {
  375. char((op >> 8) & 0xFF),
  376. char((op >> 16) & 0xFF),
  377. char((op >> 24) & 0xFF), '\0'
  378. };
  379. /* gotta cast or r.size() == potentially 3 */
  380. args.emplace_back().set_string(
  381. static_cast<char const *>(s), cs
  382. );
  383. continue;
  384. }
  385. case BC_INST_VAL | BC_RET_NULL:
  386. case BC_INST_VAL_INT | BC_RET_NULL:
  387. args.emplace_back().set_none();
  388. continue;
  389. case BC_INST_VAL | BC_RET_INT:
  390. args.emplace_back().set_integer(
  391. *reinterpret_cast<integer_type const *>(code)
  392. );
  393. code += bc_store_size<integer_type>;
  394. continue;
  395. case BC_INST_VAL_INT | BC_RET_INT:
  396. args.emplace_back().set_integer(integer_type(op) >> 8);
  397. continue;
  398. case BC_INST_VAL | BC_RET_FLOAT:
  399. args.emplace_back().set_float(
  400. *reinterpret_cast<float_type const *>(code)
  401. );
  402. code += bc_store_size<float_type>;
  403. continue;
  404. case BC_INST_VAL_INT | BC_RET_FLOAT:
  405. args.emplace_back().set_float(
  406. float_type(integer_type(op) >> 8)
  407. );
  408. continue;
  409. case BC_INST_LOCAL: {
  410. std::size_t numlocals = op >> 8;
  411. std::size_t offset = args.size() - numlocals;
  412. std::size_t idstsz = ts.idstack.size();
  413. for (std::size_t i = 0; i < numlocals; ++i) {
  414. push_alias(
  415. ts, args[offset + i].get_ident(cs),
  416. ts.idstack.emplace_back()
  417. );
  418. }
  419. auto cleanup = [&]() {
  420. for (std::size_t i = offset; i < args.size(); ++i) {
  421. pop_alias(ts, args[i].get_ident(cs));
  422. }
  423. ts.idstack.resize(idstsz);
  424. };
  425. try {
  426. code = vm_exec(ts, code, result);
  427. } catch (...) {
  428. cleanup();
  429. throw;
  430. }
  431. cleanup();
  432. return code;
  433. }
  434. case BC_INST_DO_ARGS | BC_RET_NULL:
  435. case BC_INST_DO_ARGS | BC_RET_STRING:
  436. case BC_INST_DO_ARGS | BC_RET_INT:
  437. case BC_INST_DO_ARGS | BC_RET_FLOAT:
  438. call_with_args(ts, [&]() {
  439. auto v = std::move(args.back());
  440. args.pop_back();
  441. result = v.get_code().call(cs);
  442. force_arg(cs, result, op & BC_INST_RET_MASK);
  443. });
  444. continue;
  445. /* fallthrough */
  446. case BC_INST_DO | BC_RET_NULL:
  447. case BC_INST_DO | BC_RET_STRING:
  448. case BC_INST_DO | BC_RET_INT:
  449. case BC_INST_DO | BC_RET_FLOAT: {
  450. auto v = std::move(args.back());
  451. args.pop_back();
  452. result = v.get_code().call(cs);
  453. force_arg(cs, result, op & BC_INST_RET_MASK);
  454. continue;
  455. }
  456. case BC_INST_JUMP: {
  457. std::uint32_t len = op >> 8;
  458. code += len;
  459. continue;
  460. }
  461. case BC_INST_JUMP_B | BC_INST_FLAG_TRUE: {
  462. std::uint32_t len = op >> 8;
  463. if (args.back().get_bool()) {
  464. code += len;
  465. }
  466. args.pop_back();
  467. continue;
  468. }
  469. case BC_INST_JUMP_B | BC_INST_FLAG_FALSE: {
  470. std::uint32_t len = op >> 8;
  471. if (!args.back().get_bool()) {
  472. code += len;
  473. }
  474. args.pop_back();
  475. continue;
  476. }
  477. case BC_INST_JUMP_RESULT | BC_INST_FLAG_TRUE: {
  478. std::uint32_t len = op >> 8;
  479. auto v = std::move(args.back());
  480. args.pop_back();
  481. if (v.type() == value_type::CODE) {
  482. result = v.get_code().call(cs);
  483. } else {
  484. result = std::move(v);
  485. }
  486. if (result.get_bool()) {
  487. code += len;
  488. }
  489. continue;
  490. }
  491. case BC_INST_JUMP_RESULT | BC_INST_FLAG_FALSE: {
  492. std::uint32_t len = op >> 8;
  493. auto v = std::move(args.back());
  494. args.pop_back();
  495. if (v.type() == value_type::CODE) {
  496. result = v.get_code().call(cs);
  497. } else {
  498. result = std::move(v);
  499. }
  500. if (!result.get_bool()) {
  501. code += len;
  502. }
  503. continue;
  504. }
  505. case BC_INST_BREAK | BC_INST_FLAG_FALSE:
  506. if (ts.loop_level) {
  507. throw break_exception();
  508. } else {
  509. throw error{cs, "no loop to break"};
  510. }
  511. break;
  512. case BC_INST_BREAK | BC_INST_FLAG_TRUE:
  513. if (ts.loop_level) {
  514. throw continue_exception();
  515. } else {
  516. throw error{cs, "no loop to continue"};
  517. }
  518. break;
  519. case BC_INST_BLOCK: {
  520. std::uint32_t len = op >> 8;
  521. args.emplace_back().set_code(bcode_p::make_ref(
  522. reinterpret_cast<bcode *>(code + 1)
  523. ));
  524. code += len;
  525. continue;
  526. }
  527. case BC_INST_EMPTY | BC_RET_NULL:
  528. args.emplace_back().set_code(bcode_p::make_ref(
  529. bcode_get_empty(ts.istate->empty, VAL_NULL)
  530. ));
  531. break;
  532. case BC_INST_EMPTY | BC_RET_STRING:
  533. args.emplace_back().set_code(bcode_p::make_ref(
  534. bcode_get_empty(ts.istate->empty, VAL_STRING)
  535. ));
  536. break;
  537. case BC_INST_EMPTY | BC_RET_INT:
  538. args.emplace_back().set_code(bcode_p::make_ref(
  539. bcode_get_empty(ts.istate->empty, VAL_INT)
  540. ));
  541. break;
  542. case BC_INST_EMPTY | BC_RET_FLOAT:
  543. args.emplace_back().set_code(bcode_p::make_ref(
  544. bcode_get_empty(ts.istate->empty, VAL_FLOAT)
  545. ));
  546. break;
  547. case BC_INST_COMPILE: {
  548. any_value &arg = args.back();
  549. gen_state gs{ts};
  550. switch (arg.type()) {
  551. case value_type::INTEGER:
  552. gs.gen_main_integer(arg.get_integer());
  553. break;
  554. case value_type::FLOAT:
  555. gs.gen_main_float(arg.get_float());
  556. break;
  557. case value_type::STRING:
  558. gs.gen_main(arg.get_string(cs));
  559. break;
  560. default:
  561. gs.gen_main_null();
  562. break;
  563. }
  564. arg.set_code(gs.steal_ref());
  565. continue;
  566. }
  567. case BC_INST_COND: {
  568. any_value &arg = args.back();
  569. switch (arg.type()) {
  570. case value_type::STRING: {
  571. std::string_view s = arg.get_string(cs);
  572. if (!s.empty()) {
  573. gen_state gs{ts};
  574. gs.gen_main(s);
  575. arg.set_code(gs.steal_ref());
  576. } else {
  577. arg.force_none();
  578. }
  579. break;
  580. }
  581. default:
  582. break;
  583. }
  584. continue;
  585. }
  586. case BC_INST_IDENT: {
  587. alias *a = static_cast<alias *>(
  588. ts.istate->identmap[op >> 8]
  589. );
  590. if (a->is_arg() && !ident_is_used_arg(a, ts)) {
  591. ts.get_astack(a).push(ts.idstack.emplace_back());
  592. ts.callstack->usedargs[a->index()] = true;
  593. }
  594. args.emplace_back().set_ident(*a);
  595. continue;
  596. }
  597. case BC_INST_IDENT_U: {
  598. any_value &arg = args.back();
  599. ident *id = ts.istate->id_dummy;
  600. if (arg.type() == value_type::STRING) {
  601. id = &ts.istate->new_ident(
  602. cs, arg.get_string(cs), IDENT_FLAG_UNKNOWN
  603. );
  604. }
  605. alias *a = static_cast<alias *>(id);
  606. if (a->is_arg() && !ident_is_used_arg(id, ts)) {
  607. ts.get_astack(a).push(ts.idstack.emplace_back());
  608. ts.callstack->usedargs[id->index()] = true;
  609. }
  610. arg.set_ident(*id);
  611. continue;
  612. }
  613. case BC_INST_LOOKUP_U | BC_RET_STRING:
  614. case BC_INST_LOOKUP_U | BC_RET_INT:
  615. case BC_INST_LOOKUP_U | BC_RET_FLOAT:
  616. case BC_INST_LOOKUP_U | BC_RET_NULL:
  617. args.back() = cs.lookup_value(args.back().get_string(cs));
  618. force_arg(cs, args.back(), op & BC_INST_RET_MASK);
  619. continue;
  620. case BC_INST_LOOKUP | BC_RET_STRING: {
  621. alias_stack *ast;
  622. alias *a = get_lookup_id(ts, op, ast);
  623. if (!a) {
  624. args.emplace_back().set_string("", cs);
  625. } else {
  626. auto &v = args.emplace_back();
  627. v = ast->node->val_s;
  628. v.force_string(cs);
  629. }
  630. continue;
  631. }
  632. case BC_INST_LOOKUP | BC_RET_INT: {
  633. alias_stack *ast;
  634. alias *a = get_lookup_id(ts, op, ast);
  635. if (!a) {
  636. args.emplace_back().set_integer(0);
  637. } else {
  638. args.emplace_back().set_integer(
  639. ast->node->val_s.get_integer()
  640. );
  641. }
  642. continue;
  643. }
  644. case BC_INST_LOOKUP | BC_RET_FLOAT: {
  645. alias_stack *ast;
  646. alias *a = get_lookup_id(ts, op, ast);
  647. if (!a) {
  648. args.emplace_back().set_float(float_type(0));
  649. } else {
  650. args.emplace_back().set_float(
  651. ast->node->val_s.get_float()
  652. );
  653. }
  654. continue;
  655. }
  656. case BC_INST_LOOKUP | BC_RET_NULL: {
  657. alias_stack *ast;
  658. alias *a = get_lookup_id(ts, op, ast);
  659. if (!a) {
  660. args.emplace_back().set_none();
  661. } else {
  662. args.emplace_back() = ast->node->val_s.get_plain();
  663. }
  664. continue;
  665. }
  666. case BC_INST_CONC | BC_RET_NULL:
  667. case BC_INST_CONC | BC_RET_STRING:
  668. case BC_INST_CONC | BC_RET_FLOAT:
  669. case BC_INST_CONC | BC_RET_INT:
  670. case BC_INST_CONC_W | BC_RET_NULL:
  671. case BC_INST_CONC_W | BC_RET_STRING:
  672. case BC_INST_CONC_W | BC_RET_FLOAT:
  673. case BC_INST_CONC_W | BC_RET_INT: {
  674. std::size_t numconc = op >> 8;
  675. auto buf = concat_values(
  676. cs, span_type<any_value>{
  677. &args[args.size() - numconc], numconc
  678. }, ((op & BC_INST_OP_MASK) == BC_INST_CONC) ? " " : ""
  679. );
  680. args.resize(args.size() - numconc);
  681. args.emplace_back().set_string(buf);
  682. force_arg(cs, args.back(), op & BC_INST_RET_MASK);
  683. continue;
  684. }
  685. case BC_INST_VAR | BC_RET_NULL:
  686. case BC_INST_VAR | BC_RET_INT:
  687. case BC_INST_VAR | BC_RET_FLOAT:
  688. case BC_INST_VAR | BC_RET_STRING:
  689. args.emplace_back() = static_cast<builtin_var *>(
  690. ts.istate->identmap[op >> 8]
  691. )->value();
  692. force_arg(cs, args.back(), op & BC_INST_RET_MASK);
  693. continue;
  694. case BC_INST_ALIAS: {
  695. auto *a = static_cast<alias *>(
  696. ts.istate->identmap[op >> 8]
  697. );
  698. auto &ast = ts.get_astack(a);
  699. if (a->is_arg()) {
  700. ast.set_arg(a, ts, args.back());
  701. } else {
  702. ast.set_alias(a, ts, args.back());
  703. }
  704. args.pop_back();
  705. continue;
  706. }
  707. case BC_INST_ALIAS_U: {
  708. auto v = std::move(args.back());
  709. args.pop_back();
  710. cs.assign_value(args.back().get_string(cs), std::move(v));
  711. args.pop_back();
  712. continue;
  713. }
  714. case BC_INST_CALL | BC_RET_NULL:
  715. case BC_INST_CALL | BC_RET_STRING:
  716. case BC_INST_CALL | BC_RET_FLOAT:
  717. case BC_INST_CALL | BC_RET_INT: {
  718. result.force_none();
  719. ident *id = ts.istate->identmap[op >> 8];
  720. std::size_t callargs = *code++;
  721. std::size_t nnargs = args.size();
  722. std::size_t offset = nnargs - callargs;
  723. auto *imp = static_cast<alias_impl *>(id);
  724. if (imp->is_arg()) {
  725. if (!ident_is_used_arg(id, ts)) {
  726. args.resize(offset);
  727. force_arg(cs, result, op & BC_INST_RET_MASK);
  728. continue;
  729. }
  730. }
  731. exec_alias(
  732. ts, imp, &args[0], result, callargs,
  733. nnargs, offset, 0, op
  734. );
  735. args.resize(nnargs);
  736. continue;
  737. }
  738. case BC_INST_CALL_U | BC_RET_NULL:
  739. case BC_INST_CALL_U | BC_RET_STRING:
  740. case BC_INST_CALL_U | BC_RET_FLOAT:
  741. case BC_INST_CALL_U | BC_RET_INT: {
  742. std::size_t callargs = op >> 8;
  743. std::size_t nnargs = args.size();
  744. std::size_t offset = nnargs - callargs;
  745. any_value &idarg = args[offset - 1];
  746. if (idarg.type() != value_type::STRING) {
  747. litval:
  748. result = std::move(idarg);
  749. force_arg(cs, result, op & BC_INST_RET_MASK);
  750. args.resize(offset - 1);
  751. continue;
  752. }
  753. auto idn = idarg.get_string(cs);
  754. auto id = cs.get_ident(idn);
  755. if (!id) {
  756. noid:
  757. if (!is_valid_name(idn)) {
  758. goto litval;
  759. }
  760. result.force_none();
  761. force_arg(cs, result, op & BC_INST_RET_MASK);
  762. std::string_view ids{idn};
  763. throw error{
  764. cs, "unknown command: %s", ids.data()
  765. };
  766. }
  767. result.force_none();
  768. switch (ident_p{id->get()}.impl().p_type) {
  769. default:
  770. if (!ident_is_callable(&id->get())) {
  771. args.resize(offset - 1);
  772. force_arg(cs, result, op & BC_INST_RET_MASK);
  773. continue;
  774. }
  775. /* fallthrough */
  776. case ID_COMMAND: {
  777. auto *cimp = static_cast<command_impl *>(&id->get());
  778. args.resize(offset + std::max(
  779. std::size_t(cimp->arg_count()), callargs
  780. ));
  781. exec_command(
  782. ts, cimp, cimp, &args[offset], result, callargs
  783. );
  784. force_arg(cs, result, op & BC_INST_RET_MASK);
  785. args.resize(offset - 1);
  786. continue;
  787. }
  788. case ID_LOCAL: {
  789. std::size_t idstsz = ts.idstack.size();
  790. for (size_t j = 0; j < size_t(callargs); ++j) {
  791. push_alias(
  792. ts, args[offset + j].force_ident(cs),
  793. ts.idstack.emplace_back()
  794. );
  795. }
  796. auto cleanup = [&]() {
  797. for (size_t j = 0; j < size_t(callargs); ++j) {
  798. pop_alias(ts, args[offset + j].get_ident(cs));
  799. }
  800. ts.idstack.resize(idstsz);
  801. };
  802. try {
  803. code = vm_exec(ts, code, result);
  804. } catch (...) {
  805. cleanup();
  806. throw;
  807. }
  808. cleanup();
  809. return code;
  810. }
  811. case ID_VAR: {
  812. auto *hid = static_cast<var_impl &>(
  813. id->get()
  814. ).get_setter(ts);
  815. auto *cimp = static_cast<command_impl *>(hid);
  816. /* the $ argument */
  817. args.insert(offset, any_value{});
  818. args.resize(offset + std::max(
  819. std::size_t(cimp->arg_count()), callargs
  820. ));
  821. exec_command(
  822. ts, cimp, &id->get(), &args[offset],
  823. result, callargs
  824. );
  825. force_arg(cs, result, op & BC_INST_RET_MASK);
  826. args.resize(offset - 1);
  827. continue;
  828. }
  829. case ID_ALIAS: {
  830. alias *a = static_cast<alias *>(&id->get());
  831. if (a->is_arg() && !ident_is_used_arg(a, ts)) {
  832. args.resize(offset - 1);
  833. force_arg(cs, result, op & BC_INST_RET_MASK);
  834. continue;
  835. }
  836. if (!exec_alias(
  837. ts, a, &args[0], result, callargs, nnargs,
  838. offset, 1, op, true
  839. )) {
  840. goto noid;
  841. }
  842. args.resize(nnargs);
  843. continue;
  844. }
  845. }
  846. }
  847. case BC_INST_COM | BC_RET_NULL:
  848. case BC_INST_COM | BC_RET_STRING:
  849. case BC_INST_COM | BC_RET_FLOAT:
  850. case BC_INST_COM | BC_RET_INT: {
  851. command_impl *id = static_cast<command_impl *>(
  852. ts.istate->identmap[op >> 8]
  853. );
  854. std::size_t offset = args.size() - id->arg_count();
  855. result.force_none();
  856. id->call(ts, span_type<any_value>{
  857. &args[offset], std::size_t(id->arg_count())
  858. }, result);
  859. force_arg(cs, result, op & BC_INST_RET_MASK);
  860. args.resize(offset);
  861. continue;
  862. }
  863. case BC_INST_COM_V | BC_RET_NULL:
  864. case BC_INST_COM_V | BC_RET_STRING:
  865. case BC_INST_COM_V | BC_RET_FLOAT:
  866. case BC_INST_COM_V | BC_RET_INT: {
  867. command_impl *id = static_cast<command_impl *>(
  868. ts.istate->identmap[op >> 8]
  869. );
  870. std::size_t callargs = *code++;
  871. std::size_t offset = args.size() - callargs;
  872. result.force_none();
  873. id->call(
  874. ts, span_type<any_value>{&args[offset], callargs}, result
  875. );
  876. force_arg(cs, result, op & BC_INST_RET_MASK);
  877. args.resize(offset);
  878. continue;
  879. }
  880. }
  881. }
  882. return code;
  883. }
  884. } /* namespace cubescript */