mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[Compiler] Support array fields in static objects (#284)
* first part of static inline array fields * level h
This commit is contained in:
parent
791c4abfc0
commit
cadd014add
|
@ -207,8 +207,6 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
(define-extern *level* level-group)
|
(define-extern *level* level-group)
|
||||||
;; OpenGOAL doesn not yet support setting fields to arrays in statics.
|
|
||||||
#|
|
|
||||||
(if (zero? *level*)
|
(if (zero? *level*)
|
||||||
(set! *level*
|
(set! *level*
|
||||||
(new 'static 'level-group
|
(new 'static 'level-group
|
||||||
|
@ -225,28 +223,28 @@
|
||||||
:name #f
|
:name #f
|
||||||
:status 'inactive
|
:status 'inactive
|
||||||
:foreground-sink-group
|
:foreground-sink-group
|
||||||
(new 'static 'inline-array 'dma-foreground-sink-group 3
|
(new 'static 'inline-array dma-foreground-sink-group 3
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink :bucket 10)
|
(new 'static 'dma-foreground-sink :bucket 10)
|
||||||
(new 'static 'generic-dma-foreground-sink
|
(new 'static 'generic-dma-foreground-sink
|
||||||
:bucket 11 :foreground-output-bucket 1
|
:bucket 11 :foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0)
|
)
|
||||||
)
|
)
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 49
|
:bucket 49
|
||||||
:foreground-texture-page 1
|
:foreground-texture-page 1
|
||||||
)
|
)
|
||||||
(new 'static 'generic-dma-foreground-sink :
|
(new 'static 'generic-dma-foreground-sink
|
||||||
bucket 50 :foreground-texture-page 1
|
:bucket 50 :foreground-texture-page 1
|
||||||
:foreground-output-bucket 1)
|
:foreground-output-bucket 1)
|
||||||
0)
|
)
|
||||||
)
|
)
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 58
|
:bucket 58
|
||||||
:foreground-texture-page 2
|
:foreground-texture-page 2
|
||||||
|
@ -256,7 +254,7 @@
|
||||||
:foreground-texture-page 2
|
:foreground-texture-page 2
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
:inside-sphere? #f
|
:inside-sphere? #f
|
||||||
|
@ -269,9 +267,9 @@
|
||||||
:index 1
|
:index 1
|
||||||
:status 'inactive
|
:status 'inactive
|
||||||
:foreground-sink-group
|
:foreground-sink-group
|
||||||
(new 'static 'inline-array 'dma-foreground-sink-group 3
|
(new 'static 'inline-array dma-foreground-sink-group 3
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 17
|
:bucket 17
|
||||||
:foreground-texture-level 1
|
:foreground-texture-level 1
|
||||||
|
@ -281,10 +279,10 @@
|
||||||
:foreground-texture-level 1
|
:foreground-texture-level 1
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0)
|
)
|
||||||
)
|
)
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 52
|
:bucket 52
|
||||||
:foreground-texture-page 1
|
:foreground-texture-page 1
|
||||||
|
@ -296,11 +294,11 @@
|
||||||
:foreground-texture-level 1
|
:foreground-texture-level 1
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 61
|
:bucket 61
|
||||||
:foreground-texture-page 2
|
:foreground-texture-page 2
|
||||||
|
@ -312,7 +310,7 @@
|
||||||
:foreground-texture-level 1
|
:foreground-texture-level 1
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
:inside-sphere? #f
|
:inside-sphere? #f
|
||||||
|
@ -325,9 +323,9 @@
|
||||||
:index 2
|
:index 2
|
||||||
:status 'reserved
|
:status 'reserved
|
||||||
:foreground-sink-group
|
:foreground-sink-group
|
||||||
(new 'static 'inline-array 'dma-foreground-sink-group 3
|
(new 'static 'inline-array dma-foreground-sink-group 3
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 45
|
:bucket 45
|
||||||
:foreground-texture-level 2
|
:foreground-texture-level 2
|
||||||
|
@ -337,25 +335,25 @@
|
||||||
:foreground-texture-level 2
|
:foreground-texture-level 2
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0)
|
)
|
||||||
)
|
|
||||||
(new 'static 'dma-foreground-sink-group :
|
|
||||||
sink (new 'static 'array 'dma-foreground-sink 3
|
|
||||||
(new 'static 'dma-foreground-sink
|
|
||||||
:bucket 55
|
|
||||||
:foreground-texture-page 1
|
|
||||||
:foreground-texture-level 2
|
|
||||||
)
|
|
||||||
(new 'static 'generic-dma-foreground-sink
|
|
||||||
:bucket 56
|
|
||||||
:foreground-texture-page 1
|
|
||||||
:foreground-texture-level 2
|
|
||||||
:foreground-output-bucket 1
|
|
||||||
)
|
|
||||||
0)
|
|
||||||
)
|
)
|
||||||
(new 'static 'dma-foreground-sink-group
|
(new 'static 'dma-foreground-sink-group
|
||||||
:sink (new 'static 'array 'dma-foreground-sink 3
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
|
(new 'static 'dma-foreground-sink
|
||||||
|
:bucket 55
|
||||||
|
:foreground-texture-page 1
|
||||||
|
:foreground-texture-level 2
|
||||||
|
)
|
||||||
|
(new 'static 'generic-dma-foreground-sink
|
||||||
|
:bucket 56
|
||||||
|
:foreground-texture-page 1
|
||||||
|
:foreground-texture-level 2
|
||||||
|
:foreground-output-bucket 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new 'static 'dma-foreground-sink-group
|
||||||
|
:sink (new 'static 'array dma-foreground-sink 3
|
||||||
(new 'static 'dma-foreground-sink
|
(new 'static 'dma-foreground-sink
|
||||||
:bucket 58
|
:bucket 58
|
||||||
:foreground-texture-page 2
|
:foreground-texture-page 2
|
||||||
|
@ -367,7 +365,7 @@
|
||||||
:foreground-texture-level 2
|
:foreground-texture-level 2
|
||||||
:foreground-output-bucket 1
|
:foreground-output-bucket 1
|
||||||
)
|
)
|
||||||
0
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -378,5 +376,4 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|#
|
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,23 @@ class Compiler {
|
||||||
bool boxed,
|
bool boxed,
|
||||||
Env* env);
|
Env* env);
|
||||||
|
|
||||||
|
StaticResult fill_static_inline_array(const goos::Object& form,
|
||||||
|
const goos::Object& rest,
|
||||||
|
Env* env);
|
||||||
|
|
||||||
|
void fill_static_inline_array_inline(const goos::Object& form,
|
||||||
|
const TypeSpec& content_type,
|
||||||
|
const std::vector<goos::Object>& args,
|
||||||
|
StaticStructure* structure,
|
||||||
|
int offset,
|
||||||
|
Env* env);
|
||||||
|
void fill_static_array_inline(const goos::Object& form,
|
||||||
|
const TypeSpec& content_type,
|
||||||
|
const std::vector<goos::Object>& args,
|
||||||
|
StaticStructure* structure,
|
||||||
|
int offset,
|
||||||
|
Env* env);
|
||||||
|
|
||||||
TypeSystem m_ts;
|
TypeSystem m_ts;
|
||||||
std::unique_ptr<GlobalEnv> m_global_env = nullptr;
|
std::unique_ptr<GlobalEnv> m_global_env = nullptr;
|
||||||
std::unique_ptr<None> m_none = nullptr;
|
std::unique_ptr<None> m_none = nullptr;
|
||||||
|
|
|
@ -90,7 +90,7 @@ StaticObject::LoadInfo StaticStructure::get_load_info() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int StaticStructure::get_addr_offset() const {
|
int StaticStructure::get_addr_offset() const {
|
||||||
return 0;
|
return m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaticStructure::generate_structure(emitter::ObjectGenerator* gen) {
|
void StaticStructure::generate_structure(emitter::ObjectGenerator* gen) {
|
||||||
|
|
|
@ -48,6 +48,7 @@ class StaticStructure : public StaticObject {
|
||||||
void generate_structure(emitter::ObjectGenerator* gen);
|
void generate_structure(emitter::ObjectGenerator* gen);
|
||||||
void generate(emitter::ObjectGenerator* gen) override;
|
void generate(emitter::ObjectGenerator* gen) override;
|
||||||
int get_addr_offset() const override;
|
int get_addr_offset() const override;
|
||||||
|
void set_offset(int offset) { m_offset = offset; }
|
||||||
|
|
||||||
struct SymbolRecord {
|
struct SymbolRecord {
|
||||||
int offset = -1;
|
int offset = -1;
|
||||||
|
@ -67,6 +68,9 @@ class StaticStructure : public StaticObject {
|
||||||
void add_symbol_record(std::string name, int offset);
|
void add_symbol_record(std::string name, int offset);
|
||||||
void add_pointer_record(int offset_in_this, StaticStructure* dest, int offset_in_dest);
|
void add_pointer_record(int offset_in_this, StaticStructure* dest, int offset_in_dest);
|
||||||
void add_type_record(std::string name, int offset);
|
void add_type_record(std::string name, int offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StaticBasic : public StaticStructure {
|
class StaticBasic : public StaticStructure {
|
||||||
|
|
|
@ -78,13 +78,82 @@ void Compiler::compile_static_structure_inline(const goos::Object& form,
|
||||||
field_name_def = field_name_def.substr(1);
|
field_name_def = field_name_def.substr(1);
|
||||||
auto field_info = m_ts.lookup_field_info(type_info->get_name(), field_name_def);
|
auto field_info = m_ts.lookup_field_info(type_info->get_name(), field_name_def);
|
||||||
|
|
||||||
if (field_info.field.is_dynamic() || field_info.field.is_array()) {
|
if (field_info.field.is_dynamic()) {
|
||||||
throw_compiler_error(form, "Static objects not yet implemented for dynamic/inline/array");
|
throw_compiler_error(form, "Dynamic fields are not supported for inline");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto field_offset = field_info.field.offset() + offset;
|
auto field_offset = field_info.field.offset() + offset;
|
||||||
|
|
||||||
if (is_integer(field_info.type)) {
|
if (field_info.field.is_array()) {
|
||||||
|
bool is_inline = field_info.field.is_inline();
|
||||||
|
|
||||||
|
// for an array field, we only accept (new 'static 'array <type> ...)
|
||||||
|
if (!field_value.is_list()) {
|
||||||
|
throw_compiler_error(field_value, "Array field was not properly specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
goos::Object constructor_args;
|
||||||
|
auto new_form = get_list_as_vector(field_value, &constructor_args, 5);
|
||||||
|
if (new_form.size() != 5) {
|
||||||
|
throw_compiler_error(
|
||||||
|
field_value,
|
||||||
|
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol()->name != "new") {
|
||||||
|
throw_compiler_error(
|
||||||
|
field_value,
|
||||||
|
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol()->name != "static") {
|
||||||
|
throw_compiler_error(
|
||||||
|
field_value,
|
||||||
|
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unquote(new_form.at(2)).print() != (is_inline ? "inline-array" : "array")) {
|
||||||
|
throw_compiler_error(
|
||||||
|
field_value,
|
||||||
|
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto array_content_type = parse_typespec(new_form.at(3));
|
||||||
|
|
||||||
|
if (is_inline) {
|
||||||
|
if (field_info.field.type() != array_content_type) {
|
||||||
|
throw_compiler_error(field_value, "Inline array field must have the correct type");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// allow more specific types.
|
||||||
|
m_ts.typecheck(field_info.field.type(), array_content_type, "Array content type");
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 elt_array_len;
|
||||||
|
if (!try_getting_constant_integer(new_form.at(4), &elt_array_len, env)) {
|
||||||
|
throw_compiler_error(field_value, "Array field size is invalid, got {}",
|
||||||
|
new_form.at(4).print());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elt_array_len != field_info.field.array_size()) {
|
||||||
|
throw_compiler_error(field_value, "Array field had an expected size of {} but got {}",
|
||||||
|
field_info.field.array_size(), elt_array_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arg_list = get_list_as_vector(field_value.as_pair()->cdr);
|
||||||
|
if (((int)arg_list.size() - 5) > elt_array_len) {
|
||||||
|
throw_compiler_error(field_value, "Array field definition has too many values in it.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_inline) {
|
||||||
|
fill_static_inline_array_inline(field_value, field_info.field.type(), arg_list, structure,
|
||||||
|
field_offset, env);
|
||||||
|
} else {
|
||||||
|
fill_static_array_inline(field_value, field_info.field.type(), arg_list, structure,
|
||||||
|
field_offset, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (is_integer(field_info.type)) {
|
||||||
assert(field_info.needs_deref); // for now...
|
assert(field_info.needs_deref); // for now...
|
||||||
auto deref_info = m_ts.get_deref_info(m_ts.make_pointer_typespec(field_info.type));
|
auto deref_info = m_ts.get_deref_info(m_ts.make_pointer_typespec(field_info.type));
|
||||||
auto field_size = deref_info.load_size;
|
auto field_size = deref_info.load_size;
|
||||||
|
@ -162,7 +231,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form,
|
||||||
assert(field_offset + field_size <= int(structure->data.size()));
|
assert(field_offset + field_size <= int(structure->data.size()));
|
||||||
auto sr = compile_static(field_value, env);
|
auto sr = compile_static(field_value, env);
|
||||||
if (sr.is_symbol()) {
|
if (sr.is_symbol()) {
|
||||||
if (sr.symbol_name() != "#f") {
|
if (sr.symbol_name() != "#f" && sr.symbol_name() != "_empty_") {
|
||||||
typecheck(form, field_info.type, sr.typespec());
|
typecheck(form, field_info.type, sr.typespec());
|
||||||
}
|
}
|
||||||
structure->add_symbol_record(sr.symbol_name(), field_offset);
|
structure->add_symbol_record(sr.symbol_name(), field_offset);
|
||||||
|
@ -437,6 +506,8 @@ StaticResult Compiler::compile_static(const goos::Object& form, Env* env) {
|
||||||
return fill_static_array(form, rest, true, env);
|
return fill_static_array(form, rest, true, env);
|
||||||
} else if (unquote(args.at(1)).as_symbol()->name == "array") {
|
} else if (unquote(args.at(1)).as_symbol()->name == "array") {
|
||||||
return fill_static_array(form, rest, false, env);
|
return fill_static_array(form, rest, false, env);
|
||||||
|
} else if (unquote(args.at(1)).as_symbol()->name == "inline-array") {
|
||||||
|
return fill_static_inline_array(form, rest, env);
|
||||||
} else {
|
} else {
|
||||||
auto ts = parse_typespec(unquote(args.at(1)));
|
auto ts = parse_typespec(unquote(args.at(1)));
|
||||||
if (ts == TypeSpec("string")) {
|
if (ts == TypeSpec("string")) {
|
||||||
|
@ -485,6 +556,46 @@ StaticResult Compiler::compile_static(const goos::Object& form, Env* env) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compiler::fill_static_array_inline(const goos::Object& form,
|
||||||
|
const TypeSpec& content_type,
|
||||||
|
const std::vector<goos::Object>& args,
|
||||||
|
StaticStructure* structure,
|
||||||
|
int offset,
|
||||||
|
Env* env) {
|
||||||
|
auto pointer_type = m_ts.make_pointer_typespec(content_type);
|
||||||
|
auto deref_info = m_ts.get_deref_info(pointer_type);
|
||||||
|
assert(deref_info.can_deref);
|
||||||
|
assert(deref_info.mem_deref);
|
||||||
|
for (size_t i = 4; i < args.size(); i++) {
|
||||||
|
int arg_idx = i - 4;
|
||||||
|
int elt_offset = offset + arg_idx * deref_info.stride;
|
||||||
|
auto sr = compile_static(args.at(i), env);
|
||||||
|
if (is_integer(content_type)) {
|
||||||
|
typecheck(form, TypeSpec("integer"), sr.typespec());
|
||||||
|
} else {
|
||||||
|
typecheck(form, content_type, sr.typespec());
|
||||||
|
}
|
||||||
|
if (sr.is_symbol()) {
|
||||||
|
assert(deref_info.stride == 4);
|
||||||
|
structure->add_symbol_record(sr.symbol_name(), elt_offset);
|
||||||
|
u32 symbol_placeholder = 0xffffffff;
|
||||||
|
memcpy(structure->data.data() + elt_offset, &symbol_placeholder, 4);
|
||||||
|
} else if (sr.is_reference()) {
|
||||||
|
assert(deref_info.stride == 4);
|
||||||
|
structure->add_pointer_record(elt_offset, sr.reference(), sr.reference()->get_addr_offset());
|
||||||
|
} else if (sr.is_constant_data()) {
|
||||||
|
if (!integer_fits(sr.constant_data(), deref_info.load_size, deref_info.sign_extend)) {
|
||||||
|
throw_compiler_error(form, "The integer {} doesn't fit in element {} of array of {}",
|
||||||
|
sr.constant_data(), arg_idx, content_type.print());
|
||||||
|
}
|
||||||
|
u64 data = sr.constant_data();
|
||||||
|
memcpy(structure->data.data() + elt_offset, &data, deref_info.load_size);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StaticResult Compiler::fill_static_array(const goos::Object& form,
|
StaticResult Compiler::fill_static_array(const goos::Object& form,
|
||||||
const goos::Object& rest,
|
const goos::Object& rest,
|
||||||
bool boxed,
|
bool boxed,
|
||||||
|
@ -530,34 +641,8 @@ StaticResult Compiler::fill_static_array(const goos::Object& form,
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add arguments:
|
// now add arguments:
|
||||||
for (size_t i = 4; i < args.size(); i++) {
|
fill_static_array_inline(form, content_type, args, obj.get(), array_header_size, env);
|
||||||
int arg_idx = i - 4;
|
|
||||||
int elt_offset = array_header_size + arg_idx * deref_info.stride;
|
|
||||||
auto sr = compile_static(args.at(i), env);
|
|
||||||
if (is_integer(content_type)) {
|
|
||||||
typecheck(form, TypeSpec("integer"), sr.typespec());
|
|
||||||
} else {
|
|
||||||
typecheck(form, content_type, sr.typespec());
|
|
||||||
}
|
|
||||||
if (sr.is_symbol()) {
|
|
||||||
assert(deref_info.stride == 4);
|
|
||||||
obj->add_symbol_record(sr.symbol_name(), elt_offset);
|
|
||||||
u32 symbol_placeholder = 0xffffffff;
|
|
||||||
memcpy(obj->data.data() + elt_offset, &symbol_placeholder, 4);
|
|
||||||
} else if (sr.is_reference()) {
|
|
||||||
assert(deref_info.stride == 4);
|
|
||||||
obj->add_pointer_record(elt_offset, sr.reference(), sr.reference()->get_addr_offset());
|
|
||||||
} else if (sr.is_constant_data()) {
|
|
||||||
if (!integer_fits(sr.constant_data(), deref_info.load_size, deref_info.sign_extend)) {
|
|
||||||
throw_compiler_error(form, "The integer {} doesn't fit in element {} of array of {}",
|
|
||||||
sr.constant_data(), arg_idx, content_type.print());
|
|
||||||
}
|
|
||||||
u64 data = sr.constant_data();
|
|
||||||
memcpy(obj->data.data() + elt_offset, &data, deref_info.load_size);
|
|
||||||
} else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeSpec result_type;
|
TypeSpec result_type;
|
||||||
if (boxed) {
|
if (boxed) {
|
||||||
result_type = m_ts.make_array_typespec(content_type);
|
result_type = m_ts.make_array_typespec(content_type);
|
||||||
|
@ -569,6 +654,91 @@ StaticResult Compiler::fill_static_array(const goos::Object& form,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compiler::fill_static_inline_array_inline(const goos::Object& form,
|
||||||
|
const TypeSpec& content_type,
|
||||||
|
const std::vector<goos::Object>& args,
|
||||||
|
StaticStructure* structure,
|
||||||
|
int offset,
|
||||||
|
Env* env) {
|
||||||
|
auto inline_array_type = m_ts.make_inline_array_typespec(content_type);
|
||||||
|
auto deref_info = m_ts.get_deref_info(inline_array_type);
|
||||||
|
assert(deref_info.can_deref);
|
||||||
|
assert(!deref_info.mem_deref);
|
||||||
|
|
||||||
|
for (size_t i = 4; i < args.size(); i++) {
|
||||||
|
auto arg_idx = i - 4;
|
||||||
|
int elt_offset = arg_idx * deref_info.stride;
|
||||||
|
auto& elt_def = args.at(i);
|
||||||
|
if (!elt_def.is_list()) {
|
||||||
|
throw_compiler_error(form, "Element in static inline-array must be a {}. Got {}",
|
||||||
|
content_type.print(), elt_def.print());
|
||||||
|
}
|
||||||
|
|
||||||
|
goos::Object ctor_args;
|
||||||
|
auto new_form = get_list_as_vector(elt_def, &ctor_args, 3);
|
||||||
|
if (new_form.size() != 3) {
|
||||||
|
throw_compiler_error(
|
||||||
|
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol()->name != "new") {
|
||||||
|
throw_compiler_error(
|
||||||
|
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol()->name != "static") {
|
||||||
|
throw_compiler_error(
|
||||||
|
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inlined_type = parse_typespec(unquote(new_form.at(2)));
|
||||||
|
if (inlined_type != content_type) {
|
||||||
|
throw_compiler_error(elt_def, "Cannot store a {} in an inline array of {}",
|
||||||
|
inlined_type.print(), content_type.print());
|
||||||
|
}
|
||||||
|
compile_static_structure_inline(elt_def, content_type, ctor_args, structure,
|
||||||
|
elt_offset + offset, env);
|
||||||
|
if (is_basic(content_type)) {
|
||||||
|
structure->add_type_record(content_type.base_type(), elt_offset + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticResult Compiler::fill_static_inline_array(const goos::Object& form,
|
||||||
|
const goos::Object& rest,
|
||||||
|
Env* env) {
|
||||||
|
auto fie = get_parent_env_of_type<FileEnv>(env);
|
||||||
|
// (new 'static 'inline-array ...)
|
||||||
|
// get all arguments now
|
||||||
|
auto args = get_list_as_vector(rest);
|
||||||
|
if (args.size() < 4) {
|
||||||
|
throw_compiler_error(form, "new static boxed array must have type and min-size arguments");
|
||||||
|
}
|
||||||
|
auto content_type = parse_typespec(args.at(2));
|
||||||
|
s64 min_size;
|
||||||
|
if (!try_getting_constant_integer(args.at(3), &min_size, env)) {
|
||||||
|
throw_compiler_error(form, "The length {} is not valid.", args.at(3).print());
|
||||||
|
}
|
||||||
|
s32 length = std::max(min_size, s64(args.size() - 4));
|
||||||
|
|
||||||
|
auto inline_array_type = m_ts.make_inline_array_typespec(content_type);
|
||||||
|
auto deref_info = m_ts.get_deref_info(inline_array_type);
|
||||||
|
assert(deref_info.can_deref);
|
||||||
|
assert(!deref_info.mem_deref);
|
||||||
|
// todo
|
||||||
|
auto obj = std::make_unique<StaticStructure>(MAIN_SEGMENT);
|
||||||
|
obj->set_offset(is_basic(content_type) ? 4 : 0);
|
||||||
|
obj->data.resize(length * deref_info.stride);
|
||||||
|
|
||||||
|
// now add elements:
|
||||||
|
fill_static_inline_array_inline(form, content_type, args, obj.get(), 0, env);
|
||||||
|
|
||||||
|
TypeSpec result_type = m_ts.make_inline_array_typespec(content_type);
|
||||||
|
auto result = StaticResult::make_structure_reference(obj.get(), result_type);
|
||||||
|
fie->add_static(std::move(obj));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Val* Compiler::compile_new_static_bitfield(const goos::Object& form,
|
Val* Compiler::compile_new_static_bitfield(const goos::Object& form,
|
||||||
const TypeSpec& type,
|
const TypeSpec& type,
|
||||||
const goos::Object& _field_defs,
|
const goos::Object& _field_defs,
|
||||||
|
|
|
@ -766,7 +766,8 @@ Val* Compiler::compile_static_new(const goos::Object& form,
|
||||||
Env* env) {
|
Env* env) {
|
||||||
auto unquoted = unquote(type);
|
auto unquoted = unquote(type);
|
||||||
if (unquoted.is_symbol() &&
|
if (unquoted.is_symbol() &&
|
||||||
(unquoted.as_symbol()->name == "boxed-array" || unquoted.as_symbol()->name == "array")) {
|
(unquoted.as_symbol()->name == "boxed-array" || unquoted.as_symbol()->name == "array" ||
|
||||||
|
unquoted.as_symbol()->name == "inline-array")) {
|
||||||
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
||||||
auto sr = compile_static(form, env);
|
auto sr = compile_static(form, env);
|
||||||
auto result = fe->alloc_val<StaticVal>(sr.reference(), sr.typespec());
|
auto result = fe->alloc_val<StaticVal>(sr.reference(), sr.typespec());
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
(deftype test-basic-for-static-array-field (basic)
|
||||||
|
((value uint32)
|
||||||
|
(name string)
|
||||||
|
(arr basic 12)
|
||||||
|
(lst pair)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(let ((test (new 'static 'test-basic-for-static-array-field
|
||||||
|
:value 12
|
||||||
|
:arr (new 'static 'array basic 12
|
||||||
|
"asdf"
|
||||||
|
"ghjkl"
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
(format #t "~A~%" (-> test arr 1))
|
||||||
|
)
|
|
@ -0,0 +1,57 @@
|
||||||
|
(deftype basic-elt (basic)
|
||||||
|
((name string))
|
||||||
|
)
|
||||||
|
|
||||||
|
(deftype struct-elt (structure)
|
||||||
|
((thing symbol))
|
||||||
|
)
|
||||||
|
|
||||||
|
(deftype test-basic-for-static-inline-array-field (basic)
|
||||||
|
((value uint32)
|
||||||
|
(name string)
|
||||||
|
(arr basic-elt 12 :inline)
|
||||||
|
(arr2 struct-elt 3 :inline)
|
||||||
|
(lst pair)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(let ((test (new 'static 'test-basic-for-static-inline-array-field
|
||||||
|
:value 12
|
||||||
|
:arr (new 'static 'inline-array basic-elt 12
|
||||||
|
(new 'static 'basic-elt :name "first")
|
||||||
|
(new 'static 'basic-elt :name "second")
|
||||||
|
)
|
||||||
|
:arr2 (new 'static 'inline-array struct-elt 3
|
||||||
|
(new 'static 'struct-elt :thing 'asdf)
|
||||||
|
(new 'static 'struct-elt :thing 'two)
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
(format #t "~A ~A~%" (-> test arr 1 name) (-> test arr 0 name))
|
||||||
|
(format #t "~A #x~X #x~X~%" (-> test arr 1 type) (logand 15 (the int (-> test arr))) (logand 15 (the int (-> test arr 1))))
|
||||||
|
(format #t "~A~%" (-> test arr2 1 thing))
|
||||||
|
)
|
||||||
|
|
||||||
|
(deftype test-struct-for-static-inline-array-field (structure)
|
||||||
|
((value uint32)
|
||||||
|
(name string)
|
||||||
|
(arr basic-elt 12 :inline)
|
||||||
|
(arr2 struct-elt 3 :inline)
|
||||||
|
(lst pair)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(let ((test (new 'static 'test-struct-for-static-inline-array-field
|
||||||
|
:value 12
|
||||||
|
:arr (new 'static 'inline-array basic-elt 12
|
||||||
|
(new 'static 'basic-elt :name "first")
|
||||||
|
(new 'static 'basic-elt :name "second")
|
||||||
|
)
|
||||||
|
:arr2 (new 'static 'inline-array struct-elt 3
|
||||||
|
(new 'static 'struct-elt :thing 'asdf)
|
||||||
|
(new 'static 'struct-elt :thing 'two)
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
(format #t "~A ~A~%" (-> test arr 1 name) (-> test arr 0 name))
|
||||||
|
(format #t "~A #x~X #x~X~%" (-> test arr 1 type) (logand 15 (the int (-> test arr))) (logand 15 (the int (-> test arr 1))))
|
||||||
|
(format #t "~A~%" (-> test arr2 1 thing))
|
||||||
|
)
|
|
@ -0,0 +1,47 @@
|
||||||
|
(deftype test-basic-for-static-inline (basic)
|
||||||
|
((value uint32)
|
||||||
|
(name string)
|
||||||
|
(thing symbol)
|
||||||
|
(lst pair)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(let ((test-arr (new 'static 'inline-array test-basic-for-static-inline 3
|
||||||
|
(new 'static 'test-basic-for-static-inline :value 12 :name "test-name" :thing 'beans :lst '("asdf" b ( c . d)))
|
||||||
|
(new 'static 'test-basic-for-static-inline :value 1235 :name "hello")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(format #t "~A ~A #x~X #x~X ~A~%"
|
||||||
|
(-> test-arr 0 type)
|
||||||
|
(-> test-arr 1 type)
|
||||||
|
(logand 15 (the int (-> test-arr 1)))
|
||||||
|
(logand 15 (the int test-arr))
|
||||||
|
(-> test-arr 1 name)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
(deftype test-struct-for-static-inline (structure)
|
||||||
|
((value uint32)
|
||||||
|
(name string)
|
||||||
|
(thing symbol)
|
||||||
|
(lst pair)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(let ((test-arr (new 'static 'inline-array test-struct-for-static-inline 3
|
||||||
|
(new 'static 'test-struct-for-static-inline :value 12 :name "test-name" :thing 'beans :lst '("asdf" b ( c . d)))
|
||||||
|
(new 'static 'test-struct-for-static-inline :value 1235 :name "hello")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(format #t "#x~X #x~X ~A~%"
|
||||||
|
;;(-> test-arr 0 type)
|
||||||
|
;;(-> test-arr 1 type)
|
||||||
|
(logand 15 (the int (-> test-arr 1)))
|
||||||
|
(logand 15 (the int test-arr))
|
||||||
|
(-> test-arr 1 name)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
|
@ -493,6 +493,31 @@ TEST_F(WithGameTests, StaticArray) {
|
||||||
"0\n"});
|
"0\n"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WithGameTests, StaticInlineArray) {
|
||||||
|
runner.run_static_test(
|
||||||
|
env, testCategory, "test-static-inline-array.gc",
|
||||||
|
{"test-basic-for-static-inline test-basic-for-static-inline #x4 #x4 \"hello\"\n"
|
||||||
|
"#x0 #x0 \"hello\"\n"
|
||||||
|
"0\n"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WithGameTests, StaticArrayField) {
|
||||||
|
runner.run_static_test(env, testCategory, "test-static-array-field.gc",
|
||||||
|
{"\"ghjkl\"\n"
|
||||||
|
"0\n"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WithGameTests, StaticFieldInlineArray) {
|
||||||
|
runner.run_static_test(env, testCategory, "test-static-field-inline-arrays.gc",
|
||||||
|
{"\"second\" \"first\"\n"
|
||||||
|
"basic-elt #x4 #x4\n"
|
||||||
|
"two\n"
|
||||||
|
"\"second\" \"first\"\n"
|
||||||
|
"basic-elt #x4 #x4\n"
|
||||||
|
"two\n"
|
||||||
|
"0\n"});
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TypeConsistency, TypeConsistency) {
|
TEST(TypeConsistency, TypeConsistency) {
|
||||||
Compiler compiler;
|
Compiler compiler;
|
||||||
compiler.enable_throw_on_redefines();
|
compiler.enable_throw_on_redefines();
|
||||||
|
|
Loading…
Reference in a new issue