Forward declared type
This commit is contained in:
parent
5de4ba76f5
commit
f33d448148
@ -48,5 +48,3 @@ target_link_libraries(bb PUBLIC
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(bb PRIVATE -Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -funsigned-char -fwrapv -fno-strict-aliasing)
|
target_compile_options(bb PRIVATE -Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -funsigned-char -fwrapv -fno-strict-aliasing)
|
||||||
# target_compile_options(bb PRIVATE -fsanitize=address)
|
|
||||||
# target_link_options(bb PRIVATE -fsanitize=address)
|
|
||||||
|
907
src/compiler.bbb
907
src/compiler.bbb
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
fn void compile(Arena* arena, Options options)
|
fn void compile(Arena* arena, Options options)
|
||||||
{
|
{
|
||||||
|
Module module;
|
||||||
auto base_allocation_type_count = i128_offset + // 64 * 2 for basic integer types
|
auto base_allocation_type_count = i128_offset + // 64 * 2 for basic integer types
|
||||||
2 + // u128, s128
|
2 + // u128, s128
|
||||||
2; // void, noreturn
|
2; // void, noreturn
|
||||||
@ -32,6 +33,7 @@ fn void compile(Arena* arena, Options options)
|
|||||||
},
|
},
|
||||||
.id = TypeId::integer,
|
.id = TypeId::integer,
|
||||||
.name = name,
|
.name = name,
|
||||||
|
.scope = &module.scope,
|
||||||
};
|
};
|
||||||
if (previous) previous->next = type_it;
|
if (previous) previous->next = type_it;
|
||||||
previous = type_it;
|
previous = type_it;
|
||||||
@ -50,6 +52,7 @@ fn void compile(Arena* arena, Options options)
|
|||||||
.id = TypeId::integer,
|
.id = TypeId::integer,
|
||||||
.name = name,
|
.name = name,
|
||||||
.next = previous,
|
.next = previous,
|
||||||
|
.scope = &module.scope,
|
||||||
};
|
};
|
||||||
if (previous) previous->next = type_it;
|
if (previous) previous->next = type_it;
|
||||||
previous = type_it;
|
previous = type_it;
|
||||||
@ -67,18 +70,22 @@ fn void compile(Arena* arena, Options options)
|
|||||||
.id = TypeId::void_type,
|
.id = TypeId::void_type,
|
||||||
.name = string_literal("void"),
|
.name = string_literal("void"),
|
||||||
.next = noreturn_type,
|
.next = noreturn_type,
|
||||||
|
.scope = &module.scope,
|
||||||
};
|
};
|
||||||
*noreturn_type = {
|
*noreturn_type = {
|
||||||
.id = TypeId::noreturn,
|
.id = TypeId::noreturn,
|
||||||
.name = string_literal("noreturn"),
|
.name = string_literal("noreturn"),
|
||||||
|
.scope = &module.scope,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto module = Module{
|
module = Module{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.content = options.content,
|
.content = options.content,
|
||||||
.first_type = base_type_allocation.pointer,
|
|
||||||
.last_type = noreturn_type,
|
|
||||||
.scope = {
|
.scope = {
|
||||||
|
.types = {
|
||||||
|
.first = base_type_allocation.pointer,
|
||||||
|
.last = noreturn_type,
|
||||||
|
},
|
||||||
.kind = ScopeKind::global,
|
.kind = ScopeKind::global,
|
||||||
},
|
},
|
||||||
.name = options.name,
|
.name = options.name,
|
||||||
@ -306,8 +313,12 @@ global_variable String names[] =
|
|||||||
string_literal("noreturn_macro"),
|
string_literal("noreturn_macro"),
|
||||||
string_literal("generic_pointer_array"),
|
string_literal("generic_pointer_array"),
|
||||||
|
|
||||||
string_literal("self_referential_struct"), // TODO
|
string_literal("self_referential_struct"),
|
||||||
// string_literal("forward_declared_type"),
|
string_literal("forward_declared_type"),
|
||||||
|
|
||||||
|
string_literal("enum_array"),
|
||||||
|
string_literal("opaque"),
|
||||||
|
string_literal("basic_struct_passing"),
|
||||||
};
|
};
|
||||||
|
|
||||||
void entry_point(Slice<const char*> arguments, Slice<char* const> environment)
|
void entry_point(Slice<const char*> arguments, Slice<char* const> environment)
|
||||||
@ -382,7 +393,7 @@ void entry_point(Slice<const char*> arguments, Slice<char* const> environment)
|
|||||||
|
|
||||||
if (arguments.length >= 5)
|
if (arguments.length >= 5)
|
||||||
{
|
{
|
||||||
auto has_debug_info_string = c_string_to_slice(arguments[3]);
|
auto has_debug_info_string = c_string_to_slice(arguments[4]);
|
||||||
if (has_debug_info_string.equal(string_literal("true")))
|
if (has_debug_info_string.equal(string_literal("true")))
|
||||||
{
|
{
|
||||||
has_debug_info = true;
|
has_debug_info = true;
|
||||||
@ -488,7 +499,7 @@ void entry_point(Slice<const char*> arguments, Slice<char* const> environment)
|
|||||||
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
print(string_literal("Standalone test failed: "));
|
print(string_literal("Self-hosted test failed: "));
|
||||||
print(name);
|
print(name);
|
||||||
print(string_literal("\n"));
|
print(string_literal("\n"));
|
||||||
bb_fail();
|
bb_fail();
|
||||||
|
131
src/compiler.hpp
131
src/compiler.hpp
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <lib.hpp>
|
#include <lib.hpp>
|
||||||
#include <llvm-c/Types.h>
|
#include <llvm-c/TargetMachine.h>
|
||||||
#define report_error() trap()
|
#define report_error() trap()
|
||||||
|
|
||||||
enum class Command
|
enum class Command
|
||||||
@ -314,6 +314,8 @@ enum class TypeId
|
|||||||
unresolved,
|
unresolved,
|
||||||
vector,
|
vector,
|
||||||
floating_point,
|
floating_point,
|
||||||
|
enum_array,
|
||||||
|
opaque,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeInteger
|
struct TypeInteger
|
||||||
@ -448,6 +450,13 @@ struct LLVMType
|
|||||||
LLVMMetadataRef debug;
|
LLVMMetadataRef debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TypeEnumArray
|
||||||
|
{
|
||||||
|
Type* enum_type;
|
||||||
|
Type* element_type;
|
||||||
|
Type* next;
|
||||||
|
};
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -461,10 +470,12 @@ struct Type
|
|||||||
TypeBits bits;
|
TypeBits bits;
|
||||||
TypeAlias alias;
|
TypeAlias alias;
|
||||||
TypeUnion union_type;
|
TypeUnion union_type;
|
||||||
|
TypeEnumArray enum_array;
|
||||||
};
|
};
|
||||||
TypeId id;
|
TypeId id;
|
||||||
String name;
|
String name;
|
||||||
Type* next;
|
Type* next;
|
||||||
|
Scope* scope;
|
||||||
LLVMType llvm;
|
LLVMType llvm;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -528,6 +539,17 @@ fn u64 get_byte_size(Type* type)
|
|||||||
auto result = type->union_type.byte_size;
|
auto result = type->union_type.byte_size;
|
||||||
return result;
|
return result;
|
||||||
} break;
|
} break;
|
||||||
|
case TypeId::enum_array:
|
||||||
|
{
|
||||||
|
auto enum_type = type->enum_array.enum_type;
|
||||||
|
assert(enum_type->id == TypeId::enumerator);
|
||||||
|
auto element_count = enum_type->enumerator.fields.length;
|
||||||
|
auto element_type = type->enum_array.element_type;
|
||||||
|
auto element_size = get_byte_size(element_type);
|
||||||
|
|
||||||
|
auto result = element_size * element_count;
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
default: trap();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,6 +597,10 @@ fn u32 get_byte_alignment(Type* type)
|
|||||||
{
|
{
|
||||||
return get_byte_alignment(type->alias.type);
|
return get_byte_alignment(type->alias.type);
|
||||||
} break;
|
} break;
|
||||||
|
case TypeId::enum_array:
|
||||||
|
{
|
||||||
|
return get_byte_alignment(type->enum_array.element_type);
|
||||||
|
} break;
|
||||||
default: trap();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,6 +616,12 @@ fn u64 get_bit_size(Type* type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TypeList
|
||||||
|
{
|
||||||
|
Type* first;
|
||||||
|
Type* last;
|
||||||
|
};
|
||||||
|
|
||||||
enum class ScopeKind
|
enum class ScopeKind
|
||||||
{
|
{
|
||||||
global,
|
global,
|
||||||
@ -602,6 +634,7 @@ enum class ScopeKind
|
|||||||
|
|
||||||
struct Scope
|
struct Scope
|
||||||
{
|
{
|
||||||
|
TypeList types;
|
||||||
Scope* parent;
|
Scope* parent;
|
||||||
u32 line;
|
u32 line;
|
||||||
u32 column;
|
u32 column;
|
||||||
@ -609,6 +642,13 @@ struct Scope
|
|||||||
LLVMMetadataRef llvm;
|
LLVMMetadataRef llvm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SourceLocation
|
||||||
|
{
|
||||||
|
Scope* scope;
|
||||||
|
u32 line;
|
||||||
|
u32 column;
|
||||||
|
};
|
||||||
|
|
||||||
enum class StatementId
|
enum class StatementId
|
||||||
{
|
{
|
||||||
local,
|
local,
|
||||||
@ -878,10 +918,18 @@ struct ValueVaArg
|
|||||||
Type* type;
|
Type* type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AggregateInitializationElement
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
Value* value;
|
||||||
|
u32 line;
|
||||||
|
u32 column;
|
||||||
|
};
|
||||||
|
|
||||||
struct ValueAggregateInitialization
|
struct ValueAggregateInitialization
|
||||||
{
|
{
|
||||||
Slice<String> names;
|
Slice<AggregateInitializationElement> elements;
|
||||||
Slice<Value*> values;
|
Scope* scope;
|
||||||
bool is_constant;
|
bool is_constant;
|
||||||
bool zero;
|
bool zero;
|
||||||
};
|
};
|
||||||
@ -920,6 +968,7 @@ struct MacroDeclaration
|
|||||||
{
|
{
|
||||||
Slice<Argument> arguments;
|
Slice<Argument> arguments;
|
||||||
Slice<ConstantArgument> constant_arguments;
|
Slice<ConstantArgument> constant_arguments;
|
||||||
|
TypeList types;
|
||||||
Type* return_type;
|
Type* return_type;
|
||||||
Block* block;
|
Block* block;
|
||||||
String name;
|
String name;
|
||||||
@ -987,6 +1036,7 @@ struct Value
|
|||||||
case ValueId::enum_literal:
|
case ValueId::enum_literal:
|
||||||
case ValueId::unary_type:
|
case ValueId::unary_type:
|
||||||
case ValueId::string_literal:
|
case ValueId::string_literal:
|
||||||
|
case ValueId::zero:
|
||||||
return true;
|
return true;
|
||||||
case ValueId::unary:
|
case ValueId::unary:
|
||||||
case ValueId::binary:
|
case ValueId::binary:
|
||||||
@ -1103,6 +1153,8 @@ struct ModuleLLVM
|
|||||||
LLVMBuilderRef builder;
|
LLVMBuilderRef builder;
|
||||||
LLVMDIBuilderRef di_builder;
|
LLVMDIBuilderRef di_builder;
|
||||||
LLVMMetadataRef file;
|
LLVMMetadataRef file;
|
||||||
|
LLVMTargetMachineRef target_machine;
|
||||||
|
LLVMTargetDataRef target_data;
|
||||||
LLVMMetadataRef compile_unit;
|
LLVMMetadataRef compile_unit;
|
||||||
LLVMTypeRef pointer_type;
|
LLVMTypeRef pointer_type;
|
||||||
LLVMTypeRef void_type;
|
LLVMTypeRef void_type;
|
||||||
@ -1126,9 +1178,8 @@ struct Module
|
|||||||
Type* first_slice_type;
|
Type* first_slice_type;
|
||||||
Type* first_pair_struct_type;
|
Type* first_pair_struct_type;
|
||||||
Type* first_array_type;
|
Type* first_array_type;
|
||||||
|
Type* first_enum_array_type;
|
||||||
|
|
||||||
Type* first_type;
|
|
||||||
Type* last_type;
|
|
||||||
Type* va_list_type;
|
Type* va_list_type;
|
||||||
|
|
||||||
Value* void_value;
|
Value* void_value;
|
||||||
@ -1167,7 +1218,7 @@ fn Type* integer_type(Module* module, TypeInteger integer)
|
|||||||
assert(integer.bit_count > 1);
|
assert(integer.bit_count > 1);
|
||||||
}
|
}
|
||||||
auto index = integer.bit_count == 128 ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
|
auto index = integer.bit_count == 128 ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
|
||||||
auto* result_type = module->first_type + index;
|
auto* result_type = module->scope.types.first + index;
|
||||||
assert(result_type->id == TypeId::integer);
|
assert(result_type->id == TypeId::integer);
|
||||||
assert(result_type->integer.bit_count == integer.bit_count);
|
assert(result_type->integer.bit_count == integer.bit_count);
|
||||||
assert(result_type->integer.is_signed == integer.is_signed);
|
assert(result_type->integer.is_signed == integer.is_signed);
|
||||||
@ -1176,7 +1227,7 @@ fn Type* integer_type(Module* module, TypeInteger integer)
|
|||||||
|
|
||||||
fn Type* void_type(Module* module)
|
fn Type* void_type(Module* module)
|
||||||
{
|
{
|
||||||
return module->first_type + void_offset;
|
return module->scope.types.first + void_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Type* noreturn_type(Module* module)
|
fn Type* noreturn_type(Module* module)
|
||||||
@ -1228,16 +1279,20 @@ fn Type* type_allocate_init(Module* module, Type type)
|
|||||||
auto* result = &arena_allocate<Type>(module->arena, 1)[0];
|
auto* result = &arena_allocate<Type>(module->arena, 1)[0];
|
||||||
*result = type;
|
*result = type;
|
||||||
|
|
||||||
if (module->last_type)
|
auto scope = type.scope;
|
||||||
|
assert(scope);
|
||||||
|
|
||||||
|
if (scope->types.last)
|
||||||
{
|
{
|
||||||
module->last_type->next = result;
|
assert(scope->types.first);
|
||||||
module->last_type = result;
|
scope->types.last->next = result;
|
||||||
|
scope->types.last = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(!module->first_type);
|
assert(!scope->types.first);
|
||||||
module->first_type = result;
|
scope->types.first = result;
|
||||||
module->last_type = result;
|
scope->types.last = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1310,6 +1365,7 @@ fn Type* get_pointer_type(Module* module, Type* element_type)
|
|||||||
},
|
},
|
||||||
.id = TypeId::pointer,
|
.id = TypeId::pointer,
|
||||||
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
||||||
|
.scope = element_type->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (last_pointer_type)
|
if (last_pointer_type)
|
||||||
@ -1394,6 +1450,7 @@ fn Type* get_slice_type(Module* module, Type* element_type)
|
|||||||
},
|
},
|
||||||
.id = TypeId::structure,
|
.id = TypeId::structure,
|
||||||
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
||||||
|
.scope = element_type->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (last_slice_type)
|
if (last_slice_type)
|
||||||
@ -1469,6 +1526,7 @@ fn Type* get_array_type(Module* module, Type* element_type, u64 element_count)
|
|||||||
},
|
},
|
||||||
.id = TypeId::array,
|
.id = TypeId::array,
|
||||||
.name = array_name(module, element_type, element_count),
|
.name = array_name(module, element_type, element_count),
|
||||||
|
.scope = element_type->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (last_array_type)
|
if (last_array_type)
|
||||||
@ -1714,5 +1772,52 @@ fn Local* new_local(Module* module, Scope* scope)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn Type* get_enum_array_type(Module* module, Type* enum_type, Type* element_type)
|
||||||
|
{
|
||||||
|
assert(enum_type);
|
||||||
|
assert(element_type);
|
||||||
|
|
||||||
|
Type* last_enum_type = module->first_enum_array_type;
|
||||||
|
|
||||||
|
if (last_enum_type)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
assert(last_enum_type->id == TypeId::enum_array);
|
||||||
|
|
||||||
|
if (last_enum_type->enum_array.enum_type == enum_type && last_enum_type->enum_array.element_type == element_type)
|
||||||
|
{
|
||||||
|
return last_enum_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!last_enum_type->enum_array.next)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_enum_type = last_enum_type->enum_array.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String name_parts[] = {
|
||||||
|
string_literal("enum_array["),
|
||||||
|
enum_type->name,
|
||||||
|
string_literal("]("),
|
||||||
|
element_type->name,
|
||||||
|
string_literal(")"),
|
||||||
|
};
|
||||||
|
|
||||||
|
auto enum_array_type = type_allocate_init(module, {
|
||||||
|
.enum_array = {
|
||||||
|
.enum_type = enum_type,
|
||||||
|
.element_type = element_type,
|
||||||
|
},
|
||||||
|
.id = TypeId::enum_array,
|
||||||
|
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
||||||
|
});
|
||||||
|
return enum_array_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse(Module* module);
|
void parse(Module* module);
|
||||||
void emit(Module* module);
|
void emit(Module* module);
|
||||||
|
1074
src/emitter.cpp
1074
src/emitter.cpp
File diff suppressed because it is too large
Load Diff
267
src/parser.cpp
267
src/parser.cpp
@ -450,7 +450,6 @@ fn u64 parse_integer_decimal_assume_valid(String string)
|
|||||||
|
|
||||||
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
||||||
|
|
||||||
|
|
||||||
fn Type* parse_type(Module* module, Scope* scope)
|
fn Type* parse_type(Module* module, Scope* scope)
|
||||||
{
|
{
|
||||||
auto start_character = module->content[module->offset];
|
auto start_character = module->content[module->offset];
|
||||||
@ -465,6 +464,20 @@ fn Type* parse_type(Module* module, Scope* scope)
|
|||||||
{
|
{
|
||||||
return noreturn_type(module);
|
return noreturn_type(module);
|
||||||
}
|
}
|
||||||
|
else if (identifier.equal(string_literal("enum_array")))
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
expect_character(module, left_bracket);
|
||||||
|
auto enum_type = parse_type(module, scope);
|
||||||
|
expect_character(module, right_bracket);
|
||||||
|
|
||||||
|
expect_character(module, left_parenthesis);
|
||||||
|
auto element_type = parse_type(module, scope);
|
||||||
|
expect_character(module, right_parenthesis);
|
||||||
|
|
||||||
|
auto enum_array_type = get_enum_array_type(module, enum_type, element_type);
|
||||||
|
return enum_array_type;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto is_int_type = identifier.length > 1 && (identifier[0] == 's' || identifier[0] == 'u');
|
auto is_int_type = identifier.length > 1 && (identifier[0] == 's' || identifier[0] == 'u');
|
||||||
@ -505,12 +518,18 @@ fn Type* parse_type(Module* module, Scope* scope)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (Type* type = module->first_type; type; type = type->next)
|
assert(scope);
|
||||||
|
while (scope)
|
||||||
{
|
{
|
||||||
if (identifier.equal(type->name))
|
for (Type* type = scope->types.first; type; type = type->next)
|
||||||
{
|
{
|
||||||
return type;
|
if (identifier.equal(type->name))
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope = scope->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
report_error();
|
report_error();
|
||||||
@ -1191,6 +1210,89 @@ fn Token tokenize(Module* module)
|
|||||||
|
|
||||||
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
||||||
|
|
||||||
|
fn Value* parse_aggregate_initialization(Module* module, Scope* scope, ValueBuilder builder, u8 end_ch)
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
u64 field_count = 0;
|
||||||
|
|
||||||
|
AggregateInitializationElement element_buffer[64];
|
||||||
|
bool zero = false;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, end_ch))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto field_index = field_count;
|
||||||
|
if (consume_character_if_match(module, '.'))
|
||||||
|
{
|
||||||
|
auto name = parse_identifier(module);
|
||||||
|
skip_space(module);
|
||||||
|
expect_character(module, '=');
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
auto line = get_line(module);
|
||||||
|
auto column = get_column(module);
|
||||||
|
|
||||||
|
auto value = parse_value(module, scope, {});
|
||||||
|
skip_space(module);
|
||||||
|
consume_character_if_match(module, ',');
|
||||||
|
|
||||||
|
element_buffer[field_index] = {
|
||||||
|
.name = name,
|
||||||
|
.value = value,
|
||||||
|
.line = line,
|
||||||
|
.column = column,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto token = tokenize(module);
|
||||||
|
zero = token.id == TokenId::value_keyword && token.value_keyword == ValueKeyword::zero;
|
||||||
|
if (zero)
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, ','))
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_character(module, right_brace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto elements = arena_allocate<AggregateInitializationElement>(module->arena, field_count);
|
||||||
|
memcpy(elements.pointer, element_buffer, sizeof(element_buffer[0]) * field_count);
|
||||||
|
|
||||||
|
auto result = new_value(module);
|
||||||
|
*result = {
|
||||||
|
.aggregate_initialization = {
|
||||||
|
.elements = elements,
|
||||||
|
.scope = scope,
|
||||||
|
.is_constant = false,
|
||||||
|
.zero = zero,
|
||||||
|
},
|
||||||
|
.id = ValueId::aggregate_initialization,
|
||||||
|
.kind = builder.kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
fn Value* parse_precedence(Module* module, Scope* scope, ValueBuilder builder);
|
fn Value* parse_precedence(Module* module, Scope* scope, ValueBuilder builder);
|
||||||
fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||||
{
|
{
|
||||||
@ -1422,33 +1524,42 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
u64 element_count = 0;
|
u64 element_count = 0;
|
||||||
Value* value_buffer[64];
|
Value* value_buffer[64];
|
||||||
|
|
||||||
while (1)
|
skip_space(module);
|
||||||
{
|
|
||||||
skip_space(module);
|
|
||||||
|
|
||||||
if (consume_character_if_match(module, right_bracket))
|
if (module->content[module->offset] == '.')
|
||||||
|
{
|
||||||
|
result = parse_aggregate_initialization(module, scope, builder, right_bracket);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
{
|
{
|
||||||
break;
|
skip_space(module);
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, right_bracket))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = parse_value(module, scope, {});
|
||||||
|
value_buffer[element_count] = value;
|
||||||
|
element_count += 1;
|
||||||
|
|
||||||
|
consume_character_if_match(module, ',');
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = parse_value(module, scope, {});
|
auto values = new_value_array(module, element_count);
|
||||||
value_buffer[element_count] = value;
|
memcpy(values.pointer, value_buffer, element_count * sizeof(Value*));
|
||||||
element_count += 1;
|
|
||||||
|
|
||||||
consume_character_if_match(module, ',');
|
result = new_value(module);
|
||||||
|
*result = {
|
||||||
|
.array_initialization = {
|
||||||
|
.values = values,
|
||||||
|
.is_constant = false, // This is analyzed later
|
||||||
|
},
|
||||||
|
.id = ValueId::array_initialization,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto values = new_value_array(module, element_count);
|
|
||||||
memcpy(values.pointer, value_buffer, element_count * sizeof(Value*));
|
|
||||||
|
|
||||||
result = new_value(module);
|
|
||||||
*result = {
|
|
||||||
.array_initialization = {
|
|
||||||
.values = values,
|
|
||||||
.is_constant = false, // This is analyzed later
|
|
||||||
},
|
|
||||||
.id = ValueId::array_initialization,
|
|
||||||
};
|
|
||||||
} break;
|
} break;
|
||||||
case TokenId::dot:
|
case TokenId::dot:
|
||||||
{
|
{
|
||||||
@ -1477,76 +1588,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
} break;
|
} break;
|
||||||
case TokenId::left_brace:
|
case TokenId::left_brace:
|
||||||
{
|
{
|
||||||
skip_space(module);
|
result = parse_aggregate_initialization(module, scope, builder, right_brace);
|
||||||
|
|
||||||
u64 field_count = 0;
|
|
||||||
String name_buffer[64];
|
|
||||||
Value* value_buffer[64];
|
|
||||||
bool zero = false;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
skip_space(module);
|
|
||||||
|
|
||||||
if (consume_character_if_match(module, right_brace))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto field_index = field_count;
|
|
||||||
if (consume_character_if_match(module, '.'))
|
|
||||||
{
|
|
||||||
auto name = parse_identifier(module);
|
|
||||||
name_buffer[field_index] = name;
|
|
||||||
skip_space(module);
|
|
||||||
expect_character(module, '=');
|
|
||||||
skip_space(module);
|
|
||||||
|
|
||||||
auto value = parse_value(module, scope, {});
|
|
||||||
value_buffer[field_index] = value;
|
|
||||||
skip_space(module);
|
|
||||||
consume_character_if_match(module, ',');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto token = tokenize(module);
|
|
||||||
zero = token.id == TokenId::value_keyword && token.value_keyword == ValueKeyword::zero;
|
|
||||||
if (zero)
|
|
||||||
{
|
|
||||||
skip_space(module);
|
|
||||||
|
|
||||||
if (consume_character_if_match(module, ','))
|
|
||||||
{
|
|
||||||
skip_space(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_character(module, right_brace);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
report_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto names = arena_allocate<String>(module->arena, field_count);
|
|
||||||
memcpy(names.pointer, name_buffer, sizeof(String) * field_count);
|
|
||||||
auto values = new_value_array(module, field_count);
|
|
||||||
memcpy(values.pointer, value_buffer, sizeof(Value*) * field_count);
|
|
||||||
|
|
||||||
result = new_value(module);
|
|
||||||
*result = {
|
|
||||||
.aggregate_initialization = {
|
|
||||||
.names = names,
|
|
||||||
.values = values,
|
|
||||||
.is_constant = false,
|
|
||||||
.zero = zero,
|
|
||||||
},
|
|
||||||
.id = ValueId::aggregate_initialization,
|
|
||||||
};
|
|
||||||
} break;
|
} break;
|
||||||
case TokenId::value_keyword:
|
case TokenId::value_keyword:
|
||||||
{
|
{
|
||||||
@ -2731,7 +2773,7 @@ void parse(Module* module)
|
|||||||
last_global = last_global->next;
|
last_global = last_global->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* type_it = module->first_type;
|
Type* type_it = module->scope.types.first;
|
||||||
Type* forward_declaration = 0;
|
Type* forward_declaration = 0;
|
||||||
while (type_it)
|
while (type_it)
|
||||||
{
|
{
|
||||||
@ -2779,6 +2821,7 @@ void parse(Module* module)
|
|||||||
enumerator,
|
enumerator,
|
||||||
function,
|
function,
|
||||||
macro,
|
macro,
|
||||||
|
opaque,
|
||||||
structure,
|
structure,
|
||||||
typealias,
|
typealias,
|
||||||
union_type,
|
union_type,
|
||||||
@ -2798,6 +2841,7 @@ void parse(Module* module)
|
|||||||
string_literal("enum"),
|
string_literal("enum"),
|
||||||
string_literal("fn"),
|
string_literal("fn"),
|
||||||
string_literal("macro"),
|
string_literal("macro"),
|
||||||
|
string_literal("opaque"),
|
||||||
string_literal("struct"),
|
string_literal("struct"),
|
||||||
string_literal("typealias"),
|
string_literal("typealias"),
|
||||||
string_literal("union"),
|
string_literal("union"),
|
||||||
@ -2904,6 +2948,7 @@ void parse(Module* module)
|
|||||||
},
|
},
|
||||||
.id = TypeId::bits,
|
.id = TypeId::bits,
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
|
.scope = &module->scope,
|
||||||
});
|
});
|
||||||
unused(bits_type);
|
unused(bits_type);
|
||||||
} break;
|
} break;
|
||||||
@ -3018,6 +3063,7 @@ void parse(Module* module)
|
|||||||
},
|
},
|
||||||
.id = TypeId::enumerator,
|
.id = TypeId::enumerator,
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
|
.scope = &module->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
unused(enum_type);
|
unused(enum_type);
|
||||||
@ -3189,6 +3235,7 @@ void parse(Module* module)
|
|||||||
},
|
},
|
||||||
.id = TypeId::function,
|
.id = TypeId::function,
|
||||||
.name = string_literal(""),
|
.name = string_literal(""),
|
||||||
|
.scope = &module->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
auto storage = new_value(module);
|
auto storage = new_value(module);
|
||||||
@ -3255,15 +3302,11 @@ void parse(Module* module)
|
|||||||
} break;
|
} break;
|
||||||
case GlobalKeyword::macro:
|
case GlobalKeyword::macro:
|
||||||
{
|
{
|
||||||
Type* type_argument_buffer[64];
|
|
||||||
u64 type_argument_count = 0;
|
|
||||||
unused(type_argument_buffer);
|
|
||||||
unused(type_argument_count);
|
|
||||||
|
|
||||||
ConstantArgument constant_argument_buffer[64];
|
ConstantArgument constant_argument_buffer[64];
|
||||||
u64 constant_argument_count = 0;
|
u64 constant_argument_count = 0;
|
||||||
|
|
||||||
auto is_generic = consume_character_if_match(module, left_bracket);
|
auto is_generic = consume_character_if_match(module, left_bracket);
|
||||||
|
auto macro_declaration = &arena_allocate<MacroDeclaration>(module->arena, 1)[0];
|
||||||
|
|
||||||
if (is_generic)
|
if (is_generic)
|
||||||
{
|
{
|
||||||
@ -3293,6 +3336,7 @@ void parse(Module* module)
|
|||||||
auto ty = type_allocate_init(module, {
|
auto ty = type_allocate_init(module, {
|
||||||
.id = TypeId::unresolved,
|
.id = TypeId::unresolved,
|
||||||
.name = argument_name,
|
.name = argument_name,
|
||||||
|
.scope = ¯o_declaration->scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
constant_argument_buffer[constant_argument_index] = {
|
constant_argument_buffer[constant_argument_index] = {
|
||||||
@ -3325,7 +3369,6 @@ void parse(Module* module)
|
|||||||
auto constant_arguments = arena_allocate<ConstantArgument>(module->arena, constant_argument_count);
|
auto constant_arguments = arena_allocate<ConstantArgument>(module->arena, constant_argument_count);
|
||||||
memcpy(constant_arguments.pointer, constant_argument_buffer, sizeof(constant_argument_buffer[0]) * constant_argument_count);
|
memcpy(constant_arguments.pointer, constant_argument_buffer, sizeof(constant_argument_buffer[0]) * constant_argument_count);
|
||||||
|
|
||||||
auto macro_declaration = &arena_allocate<MacroDeclaration>(module->arena, 1)[0];
|
|
||||||
*macro_declaration = {
|
*macro_declaration = {
|
||||||
.arguments = {},
|
.arguments = {},
|
||||||
.constant_arguments = constant_arguments,
|
.constant_arguments = constant_arguments,
|
||||||
@ -3432,6 +3475,7 @@ void parse(Module* module)
|
|||||||
struct_type = type_allocate_init(module, {
|
struct_type = type_allocate_init(module, {
|
||||||
.id = TypeId::forward_declaration,
|
.id = TypeId::forward_declaration,
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
|
.scope = &module->scope,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3485,6 +3529,9 @@ void parse(Module* module)
|
|||||||
field_count += 1;
|
field_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte_size = align_forward(byte_size, byte_alignment);
|
||||||
|
assert(byte_size % byte_alignment == 0);
|
||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
consume_character_if_match(module, ';');
|
consume_character_if_match(module, ';');
|
||||||
|
|
||||||
@ -3523,6 +3570,7 @@ void parse(Module* module)
|
|||||||
},
|
},
|
||||||
.id = TypeId::alias,
|
.id = TypeId::alias,
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
|
.scope = scope,
|
||||||
});
|
});
|
||||||
unused(alias_type);
|
unused(alias_type);
|
||||||
} break;
|
} break;
|
||||||
@ -3581,7 +3629,7 @@ void parse(Module* module)
|
|||||||
.line = field_line,
|
.line = field_line,
|
||||||
};
|
};
|
||||||
|
|
||||||
biggest_field = byte_size > field_byte_size ? field_index : biggest_field;
|
biggest_field = field_byte_size > byte_size ? field_index : biggest_field;
|
||||||
byte_alignment = MAX(byte_alignment, field_byte_alignment);
|
byte_alignment = MAX(byte_alignment, field_byte_alignment);
|
||||||
byte_size = MAX(byte_size, field_byte_size);
|
byte_size = MAX(byte_size, field_byte_size);
|
||||||
|
|
||||||
@ -3596,6 +3644,9 @@ void parse(Module* module)
|
|||||||
auto fields = arena_allocate<UnionField>(module->arena, field_count);
|
auto fields = arena_allocate<UnionField>(module->arena, field_count);
|
||||||
memcpy(fields.pointer, field_buffer, sizeof(field_buffer[0]) * field_count);
|
memcpy(fields.pointer, field_buffer, sizeof(field_buffer[0]) * field_count);
|
||||||
|
|
||||||
|
auto biggest_size = get_byte_size(fields[biggest_field].type);
|
||||||
|
assert(biggest_size == byte_size);
|
||||||
|
|
||||||
union_type->union_type = {
|
union_type->union_type = {
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
.byte_size = byte_size,
|
.byte_size = byte_size,
|
||||||
@ -3605,6 +3656,16 @@ void parse(Module* module)
|
|||||||
};
|
};
|
||||||
union_type->id = TypeId::union_type;
|
union_type->id = TypeId::union_type;
|
||||||
} break;
|
} break;
|
||||||
|
case GlobalKeyword::opaque:
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
expect_character(module, ';');
|
||||||
|
auto opaque_type = type_allocate_init(module, {
|
||||||
|
.id = TypeId::opaque,
|
||||||
|
.name = global_name,
|
||||||
|
});
|
||||||
|
unused(opaque_type);
|
||||||
|
} break;
|
||||||
case GlobalKeyword::count:
|
case GlobalKeyword::count:
|
||||||
{
|
{
|
||||||
set_checkpoint(module, checkpoint);
|
set_checkpoint(module, checkpoint);
|
||||||
|
140
tests/basic_struct_passing.bbb
Normal file
140
tests/basic_struct_passing.bbb
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
CallingConvention = enum
|
||||||
|
{
|
||||||
|
c,
|
||||||
|
}
|
||||||
|
|
||||||
|
InlineBehavior = enum
|
||||||
|
{
|
||||||
|
default = 0,
|
||||||
|
always_inline = 1,
|
||||||
|
no_inline = 2,
|
||||||
|
inline_hint = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionAttributes = struct
|
||||||
|
{
|
||||||
|
inline_behavior: InlineBehavior,
|
||||||
|
naked: u1,
|
||||||
|
}
|
||||||
|
|
||||||
|
Type = struct;
|
||||||
|
|
||||||
|
TypeId = enum
|
||||||
|
{
|
||||||
|
void,
|
||||||
|
noreturn,
|
||||||
|
forward_declaration,
|
||||||
|
integer,
|
||||||
|
function,
|
||||||
|
pointer,
|
||||||
|
array,
|
||||||
|
enum,
|
||||||
|
struct,
|
||||||
|
bits,
|
||||||
|
alias,
|
||||||
|
union,
|
||||||
|
unresolved,
|
||||||
|
vector,
|
||||||
|
floating_point,
|
||||||
|
enum_array,
|
||||||
|
opaque,
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInteger = struct
|
||||||
|
{
|
||||||
|
bit_count: u32,
|
||||||
|
signed: u1,
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePointer = struct
|
||||||
|
{
|
||||||
|
element_type: &Type,
|
||||||
|
next: &Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
AbiRegisterCountSystemV = struct
|
||||||
|
{
|
||||||
|
gpr: u32,
|
||||||
|
sse: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
AbiRegisterCount = union
|
||||||
|
{
|
||||||
|
system_v: AbiRegisterCountSystemV,
|
||||||
|
};
|
||||||
|
|
||||||
|
AbiInformation = struct
|
||||||
|
{
|
||||||
|
foo: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeFunction = struct
|
||||||
|
{
|
||||||
|
semantic_return_type: &Type,
|
||||||
|
semantic_argument_types: []&Type,
|
||||||
|
calling_convention: CallingConvention,
|
||||||
|
is_variable_arguments: u1,
|
||||||
|
|
||||||
|
abi_argument_types: []&Type,
|
||||||
|
abi_return_type: &Type,
|
||||||
|
available_registers: AbiRegisterCount,
|
||||||
|
argument_abis: []AbiInformation,
|
||||||
|
return_abi: AbiInformation,
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeContent = union
|
||||||
|
{
|
||||||
|
integer: TypeInteger,
|
||||||
|
function: TypeFunction,
|
||||||
|
pointer: TypePointer,
|
||||||
|
}
|
||||||
|
|
||||||
|
Type = struct
|
||||||
|
{
|
||||||
|
content: TypeContent,
|
||||||
|
id: TypeId,
|
||||||
|
name: []u8,
|
||||||
|
next: &Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
give_me_string = fn () []u8
|
||||||
|
{
|
||||||
|
return "foooo";
|
||||||
|
}
|
||||||
|
|
||||||
|
get_type = fn (src: &Type, type: Type) &Type
|
||||||
|
{
|
||||||
|
src.& = type;
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
require = fn (ok: u1) void
|
||||||
|
{
|
||||||
|
if (!ok) #trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>buffer: Type = undefined;
|
||||||
|
>pointer = &buffer;
|
||||||
|
require(pointer == &buffer);
|
||||||
|
require(pointer != zero);
|
||||||
|
>result = get_type(pointer, {
|
||||||
|
.content = {
|
||||||
|
.pointer = {
|
||||||
|
.element_type = pointer,
|
||||||
|
zero,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .pointer,
|
||||||
|
.name = give_me_string(),
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
require(pointer != zero);
|
||||||
|
require(pointer == &buffer);
|
||||||
|
require(buffer.content.pointer.element_type == pointer);
|
||||||
|
require(buffer.id == .pointer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
22
tests/enum_array.bbb
Normal file
22
tests/enum_array.bbb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
require = fn (ok: u1) void
|
||||||
|
{
|
||||||
|
if (!ok) #trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
E = enum
|
||||||
|
{
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>some_enum_array: enum_array[E](u32) = [ .a = 4, .b = 3, .c = 2, .d = 1 ];
|
||||||
|
require(some_enum_array[.a] == 4);
|
||||||
|
require(some_enum_array[.b] == 3);
|
||||||
|
require(some_enum_array[.c] == 2);
|
||||||
|
require(some_enum_array[.d] == 1);
|
||||||
|
return 0;
|
||||||
|
}
|
16
tests/opaque.bbb
Normal file
16
tests/opaque.bbb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
OpaqueType = opaque;
|
||||||
|
|
||||||
|
[extern] memcpy = fn [cc(c)] (destination: &s32, source: &s32, size: u64) &OpaqueType;
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>destination: s32 = 1;
|
||||||
|
>source: s32 = 0;
|
||||||
|
>opaque_pointer = memcpy(&destination, &source, #byte_size(s32));
|
||||||
|
>pointer: &s32 = #pointer_cast(opaque_pointer);
|
||||||
|
if (pointer != &destination)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user