462 lines
7.3 KiB
C++
462 lines
7.3 KiB
C++
#pragma once
|
|
|
|
#include <lib.h>
|
|
|
|
#define report_error() trap_raw()
|
|
|
|
enum class Command
|
|
{
|
|
compile,
|
|
test,
|
|
count,
|
|
};
|
|
|
|
enum class BuildMode
|
|
{
|
|
debug_none,
|
|
debug,
|
|
soft_optimize,
|
|
optimize_for_speed,
|
|
optimize_for_size,
|
|
aggressively_optimize_for_speed,
|
|
aggressively_optimize_for_size,
|
|
count,
|
|
};
|
|
|
|
fn String build_mode_to_string(BuildMode build_mode)
|
|
{
|
|
switch (build_mode)
|
|
{
|
|
case_to_name(BuildMode, debug_none);
|
|
case_to_name(BuildMode, debug);
|
|
case_to_name(BuildMode, soft_optimize);
|
|
case_to_name(BuildMode, optimize_for_speed);
|
|
case_to_name(BuildMode, optimize_for_size);
|
|
case_to_name(BuildMode, aggressively_optimize_for_speed);
|
|
case_to_name(BuildMode, aggressively_optimize_for_size);
|
|
case BuildMode::count: unreachable();
|
|
}
|
|
}
|
|
|
|
enum class CPUArchitecture
|
|
{
|
|
x86_64,
|
|
};
|
|
|
|
enum class OperatingSystem
|
|
{
|
|
linux_,
|
|
};
|
|
|
|
struct Type;
|
|
struct Value;
|
|
struct Local;
|
|
struct Global;
|
|
struct Block;
|
|
struct Statement;
|
|
|
|
struct Target
|
|
{
|
|
CPUArchitecture cpu;
|
|
OperatingSystem os;
|
|
};
|
|
|
|
struct Compile
|
|
{
|
|
String relative_file_path;
|
|
BuildMode build_mode;
|
|
bool has_debug_info;
|
|
bool silent;
|
|
};
|
|
|
|
#define base_cache_dir "bb-cache"
|
|
|
|
enum class CallingConvention
|
|
{
|
|
c,
|
|
count,
|
|
};
|
|
|
|
enum class InlineBehavior
|
|
{
|
|
normal,
|
|
always_inline,
|
|
no_inline,
|
|
inline_hint,
|
|
};
|
|
|
|
struct FunctionAttributes
|
|
{
|
|
InlineBehavior inline_behavior;
|
|
bool naked;
|
|
};
|
|
|
|
enum class TypeId
|
|
{
|
|
void_type,
|
|
noreturn,
|
|
forward_declaration,
|
|
integer,
|
|
function,
|
|
pointer,
|
|
};
|
|
|
|
struct TypeInteger
|
|
{
|
|
u32 bit_count;
|
|
bool is_signed;
|
|
};
|
|
|
|
struct TypeFunction
|
|
{
|
|
Type* semantic_return_type;
|
|
Slice<Type*> semantic_argument_types;
|
|
CallingConvention calling_convention;
|
|
bool is_variable_arguments;
|
|
};
|
|
|
|
struct TypePointer
|
|
{
|
|
Type* element_type;
|
|
Type* next;
|
|
};
|
|
|
|
struct Type
|
|
{
|
|
union
|
|
{
|
|
TypeInteger integer;
|
|
TypeFunction function;
|
|
TypePointer pointer;
|
|
};
|
|
TypeId id;
|
|
String name;
|
|
Type* next;
|
|
};
|
|
|
|
enum class ScopeKind
|
|
{
|
|
global,
|
|
function,
|
|
local,
|
|
for_each,
|
|
macro_declaration,
|
|
macro_instantiation,
|
|
};
|
|
|
|
struct Scope
|
|
{
|
|
Scope* parent;
|
|
u32 line;
|
|
u32 column;
|
|
ScopeKind kind;
|
|
};
|
|
|
|
enum class StatementId
|
|
{
|
|
local,
|
|
expression,
|
|
return_st,
|
|
};
|
|
|
|
struct Statement
|
|
{
|
|
union
|
|
{
|
|
Local* local;
|
|
Value* expression;
|
|
Value* return_st;
|
|
};
|
|
Statement* next;
|
|
StatementId id;
|
|
u32 line;
|
|
u32 column;
|
|
};
|
|
|
|
struct Block
|
|
{
|
|
Local* first_local;
|
|
Local* last_local;
|
|
Statement* first_statement;
|
|
Scope scope;
|
|
};
|
|
|
|
enum class ValueId
|
|
{
|
|
infer_or_ignore,
|
|
external_function,
|
|
function,
|
|
constant_integer,
|
|
unary,
|
|
binary,
|
|
};
|
|
|
|
enum class ValueKind
|
|
{
|
|
right,
|
|
left,
|
|
};
|
|
|
|
struct ValueConstantInteger
|
|
{
|
|
u64 value;
|
|
bool is_signed;
|
|
};
|
|
|
|
struct ValueFunction
|
|
{
|
|
Slice<Local*> arguments;
|
|
Scope scope;
|
|
Block* block;
|
|
FunctionAttributes attributes;
|
|
};
|
|
|
|
enum class UnaryId
|
|
{
|
|
minus,
|
|
plus,
|
|
ampersand,
|
|
exclamation,
|
|
tilde,
|
|
};
|
|
|
|
struct ValueUnary
|
|
{
|
|
Value* value;
|
|
UnaryId id;
|
|
};
|
|
|
|
enum class BinaryId
|
|
{
|
|
add,
|
|
sub,
|
|
mul,
|
|
div,
|
|
rem,
|
|
bitwise_and,
|
|
bitwise_or,
|
|
bitwise_xor,
|
|
shift_left,
|
|
shift_right,
|
|
compare_equal,
|
|
compare_not_equal,
|
|
compare_greater,
|
|
compare_less,
|
|
compare_greater_equal,
|
|
compare_less_equal,
|
|
logical_and,
|
|
logical_or,
|
|
logical_and_shortcircuit,
|
|
logical_or_shortcircuit,
|
|
};
|
|
|
|
struct ValueBinary
|
|
{
|
|
Value* left;
|
|
Value* right;
|
|
BinaryId id;
|
|
};
|
|
|
|
struct Value
|
|
{
|
|
Type* type;
|
|
union
|
|
{
|
|
ValueConstantInteger constant_integer;
|
|
ValueFunction function;
|
|
ValueUnary unary;
|
|
ValueBinary binary;
|
|
};
|
|
ValueId id;
|
|
};
|
|
|
|
struct Variable
|
|
{
|
|
Value* storage;
|
|
Value* initial_value;
|
|
Type* type;
|
|
Scope* scope;
|
|
String name;
|
|
u32 line;
|
|
u32 column;
|
|
};
|
|
|
|
enum class Linkage
|
|
{
|
|
internal,
|
|
external,
|
|
};
|
|
|
|
struct Global
|
|
{
|
|
Variable variable;
|
|
Linkage linkage;
|
|
Global* next;
|
|
};
|
|
|
|
struct Local
|
|
{
|
|
Variable variable;
|
|
};
|
|
|
|
struct MacroDeclaration
|
|
{
|
|
};
|
|
|
|
struct MacroInstantiation
|
|
{
|
|
};
|
|
|
|
struct Module
|
|
{
|
|
Arena& arena;
|
|
String content;
|
|
u64 offset;
|
|
u64 line_offset;
|
|
u64 line_character_offset;
|
|
|
|
Type* first_pointer_type;
|
|
Type* first_slice_type;
|
|
Type* first_pair_struct_type;
|
|
Type* first_array_type;
|
|
|
|
Type* first_type;
|
|
Type* last_type;
|
|
Type* va_list_type;
|
|
|
|
Value* void_value;
|
|
Global* first_global;
|
|
Global* last_global;
|
|
Global* current_function;
|
|
MacroDeclaration* current_macro_declaration;
|
|
MacroInstantiation* current_macro_instantiation;
|
|
|
|
Scope scope;
|
|
|
|
String name;
|
|
String path;
|
|
String executable;
|
|
Slice<String>objects;
|
|
|
|
Target target;
|
|
BuildMode build_mode;
|
|
bool has_debug_info;
|
|
bool silent;
|
|
};
|
|
|
|
constexpr u64 i128_offset = 64 * 2;
|
|
constexpr u64 void_offset = i128_offset + 2;
|
|
|
|
fn Type* integer_type(Module& module, TypeInteger integer)
|
|
{
|
|
assert(integer.bit_count);
|
|
assert(integer.bit_count <= 64 || integer.bit_count == 128);
|
|
auto index = integer.bit_count ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
|
|
return module.first_type + index;
|
|
}
|
|
|
|
fn Type* void_type(Module& module)
|
|
{
|
|
return module.first_type + void_offset;
|
|
}
|
|
|
|
fn Type* noreturn_type(Module& module)
|
|
{
|
|
return void_type(module) + 1;
|
|
}
|
|
|
|
struct Options
|
|
{
|
|
String content;
|
|
String path;
|
|
String executable;
|
|
String name;
|
|
Slice<String> objects;
|
|
Target target;
|
|
BuildMode build_mode;
|
|
bool has_debug_info;
|
|
bool silent;
|
|
};
|
|
|
|
fn Type* type_allocate_init(Module& module, Type type)
|
|
{
|
|
auto* result = &arena_allocate<Type>(module.arena, 1)[0];
|
|
*result = type;
|
|
|
|
if (module.last_type)
|
|
{
|
|
module.last_type->next = result;
|
|
module.last_type = result;
|
|
}
|
|
else
|
|
{
|
|
assert(!module.first_type);
|
|
module.first_type = result;
|
|
module.last_type = result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
fn Value* new_value(Module& module)
|
|
{
|
|
auto* result = &arena_allocate<Value>(module.arena, 1)[0];
|
|
return result;
|
|
}
|
|
|
|
fn Global* new_global(Module& module)
|
|
{
|
|
auto* result = &arena_allocate<Global>(module.arena, 1)[0];
|
|
|
|
if (module.last_global)
|
|
{
|
|
module.last_global->next = result;
|
|
module.last_global = result;
|
|
}
|
|
else
|
|
{
|
|
assert(!module.first_global);
|
|
module.first_global = result;
|
|
module.last_global = result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
fn Type* get_pointer_type(Module& module, Type* element_type)
|
|
{
|
|
auto last_pointer_type = module.first_pointer_type;
|
|
while (last_pointer_type)
|
|
{
|
|
assert(last_pointer_type->id == TypeId::pointer);
|
|
if (last_pointer_type->pointer.element_type == element_type)
|
|
{
|
|
return last_pointer_type;
|
|
}
|
|
|
|
if (!last_pointer_type->pointer.next)
|
|
{
|
|
break;
|
|
}
|
|
|
|
last_pointer_type = last_pointer_type->pointer.next;
|
|
}
|
|
|
|
String name_parts[] = {
|
|
str("&"),
|
|
element_type->name,
|
|
};
|
|
auto result = type_allocate_init(module, {
|
|
.pointer = {
|
|
.element_type = element_type,
|
|
},
|
|
.id = TypeId::pointer,
|
|
.name = arena_join_string(module.arena, array_to_slice(name_parts)),
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
void parse(Module& module);
|
|
void emit(Module& module);
|