@@ 936,11 936,6 @@ private:
return type_hash;
}
- /// Fill the offset type value based on the type reference.
- /// This will generate new array types if necessary.
- /// @param array_length Only valid if @a type_reference refers to an array.
- bool fill_offset_value(bool generate, const TypeReference &type_reference, int32_t array_length, const SourceLocation &source_location, Value &value);
-
/// Generate a type from a type reference structure. This can reuse an existing type or create new ones.
/// @return True if successful.
bool generate_offset_type(bool generate, const TypeReference &type_reference, const std::vector<int32_t> array_lengths, const SourceLocation &source_location, ValueType &type, uint64_t &type_hash);
@@ 983,18 978,37 @@ private:
bool verify_and_define_object(bool generate, const ExpressionToken &expr, const TypeDescription &type_desc, const Value &value);
/// Parse and define data for one array. Adds data to section and increases the program counter.
- /// @param array_length The known length of an array, or zero to be updated with the length when known.
- const SyntaxToken *parse_define_array(bool generate, bool &success, const SyntaxToken *t, const TypeDescription &element_type, int32_t &array_length);
+ /// @param innermost_type_hash The type hash for the innermost type in the array
+ /// @param adjacent_type_hash The type hash that THIS array should be using (forced by an adjacent array index). Pass zero if undetermined.
+ /// @param return_type_hash The type hash that this array must be. The same as adjacent_type_hash if that isn't zero.
+ const SyntaxToken *parse_define_array(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t innermost_type_hash
+ , uint64_t adjacent_type_hash
+ , uint64_t &return_type_hash
+ , const std::vector<int32_t> &array_sizes
+ , size_t array_depth
+ );
/// Parse and define data for one object. Adds data to section and increases the program counter.
- const SyntaxToken *parse_define_object(bool generate, bool &success, const SyntaxToken *t, const TypeDescription &type_desc);
+ const SyntaxToken *parse_define_object(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t innermost_type_hash
+ );
- /// Parse data for one type and recurse until all containing data is parsed.
- /// Data is verified and added to the section data.
- /// @param array_updated_type Optional type pointer to update with length of parsed array. This is used for arrays without length.
- /// @param type_desc Type we are going to parse.
- /// @param array_length Length of array, if applicable, otherwise 0.
- const SyntaxToken *parse_define_data(bool generate, const SyntaxToken *t, TypeDescription *array_updated_type, const TypeDescription &type_desc, int32_t array_length);
+ const SyntaxToken *parse_define_any(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t innermost_type_hash
+ , uint64_t &return_type_hash
+ , const std::vector<int32_t> &array_sizes
+ , size_t array_depth
+ );
/// Parse the loop body over a collection loop.
const SyntaxToken *parse_range_list_loop(bool generate, const SyntaxToken *t, RangedLoopContainer &loop_container, const RangedForLoopToken &loop_token, bool &early_return);
@@ 591,38 591,6 @@ bool Assembler::resolve_type_hash(bool g
UNREACHABLE_CODE(throw Exception("internal error"));
}
-// TODO: REMOVE
-bool Assembler::fill_offset_value(bool generate, const TypeReference &type_reference, int32_t array_length, const SourceLocation &source_location, Value &value)
-{
- /*
- uint64_t underlying_type_hash;
- if (!resolve_type_hash(generate, type_reference, source_location, underlying_type_hash))
- return false;
-
- // map typenames to offset types for typenames in symbols
- underlying_type_hash = map_fundamental_types_to_offset_types(underlying_type_hash);
-
- // select the value type
- if (type_reference.array_flag == ArrayFlag::ArrayWithSize || type_reference.array_flag == ArrayFlag::ArrayWithUnknownSize) {
- // create a type description for this array length
- uint64_t type_hash = add_array_type_description(underlying_type_hash, array_length);
-
- // store array type
- value.type = ValueType::ArrayOffset;
- value.type_hash = type_hash;
-
- } else if (type_reference.array_flag == ArrayFlag::Single) {
- const TypeDescription &type_desc = find_type(underlying_type_hash);
- value.type = type_desc.type;
- value.type_hash = underlying_type_hash;
- }
-
- return true;
- */
- assert(false);
- return false;
-}
-
bool Assembler::generate_offset_type(bool generate, const TypeReference &type_reference, const std::vector<int32_t> array_lengths, const SourceLocation &source_location, ValueType &type, uint64_t &type_hash)
{
uint64_t underlying_type_hash;
@@ 807,19 775,35 @@ bool Assembler::define_single_fundamenta
return true;
}
-const SyntaxToken *Assembler::parse_define_array(bool generate, bool &success, const SyntaxToken *t, const TypeDescription &element_type, int32_t &array_length)
+const SyntaxToken *Assembler::parse_define_array(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t innermost_type_hash
+ , uint64_t adjacent_type_hash
+ , uint64_t &return_type_hash
+ , const std::vector<int32_t> &array_sizes
+ , size_t array_depth
+)
{
assert(_data_generation_depth == 1);
+ int32_t array_length = array_sizes[array_depth-1];
bool is_fixed_array = array_length > 0;
+ // pick size from an adjacent array
+ if (!is_fixed_array && adjacent_type_hash != 0) {
+ const TypeDescription &adjacent_type = find_type(adjacent_type_hash);
+ array_length = adjacent_type.array_size;
+ is_fixed_array = true;
+ }
+
// expecting a group for the array
if (t->type == SyntaxTokenType::Expression) {
if (generate) {
const ExpressionToken &expr = *static_cast<const ExpressionToken *>(t);
- std::stringstream ss;
- ss << "Expected array definition.";
- report_error(expr.source_location, AssemblyErrorCodes::ExpectedArrayDefinition, ss.str());
+ std::string s("Expected array definition.");
+ report_error(expr.source_location, AssemblyErrorCodes::ExpectedArrayDefinition, s);
}
success = false;
return t;
@@ 831,9 815,8 @@ const SyntaxToken *Assembler::parse_defi
if (!is_fixed_array && group->repeated_pattern) {
if (generate) {
- std::stringstream ss;
- ss << "Array definition with repeating pattern must have specified size.";
- report_error(group->source_location, AssemblyErrorCodes::DynamicArrayCantHaveRepeatingPattern, ss.str());
+ std::string s("Array definition with repeating pattern must have specified size.");
+ report_error(group->source_location, AssemblyErrorCodes::DynamicArrayCantHaveRepeatingPattern, s);
}
success = false;
return t;
@@ 848,71 831,115 @@ const SyntaxToken *Assembler::parse_defi
// loop until the end of the group
int32_t defined_array_elements = 0;
- for(int i = 0; i < group->num_elements; ++i) {
- assert(element_type.array_size == 0); // arrays of arrays is not supported yet
-
+ uint64_t child_type_hash = 0;
+ if (array_depth > 1) {
+ // array in array
+ for(int i = 0; i < group->num_elements; ++i) {
+ ++defined_array_elements;
+
+ // check upper bounds on array in case it isn't a repeated pattern
+ if (!group->repeated_pattern && is_fixed_array && defined_array_elements > array_length) {
+ if (generate) {
+ const SourceLocation *location = nullptr;
+ if (t->type == SyntaxTokenType::Expression) {
+ const ExpressionToken &expr = *static_cast<const ExpressionToken *>(t);
+ location = &expr.source_location;
+ } else {
+ assert(t->type == SyntaxTokenType::DefineGroup);
+ const DefineGroupToken *token = static_cast<const DefineGroupToken *>(t);
+ location = &token->source_location;
+ }
+
+ std::stringstream ss;
+ ss << "Number of values in array exceeds array length.";
+ report_error(*location, AssemblyErrorCodes::NoOfValuesExceedArray, ss.str());
+ }
+ success = false;
+ return t;
+ }
+
+ t = parse_define_array(
+ generate
+ , success
+ , t
+ , innermost_type_hash
+ , child_type_hash
+ , child_type_hash
+ , array_sizes
+ , array_depth - 1
+ );
+ if (!success) {
+ return t;
+ }
+ }
+ } else {
+ child_type_hash = innermost_type_hash;
+ const TypeDescription &element_type = find_type(innermost_type_hash);
bool is_fundamental_type = element_type.type == ValueType::ByteOffset
|| element_type.type == ValueType::WordOffset
|| element_type.type == ValueType::LongOffset;
if (is_fundamental_type) {
- if (t->type != SyntaxTokenType::Expression) {
- assert(t->type == SyntaxTokenType::DefineGroup);
- const DefineGroupToken *g = static_cast<const DefineGroupToken *>(t);
- if (generate) {
- std::stringstream ss;
- ss << "Expected single value definition but found start of group.";
- report_error(g->source_location, AssemblyErrorCodes::ExpectedSingleValueDefinition, ss.str());
+ for(int i = 0; i < group->num_elements; ++i) {
+ if (t->type != SyntaxTokenType::Expression) {
+ assert(t->type == SyntaxTokenType::DefineGroup);
+ const DefineGroupToken *g = static_cast<const DefineGroupToken *>(t);
+ if (generate) {
+ std::stringstream ss;
+ ss << "Expected single value definition but found start of group.";
+ report_error(g->source_location, AssemblyErrorCodes::ExpectedSingleValueDefinition, ss.str());
+ }
+ success = false;
+ return t;
}
- success = false;
- return t;
- }
-
- const ExpressionToken *expr = static_cast<const ExpressionToken *>(t);
- const Value expr_value = follow_reference_or_value(evaluate_expression(generate, t));
- t = consume_next_token();
-
- // special case for arrays of fundamental types, which supports strings as input
- if (is_string(expr_value)) {
- // define a range of objects
- std::string_view s = dereference_string(expr_value);
- wchar_t wide = 0;
- const char *source = s.data();
- size_t source_size = s.size();
- while(source_size != 0) {
- core::utf8_to_wide(source, source_size, wide);
- if (!define_single_fundamental_type(generate, element_type.type, static_cast<int32_t>(wide), expr->source_location)) {
+
+ const ExpressionToken *expr = static_cast<const ExpressionToken *>(t);
+ const Value expr_value = follow_reference_or_value(evaluate_expression(generate, t));
+ t = consume_next_token();
+
+ // special case for arrays of fundamental types, which supports strings as input
+ if (is_string(expr_value)) {
+ // define a range of objects
+ std::string_view s = dereference_string(expr_value);
+ wchar_t wide = 0;
+ const char *source = s.data();
+ size_t source_size = s.size();
+ while(source_size != 0) {
+ core::utf8_to_wide(source, source_size, wide);
+ if (!define_single_fundamental_type(generate, element_type.type, static_cast<int32_t>(wide), expr->source_location)) {
+ success = false;
+ return t;
+ }
+ ++defined_array_elements;
+ }
+
+ } else {
+ // define one object
+ if (!verify_and_define_object(generate, *expr, element_type, expr_value)) {
success = false;
return t;
}
++defined_array_elements;
}
- } else {
- // define one object
- if (!verify_and_define_object(generate, *expr, element_type, expr_value)) {
+ // check upper bounds on array in case it isn't a repeated pattern
+ if (!group->repeated_pattern && is_fixed_array && defined_array_elements > array_length) {
+ if (generate) {
+ std::stringstream ss;
+ ss << "Number of values in array exceeds array length.";
+ report_error(expr->source_location, AssemblyErrorCodes::NoOfValuesExceedArray, ss.str());
+ }
success = false;
return t;
}
- ++defined_array_elements;
}
-
- // check upper bounds on array in case it isn't a repeated pattern
- if (!group->repeated_pattern && is_fixed_array && defined_array_elements > array_length) {
- if (generate) {
- std::stringstream ss;
- ss << "Number of values in array exceeds array length.";
- report_error(expr->source_location, AssemblyErrorCodes::NoOfValuesExceedArray, ss.str());
- }
+ } else if (element_type.type == ValueType::StructOffset) {
+ //for(int i = 0; i < group->num_elements; ++i) {
+ // call a special version of the parse object method which checks for group and all that
+ assert(false);
success = false;
return t;
- }
-
- } else if (element_type.type == ValueType::StructOffset) {
- // call a special version of the parse object method which checks for group and all that
- assert(false);
- success = false;
- return t;
+ //}
} else {
// this should never happen
assert(false);
@@ 920,8 947,10 @@ const SyntaxToken *Assembler::parse_defi
return t;
}
}
+ assert(child_type_hash != 0);
if (group->repeated_pattern) {
+ const TypeDescription &element_type = find_type(child_type_hash);
// the defined data may be longer than the repeated pattern so we begin by cropping the output
int32_t desired_size = array_length * element_type.byte_size;
@@ 963,11 992,10 @@ const SyntaxToken *Assembler::parse_defi
success = false;
return t;
}
-
- if (!is_fixed_array) {
- array_length = defined_array_elements;
- }
+ // create a type description for this array length
+ return_type_hash = add_array_type_description(child_type_hash, defined_array_elements);
+
success = true;
return t;
}
@@ 1069,7 1097,12 @@ bool Assembler::verify_and_define_object
return true;
}
-const SyntaxToken *Assembler::parse_define_object(bool generate, bool &success, const SyntaxToken *t, const TypeDescription &type_desc)
+const SyntaxToken *Assembler::parse_define_object(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t type_hash
+)
{
// This isn't made for structs. This should only be called for fundamental types and structs will
// have to have their own parse object method.
@@ 1091,6 1124,7 @@ const SyntaxToken *Assembler::parse_defi
const Value expr_value = follow_reference_or_value(evaluate_expression(generate, t));
t = consume_next_token();
+ const TypeDescription &type_desc = find_type(type_hash);
if (!verify_and_define_object(generate, *expr, type_desc, expr_value)) {
success = false;
return t;
@@ 1100,6 1134,24 @@ const SyntaxToken *Assembler::parse_defi
return t;
}
+const SyntaxToken *Assembler::parse_define_any(
+ bool generate
+ , bool &success
+ , const SyntaxToken *t
+ , uint64_t innermost_type_hash
+ , uint64_t &return_type_hash
+ , const std::vector<int32_t> &array_sizes
+ , size_t array_depth
+)
+{
+ if (array_depth > 0) {
+ return parse_define_array(generate, success, t, innermost_type_hash, 0, return_type_hash, array_sizes, array_depth);
+ } else {
+ return_type_hash = innermost_type_hash;
+ return parse_define_object(generate, success, t, innermost_type_hash);
+ }
+}
+
const SyntaxToken *Assembler::parse_define(bool generate, const SyntaxToken *t, bool export_enabled)
{
const DefineToken &define = *static_cast<const DefineToken *>(t);
@@ 1146,16 1198,24 @@ const SyntaxToken *Assembler::parse_defi
// Groups are used for arrays and structs. A string is a form of multi byte entry
// so that will require a group.
- assert(false); // TODO: Fix
-/*
- // parse the size of the array if that is specified
- int32_t array_length = 0;
- if (define.type_reference.array_flag == ArrayFlag::ArrayWithSize) {
- bool success;
- t = parse_array_length(generate, success, t, 0, array_length);
- if (!success) {
- set_unknown(value);
- return skip_to_end_of_define(t);
+ // parse all array sizes
+ std::vector<int32_t> array_sizes;
+ if (define.type_reference.is_array) {
+ array_sizes.resize(define.type_reference.array_depth);
+ for(uint32_t index = 0; index < define.type_reference.array_depth; ++index) {
+ ArrayFlag flag = define.type_reference.array_flags[index];
+ if (flag == ArrayFlag::ArrayWithSize) {
+ bool success = false;
+ int32_t array_length = 0;
+ t = parse_array_length(generate, success, t, 0, array_length);
+ if (!success) {
+ set_unknown(value);
+ return skip_to_end_of_define(t);
+ }
+ array_sizes[index] = array_length;
+ } else {
+ array_sizes[index] = 0; // zero means the size hasn't been determined yet.
+ }
}
}
@@ 1168,7 1228,6 @@ const SyntaxToken *Assembler::parse_defi
// map type names in symbols to offset types
underlying_type_hash = map_fundamental_types_to_offset_types(underlying_type_hash);
-
// set the value base and offset (this will enable use of offsetof() and further offsetting
int32_t program_counter_before = _program_counter.integer_value;
value.offset_base = program_counter_before;
@@ 1177,24 1236,25 @@ const SyntaxToken *Assembler::parse_defi
auto &data = _section->generated_data();
size_t data_size_before = data.size();
- bool is_array_type = define.type_reference.array_flag != ArrayFlag::Single;
- bool success;
- //t = parse_define_data(generate, success, t, array_updated_type, find_type(value.type_hash), is_array_type, array_length);
- if (is_array_type)
- t = parse_define_array(generate, success, t, find_type(underlying_type_hash), array_length);
- else
- t = parse_define_object(generate, success, t, find_type(underlying_type_hash));
-
- if (!success) {
- set_unknown(value);
- return skip_to_end_of_define(t);
+ // Parse recursive from the outermost array and generate types on the way back when
+ // the size of each array has been determined. Fail as soon as mismatches in lengths
+ // are found.
+
+ uint64_t final_type_hash = 0;
+ {
+ bool success = false;
+ t = parse_define_any(generate, success, t, underlying_type_hash, final_type_hash, array_sizes, define.type_reference.array_depth);
+
+ if (!success) {
+ set_unknown(value);
+ return skip_to_end_of_define(t);
+ }
}
// fill the type description now when array length has been determined
- if (!fill_offset_value(generate, define.type_reference, array_length, define.source_location, value)) {
- set_unknown(value);
- return skip_to_end_of_define(t);
- }
+ const TypeDescription &type_desc = find_type(final_type_hash);
+ value.type = type_desc.type;
+ value.type_hash = type_desc.underlying_type_hash;
if (generate && _hex_source_writer != nullptr) {
uint32_t generated_size = static_cast<uint32_t>(data.size() - data_size_before);
@@ 1206,7 1266,6 @@ const SyntaxToken *Assembler::parse_defi
constexpr bool increase = true;
_hex_source_writer->write_data(static_cast<uint32_t>(program_counter_before), &data[data_size_before], increase, generated_size, define.source_location.file_index, define.source_location.row, end_line);
}
- */
t = skip_to_end_of_define(t);
return t;