#pragma once #include #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 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 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; Sliceobjects; 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 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(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(module.arena, 1)[0]; return result; } fn Global* new_global(Module& module) { auto* result = &arena_allocate(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);