Compare commits

...

7 Commits

5 changed files with 78 additions and 46 deletions

View File

@ -2,6 +2,7 @@ module;
#include <cstdint>
#include <cstddef>
#include <type_traits>
export module coral;
@ -282,7 +283,7 @@ export namespace coral {
optional(optional const & that) : buffer{0} {
if (that.has_value()) {
(*reinterpret_cast<element *>(this->buffer)) = that.value();
(*reinterpret_cast<element *>(this->buffer)) = *that;
this->buffer[sizeof(element)] = 1;
} else {
this->buffer[sizeof(element)] = 0;
@ -296,6 +297,17 @@ export namespace coral {
return this->buffer[sizeof(element)] == 1;
}
/**
* Attempts to call `apply` on the contained value, returning a new [optional] of whatever type `apply` returns.
*
* If the optional is empty, an empty optional will always be returned.
*/
template<typename functor> std::invoke_result_t<functor, element> map(functor const & apply) const {
if (this->has_value()) return apply(**this);
return {};
}
/**
* Returns the contained value or `fallback` if the optional is empty.
*/
@ -303,25 +315,15 @@ export namespace coral {
return this->has_value() ? *reinterpret_cast<element const *>(this->buffer) : fallback;
}
/**
* Returns a reference to the contained value.
*
* *Note*: attempting to access the value of an empty optional will trigger safety-checked
* behavior.
*/
element & value() {
element & operator *() {
if (!this->has_value()) unreachable();
return *reinterpret_cast<element *>(this->buffer);
}
/**
* Returns the contained value.
*
* *Note*: attempting to access the value of an empty optional will trigger safety-checked
* behavior.
*/
element const & value() const {
element const & operator *() const {
if (!this->has_value()) unreachable();
return *reinterpret_cast<element const *>(this->buffer);
}
@ -461,6 +463,13 @@ export namespace coral {
// Input/output operations.
export namespace coral {
/**
* Returns `value` reinterpreted as a sequence of bytes.
*/
slice<u8 const> as_bytes(auto const * value) {
return {reinterpret_cast<u8 const *>(value), sizeof(value)};
}
/**
* Compares `a` and `b`, returning the difference between them or `0` if they are identical.
*/
@ -586,7 +595,7 @@ export namespace coral {
for (usize i = 0; i < half_buffer_count; i += 1)
swap(buffer[i], buffer[buffer_count - i - 1]);
return output.write(slice{buffer, buffer_count});
return output.write({buffer, buffer_count});
}
/**

View File

@ -15,35 +15,50 @@ export namespace kym {
};
struct value {
value_type type;
value_type type{value_type::nil};
union {
bool boolean;
value() = default;
coral::i64 integer;
value(bool boolean) {
this->data[1] = 0xff * boolean;
this->type = value_type::boolean;
}
coral::f64 scalar;
value(coral::i64 integer) {
(*reinterpret_cast<coral::u64 *>(this->data)) =
(*reinterpret_cast<coral::u64 *>(&integer));
coral::vector2 vector2;
this->type = value_type::integer;
}
coral::vector3 vector3;
value(coral::f64 scalar) {
(*reinterpret_cast<coral::u64 *>(this->data)) =
(*reinterpret_cast<coral::u64 *>(&scalar));
void * object;
} as;
this->type = value_type::scalar;
}
coral::optional<coral::u16> as_u16() const {
if ((this->type == value_type::integer) &&
(this->as.integer >= 0) && (this->as.integer <= coral::u16_max)) {
value(coral::vector2 vector2) {
(*reinterpret_cast<coral::u64 *>(this->data)) =
(*reinterpret_cast<coral::u64 *>(&vector2));
return static_cast<coral::u16>(this->as.integer);
}
this->type = value_type::vector2;
}
value(coral::vector3 const & vector3) {
coral::copy(this->data, coral::as_bytes(&vector3));
this->type = value_type::vector3;
}
coral::optional<coral::i64> as_integer() const {
if (this->type == value_type::integer)
return (*reinterpret_cast<coral::i64 const *>(&this->data));
return {};
}
};
value nil = {
.type = value_type::nil,
.as = {.object = nullptr},
private:
coral::u8 data[12]{0};
};
};

View File

@ -57,7 +57,7 @@ struct bytecode {
}
kym::value execute(kym::vm & vm, coral::slice<kym::value const> const & arguments) {
return kym::nil;
return {};
}
private:
@ -66,7 +66,7 @@ struct bytecode {
export namespace kym {
value default_call(vm & owning_vm, void * userdata, coral::slice<value const> const & arguments) {
return nil;
return {};
}
coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writer & output) {
@ -103,7 +103,7 @@ export namespace kym {
}
value get_field(coral::slice<char const> const & field_name) {
return nil;
return {};
}
private:
@ -139,14 +139,14 @@ export namespace kym {
value compile(coral::slice<char const> const & source) {
bytecode * source_bytecode = new (*this->allocator) bytecode{allocator};
if (source_bytecode == nullptr) return nil;
if (source_bytecode == nullptr) return {};
if (!source_bytecode->compile(tokenizer{source}, [&](coral::slice<char const> error_message) {
this->log(error_message);
})) {
this->allocator->deallocate(source_bytecode);
return nil;
return {};
}
return this->new_object([this, source_bytecode](bound_object & object) {
@ -165,7 +165,7 @@ export namespace kym {
}
value new_object(coral::callable<void(bound_object &)> const & then) {
return nil;
return {};
}
void with_object(value object_value, coral::callable<void(bound_object &)> const & then) {

View File

@ -82,9 +82,8 @@ export namespace oar {
header const * const archive_header{reinterpret_cast<header const *>(archive_header_buffer)};
if (!coral::equals(coral::slice{archive_header->signature_magic,
signature_identifier_length}, coral::slice{signature_magic,
signature_identifier_length})) return open_result::archive_invalid;
if (!coral::equals({archive_header->signature_magic, signature_identifier_length},
{signature_magic, signature_identifier_length})) return open_result::archive_invalid;
if (archive_header->signature_magic[signature_identifier_length] !=
signature_magic[signature_identifier_length]) return open_result::archive_unsupported;

View File

@ -38,13 +38,22 @@ extern "C" int main(int argc, char const * const * argv) {
}
vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) {
vm.with_object(script.call({}), [&](kym::bound_object & config) {
coral::u16 const width{config.get_field("width").as_u16().value_or(0)};
vm.with_object(script.call({}), [&](kym::bound_object config) {
constexpr auto as_u16 = [](coral::i64 value) -> coral::optional<coral::i16> {
if ((value >= 0) && (value <= coral::u16_max))
return static_cast<coral::u16>(value);
return {};
};
coral::u16 const width{config.get_field("width").
as_integer().map(as_u16).value_or(0)};
if (width == 0) return system.log(app::log_level::error,
"failed to decode `width` property of config");
coral::u16 const height{config.get_field("height").as_u16().value_or(0)};
coral::u16 const height{config.get_field("height").
as_integer().map(as_u16).value_or(0)};
if (height == 0) return system.log(app::log_level::error,
"failed to decode `height` property of config");