export module kym.environment; import core; import core.sequence; import kym; using loggable = core::callable const &)>; export namespace kym { struct vm; } enum class token_kind { end, }; struct token { core::slice text; token_kind kind; }; struct tokenizer { core::slice source; tokenizer(core::slice const & source) : source{source} {} token next() { core::usize cursor = 0; while (cursor < source.length) { } return token{ .kind = token_kind::end, }; } }; struct bytecode { bytecode(core::allocator * allocator) : error_message_buffer{allocator} { } bool compile(tokenizer bytecode_tokenizer, loggable const & log_error) { for (;;) { token const initial_token = bytecode_tokenizer.next(); switch (initial_token.kind) { case token_kind::end: return true; default: core::unreachable(); } } } kym::value execute(kym::vm & vm, core::slice const & arguments) { return kym::nil; } private: core::stack error_message_buffer; }; export namespace kym { value default_call(vm & owning_vm, void * userdata, core::slice const & arguments) { return nil; } core::expected default_stringify(vm & owning_vm, void * userdata, core::writable const & output) { return output(core::slice("[object]").as_bytes()); } struct bound_object { void * userdata; struct { void(*cleanup)(vm &, void *); value(*call)(vm &, void *, core::slice const &); core::expected(*stringify)(vm &, void *, core::writable const &); } behavior; bound_object(vm * owning_vm) : userdata{nullptr}, owning_vm{owning_vm}, behavior{ .cleanup = [](vm & owning_vm, void * userdata) {}, .call = default_call, .stringify = default_stringify, } {} void cleanup() { this->behavior.cleanup(*this->owning_vm, this->userdata); } value call(core::slice const & arguments) { return this->behavior.call(*this->owning_vm, this->userdata, arguments); } core::expected stringify(core::writable const & output) { return this->behavior.stringify(*this->owning_vm, this->userdata, output); } value get_field(core::slice const & field_name) { return nil; } private: vm * owning_vm; }; struct vm { struct init_options { core::u16 datastack_size; core::u16 callstack_size; }; vm(core::allocator * allocator, auto log) : allocator{allocator}, log{log}, data_stack{} {} ~vm() { if (this->data_stack.pointer != nullptr) this->allocator->deallocate(this->data_stack.pointer); } bool init(init_options const & options) { core::u8 * const data_stack_buffer = this->allocator->reallocate(reinterpret_cast (this->data_stack.pointer), options.datastack_size * sizeof(value)); if (data_stack_buffer == nullptr) return false; this->data_stack = { reinterpret_cast(data_stack_buffer), options.datastack_size}; return true; } value compile(core::slice const & source) { bytecode * source_bytecode = new (*this->allocator) bytecode{allocator}; if (source_bytecode == nullptr) return nil; if (!source_bytecode->compile(tokenizer{source}, [&](core::slice error_message) { this->log(error_message); })) { this->allocator->deallocate(source_bytecode); return nil; } return this->new_object([this, source_bytecode](bound_object & object) { object.userdata = source_bytecode; object.behavior.cleanup = [](vm & owning_vm, void * userdata) { owning_vm.allocator->deallocate(userdata); }; object.behavior.call = [](vm & owning_vm, void * userdata, core::slice const & arguments) -> value { return reinterpret_cast(userdata)->execute(owning_vm, arguments); }; this->allocator->deallocate(source_bytecode); }); } value new_object(core::callable const & then) { return nil; } void with_object(value object_value, core::callable const & then) { } private: core::slice data_stack; loggable log; core::allocator * allocator; }; }