// SPDX-License-Identifier: MIT // Copyright (c) 2023 John Watts and the LuminaSensum contributors #include "bytecode.h" #include "error.h" #include "number.h" #include <stddef.h> enum opcodes { OP_NUM = 0x01, OP_RET = 0x03, OP_CALL = 0x04, OP_NULL = 0x05, }; // clang-format off static const unsigned char bytecode[] = { OP_NUM, 0xaa, 0xaa, 0xaa, 0xaa, OP_NUM, 0xbb, 0xbb, 0xbb, 0xbb, OP_NUM, 0xcc, 0xcc, 0xcc, 0xcc, OP_NULL, OP_NUM, 0x69, 0x02, 0x00, 0x00, OP_NUM, 0x69, 0x02, 0x00, 0x00, OP_CALL, 'A', 'd', 'd', '\0', OP_RET }; // clang-format on void bytecode_run(struct object **stack) { abort_if(!stack, "bytecode_run has no stack"); const unsigned char *pos_code = &bytecode[0]; struct object **pos_stack = stack; unsigned char op = OP_RET; while ((op = *pos_code++) != OP_RET) { // Skip over NOP, ASCII and unknown OPs switch (op) { case OP_NUM: { int num = 0; num |= *pos_code++ << 0; num |= *pos_code++ << 8; num |= *pos_code++ << 16; num |= *pos_code++ << 24; *pos_stack++ = number_create(num); break; } case OP_CALL: { const char *dispatch = (const char *)pos_code; struct object *obj = *(--pos_stack); struct object **args = pos_stack - 2; dispatch_call(obj, dispatch, 1, args); // Free arguments and object we've called object_drop(args + 1); object_drop(&obj); --pos_stack; break; } case OP_NULL: { *pos_stack++ = NULL; break; } } } // Clean up the stack and return 1 value struct object **pos_stack_start = stack; while (pos_stack_start != pos_stack - 1) { object_drop(pos_stack_start++); } *stack = *(pos_stack - 1); }