wip
This commit is contained in:
		
							parent
							
								
									c07849aa79
								
							
						
					
					
						commit
						ba48187e57
					
				@ -21,6 +21,7 @@ add_executable(bb
 | 
				
			|||||||
    src/llvm.cpp
 | 
					    src/llvm.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_include_directories(bb PUBLIC src)
 | 
					target_include_directories(bb PUBLIC src)
 | 
				
			||||||
target_compile_definitions(bb PUBLIC
 | 
					target_compile_definitions(bb PUBLIC
 | 
				
			||||||
  $<$<CONFIG:Debug>:BB_DEBUG=1>
 | 
					  $<$<CONFIG:Debug>:BB_DEBUG=1>
 | 
				
			||||||
@ -45,5 +46,9 @@ target_link_libraries(bb PUBLIC
 | 
				
			|||||||
    # ${LLD_WASM}
 | 
					    # ${LLD_WASM}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#target_compile_options(bb PRIVATE -fsanitize=address)
 | 
					target_compile_options(bb PRIVATE -Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -funsigned-char -fwrapv -fno-strict-aliasing)
 | 
				
			||||||
#target_link_options(bb PRIVATE -fsanitize=address)
 | 
					if (NOT APPLE)
 | 
				
			||||||
 | 
					    target_compile_options(bb PRIVATE -Wno-missing-designated-field-initializers)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					# target_compile_options(bb PRIVATE -fsanitize=address)
 | 
				
			||||||
 | 
					# target_link_options(bb PRIVATE -fsanitize=address)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								generate.sh
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								generate.sh
									
									
									
									
									
								
							@ -1,7 +1,34 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
rm -rf build
 | 
					CMAKE_BUILD_TYPE=Debug
 | 
				
			||||||
mkdir build
 | 
					LLVM_CMAKE_BUILD_TYPE=Release
 | 
				
			||||||
cd build
 | 
					BUILD_DIR=build
 | 
				
			||||||
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=MOLD -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release -DCMAKE_COLOR_DIAGNOSTICS=ON
 | 
					
 | 
				
			||||||
 | 
					BIRTH_NATIVE_OS_STRING=$OSTYPE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$BIRTH_NATIVE_OS_STRING" in
 | 
				
			||||||
 | 
					    darwin*) BIRTH_OS="macos";;
 | 
				
			||||||
 | 
					    linux*) BIRTH_OS="linux";;
 | 
				
			||||||
 | 
					    msys*) BIRTH_OS="windows";;
 | 
				
			||||||
 | 
					    *) exit 1
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BIRTH_NATIVE_ARCH_STRING="$(uname -m)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$BIRTH_NATIVE_ARCH_STRING" in
 | 
				
			||||||
 | 
					    x86_64) BIRTH_ARCH="x86_64";;
 | 
				
			||||||
 | 
					    arm64) BIRTH_ARCH="aarch64";;
 | 
				
			||||||
 | 
					    *) exit 1
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$BIRTH_OS" in
 | 
				
			||||||
 | 
					    linux) LINKER_TYPE=MOLD;;
 | 
				
			||||||
 | 
					    *) LINKER_TYPE=DEFAULT;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rm -rf $BUILD_DIR
 | 
				
			||||||
 | 
					mkdir $BUILD_DIR
 | 
				
			||||||
 | 
					cd $BUILD_DIR
 | 
				
			||||||
 | 
					cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=$LINKER_TYPE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=$HOME/dev/llvm/install/llvm_20.1.3_$BIRTH_ARCH-$BIRTH_OS-$LLVM_CMAKE_BUILD_TYPE -DCMAKE_COLOR_DIAGNOSTICS=ON
 | 
				
			||||||
cd ..
 | 
					cd ..
 | 
				
			||||||
 | 
				
			|||||||
@ -60,7 +60,7 @@ fn void compile(Arena* arena, Options options)
 | 
				
			|||||||
    type_it += 1;
 | 
					    type_it += 1;
 | 
				
			||||||
    auto noreturn_type = type_it;
 | 
					    auto noreturn_type = type_it;
 | 
				
			||||||
    type_it += 1;
 | 
					    type_it += 1;
 | 
				
			||||||
    assert(type_it - base_type_allocation.pointer == base_allocation_type_count);
 | 
					    assert((u64)(type_it - base_type_allocation.pointer) == base_allocation_type_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    previous->next = void_type;
 | 
					    previous->next = void_type;
 | 
				
			||||||
    *void_type = {
 | 
					    *void_type = {
 | 
				
			||||||
@ -260,12 +260,14 @@ global_variable String names[] = {
 | 
				
			|||||||
    string_literal("c_string_to_slice"),
 | 
					    string_literal("c_string_to_slice"),
 | 
				
			||||||
    string_literal("c_struct_with_array"),
 | 
					    string_literal("c_struct_with_array"),
 | 
				
			||||||
    string_literal("c_function_pointer"),
 | 
					    string_literal("c_function_pointer"),
 | 
				
			||||||
 | 
					    string_literal("basic_bool_call"),
 | 
				
			||||||
    string_literal("c_abi"),
 | 
					    string_literal("c_abi"),
 | 
				
			||||||
    string_literal("string_to_enum"),
 | 
					    string_literal("string_to_enum"),
 | 
				
			||||||
    string_literal("abi_enum_bool"),
 | 
					    string_literal("abi_enum_bool"),
 | 
				
			||||||
    string_literal("empty_if"),
 | 
					    string_literal("empty_if"),
 | 
				
			||||||
    string_literal("else_if"),
 | 
					    string_literal("else_if"),
 | 
				
			||||||
    string_literal("else_if_complicated"),
 | 
					    string_literal("else_if_complicated"),
 | 
				
			||||||
 | 
					    string_literal("basic_shortcircuiting_if"),
 | 
				
			||||||
    string_literal("shortcircuiting_if"),
 | 
					    string_literal("shortcircuiting_if"),
 | 
				
			||||||
    string_literal("field_access_left_assign"),
 | 
					    string_literal("field_access_left_assign"),
 | 
				
			||||||
    string_literal("for_each"),
 | 
					    string_literal("for_each"),
 | 
				
			||||||
@ -280,8 +282,8 @@ global_variable String names[] = {
 | 
				
			|||||||
    string_literal("basic_union"),
 | 
					    string_literal("basic_union"),
 | 
				
			||||||
    string_literal("break_continue"),
 | 
					    string_literal("break_continue"),
 | 
				
			||||||
    string_literal("constant_global_reference"),
 | 
					    string_literal("constant_global_reference"),
 | 
				
			||||||
    string_literal("self_referential_struct"),
 | 
					    // string_literal("self_referential_struct"), // TODO
 | 
				
			||||||
    string_literal("forward_declared_type"),
 | 
					    // string_literal("forward_declared_type"),
 | 
				
			||||||
    string_literal("basic_macro"),
 | 
					    string_literal("basic_macro"),
 | 
				
			||||||
    string_literal("generic_macro"),
 | 
					    string_literal("generic_macro"),
 | 
				
			||||||
    string_literal("generic_pointer_macro"),
 | 
					    string_literal("generic_pointer_macro"),
 | 
				
			||||||
@ -291,6 +293,7 @@ global_variable String names[] = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
 | 
					void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    unused(environment);
 | 
				
			||||||
    Arena* arena = arena_initialize_default(8 * mb);
 | 
					    Arena* arena = arena_initialize_default(8 * mb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (arguments.length < 2)
 | 
					    if (arguments.length < 2)
 | 
				
			||||||
@ -407,7 +410,7 @@ void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
 | 
				
			|||||||
                        .relative_file_path = relative_file_path,
 | 
					                        .relative_file_path = relative_file_path,
 | 
				
			||||||
                        .build_mode = build_mode,
 | 
					                        .build_mode = build_mode,
 | 
				
			||||||
                        .has_debug_info = has_debug_info,
 | 
					                        .has_debug_info = has_debug_info,
 | 
				
			||||||
                        .silent = false,
 | 
					                        .silent = true,
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // TODO: introduce test
 | 
					                // TODO: introduce test
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										654
									
								
								src/compiler.h
									
									
									
									
									
								
							
							
						
						
									
										654
									
								
								src/compiler.h
									
									
									
									
									
								
							@ -1,8 +1,8 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <lib.h>
 | 
					#include <lib.h>
 | 
				
			||||||
 | 
					#include <llvm-c/Types.h>
 | 
				
			||||||
#define report_error() trap_raw()
 | 
					#define report_error() trap()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Command
 | 
					enum class Command
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -38,6 +38,23 @@ fn String build_mode_to_string(BuildMode build_mode)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn bool build_mode_is_optimized(BuildMode build_mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (build_mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case BuildMode::debug_none:
 | 
				
			||||||
 | 
					        case BuildMode::debug:
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        case BuildMode::soft_optimize:
 | 
				
			||||||
 | 
					        case BuildMode::optimize_for_speed:
 | 
				
			||||||
 | 
					        case BuildMode::optimize_for_size:
 | 
				
			||||||
 | 
					        case BuildMode::aggressively_optimize_for_speed:
 | 
				
			||||||
 | 
					        case BuildMode::aggressively_optimize_for_size:
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        case BuildMode::count: unreachable();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class ValueKind
 | 
					enum class ValueKind
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    right,
 | 
					    right,
 | 
				
			||||||
@ -65,6 +82,165 @@ struct Argument;
 | 
				
			|||||||
struct Scope;
 | 
					struct Scope;
 | 
				
			||||||
struct MacroDeclaration;
 | 
					struct MacroDeclaration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DirectAttributes
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u32 offset;
 | 
				
			||||||
 | 
					    u32 alignment;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct IndirectAttributes
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u32 alignment;
 | 
				
			||||||
 | 
					    u32 address_space;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class AbiKind : u8
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ignore,
 | 
				
			||||||
 | 
					    direct,
 | 
				
			||||||
 | 
					    extend,
 | 
				
			||||||
 | 
					    indirect,
 | 
				
			||||||
 | 
					    indirect_aliased,
 | 
				
			||||||
 | 
					    expand,
 | 
				
			||||||
 | 
					    coerce_and_expand,
 | 
				
			||||||
 | 
					    in_alloca,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AbiFlags
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AbiKind kind;
 | 
				
			||||||
 | 
					    bool padding_in_reg;
 | 
				
			||||||
 | 
					    bool in_alloca_sret;
 | 
				
			||||||
 | 
					    bool in_alloca_indirect;
 | 
				
			||||||
 | 
					    bool indirect_by_value;
 | 
				
			||||||
 | 
					    bool indirect_realign;
 | 
				
			||||||
 | 
					    bool sret_after_this;
 | 
				
			||||||
 | 
					    bool in_reg;
 | 
				
			||||||
 | 
					    bool can_be_flattened;
 | 
				
			||||||
 | 
					    bool sign_extension;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AbiInformation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Type* semantic_type;
 | 
				
			||||||
 | 
					    Type* coerce_to_type;
 | 
				
			||||||
 | 
					    union
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Type* type;
 | 
				
			||||||
 | 
					        Type* unpadded_coerce_and_expand_type;
 | 
				
			||||||
 | 
					    } padding;
 | 
				
			||||||
 | 
					    u16 padding_argument_index;
 | 
				
			||||||
 | 
					    union
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DirectAttributes direct;
 | 
				
			||||||
 | 
					        IndirectAttributes indirect;
 | 
				
			||||||
 | 
					        u32 alloca_field_index;
 | 
				
			||||||
 | 
					    } attributes;
 | 
				
			||||||
 | 
					    AbiFlags flags;
 | 
				
			||||||
 | 
					    u16 abi_start;
 | 
				
			||||||
 | 
					    u16 abi_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_sret_after_this(bool sret_after_this)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::indirect);
 | 
				
			||||||
 | 
					        flags.sret_after_this = sret_after_this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_indirect_realign(bool realign)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::indirect);
 | 
				
			||||||
 | 
					        flags.indirect_realign = realign;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_indirect_by_value(bool by_value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::indirect);
 | 
				
			||||||
 | 
					        flags.indirect_by_value = by_value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_indirect_align(u32 alignment)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::indirect || flags.kind == AbiKind::indirect_aliased);
 | 
				
			||||||
 | 
					        attributes.indirect.alignment = alignment;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline bool can_have_coerce_to_type()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (flags.kind)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case AbiKind::direct:
 | 
				
			||||||
 | 
					            case AbiKind::extend:
 | 
				
			||||||
 | 
					            case AbiKind::coerce_and_expand:
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_coerce_to_type(Type* coerce_to_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(can_have_coerce_to_type());
 | 
				
			||||||
 | 
					        this->coerce_to_type = coerce_to_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline Type* get_coerce_to_type()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(can_have_coerce_to_type());
 | 
				
			||||||
 | 
					        return coerce_to_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_padding_type(Type* padding_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(can_have_padding_type());
 | 
				
			||||||
 | 
					        padding = {
 | 
				
			||||||
 | 
					            .type = padding_type,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline bool can_have_padding_type()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (flags.kind)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case AbiKind::direct:
 | 
				
			||||||
 | 
					            case AbiKind::extend:
 | 
				
			||||||
 | 
					            case AbiKind::indirect:
 | 
				
			||||||
 | 
					            case AbiKind::indirect_aliased:
 | 
				
			||||||
 | 
					            case AbiKind::expand:
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline Type* get_padding_type()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return can_have_padding_type() ? padding.type : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_direct_offset(u32 offset)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
 | 
				
			||||||
 | 
					        attributes.direct.offset = offset;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_direct_alignment(u32 alignment)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
 | 
				
			||||||
 | 
					        attributes.direct.alignment = alignment;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_can_be_flattened(bool can_be_flattened)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(flags.kind == AbiKind::direct);
 | 
				
			||||||
 | 
					        flags.can_be_flattened = can_be_flattened;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline bool get_can_be_flattened()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return flags.can_be_flattened;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Target
 | 
					struct Target
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUArchitecture cpu;
 | 
					    CPUArchitecture cpu;
 | 
				
			||||||
@ -87,6 +263,24 @@ enum class CallingConvention
 | 
				
			|||||||
    count,
 | 
					    count,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class ResolvedCallingConvention
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    system_v,
 | 
				
			||||||
 | 
					    win64,
 | 
				
			||||||
 | 
					    count,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn ResolvedCallingConvention resolve_calling_convention(CallingConvention cc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (cc)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case CallingConvention::c:
 | 
				
			||||||
 | 
					            // TODO:
 | 
				
			||||||
 | 
					            return ResolvedCallingConvention::system_v;
 | 
				
			||||||
 | 
					        case CallingConvention::count: unreachable();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class InlineBehavior
 | 
					enum class InlineBehavior
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    normal,
 | 
					    normal,
 | 
				
			||||||
@ -116,6 +310,8 @@ enum class TypeId
 | 
				
			|||||||
    alias,
 | 
					    alias,
 | 
				
			||||||
    union_type,
 | 
					    union_type,
 | 
				
			||||||
    unresolved,
 | 
					    unresolved,
 | 
				
			||||||
 | 
					    vector,
 | 
				
			||||||
 | 
					    floating_point,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TypeInteger
 | 
					struct TypeInteger
 | 
				
			||||||
@ -124,12 +320,29 @@ struct TypeInteger
 | 
				
			|||||||
    bool is_signed;
 | 
					    bool is_signed;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AbiRegisterCountSystemV
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u32 gpr;
 | 
				
			||||||
 | 
					    u32 sse;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					union AbiRegisterCount
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AbiRegisterCountSystemV system_v;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TypeFunction
 | 
					struct TypeFunction
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Type* semantic_return_type;
 | 
					    Type* semantic_return_type;
 | 
				
			||||||
    Slice<Type*> semantic_argument_types;
 | 
					    Slice<Type*> semantic_argument_types;
 | 
				
			||||||
    CallingConvention calling_convention;
 | 
					    CallingConvention calling_convention;
 | 
				
			||||||
    bool is_variable_arguments;
 | 
					    bool is_variable_arguments;
 | 
				
			||||||
 | 
					    // ABI
 | 
				
			||||||
 | 
					    Slice<Type*> abi_argument_types;
 | 
				
			||||||
 | 
					    Type* abi_return_type;
 | 
				
			||||||
 | 
					    AbiRegisterCount available_registers;
 | 
				
			||||||
 | 
					    Slice<AbiInformation> argument_abis;
 | 
				
			||||||
 | 
					    AbiInformation return_abi;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TypePointer
 | 
					struct TypePointer
 | 
				
			||||||
@ -140,8 +353,9 @@ struct TypePointer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct TypeArray 
 | 
					struct TypeArray 
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    u64 element_count;
 | 
					 | 
				
			||||||
    Type* element_type;
 | 
					    Type* element_type;
 | 
				
			||||||
 | 
					    u64 element_count;
 | 
				
			||||||
 | 
					    Type* next;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct UnresolvedEnumField
 | 
					struct UnresolvedEnumField
 | 
				
			||||||
@ -169,6 +383,10 @@ struct TypeEnum
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    Slice<EnumField> fields;
 | 
					    Slice<EnumField> fields;
 | 
				
			||||||
    Type* backing_type;
 | 
					    Type* backing_type;
 | 
				
			||||||
 | 
					    LLVMValueRef enum_to_string_function;
 | 
				
			||||||
 | 
					    LLVMValueRef string_to_enum_function;
 | 
				
			||||||
 | 
					    Type* string_to_enum_struct_type;
 | 
				
			||||||
 | 
					    Global* name_array;
 | 
				
			||||||
    u32 line;
 | 
					    u32 line;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,6 +439,13 @@ struct TypeUnion
 | 
				
			|||||||
    u32 biggest_field;
 | 
					    u32 biggest_field;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LLVMType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LLVMTypeRef abi;
 | 
				
			||||||
 | 
					    LLVMTypeRef memory;
 | 
				
			||||||
 | 
					    LLVMMetadataRef debug;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Type
 | 
					struct Type
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    union
 | 
					    union
 | 
				
			||||||
@ -238,6 +463,7 @@ struct Type
 | 
				
			|||||||
    TypeId id;
 | 
					    TypeId id;
 | 
				
			||||||
    String name;
 | 
					    String name;
 | 
				
			||||||
    Type* next;
 | 
					    Type* next;
 | 
				
			||||||
 | 
					    LLVMType llvm;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn u32 align_bit_count(u32 bit_count)
 | 
					fn u32 align_bit_count(u32 bit_count)
 | 
				
			||||||
@ -263,6 +489,10 @@ fn u64 get_byte_size(Type* type)
 | 
				
			|||||||
                assert(byte_count == 1 || byte_count == 2 || byte_count == 4 || byte_count == 8 || byte_count == 16);
 | 
					                assert(byte_count == 1 || byte_count == 2 || byte_count == 4 || byte_count == 8 || byte_count == 16);
 | 
				
			||||||
                return byte_count;
 | 
					                return byte_count;
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
 | 
					        case TypeId::pointer:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return 8;
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
        case TypeId::array:
 | 
					        case TypeId::array:
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                auto element_type = type->array.element_type;
 | 
					                auto element_type = type->array.element_type;
 | 
				
			||||||
@ -281,7 +511,12 @@ fn u64 get_byte_size(Type* type)
 | 
				
			|||||||
                auto result = get_byte_size(type->enumerator.backing_type);
 | 
					                auto result = get_byte_size(type->enumerator.backing_type);
 | 
				
			||||||
                return result;
 | 
					                return result;
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
        default: trap_raw();
 | 
					        case TypeId::bits:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto result = get_byte_size(type->bits.backing_type);
 | 
				
			||||||
 | 
					                return result;
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        default: trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -311,7 +546,20 @@ fn u32 get_byte_alignment(Type* type)
 | 
				
			|||||||
                auto result = get_byte_alignment(type->enumerator.backing_type);
 | 
					                auto result = get_byte_alignment(type->enumerator.backing_type);
 | 
				
			||||||
                return result;
 | 
					                return result;
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
        default: trap_raw();
 | 
					        case TypeId::pointer:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return 8;
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        case TypeId::bits:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto result = get_byte_alignment(type->bits.backing_type);
 | 
				
			||||||
 | 
					                return result;
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        case TypeId::union_type:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return type->union_type.byte_alignment;
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        default: trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -320,7 +568,8 @@ fn u64 get_bit_size(Type* type)
 | 
				
			|||||||
    switch (type->id)
 | 
					    switch (type->id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        case TypeId::integer: return type->integer.bit_count;
 | 
					        case TypeId::integer: return type->integer.bit_count;
 | 
				
			||||||
        default: trap_raw();
 | 
					        case TypeId::enumerator: return get_bit_size(type->enumerator.backing_type);
 | 
				
			||||||
 | 
					        default: trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -340,6 +589,7 @@ struct Scope
 | 
				
			|||||||
    u32 line;
 | 
					    u32 line;
 | 
				
			||||||
    u32 column;
 | 
					    u32 column;
 | 
				
			||||||
    ScopeKind kind;
 | 
					    ScopeKind kind;
 | 
				
			||||||
 | 
					    LLVMMetadataRef llvm;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class StatementId
 | 
					enum class StatementId
 | 
				
			||||||
@ -396,6 +646,7 @@ struct StatementSwitchClause
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    Slice<Value*> values;
 | 
					    Slice<Value*> values;
 | 
				
			||||||
    Block* block;
 | 
					    Block* block;
 | 
				
			||||||
 | 
					    LLVMBasicBlockRef basic_block;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct StatementSwitch
 | 
					struct StatementSwitch
 | 
				
			||||||
@ -461,7 +712,6 @@ enum class ValueId
 | 
				
			|||||||
    variable_reference,
 | 
					    variable_reference,
 | 
				
			||||||
    macro_reference,
 | 
					    macro_reference,
 | 
				
			||||||
    macro_instantiation,
 | 
					    macro_instantiation,
 | 
				
			||||||
    dereference,
 | 
					 | 
				
			||||||
    call,
 | 
					    call,
 | 
				
			||||||
    global,
 | 
					    global,
 | 
				
			||||||
    array_initialization,
 | 
					    array_initialization,
 | 
				
			||||||
@ -479,6 +729,8 @@ enum class ValueId
 | 
				
			|||||||
    zero,
 | 
					    zero,
 | 
				
			||||||
    select,
 | 
					    select,
 | 
				
			||||||
    string_to_enum,
 | 
					    string_to_enum,
 | 
				
			||||||
 | 
					    local,
 | 
				
			||||||
 | 
					    argument,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ValueConstantInteger
 | 
					struct ValueConstantInteger
 | 
				
			||||||
@ -487,12 +739,19 @@ struct ValueConstantInteger
 | 
				
			|||||||
    bool is_signed;
 | 
					    bool is_signed;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FunctionLLVM
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LLVMBasicBlockRef return_block;
 | 
				
			||||||
 | 
					    LLVMValueRef return_alloca;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ValueFunction
 | 
					struct ValueFunction
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Slice<Argument> arguments;
 | 
					    Slice<Argument> arguments;
 | 
				
			||||||
    Scope scope;
 | 
					    Scope scope;
 | 
				
			||||||
    Block* block;
 | 
					    Block* block;
 | 
				
			||||||
    FunctionAttributes attributes;
 | 
					    FunctionAttributes attributes;
 | 
				
			||||||
 | 
					    FunctionLLVM llvm;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class UnaryId
 | 
					enum class UnaryId
 | 
				
			||||||
@ -510,6 +769,7 @@ enum class UnaryId
 | 
				
			|||||||
    int_from_pointer,
 | 
					    int_from_pointer,
 | 
				
			||||||
    va_end,
 | 
					    va_end,
 | 
				
			||||||
    bitwise_not,
 | 
					    bitwise_not,
 | 
				
			||||||
 | 
					    dereference,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ValueUnary
 | 
					struct ValueUnary
 | 
				
			||||||
@ -565,6 +825,7 @@ struct ValueCall
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    Value* callable;
 | 
					    Value* callable;
 | 
				
			||||||
    Slice<Value*> arguments;
 | 
					    Slice<Value*> arguments;
 | 
				
			||||||
 | 
					    Type* function_type;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ValueArrayInitialization
 | 
					struct ValueArrayInitialization
 | 
				
			||||||
@ -666,6 +927,8 @@ struct MacroInstantiation
 | 
				
			|||||||
    u32 column;
 | 
					    u32 column;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn bool variable_is_constant(Value* value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Value
 | 
					struct Value
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    union
 | 
					    union
 | 
				
			||||||
@ -676,7 +939,6 @@ struct Value
 | 
				
			|||||||
        ValueBinary binary;
 | 
					        ValueBinary binary;
 | 
				
			||||||
        Variable* variable_reference;
 | 
					        Variable* variable_reference;
 | 
				
			||||||
        ValueUnaryType unary_type;
 | 
					        ValueUnaryType unary_type;
 | 
				
			||||||
        Value* dereference;
 | 
					 | 
				
			||||||
        ValueCall call;
 | 
					        ValueCall call;
 | 
				
			||||||
        ValueArrayInitialization array_initialization;
 | 
					        ValueArrayInitialization array_initialization;
 | 
				
			||||||
        ValueArrayExpression array_expression;
 | 
					        ValueArrayExpression array_expression;
 | 
				
			||||||
@ -694,14 +956,36 @@ struct Value
 | 
				
			|||||||
    Type* type;
 | 
					    Type* type;
 | 
				
			||||||
    ValueId id;
 | 
					    ValueId id;
 | 
				
			||||||
    ValueKind kind;
 | 
					    ValueKind kind;
 | 
				
			||||||
 | 
					    LLVMValueRef llvm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool is_constant()
 | 
					    bool is_constant()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        switch (id)
 | 
					        switch (id)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            case ValueId::constant_integer: 
 | 
					            case ValueId::constant_integer: 
 | 
				
			||||||
 | 
					            case ValueId::enum_literal:
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
            default: trap_raw();
 | 
					            case ValueId::unary:
 | 
				
			||||||
 | 
					            case ValueId::binary:
 | 
				
			||||||
 | 
					            case ValueId::field_access:
 | 
				
			||||||
 | 
					            case ValueId::array_expression:
 | 
				
			||||||
 | 
					            case ValueId::call:
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            case ValueId::variable_reference:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return variable_is_constant(this);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ValueId::array_initialization:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(type); // This asserts that the value type has been analyzed and `is_constant` was properly set 
 | 
				
			||||||
 | 
					                    return array_initialization.is_constant;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ValueId::aggregate_initialization:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(type); // This asserts that the value type has been analyzed and `is_constant` was properly set 
 | 
				
			||||||
 | 
					                    return aggregate_initialization.is_constant;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            default: trap();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -717,6 +1001,28 @@ struct Variable
 | 
				
			|||||||
    u32 column;
 | 
					    u32 column;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn bool variable_is_constant(Value* value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(value->id == ValueId::variable_reference);
 | 
				
			||||||
 | 
					    auto* variable = value->variable_reference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (value->kind)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case ValueKind::left:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (variable->scope->kind)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ScopeKind::global:
 | 
				
			||||||
 | 
					                        return true;
 | 
				
			||||||
 | 
					                    default:
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        case ValueKind::right:
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Linkage
 | 
					enum class Linkage
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    internal,
 | 
					    internal,
 | 
				
			||||||
@ -727,6 +1033,7 @@ struct Global
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    Variable variable;
 | 
					    Variable variable;
 | 
				
			||||||
    Linkage linkage;
 | 
					    Linkage linkage;
 | 
				
			||||||
 | 
					    bool emitted;
 | 
				
			||||||
    Global* next;
 | 
					    Global* next;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -742,6 +1049,47 @@ struct Argument
 | 
				
			|||||||
    u32 index;
 | 
					    u32 index;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LLVMIntrinsicId
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u32 n;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class IntrinsicIndex
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    trap,
 | 
				
			||||||
 | 
					    va_start,
 | 
				
			||||||
 | 
					    va_end,
 | 
				
			||||||
 | 
					    va_copy,
 | 
				
			||||||
 | 
					    count,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global_variable String intrinsic_names[] = {
 | 
				
			||||||
 | 
					    string_literal("llvm.trap"),
 | 
				
			||||||
 | 
					    string_literal("llvm.va_start"),
 | 
				
			||||||
 | 
					    string_literal("llvm.va_end"),
 | 
				
			||||||
 | 
					    string_literal("llvm.va_copy"),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(array_length(intrinsic_names) == (u64)IntrinsicIndex::count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ModuleLLVM
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LLVMContextRef context;
 | 
				
			||||||
 | 
					    LLVMModuleRef module;
 | 
				
			||||||
 | 
					    LLVMBuilderRef builder;
 | 
				
			||||||
 | 
					    LLVMDIBuilderRef di_builder;
 | 
				
			||||||
 | 
					    LLVMMetadataRef file;
 | 
				
			||||||
 | 
					    LLVMMetadataRef compile_unit;
 | 
				
			||||||
 | 
					    LLVMTypeRef pointer_type;
 | 
				
			||||||
 | 
					    LLVMTypeRef void_type;
 | 
				
			||||||
 | 
					    LLVMIntrinsicId intrinsic_table[(u64)IntrinsicIndex::count];
 | 
				
			||||||
 | 
					    LLVMValueRef memcmp;
 | 
				
			||||||
 | 
					    LLVMMetadataRef inlined_at;
 | 
				
			||||||
 | 
					    LLVMBasicBlockRef continue_block;
 | 
				
			||||||
 | 
					    LLVMBasicBlockRef exit_block;
 | 
				
			||||||
 | 
					    u32 debug_tag;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Module
 | 
					struct Module
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Arena* arena;
 | 
					    Arena* arena;
 | 
				
			||||||
@ -768,6 +1116,7 @@ struct Module
 | 
				
			|||||||
    MacroDeclaration* current_macro_declaration;
 | 
					    MacroDeclaration* current_macro_declaration;
 | 
				
			||||||
    MacroInstantiation* current_macro_instantiation;
 | 
					    MacroInstantiation* current_macro_instantiation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ModuleLLVM llvm;
 | 
				
			||||||
    Scope scope;
 | 
					    Scope scope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    String name;
 | 
					    String name;
 | 
				
			||||||
@ -788,6 +1137,10 @@ fn Type* integer_type(Module* module, TypeInteger integer)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    assert(integer.bit_count);
 | 
					    assert(integer.bit_count);
 | 
				
			||||||
    assert(integer.bit_count <= 64 || integer.bit_count == 128);
 | 
					    assert(integer.bit_count <= 64 || integer.bit_count == 128);
 | 
				
			||||||
 | 
					    if (integer.is_signed)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        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->first_type + index;
 | 
				
			||||||
    assert(result_type->id == TypeId::integer);
 | 
					    assert(result_type->id == TypeId::integer);
 | 
				
			||||||
@ -806,6 +1159,31 @@ fn Type* noreturn_type(Module* module)
 | 
				
			|||||||
    return void_type(module) + 1;
 | 
					    return void_type(module) + 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* uint1(Module* module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return integer_type(module, { .bit_count = 1, .is_signed = false });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* uint8(Module* module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return integer_type(module, { .bit_count = 8, .is_signed = false });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* uint32(Module* module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return integer_type(module, { .bit_count = 32, .is_signed = false });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* uint64(Module* module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return integer_type(module, { .bit_count = 64, .is_signed = false });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* sint32(Module* module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return integer_type(module, { .bit_count = 32, .is_signed = true });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Options
 | 
					struct Options
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    String content;
 | 
					    String content;
 | 
				
			||||||
@ -899,6 +1277,7 @@ fn Type* get_pointer_type(Module* module, Type* element_type)
 | 
				
			|||||||
        string_literal("&"),
 | 
					        string_literal("&"),
 | 
				
			||||||
        element_type->name,
 | 
					        element_type->name,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto result = type_allocate_init(module, {
 | 
					    auto result = type_allocate_init(module, {
 | 
				
			||||||
        .pointer = {
 | 
					        .pointer = {
 | 
				
			||||||
            .element_type = element_type,
 | 
					            .element_type = element_type,
 | 
				
			||||||
@ -907,6 +1286,17 @@ fn Type* get_pointer_type(Module* module, Type* element_type)
 | 
				
			|||||||
        .name = arena_join_string(module->arena, array_to_slice(name_parts)),
 | 
					        .name = arena_join_string(module->arena, array_to_slice(name_parts)),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (last_pointer_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(module->first_pointer_type);
 | 
				
			||||||
 | 
					        last_pointer_type->pointer.next = result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(!module->first_pointer_type);
 | 
				
			||||||
 | 
					        module->first_pointer_type = result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -959,7 +1349,7 @@ fn Type* get_slice_type(Module* module, Type* element_type)
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    fields[1] = {
 | 
					    fields[1] = {
 | 
				
			||||||
        .name = string_literal("length"),
 | 
					        .name = string_literal("length"),
 | 
				
			||||||
        .type = integer_type(module, { .bit_count = 64, .is_signed = false }),
 | 
					        .type = uint64(module),
 | 
				
			||||||
        .offset = 8,
 | 
					        .offset = 8,
 | 
				
			||||||
        .line = 0,
 | 
					        .line = 0,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -982,7 +1372,7 @@ fn Type* get_slice_type(Module* module, Type* element_type)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (last_slice_type)
 | 
					    if (last_slice_type)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        last_slice_type->next = result;
 | 
					        last_slice_type->structure.next = result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -992,5 +1382,247 @@ fn Type* get_slice_type(Module* module, Type* element_type)
 | 
				
			|||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn String array_name(Module* module, Type* element_type, u64 element_count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u8 buffer[512];
 | 
				
			||||||
 | 
					    auto buffer_slice = String{ .pointer = buffer, .length = array_length(buffer) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u64 i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buffer[i] = '[';
 | 
				
			||||||
 | 
					    i += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i += format_integer_decimal(buffer_slice(i), element_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buffer[i] = ']';
 | 
				
			||||||
 | 
					    i += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto element_name = element_type->name;
 | 
				
			||||||
 | 
					    memcpy(buffer + i, element_name.pointer, element_name.length);
 | 
				
			||||||
 | 
					    i += element_name.length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto name = arena_duplicate_string(module->arena, buffer_slice(0, i));
 | 
				
			||||||
 | 
					    return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Type* get_array_type(Module* module, Type* element_type, u64 element_count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(element_type);
 | 
				
			||||||
 | 
					    assert(element_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Type* array_type = module->first_array_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (array_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        while (1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            assert(array_type->id == TypeId::array);
 | 
				
			||||||
 | 
					            auto* candidate_element_type = array_type->array.element_type;
 | 
				
			||||||
 | 
					            if (candidate_element_type == element_type)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return array_type;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!array_type->array.next)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            array_type = array_type->array.next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Type* last_array_type = array_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto result = type_allocate_init(module, {
 | 
				
			||||||
 | 
					        .array = {
 | 
				
			||||||
 | 
					            .element_type = element_type,
 | 
				
			||||||
 | 
					            .element_count = element_count,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .id = TypeId::array,
 | 
				
			||||||
 | 
					        .name = array_name(module, element_type, element_count),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (last_array_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        last_array_type->array.next = result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        module->first_array_type = result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Block* scope_to_block(Scope* scope)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(scope->kind == ScopeKind::local);
 | 
				
			||||||
 | 
					    auto byte_offset = offsetof(Block, scope);
 | 
				
			||||||
 | 
					    auto result = (Block*)((u8*)scope - byte_offset);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn StatementForEach* scope_to_for_each(Scope* scope)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(scope->kind == ScopeKind::for_each);
 | 
				
			||||||
 | 
					    auto byte_offset = offsetof(StatementForEach, scope);
 | 
				
			||||||
 | 
					    auto result = (StatementForEach*)((u8*)scope - byte_offset);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn MacroDeclaration* scope_to_macro_declaration(Scope* scope)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(scope->kind == ScopeKind::macro_declaration);
 | 
				
			||||||
 | 
					    auto byte_offset = offsetof(MacroDeclaration, scope);
 | 
				
			||||||
 | 
					    auto result = (MacroDeclaration*)((u8*)scope - byte_offset);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn ValueFunction* scope_to_function(Scope* scope)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(scope->kind == ScopeKind::function);
 | 
				
			||||||
 | 
					    auto byte_offset = offsetof(ValueFunction, scope);
 | 
				
			||||||
 | 
					    auto result = (ValueFunction*)((u8*)scope - byte_offset);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Module* scope_to_module(Scope* scope)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(scope->kind == ScopeKind::global);
 | 
				
			||||||
 | 
					    auto byte_offset = offsetof(Module, scope);
 | 
				
			||||||
 | 
					    auto result = (Module*)((u8*)scope - byte_offset);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn Value* reference_identifier(Module* module, Scope* current_scope, String identifier, ValueKind kind)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(!identifier.equal(string_literal("")));
 | 
				
			||||||
 | 
					    assert(!identifier.equal(string_literal("_")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Variable* variable = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (Scope* scope = current_scope; scope; scope = scope->parent)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (scope->kind)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case ScopeKind::global:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(module == scope_to_module(scope));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (Global* global = module->first_global; global; global = global->next)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(global->variable.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            variable = &global->variable;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (MacroDeclaration* macro_declaration = module->first_macro_declaration; macro_declaration; macro_declaration = macro_declaration->next)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(macro_declaration->name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            auto result = new_value(module);
 | 
				
			||||||
 | 
					                            *result = {
 | 
				
			||||||
 | 
					                                .macro_reference = macro_declaration,
 | 
				
			||||||
 | 
					                                .id = ValueId::macro_reference,
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					                            return result;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ScopeKind::function:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(scope->parent);
 | 
				
			||||||
 | 
					                    auto function = scope_to_function(scope);
 | 
				
			||||||
 | 
					                    for (auto& argument: function->arguments)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(argument.variable.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            variable = &argument.variable;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ScopeKind::local:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(scope->parent);
 | 
				
			||||||
 | 
					                    assert(scope->parent->kind != ScopeKind::global);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    auto block = scope_to_block(scope);
 | 
				
			||||||
 | 
					                    for (Local* local = block->first_local; local; local = local->next)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(local->variable.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            variable = &local->variable;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ScopeKind::for_each:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(scope->parent);
 | 
				
			||||||
 | 
					                    auto for_each = scope_to_for_each(scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (Local* local = for_each->first_local; local; local = local->next)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(local->variable.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            variable = &local->variable;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ScopeKind::macro_declaration:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    assert(scope->parent);
 | 
				
			||||||
 | 
					                    auto macro_declaration = scope_to_macro_declaration(scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (auto& constant_argument: macro_declaration->constant_arguments)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(constant_argument.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            trap();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (auto& argument: macro_declaration->arguments)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (identifier.equal(argument.variable.name))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            variable = &argument.variable;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            case ScopeKind::macro_instantiation:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    trap();
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (variable)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (variable)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto result = new_value(module);
 | 
				
			||||||
 | 
					        *result = {
 | 
				
			||||||
 | 
					            .variable_reference = variable,
 | 
				
			||||||
 | 
					            .id = ValueId::variable_reference,
 | 
				
			||||||
 | 
					            .kind = kind,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        report_error();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void parse(Module* module);
 | 
					void parse(Module* module);
 | 
				
			||||||
void emit(Module* module);
 | 
					void emit(Module* module);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7852
									
								
								src/emitter.cpp
									
									
									
									
									
								
							
							
						
						
									
										7852
									
								
								src/emitter.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										63
									
								
								src/lib.h
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								src/lib.h
									
									
									
									
									
								
							@ -8,6 +8,7 @@
 | 
				
			|||||||
#define breakpoint() __builtin_debugtrap()
 | 
					#define breakpoint() __builtin_debugtrap()
 | 
				
			||||||
#define string_literal_length(s) (sizeof(s) - 1)
 | 
					#define string_literal_length(s) (sizeof(s) - 1)
 | 
				
			||||||
#define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), })
 | 
					#define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), })
 | 
				
			||||||
 | 
					#define split_string_literal(s) (char*)(s), string_literal_length(s)
 | 
				
			||||||
#define offsetof(S, f) __builtin_offsetof(S, f)
 | 
					#define offsetof(S, f) __builtin_offsetof(S, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
 | 
					#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
 | 
				
			||||||
@ -16,9 +17,9 @@
 | 
				
			|||||||
#define backing_type(E) __underlying_type(E)
 | 
					#define backing_type(E) __underlying_type(E)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define unreachable_raw() __builtin_unreachable()
 | 
					#define unreachable_raw() __builtin_unreachable()
 | 
				
			||||||
#define trap_raw() __builtin_trap()
 | 
					#define trap() __builtin_trap()
 | 
				
			||||||
#if BB_DEBUG
 | 
					#if BB_DEBUG
 | 
				
			||||||
#define unreachable() trap_raw()
 | 
					#define unreachable() trap()
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define unreachable() unreachable_raw()
 | 
					#define unreachable() unreachable_raw()
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -300,14 +301,32 @@ fn void* os_reserve(void* base, u64 size, ProtectionFlags protection, MapFlags m
 | 
				
			|||||||
        .read = protection.read,
 | 
					        .read = protection.read,
 | 
				
			||||||
        .write = protection.write,
 | 
					        .write = protection.write,
 | 
				
			||||||
        .execute = protection.execute,
 | 
					        .execute = protection.execute,
 | 
				
			||||||
 | 
					        .sem = 0,
 | 
				
			||||||
 | 
					        ._ = 0,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto map_flags = MAP
 | 
					    auto map_flags = MAP
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        .type = map.priv ? MAP::Type::priv : MAP::Type::shared,
 | 
					        .type = map.priv ? MAP::Type::priv : MAP::Type::shared,
 | 
				
			||||||
 | 
					        .fixed = 0,
 | 
				
			||||||
        .anonymous = map.anonymous,
 | 
					        .anonymous = map.anonymous,
 | 
				
			||||||
 | 
					        .bit32 = 0,
 | 
				
			||||||
 | 
					        ._0 = 0,
 | 
				
			||||||
 | 
					        .grows_down = 0,
 | 
				
			||||||
 | 
					        ._1 = 0,
 | 
				
			||||||
 | 
					        .deny_write = 0,
 | 
				
			||||||
 | 
					        .executable = 0,
 | 
				
			||||||
 | 
					        .locked = 0,
 | 
				
			||||||
        .no_reserve = map.no_reserve,
 | 
					        .no_reserve = map.no_reserve,
 | 
				
			||||||
        .populate = map.populate,
 | 
					        .populate = map.populate,
 | 
				
			||||||
 | 
					        .non_block = 0,
 | 
				
			||||||
 | 
					        .stack = 0,
 | 
				
			||||||
 | 
					        .huge_tlb = 0,
 | 
				
			||||||
 | 
					        .sync = 0,
 | 
				
			||||||
 | 
					        .fixed_no_replace = 0,
 | 
				
			||||||
 | 
					        ._2 = 0,
 | 
				
			||||||
 | 
					        .uninitialized = 0,
 | 
				
			||||||
 | 
					        ._3 = 0,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto* address = mmap(base, size, protection_flags, map_flags, -1, 0);
 | 
					    auto* address = mmap(base, size, protection_flags, map_flags, -1, 0);
 | 
				
			||||||
@ -323,6 +342,8 @@ fn void os_commit(void* address, u64 size, ProtectionFlags protection)
 | 
				
			|||||||
        .read = protection.read,
 | 
					        .read = protection.read,
 | 
				
			||||||
        .write = protection.write,
 | 
					        .write = protection.write,
 | 
				
			||||||
        .execute = protection.execute,
 | 
					        .execute = protection.execute,
 | 
				
			||||||
 | 
					        .sem = 0,
 | 
				
			||||||
 | 
					        ._ = 0,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    auto result = mprotect(address, size, protection_flags);
 | 
					    auto result = mprotect(address, size, protection_flags);
 | 
				
			||||||
    assert(!result);
 | 
					    assert(!result);
 | 
				
			||||||
@ -616,7 +637,7 @@ fn String file_read(Arena* arena, String file_path)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    if (os_is_debugger_present())
 | 
					    if (os_is_debugger_present())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        trap_raw();
 | 
					        trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    exit(1);
 | 
					    exit(1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -639,3 +660,39 @@ fn u64 next_power_of_two(u64 n)
 | 
				
			|||||||
    n += 1;
 | 
					    n += 1;
 | 
				
			||||||
    return n;
 | 
					    return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn u8 format_integer_decimal(String buffer, u64 v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u8 byte_count = 0;
 | 
				
			||||||
 | 
					    auto value = v;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value != 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        u8 reverse_buffer[64];
 | 
				
			||||||
 | 
					        u8 reverse_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (value != 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto digit_value = (u8)(value % 10);
 | 
				
			||||||
 | 
					            auto ascii_character = digit_value + '0';
 | 
				
			||||||
 | 
					            value /= 10;
 | 
				
			||||||
 | 
					            reverse_buffer[reverse_index] = ascii_character;
 | 
				
			||||||
 | 
					            reverse_index += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (reverse_index != 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            reverse_index -= 1;
 | 
				
			||||||
 | 
					            buffer[byte_count] = reverse_buffer[reverse_index];
 | 
				
			||||||
 | 
					            byte_count += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        buffer[0] = '0';
 | 
				
			||||||
 | 
					        byte_count = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return byte_count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										861
									
								
								src/llvm.cpp
									
									
									
									
									
								
							
							
						
						
									
										861
									
								
								src/llvm.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										342
									
								
								src/llvm.h
									
									
									
									
									
								
							
							
						
						
									
										342
									
								
								src/llvm.h
									
									
									
									
									
								
							@ -1,46 +1,320 @@
 | 
				
			|||||||
#include <lib.h>
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace llvm
 | 
					#include <lib.h>
 | 
				
			||||||
 | 
					#include <llvm-c/Core.h>
 | 
				
			||||||
 | 
					#include <llvm-c/Analysis.h>
 | 
				
			||||||
 | 
					#include <llvm-c/Target.h>
 | 
				
			||||||
 | 
					#include <llvm-c/Analysis.h>
 | 
				
			||||||
 | 
					#include <llvm-c/DebugInfo.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class BBLLVMUWTableKind : u64
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class Type;
 | 
					    None = 0,  ///< No unwind table requested
 | 
				
			||||||
    class Value;
 | 
					    Sync = 1,  ///< "Synchronous" unwind tables
 | 
				
			||||||
}
 | 
					    Async = 2, ///< "Asynchronous" unwind tables (instr precise)
 | 
				
			||||||
 | 
					    Default = 2,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class BBLLVMFramePointerKind : u64
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    none = 0,
 | 
				
			||||||
 | 
					    reserved = 1,
 | 
				
			||||||
 | 
					    non_leaf = 2,
 | 
				
			||||||
 | 
					    all = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class ZeroCallUsedRegsKind : u64
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    all = 0,
 | 
				
			||||||
 | 
					    skip = 1 << 0,
 | 
				
			||||||
 | 
					    only_used = 1 << 1,
 | 
				
			||||||
 | 
					    only_gpr = 1 << 2,
 | 
				
			||||||
 | 
					    only_arg = 1 << 3,
 | 
				
			||||||
 | 
					    used_gpr_arg = only_used | only_gpr | only_arg,
 | 
				
			||||||
 | 
					    used_gpr = only_used | only_gpr,
 | 
				
			||||||
 | 
					    used_arg = only_used | only_arg,
 | 
				
			||||||
 | 
					    used = only_used,
 | 
				
			||||||
 | 
					    all_gpr_arg = only_gpr | only_arg,
 | 
				
			||||||
 | 
					    all_gpr = only_gpr,
 | 
				
			||||||
 | 
					    all_arg = only_arg,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BBLLVMFunctionAttributesFlags0
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u64 noreturn:1;
 | 
				
			||||||
 | 
					    u64 cmse_ns_call:1;
 | 
				
			||||||
 | 
					    u64 nounwind:1;
 | 
				
			||||||
 | 
					    u64 returns_twice:1;
 | 
				
			||||||
 | 
					    u64 cold:1;
 | 
				
			||||||
 | 
					    u64 hot:1;
 | 
				
			||||||
 | 
					    u64 no_duplicate:1;
 | 
				
			||||||
 | 
					    u64 convergent:1;
 | 
				
			||||||
 | 
					    u64 no_merge:1;
 | 
				
			||||||
 | 
					    u64 will_return:1;
 | 
				
			||||||
 | 
					    u64 no_caller_saved_registers:1;
 | 
				
			||||||
 | 
					    u64 no_cf_check:1;
 | 
				
			||||||
 | 
					    u64 no_callback:1;
 | 
				
			||||||
 | 
					    u64 alloc_size:1;
 | 
				
			||||||
 | 
					    u64 uniform_work_group_size:1;
 | 
				
			||||||
 | 
					    u64 aarch64_pstate_sm_body:1;
 | 
				
			||||||
 | 
					    u64 aarch64_pstate_sm_enabled:1;
 | 
				
			||||||
 | 
					    u64 aarch64_pstate_sm_compatible:1;
 | 
				
			||||||
 | 
					    u64 aarch64_preserves_za:1;
 | 
				
			||||||
 | 
					    u64 aarch64_in_za:1;
 | 
				
			||||||
 | 
					    u64 aarch64_out_za:1;
 | 
				
			||||||
 | 
					    u64 aarch64_inout_za:1;
 | 
				
			||||||
 | 
					    u64 aarch64_preserves_zt0:1;
 | 
				
			||||||
 | 
					    u64 aarch64_in_zt0:1;
 | 
				
			||||||
 | 
					    u64 aarch64_out_zt0:1;
 | 
				
			||||||
 | 
					    u64 aarch64_inout_zt0:1;
 | 
				
			||||||
 | 
					    u64 optimize_for_size:1;
 | 
				
			||||||
 | 
					    u64 min_size:1;
 | 
				
			||||||
 | 
					    u64 no_red_zone:1;
 | 
				
			||||||
 | 
					    u64 indirect_tls_seg_refs:1;
 | 
				
			||||||
 | 
					    u64 no_implicit_floats:1;
 | 
				
			||||||
 | 
					    u64 sample_profile_suffix_elision_policy:1;
 | 
				
			||||||
 | 
					    u64 memory_none:1;
 | 
				
			||||||
 | 
					    u64 memory_readonly:1;
 | 
				
			||||||
 | 
					    u64 memory_inaccessible_or_arg_memory_only:1;
 | 
				
			||||||
 | 
					    u64 memory_arg_memory_only:1;
 | 
				
			||||||
 | 
					    u64 strict_fp:1;
 | 
				
			||||||
 | 
					    u64 no_inline:1;
 | 
				
			||||||
 | 
					    u64 always_inline:1;
 | 
				
			||||||
 | 
					    u64 guard_no_cf:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: branch protection function attributes
 | 
				
			||||||
 | 
					    // TODO: cpu features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Call-site begin
 | 
				
			||||||
 | 
					    u64 call_no_builtins:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BBLLVMFramePointerKind definition_frame_pointer_kind:2;
 | 
				
			||||||
 | 
					    u64 definition_less_precise_fpmad:1;
 | 
				
			||||||
 | 
					    u64 definition_null_pointer_is_valid:1;
 | 
				
			||||||
 | 
					    u64 definition_no_trapping_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_no_infs_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_no_nans_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_approx_func_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_unsafe_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_use_soft_float:1;
 | 
				
			||||||
 | 
					    u64 definition_no_signed_zeroes_fp_math:1;
 | 
				
			||||||
 | 
					    u64 definition_stack_realignment:1;
 | 
				
			||||||
 | 
					    u64 definition_backchain:1;
 | 
				
			||||||
 | 
					    u64 definition_split_stack:1;
 | 
				
			||||||
 | 
					    u64 definition_speculative_load_hardening:1;
 | 
				
			||||||
 | 
					    ZeroCallUsedRegsKind definition_zero_call_used_registers:4;
 | 
				
			||||||
 | 
					    // TODO: denormal builtins
 | 
				
			||||||
 | 
					    u64 definition_non_lazy_bind:1;
 | 
				
			||||||
 | 
					    u64 definition_cmse_nonsecure_entry:1;
 | 
				
			||||||
 | 
					    BBLLVMUWTableKind definition_unwind_table_kind:2;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(BBLLVMFunctionAttributesFlags0) == sizeof(u64));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BBLLVMFunctionAttributesFlags1
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    u64 definition_disable_tail_calls:1;
 | 
				
			||||||
 | 
					    u64 definition_stack_protect_strong:1;
 | 
				
			||||||
 | 
					    u64 definition_stack_protect:1;
 | 
				
			||||||
 | 
					    u64 definition_stack_protect_req:1;
 | 
				
			||||||
 | 
					    u64 definition_aarch64_new_za:1;
 | 
				
			||||||
 | 
					    u64 definition_aarch64_new_zt0:1;
 | 
				
			||||||
 | 
					    u64 definition_optimize_none:1;
 | 
				
			||||||
 | 
					    u64 definition_naked:1;
 | 
				
			||||||
 | 
					    u64 definition_inline_hint:1;
 | 
				
			||||||
 | 
					    u64 _:55;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(BBLLVMFunctionAttributesFlags1) == sizeof(u64));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BBLLVMFunctionAttributes
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    String prefer_vector_width;
 | 
				
			||||||
 | 
					    String stack_protector_buffer_size;
 | 
				
			||||||
 | 
					    String definition_probe_stack;
 | 
				
			||||||
 | 
					    String definition_stack_probe_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BBLLVMFunctionAttributesFlags0 flags0;
 | 
				
			||||||
 | 
					    BBLLVMFunctionAttributesFlags1 flags1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(BBLLVMFunctionAttributes) == 10 * sizeof(u64));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BBLLVMArgumentAttributes
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LLVMTypeRef semantic_type;
 | 
				
			||||||
 | 
					    LLVMTypeRef abi_type;
 | 
				
			||||||
 | 
					    u64 dereferenceable_bytes;
 | 
				
			||||||
 | 
					    u32 alignment;
 | 
				
			||||||
 | 
					    u32 no_alias:1;
 | 
				
			||||||
 | 
					    u32 non_null:1;
 | 
				
			||||||
 | 
					    u32 no_undef:1;
 | 
				
			||||||
 | 
					    u32 sign_extend:1;
 | 
				
			||||||
 | 
					    u32 zero_extend:1;
 | 
				
			||||||
 | 
					    u32 in_reg:1;
 | 
				
			||||||
 | 
					    u32 no_fp_class:10;
 | 
				
			||||||
 | 
					    u32 struct_return:1;
 | 
				
			||||||
 | 
					    u32 writable:1;
 | 
				
			||||||
 | 
					    u32 dead_on_unwind:1;
 | 
				
			||||||
 | 
					    u32 in_alloca:1;
 | 
				
			||||||
 | 
					    u32 dereferenceable:1;
 | 
				
			||||||
 | 
					    u32 dereferenceable_or_null:1;
 | 
				
			||||||
 | 
					    u32 nest:1;
 | 
				
			||||||
 | 
					    u32 by_value:1;
 | 
				
			||||||
 | 
					    u32 by_reference:1;
 | 
				
			||||||
 | 
					    u32 no_capture:1;
 | 
				
			||||||
 | 
					    u32 _:6;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(BBLLVMArgumentAttributes) == 2 * sizeof(LLVMTypeRef) + 2 * sizeof(u64));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BBLLVMAttributeListOptions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BBLLVMFunctionAttributes function;
 | 
				
			||||||
 | 
					    BBLLVMArgumentAttributes return_;
 | 
				
			||||||
 | 
					    BBLLVMArgumentAttributes* argument_pointer;
 | 
				
			||||||
 | 
					    u64 argument_count;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(BBLLVMAttributeListOptions) == sizeof(BBLLVMFunctionAttributes) + sizeof(BBLLVMArgumentAttributes) + sizeof(void*) + sizeof(u64));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void* BBLLVMAttributeList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class DwarfEmissionKind
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    none,
 | 
				
			||||||
 | 
					    full,
 | 
				
			||||||
 | 
					    line_tables_only,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class DwarfType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void_type = 0x0,
 | 
				
			||||||
 | 
					    address = 0x1,
 | 
				
			||||||
 | 
					    boolean = 0x2,
 | 
				
			||||||
 | 
					    complex_float = 0x3,
 | 
				
			||||||
 | 
					    float_type = 0x4,
 | 
				
			||||||
 | 
					    signed_type = 0x5,
 | 
				
			||||||
 | 
					    signed_char = 0x6,
 | 
				
			||||||
 | 
					    unsigned_type = 0x7,
 | 
				
			||||||
 | 
					    unsigned_char = 0x8,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // DWARF 3.
 | 
				
			||||||
 | 
					    imaginary_float = 0x9,
 | 
				
			||||||
 | 
					    packed_decimal = 0xa,
 | 
				
			||||||
 | 
					    numeric_string = 0xb,
 | 
				
			||||||
 | 
					    edited = 0xc,
 | 
				
			||||||
 | 
					    signed_fixed = 0xd,
 | 
				
			||||||
 | 
					    unsigned_fixed = 0xe,
 | 
				
			||||||
 | 
					    decimal_float = 0xf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // DWARF 4.
 | 
				
			||||||
 | 
					    UTF = 0x10,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // DWARF 5.
 | 
				
			||||||
 | 
					    UCS = 0x11,
 | 
				
			||||||
 | 
					    ASCII = 0x12,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // HP extensions.
 | 
				
			||||||
 | 
					    HP_float80 = 0x80, // Floating-point (80 bit).
 | 
				
			||||||
 | 
					    HP_complex_float80 = 0x81, // Complex floating-point (80 bit).
 | 
				
			||||||
 | 
					    HP_float128 = 0x82, // Floating-point (128 bit).
 | 
				
			||||||
 | 
					    HP_complex_float128 = 0x83, // Complex fp (128 bit).
 | 
				
			||||||
 | 
					    HP_floathpintel = 0x84, // Floating-point (82 bit IA64).
 | 
				
			||||||
 | 
					    HP_imaginary_float80 = 0x85,
 | 
				
			||||||
 | 
					    HP_imaginary_float128 = 0x86,
 | 
				
			||||||
 | 
					    HP_VAX_float = 0x88, // F or G floating.
 | 
				
			||||||
 | 
					    HP_VAX_float_d = 0x89, // D floating.
 | 
				
			||||||
 | 
					    HP_packed_decimal = 0x8a, // Cobol.
 | 
				
			||||||
 | 
					    HP_zoned_decimal = 0x8b, // Cobol.
 | 
				
			||||||
 | 
					    HP_edited = 0x8c, // Cobol.
 | 
				
			||||||
 | 
					    HP_signed_fixed = 0x8d, // Cobol.
 | 
				
			||||||
 | 
					    HP_unsigned_fixed = 0x8e, // Cobol.
 | 
				
			||||||
 | 
					    HP_VAX_complex_float = 0x8f, // F or G floating complex.
 | 
				
			||||||
 | 
					    HP_VAX_complex_float_d = 0x90, // D floating complex.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class DIFlagsVisibility : u32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    none = 0,
 | 
				
			||||||
 | 
					    private_ = 1,
 | 
				
			||||||
 | 
					    protected_ = 2,
 | 
				
			||||||
 | 
					    public_ = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class DIFlagsInheritance : u32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    none = 0,
 | 
				
			||||||
 | 
					    single_ = 1,
 | 
				
			||||||
 | 
					    multiple_ = 2,
 | 
				
			||||||
 | 
					    virtual_ = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DIFlags
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DIFlagsVisibility visibility:2;
 | 
				
			||||||
 | 
					    u32 forward_declaration:1;
 | 
				
			||||||
 | 
					    u32 apple_block:1;
 | 
				
			||||||
 | 
					    u32 block_by_ref_struct:1;
 | 
				
			||||||
 | 
					    u32 virtual_:1;
 | 
				
			||||||
 | 
					    u32 artificial:1;
 | 
				
			||||||
 | 
					    u32 explicit_:1;
 | 
				
			||||||
 | 
					    u32 prototyped:1;
 | 
				
			||||||
 | 
					    u32 objective_c_class_complete:1;
 | 
				
			||||||
 | 
					    u32 object_pointer:1;
 | 
				
			||||||
 | 
					    u32 vector:1;
 | 
				
			||||||
 | 
					    u32 static_member:1;
 | 
				
			||||||
 | 
					    u32 lvalue_reference:1;
 | 
				
			||||||
 | 
					    u32 rvalue_reference:1;
 | 
				
			||||||
 | 
					    u32 reserved:1;
 | 
				
			||||||
 | 
					    DIFlagsInheritance inheritance:2;
 | 
				
			||||||
 | 
					    u32 introduced_virtual:1;
 | 
				
			||||||
 | 
					    u32 bit_field:1;
 | 
				
			||||||
 | 
					    u32 no_return:1;
 | 
				
			||||||
 | 
					    u32 type_pass_by_value:1;
 | 
				
			||||||
 | 
					    u32 type_pass_by_reference:1;
 | 
				
			||||||
 | 
					    u32 enum_class:1;
 | 
				
			||||||
 | 
					    u32 thunk:1;
 | 
				
			||||||
 | 
					    u32 non_trivial:1;
 | 
				
			||||||
 | 
					    u32 big_endian:1;
 | 
				
			||||||
 | 
					    u32 little_endian:1;
 | 
				
			||||||
 | 
					    u32 all_calls_described:1;
 | 
				
			||||||
 | 
					    u32 _:3;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_assert(sizeof(DIFlags) == sizeof(u32));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn bool llvm_initialized = false;
 | 
					fn bool llvm_initialized = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" void LLVMInitializeX86TargetInfo();
 | 
					 | 
				
			||||||
extern "C" void LLVMInitializeX86Target();
 | 
					 | 
				
			||||||
extern "C" void LLVMInitializeX86TargetMC();
 | 
					 | 
				
			||||||
extern "C" void LLVMInitializeX86AsmPrinter();
 | 
					 | 
				
			||||||
extern "C" void LLVMInitializeX86AsmParser();
 | 
					 | 
				
			||||||
extern "C" void LLVMInitializeX86Disassembler();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern "C" String llvm_default_target_triple();
 | 
					extern "C" String llvm_default_target_triple();
 | 
				
			||||||
extern "C" String llvm_host_cpu_name();
 | 
					extern "C" String llvm_host_cpu_name();
 | 
				
			||||||
extern "C" String llvm_host_cpu_features();
 | 
					extern "C" String llvm_host_cpu_features();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct LLVMGlobal
 | 
					extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    String host_triple;
 | 
					 | 
				
			||||||
    String host_cpu_model;
 | 
					 | 
				
			||||||
    String host_cpu_features;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
global_variable LLVMGlobal llvm_global;
 | 
					extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name);
 | 
				
			||||||
 | 
					extern "C" void llvm_function_set_attributes(LLVMValueRef function, BBLLVMAttributeList attribute_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn void initialize_all()
 | 
					extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function);
 | 
				
			||||||
{
 | 
					
 | 
				
			||||||
    assert(!llvm_initialized);
 | 
					extern "C" LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized);
 | 
				
			||||||
    LLVMInitializeX86TargetInfo();
 | 
					
 | 
				
			||||||
    LLVMInitializeX86Target();
 | 
					extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name);
 | 
				
			||||||
    LLVMInitializeX86TargetMC();
 | 
					extern "C" bool llvm_value_has_one_use(LLVMValueRef value);
 | 
				
			||||||
    LLVMInitializeX86AsmPrinter();
 | 
					extern "C" LLVMValueRef llvm_basic_block_user_begin(LLVMBasicBlockRef basic_block);
 | 
				
			||||||
    LLVMInitializeX86AsmParser();
 | 
					extern "C" void llvm_basic_block_delete(LLVMBasicBlockRef basic_block);
 | 
				
			||||||
    LLVMInitializeX86Disassembler();
 | 
					extern "C" bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block);
 | 
				
			||||||
 | 
					extern "C" void llvm_function_set_attributes(LLVMValueRef f, BBLLVMAttributeList attribute_list_handle);
 | 
				
			||||||
 | 
					extern "C" void llvm_call_base_set_attributes(LLVMValueRef call_value, BBLLVMAttributeList attribute_list_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" BBLLVMAttributeList llvm_attribute_list_build(LLVMContextRef context, BBLLVMAttributeListOptions* attributes, bool call_site);
 | 
				
			||||||
 | 
					extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et);
 | 
				
			||||||
 | 
					extern "C" bool llvm_value_use_empty(LLVMValueRef value);
 | 
				
			||||||
 | 
					extern "C" bool llvm_function_verify(LLVMValueRef function_value, String* error_message);
 | 
				
			||||||
 | 
					extern "C" bool llvm_module_verify(LLVMModuleRef m, String* error_message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" String llvm_module_to_string(LLVMModuleRef module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    llvm_global = {
 | 
					 | 
				
			||||||
        .host_triple = llvm_default_target_triple(),
 | 
					 | 
				
			||||||
        .host_cpu_model = llvm_host_cpu_name(),
 | 
					 | 
				
			||||||
        .host_cpu_features = llvm_host_cpu_features(),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										414
									
								
								src/parser.cpp
									
									
									
									
									
								
							
							
						
						
									
										414
									
								
								src/parser.cpp
									
									
									
									
									
								
							@ -21,46 +21,6 @@ enum class ValueIntrinsic
 | 
				
			|||||||
    count,
 | 
					    count,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn Block* scope_to_block(Scope* scope)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(scope->kind == ScopeKind::local);
 | 
					 | 
				
			||||||
    auto byte_offset = offsetof(Block, scope);
 | 
					 | 
				
			||||||
    auto result = (Block*)((u8*)scope - byte_offset);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn StatementForEach* scope_to_for_each(Scope* scope)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(scope->kind == ScopeKind::for_each);
 | 
					 | 
				
			||||||
    auto byte_offset = offsetof(StatementForEach, scope);
 | 
					 | 
				
			||||||
    auto result = (StatementForEach*)((u8*)scope - byte_offset);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn MacroDeclaration* scope_to_macro_declaration(Scope* scope)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(scope->kind == ScopeKind::macro_declaration);
 | 
					 | 
				
			||||||
    auto byte_offset = offsetof(MacroDeclaration, scope);
 | 
					 | 
				
			||||||
    auto result = (MacroDeclaration*)((u8*)scope - byte_offset);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn ValueFunction* scope_to_function(Scope* scope)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(scope->kind == ScopeKind::function);
 | 
					 | 
				
			||||||
    auto byte_offset = offsetof(ValueFunction, scope);
 | 
					 | 
				
			||||||
    auto result = (ValueFunction*)((u8*)scope - byte_offset);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn Module* scope_to_module(Scope* scope)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(scope->kind == ScopeKind::global);
 | 
					 | 
				
			||||||
    auto byte_offset = offsetof(Module, scope);
 | 
					 | 
				
			||||||
    auto result = (Module*)((u8*)scope - byte_offset);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn Local* new_local(Module* module, Scope* scope)
 | 
					fn Local* new_local(Module* module, Scope* scope)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto* result = &arena_allocate<Local>(module->arena, 1)[0];
 | 
					    auto* result = &arena_allocate<Local>(module->arena, 1)[0];
 | 
				
			||||||
@ -309,22 +269,22 @@ fn bool is_hexadecimal_alpha_upper(u8 ch)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn bool is_hexadecimal_alpha(u8 ch)
 | 
					fn bool is_hexadecimal_alpha(u8 ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return is_hexadecimal_alpha_lower(ch) | is_hexadecimal_alpha_upper(ch);
 | 
					    return is_hexadecimal_alpha_lower(ch) || is_hexadecimal_alpha_upper(ch);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn bool is_hexadecimal(u8 ch)
 | 
					fn bool is_hexadecimal(u8 ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return is_decimal(ch) | is_hexadecimal_alpha(ch);
 | 
					    return is_decimal(ch) || is_hexadecimal_alpha(ch);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn bool is_identifier_start(u8 ch)
 | 
					fn bool is_identifier_start(u8 ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return (is_lower(ch) | is_upper(ch)) | (ch == '_');
 | 
					    return (is_lower(ch) || is_upper(ch)) || (ch == '_');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn bool is_identifier(u8 ch)
 | 
					fn bool is_identifier(u8 ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return is_identifier_start(ch) | is_decimal(ch);
 | 
					    return is_identifier_start(ch) || is_decimal(ch);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn u32 get_line(Module* module)
 | 
					fn u32 get_line(Module* module)
 | 
				
			||||||
@ -530,64 +490,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 u8 format_integer_decimal(String buffer, u64 v)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    u8 byte_count = 0;
 | 
					 | 
				
			||||||
    auto value = v;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (value != 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        u8 reverse_buffer[64];
 | 
					 | 
				
			||||||
        u8 reverse_index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (value != 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto digit_value = (u8)(value % 10);
 | 
					 | 
				
			||||||
            auto ascii_character = digit_value + '0';
 | 
					 | 
				
			||||||
            value /= 10;
 | 
					 | 
				
			||||||
            reverse_buffer[reverse_index] = ascii_character;
 | 
					 | 
				
			||||||
            reverse_index += 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (reverse_index != 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            reverse_index -= 1;
 | 
					 | 
				
			||||||
            buffer[byte_count] = reverse_buffer[reverse_index];
 | 
					 | 
				
			||||||
            byte_count += 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        buffer[0] = '0';
 | 
					 | 
				
			||||||
        byte_count = 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return byte_count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn String array_name(Module* module, Type* element_type, u64 element_count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    u8 buffer[512];
 | 
					 | 
				
			||||||
    auto buffer_slice = String{ .pointer = buffer, .length = array_length(buffer) };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    u64 i = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    buffer[i] = left_bracket;
 | 
					 | 
				
			||||||
    i += 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    i += format_integer_decimal(buffer_slice(i), element_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    buffer[i] = right_bracket;
 | 
					 | 
				
			||||||
    i += 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto element_name = element_type->name;
 | 
					 | 
				
			||||||
    memcpy(buffer + i, element_name.pointer, element_name.length);
 | 
					 | 
				
			||||||
    i += element_name.length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto name = arena_duplicate_string(module->arena, buffer_slice(0, i));
 | 
					 | 
				
			||||||
    return name;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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];
 | 
				
			||||||
@ -729,8 +631,8 @@ fn Type* parse_type(Module* module, Scope* scope)
 | 
				
			|||||||
                assert(!length_value);
 | 
					                assert(!length_value);
 | 
				
			||||||
                auto result = type_allocate_init(module, {
 | 
					                auto result = type_allocate_init(module, {
 | 
				
			||||||
                    .array = {
 | 
					                    .array = {
 | 
				
			||||||
                        .element_count = 0,
 | 
					 | 
				
			||||||
                        .element_type = element_type,
 | 
					                        .element_type = element_type,
 | 
				
			||||||
 | 
					                        .element_count = 0,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    .id = TypeId::array,
 | 
					                    .id = TypeId::array,
 | 
				
			||||||
                    .name = string_literal(""),
 | 
					                    .name = string_literal(""),
 | 
				
			||||||
@ -747,15 +649,8 @@ fn Type* parse_type(Module* module, Scope* scope)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                assert(element_count != 0);
 | 
					                assert(element_count != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                auto result = type_allocate_init(module, {
 | 
					                auto array_type = get_array_type(module, element_type, element_count);
 | 
				
			||||||
                    .array = {
 | 
					                return array_type;
 | 
				
			||||||
                        .element_count = element_count,
 | 
					 | 
				
			||||||
                        .element_type = element_type,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    .id = TypeId::array,
 | 
					 | 
				
			||||||
                    .name = array_name(module, element_type, element_count),
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                return result;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -886,7 +781,7 @@ fn u8 escape_character(u8 ch)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    switch (ch)
 | 
					    switch (ch)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        default: trap_raw();
 | 
					        default: trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -984,7 +879,7 @@ fn Token tokenize(Module* module)
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    trap_raw();
 | 
					                    trap();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
        case '<':
 | 
					        case '<':
 | 
				
			||||||
@ -1100,12 +995,11 @@ fn Token tokenize(Module* module)
 | 
				
			|||||||
                    auto ch = module->content[module->offset];
 | 
					                    auto ch = module->content[module->offset];
 | 
				
			||||||
                    if (ch == '"')
 | 
					                    if (ch == '"')
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        module->offset += 1;
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (ch == '\\')
 | 
					                    else if (ch == '\\')
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        trap_raw();
 | 
					                        trap();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@ -1114,6 +1008,7 @@ fn Token tokenize(Module* module)
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                auto end = module->offset;
 | 
					                auto end = module->offset;
 | 
				
			||||||
 | 
					                module->offset += 1;
 | 
				
			||||||
                auto string_literal = module->content(start, end);
 | 
					                auto string_literal = module->content(start, end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                token = {
 | 
					                token = {
 | 
				
			||||||
@ -1328,134 +1223,6 @@ fn Token tokenize(Module* module)
 | 
				
			|||||||
    return token;
 | 
					    return token;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn Value* reference_identifier(Module* module, Scope* current_scope, String identifier, ValueKind kind)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(!identifier.equal(string_literal("")));
 | 
					 | 
				
			||||||
    assert(!identifier.equal(string_literal("_")));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Variable* variable = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (Scope* scope = current_scope; scope; scope = scope->parent)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        switch (scope->kind)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case ScopeKind::global:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    assert(module == scope_to_module(scope));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (Global* global = module->first_global; global; global = global->next)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(global->variable.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            variable = &global->variable;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (MacroDeclaration* macro_declaration = module->first_macro_declaration; macro_declaration; macro_declaration = macro_declaration->next)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(macro_declaration->name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            auto result = new_value(module);
 | 
					 | 
				
			||||||
                            *result = {
 | 
					 | 
				
			||||||
                                .macro_reference = macro_declaration,
 | 
					 | 
				
			||||||
                                .id = ValueId::macro_reference,
 | 
					 | 
				
			||||||
                            };
 | 
					 | 
				
			||||||
                            return result;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
            case ScopeKind::function:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    assert(scope->parent);
 | 
					 | 
				
			||||||
                    auto function = scope_to_function(scope);
 | 
					 | 
				
			||||||
                    for (auto argument: function->arguments)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(argument.variable.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            variable = &argument.variable;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
            case ScopeKind::local:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    assert(scope->parent);
 | 
					 | 
				
			||||||
                    assert(scope->parent->kind != ScopeKind::global);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    auto block = scope_to_block(scope);
 | 
					 | 
				
			||||||
                    for (Local* local = block->first_local; local; local = local->next)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(local->variable.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            variable = &local->variable;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
            case ScopeKind::for_each:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    assert(scope->parent);
 | 
					 | 
				
			||||||
                    auto for_each = scope_to_for_each(scope);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (Local* local = for_each->first_local; local; local = local->next)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(local->variable.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            variable = &local->variable;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
            case ScopeKind::macro_declaration:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    assert(scope->parent);
 | 
					 | 
				
			||||||
                    auto macro_declaration = scope_to_macro_declaration(scope);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (auto& constant_argument: macro_declaration->constant_arguments)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(constant_argument.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            trap_raw();
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (auto& argument: macro_declaration->arguments)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (identifier.equal(argument.variable.name))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            variable = &argument.variable;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
            case ScopeKind::macro_instantiation:
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    trap_raw();
 | 
					 | 
				
			||||||
                } break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (variable)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (variable)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto result = new_value(module);
 | 
					 | 
				
			||||||
        *result = {
 | 
					 | 
				
			||||||
            .variable_reference = variable,
 | 
					 | 
				
			||||||
            .id = ValueId::variable_reference,
 | 
					 | 
				
			||||||
            .kind = kind,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        report_error();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
 | 
					fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn Value* parse_precedence(Module* module, Scope* scope, ValueBuilder builder);
 | 
					fn Value* parse_precedence(Module* module, Scope* scope, ValueBuilder builder);
 | 
				
			||||||
@ -1520,7 +1287,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    case ValueIntrinsic::align_of:
 | 
					                    case ValueIntrinsic::align_of:
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            trap_raw();
 | 
					                            trap();
 | 
				
			||||||
                        } break;
 | 
					                        } break;
 | 
				
			||||||
                    case ValueIntrinsic::enum_name:
 | 
					                    case ValueIntrinsic::enum_name:
 | 
				
			||||||
                    case ValueIntrinsic::extend:
 | 
					                    case ValueIntrinsic::extend:
 | 
				
			||||||
@ -1679,7 +1446,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                        } break;
 | 
					                        } break;
 | 
				
			||||||
                    case ValueIntrinsic::va_copy:
 | 
					                    case ValueIntrinsic::va_copy:
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            trap_raw();
 | 
					                            trap();
 | 
				
			||||||
                        } break;
 | 
					                        } break;
 | 
				
			||||||
                    case ValueIntrinsic::count: unreachable();
 | 
					                    case ValueIntrinsic::count: unreachable();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -1834,11 +1601,11 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn Precedence get_token_precedence(TokenId id)
 | 
					fn Precedence get_token_precedence(Token token)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Precedence precedence;
 | 
					    Precedence precedence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (id)
 | 
					    switch (token.id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        case TokenId::none: unreachable();
 | 
					        case TokenId::none: unreachable();
 | 
				
			||||||
        case TokenId::comma:
 | 
					        case TokenId::comma:
 | 
				
			||||||
@ -1862,6 +1629,23 @@ fn Precedence get_token_precedence(TokenId id)
 | 
				
			|||||||
        case TokenId::assign_ampersand:
 | 
					        case TokenId::assign_ampersand:
 | 
				
			||||||
            precedence = Precedence::assignment;
 | 
					            precedence = Precedence::assignment;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case TokenId::operator_keyword: // TODO: check if any other operator that is not bitwise is added
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (token.operator_keyword)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case OperatorKeyword::and_op:
 | 
				
			||||||
 | 
					                    case OperatorKeyword::or_op:
 | 
				
			||||||
 | 
					                        precedence = Precedence::bitwise;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case OperatorKeyword::and_op_shortcircuit:
 | 
				
			||||||
 | 
					                        precedence = Precedence::boolean_and;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case OperatorKeyword::or_op_shortcircuit:
 | 
				
			||||||
 | 
					                        precedence = Precedence::boolean_or;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case OperatorKeyword::count: unreachable();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
        case TokenId::compare_equal:
 | 
					        case TokenId::compare_equal:
 | 
				
			||||||
        case TokenId::compare_not_equal:
 | 
					        case TokenId::compare_not_equal:
 | 
				
			||||||
        case TokenId::compare_less:
 | 
					        case TokenId::compare_less:
 | 
				
			||||||
@ -1870,7 +1654,6 @@ fn Precedence get_token_precedence(TokenId id)
 | 
				
			|||||||
        case TokenId::compare_greater_equal:
 | 
					        case TokenId::compare_greater_equal:
 | 
				
			||||||
            precedence = Precedence::comparison;
 | 
					            precedence = Precedence::comparison;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case TokenId::operator_keyword: // TODO: check if any other operator that is not bitwise is added
 | 
					 | 
				
			||||||
        case TokenId::ampersand:
 | 
					        case TokenId::ampersand:
 | 
				
			||||||
        case TokenId::bar:
 | 
					        case TokenId::bar:
 | 
				
			||||||
        case TokenId::caret:
 | 
					        case TokenId::caret:
 | 
				
			||||||
@ -1895,7 +1678,7 @@ fn Precedence get_token_precedence(TokenId id)
 | 
				
			|||||||
        case TokenId::dot:
 | 
					        case TokenId::dot:
 | 
				
			||||||
            precedence = Precedence::postfix;
 | 
					            precedence = Precedence::postfix;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default: trap_raw();
 | 
					        default: trap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return precedence;
 | 
					    return precedence;
 | 
				
			||||||
@ -1966,12 +1749,21 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
        case TokenId::operator_keyword:
 | 
					        case TokenId::operator_keyword:
 | 
				
			||||||
            // Binary
 | 
					            // Binary
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                auto precedence = get_token_precedence(token.id);
 | 
					                auto precedence = get_token_precedence(token);
 | 
				
			||||||
                assert(precedence != Precedence::assignment);
 | 
					                assert(precedence != Precedence::assignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                BinaryId id;
 | 
					                BinaryId id;
 | 
				
			||||||
                switch (token.id)
 | 
					                switch (token.id)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 | 
					                    case TokenId::operator_keyword:
 | 
				
			||||||
 | 
					                        switch (token.operator_keyword)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case OperatorKeyword::and_op: id = BinaryId::logical_and; break;
 | 
				
			||||||
 | 
					                            case OperatorKeyword::or_op: id = BinaryId::logical_or; break;
 | 
				
			||||||
 | 
					                            case OperatorKeyword::and_op_shortcircuit: id = BinaryId::logical_and_shortcircuit; break;
 | 
				
			||||||
 | 
					                            case OperatorKeyword::or_op_shortcircuit: id = BinaryId::logical_or_shortcircuit; break;
 | 
				
			||||||
 | 
					                            case OperatorKeyword::count: unreachable();
 | 
				
			||||||
 | 
					                        } break;
 | 
				
			||||||
                    case TokenId::plus: id = BinaryId::add; break;
 | 
					                    case TokenId::plus: id = BinaryId::add; break;
 | 
				
			||||||
                    case TokenId::dash: id = BinaryId::sub; break;
 | 
					                    case TokenId::dash: id = BinaryId::sub; break;
 | 
				
			||||||
                    case TokenId::asterisk: id = BinaryId::mul; break;
 | 
					                    case TokenId::asterisk: id = BinaryId::mul; break;
 | 
				
			||||||
@ -1988,15 +1780,6 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                    case TokenId::compare_less_equal: id = BinaryId::compare_less_equal; break;
 | 
					                    case TokenId::compare_less_equal: id = BinaryId::compare_less_equal; break;
 | 
				
			||||||
                    case TokenId::compare_greater: id = BinaryId::compare_greater; break;
 | 
					                    case TokenId::compare_greater: id = BinaryId::compare_greater; break;
 | 
				
			||||||
                    case TokenId::compare_greater_equal: id = BinaryId::compare_greater_equal; break;
 | 
					                    case TokenId::compare_greater_equal: id = BinaryId::compare_greater_equal; break;
 | 
				
			||||||
                    case TokenId::operator_keyword: switch (token.operator_keyword)
 | 
					 | 
				
			||||||
                                                    {
 | 
					 | 
				
			||||||
                                                        case OperatorKeyword::and_op: id = BinaryId::logical_and; break;
 | 
					 | 
				
			||||||
                                                        case OperatorKeyword::or_op: id = BinaryId::logical_or; break;
 | 
					 | 
				
			||||||
                                                        case OperatorKeyword::and_op_shortcircuit: id = BinaryId::logical_and_shortcircuit; break;
 | 
					 | 
				
			||||||
                                                        case OperatorKeyword::or_op_shortcircuit: id = BinaryId::logical_or_shortcircuit; break;
 | 
					 | 
				
			||||||
                                                        case OperatorKeyword::count: unreachable();
 | 
					 | 
				
			||||||
                                                            break;
 | 
					 | 
				
			||||||
                                                    } break;
 | 
					 | 
				
			||||||
                    default: unreachable();
 | 
					                    default: unreachable();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2018,8 +1801,11 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                result = new_value(module);
 | 
					                result = new_value(module);
 | 
				
			||||||
                *result = {
 | 
					                *result = {
 | 
				
			||||||
                    .dereference = left,
 | 
					                    .unary = {
 | 
				
			||||||
                    .id = ValueId::dereference,
 | 
					                        .value = left,
 | 
				
			||||||
 | 
					                        .id = UnaryId::dereference,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    .id = ValueId::unary,
 | 
				
			||||||
                    .kind = ValueKind::right,
 | 
					                    .kind = ValueKind::right,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
@ -2116,7 +1902,7 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                        case ConstantArgumentId::value:
 | 
					                        case ConstantArgumentId::value:
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                trap_raw(); // TODO
 | 
					                                trap(); // TODO
 | 
				
			||||||
                            } break;
 | 
					                            } break;
 | 
				
			||||||
                        case ConstantArgumentId::type:
 | 
					                        case ConstantArgumentId::type:
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@ -2188,6 +1974,7 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                                .index = index,
 | 
					                                .index = index,
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            .id = ValueId::array_expression,
 | 
					                            .id = ValueId::array_expression,
 | 
				
			||||||
 | 
					                            .kind = builder.kind,
 | 
				
			||||||
                        };
 | 
					                        };
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
@ -2208,6 +1995,7 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
                                .start = start_value,
 | 
					                                .start = start_value,
 | 
				
			||||||
                                .end = end_value,
 | 
					                                .end = end_value,
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
 | 
					                            .id = ValueId::slice_expression,
 | 
				
			||||||
                        };
 | 
					                        };
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -2244,7 +2032,7 @@ fn Value* parse_precedence_left(Module* module, Scope* scope, ValueBuilder build
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        auto checkpoint = get_checkpoint(module);
 | 
					        auto checkpoint = get_checkpoint(module);
 | 
				
			||||||
        auto token = tokenize(module);
 | 
					        auto token = tokenize(module);
 | 
				
			||||||
        auto token_precedence = get_token_precedence(token.id);
 | 
					        auto token_precedence = get_token_precedence(token);
 | 
				
			||||||
        if (token_precedence == Precedence::assignment)
 | 
					        if (token_precedence == Precedence::assignment)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            token_precedence = builder.allow_assignment_operators ? Precedence::assignment : Precedence::none;
 | 
					            token_precedence = builder.allow_assignment_operators ? Precedence::assignment : Precedence::none;
 | 
				
			||||||
@ -2283,6 +2071,53 @@ fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn Block* parse_block(Module* module, Scope* parent_scope);
 | 
					fn Block* parse_block(Module* module, Scope* parent_scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn void print_value(Value* value, u32 identation)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unused(identation);
 | 
				
			||||||
 | 
					    for (u32 i = 0; i < identation; i += 1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        print(string_literal("  "));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (value->id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case ValueId::binary:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (value->binary.id)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case BinaryId::compare_not_equal:
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            print(string_literal("!="));
 | 
				
			||||||
 | 
					                        } break;
 | 
				
			||||||
 | 
					                    case BinaryId::logical_and_shortcircuit:
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            print(string_literal("and?"));
 | 
				
			||||||
 | 
					                        } break;
 | 
				
			||||||
 | 
					                    case BinaryId::logical_or_shortcircuit:
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            print(string_literal("or?"));
 | 
				
			||||||
 | 
					                        } break;
 | 
				
			||||||
 | 
					                    default: unreachable();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                print(string_literal("\n"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                print_value(value->binary.left, identation + 1);
 | 
				
			||||||
 | 
					                print_value(value->binary.right, identation + 1);
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        case ValueId::variable_reference:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                print(value->variable_reference->name);
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        case ValueId::constant_integer:
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                print(string_literal("constant_integer"));
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					        default: unreachable();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(string_literal("\n"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn Statement* parse_statement(Module* module, Scope* scope)
 | 
					fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bool require_semicolon = true;
 | 
					    bool require_semicolon = true;
 | 
				
			||||||
@ -2394,7 +2229,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        case StatementStartKeyword::underscore_st:
 | 
					                        case StatementStartKeyword::underscore_st:
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                trap_raw();
 | 
					                                trap();
 | 
				
			||||||
                            } break;
 | 
					                            } break;
 | 
				
			||||||
                        case StatementStartKeyword::return_st:
 | 
					                        case StatementStartKeyword::return_st:
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@ -2462,7 +2297,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			|||||||
                                        .right_values = {},
 | 
					                                        .right_values = {},
 | 
				
			||||||
                                        .predicate = 0,
 | 
					                                        .predicate = 0,
 | 
				
			||||||
                                        .scope = {
 | 
					                                        .scope = {
 | 
				
			||||||
                                            .parent = scope,
 | 
					                                            .parent = parent_scope,
 | 
				
			||||||
                                            .line = statement_line,
 | 
					                                            .line = statement_line,
 | 
				
			||||||
                                            .column = statement_column,
 | 
					                                            .column = statement_column,
 | 
				
			||||||
                                            .kind = ScopeKind::for_each,
 | 
					                                            .kind = ScopeKind::for_each,
 | 
				
			||||||
@ -2511,7 +2346,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			|||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                    else
 | 
					                                    else
 | 
				
			||||||
                                    {
 | 
					                                    {
 | 
				
			||||||
                                        trap_raw();
 | 
					                                        trap();
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    skip_space(module);
 | 
					                                    skip_space(module);
 | 
				
			||||||
@ -2741,7 +2576,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			|||||||
                                        case TokenId::assign_ampersand: id = StatementAssignmentId::assign_and; break;
 | 
					                                        case TokenId::assign_ampersand: id = StatementAssignmentId::assign_and; break;
 | 
				
			||||||
                                        case TokenId::assign_bar: id = StatementAssignmentId::assign_or; break;
 | 
					                                        case TokenId::assign_bar: id = StatementAssignmentId::assign_or; break;
 | 
				
			||||||
                                        case TokenId::assign_caret: id = StatementAssignmentId::assign_xor; break;
 | 
					                                        case TokenId::assign_caret: id = StatementAssignmentId::assign_xor; break;
 | 
				
			||||||
                                        default: trap_raw();
 | 
					                                        default: trap();
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    skip_space(module);
 | 
					                                    skip_space(module);
 | 
				
			||||||
@ -2759,7 +2594,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    trap_raw();
 | 
					                    trap();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2804,6 +2639,10 @@ fn Block* parse_block(Module* module, Scope* parent_scope)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto* statement = parse_statement(module, scope);
 | 
					        auto* statement = parse_statement(module, scope);
 | 
				
			||||||
 | 
					        if (!block->first_statement)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            block->first_statement = statement;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (current_statement)
 | 
					        if (current_statement)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -2951,8 +2790,6 @@ void parse(Module* module)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        skip_space(module);
 | 
					        skip_space(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool is_global_keyword = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        enum class GlobalKeyword
 | 
					        enum class GlobalKeyword
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            bits,
 | 
					            bits,
 | 
				
			||||||
@ -3099,16 +2936,13 @@ void parse(Module* module)
 | 
				
			|||||||
                        skip_space(module);
 | 
					                        skip_space(module);
 | 
				
			||||||
                        expect_character(module, left_brace);
 | 
					                        expect_character(module, left_brace);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        u64 highest_value = 0;
 | 
					 | 
				
			||||||
                        u64 lowest_value = ~(u64)0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        u64 field_count = 0;
 | 
					                        u64 field_count = 0;
 | 
				
			||||||
                        String name_buffer[64];
 | 
					                        String name_buffer[64];
 | 
				
			||||||
                        Value* value_buffer[64];
 | 
					 | 
				
			||||||
                        u64 int_value_buffer[64];
 | 
					                        u64 int_value_buffer[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        bool is_resolved = true;
 | 
					                        bool is_resolved = true;
 | 
				
			||||||
                        bool implicit_value = false;
 | 
					                        bool implicit_value = false;
 | 
				
			||||||
 | 
					                        unused(implicit_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        while (1)
 | 
					                        while (1)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@ -3122,11 +2956,11 @@ void parse(Module* module)
 | 
				
			|||||||
                            field_count += 1;
 | 
					                            field_count += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            auto field_name = parse_identifier(module);
 | 
					                            auto field_name = parse_identifier(module);
 | 
				
			||||||
 | 
					                            name_buffer[field_index] = field_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            skip_space(module);
 | 
					                            skip_space(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            u64 field_integer_value = field_index;
 | 
					                            u64 field_integer_value = field_index;
 | 
				
			||||||
                            Value* field_value = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if (consume_character_if_match(module, '='))
 | 
					                            if (consume_character_if_match(module, '='))
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@ -3142,17 +2976,17 @@ void parse(Module* module)
 | 
				
			|||||||
                                                {
 | 
					                                                {
 | 
				
			||||||
                                                    field_integer_value = field_value->constant_integer.value;
 | 
					                                                    field_integer_value = field_value->constant_integer.value;
 | 
				
			||||||
                                                } break;
 | 
					                                                } break;
 | 
				
			||||||
                                            default: trap_raw();
 | 
					                                            default: trap();
 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                    else
 | 
					                                    else
 | 
				
			||||||
                                    {
 | 
					                                    {
 | 
				
			||||||
                                        trap_raw();
 | 
					                                        trap();
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                else
 | 
					                                else
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    trap_raw();
 | 
					                                    trap();
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
@ -3163,6 +2997,8 @@ void parse(Module* module)
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            int_value_buffer[field_index] = field_integer_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            skip_space(module);
 | 
					                            skip_space(module);
 | 
				
			||||||
                            consume_character_if_match(module, ',');
 | 
					                            consume_character_if_match(module, ',');
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@ -3171,11 +3007,12 @@ void parse(Module* module)
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            auto fields = arena_allocate<EnumField>(module->arena, field_count);
 | 
					                            auto fields = arena_allocate<EnumField>(module->arena, field_count);
 | 
				
			||||||
                            u64 highest_value = 0;
 | 
					                            u64 highest_value = 0;
 | 
				
			||||||
                            auto lowest_value = ~(u64)0;
 | 
					                            // auto lowest_value = ~(u64)0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            for (u64 i = 0; i < field_count; i += 1)
 | 
					                            for (u64 i = 0; i < field_count; i += 1)
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                auto value = int_value_buffer[i];
 | 
					                                auto value = int_value_buffer[i];
 | 
				
			||||||
 | 
					                                highest_value = MAX(highest_value, value);
 | 
				
			||||||
                                fields[i] = {
 | 
					                                fields[i] = {
 | 
				
			||||||
                                    .name = name_buffer[i],
 | 
					                                    .name = name_buffer[i],
 | 
				
			||||||
                                    .value = value,
 | 
					                                    .value = value,
 | 
				
			||||||
@ -3204,7 +3041,7 @@ void parse(Module* module)
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else
 | 
					                        else
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            trap_raw();
 | 
					                            trap();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    } break;
 | 
					                    } break;
 | 
				
			||||||
                case GlobalKeyword::function:
 | 
					                case GlobalKeyword::function:
 | 
				
			||||||
@ -3390,10 +3227,10 @@ void parse(Module* module)
 | 
				
			|||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            .linkage = (is_export | is_extern) ? Linkage::external : Linkage::internal,
 | 
					                            .linkage = (is_export | is_extern) ? Linkage::external : Linkage::internal,
 | 
				
			||||||
                        };
 | 
					                        };
 | 
				
			||||||
                        module->current_function = global;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if (!is_declaration)
 | 
					                        if (!is_declaration)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
 | 
					                            module->current_function = global;
 | 
				
			||||||
                            Slice<Argument> arguments = arena_allocate<Argument>(module->arena, semantic_argument_count);
 | 
					                            Slice<Argument> arguments = arena_allocate<Argument>(module->arena, semantic_argument_count);
 | 
				
			||||||
                            for (u32 i = 0; i < semantic_argument_count; i += 1)
 | 
					                            for (u32 i = 0; i < semantic_argument_count; i += 1)
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@ -3412,7 +3249,7 @@ void parse(Module* module)
 | 
				
			|||||||
                                        .line = line,
 | 
					                                        .line = line,
 | 
				
			||||||
                                        .column = 0,
 | 
					                                        .column = 0,
 | 
				
			||||||
                                    },
 | 
					                                    },
 | 
				
			||||||
                                    .index = i,
 | 
					                                    .index = i + 1,
 | 
				
			||||||
                                };
 | 
					                                };
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3430,12 +3267,15 @@ void parse(Module* module)
 | 
				
			|||||||
                            storage->id = ValueId::function;
 | 
					                            storage->id = ValueId::function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            storage->function.block = parse_block(module, &storage->function.scope);
 | 
					                            storage->function.block = parse_block(module, &storage->function.scope);
 | 
				
			||||||
 | 
					                            module->current_function = 0;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    } break;
 | 
					                    } break;
 | 
				
			||||||
                case GlobalKeyword::macro:
 | 
					                case GlobalKeyword::macro:
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        Type* type_argument_buffer[64];
 | 
					                        Type* type_argument_buffer[64];
 | 
				
			||||||
                        u64 type_argument_count = 0;
 | 
					                        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;
 | 
				
			||||||
@ -3463,7 +3303,7 @@ void parse(Module* module)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                                if (has_value)
 | 
					                                if (has_value)
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    trap_raw(); // TODO
 | 
					                                    trap(); // TODO
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                else
 | 
					                                else
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
@ -3520,7 +3360,7 @@ void parse(Module* module)
 | 
				
			|||||||
                        if (module->last_macro_declaration)
 | 
					                        if (module->last_macro_declaration)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            assert(module->first_macro_declaration);
 | 
					                            assert(module->first_macro_declaration);
 | 
				
			||||||
                            trap_raw();
 | 
					                            trap();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else
 | 
					                        else
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@ -3568,7 +3408,7 @@ void parse(Module* module)
 | 
				
			|||||||
                                    .line = argument_line,
 | 
					                                    .line = argument_line,
 | 
				
			||||||
                                    .column = argument_column,
 | 
					                                    .column = argument_column,
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
                                .index = argument_index,
 | 
					                                .index = argument_index + 1,
 | 
				
			||||||
                            };
 | 
					                            };
 | 
				
			||||||
                            argument_count += 1;
 | 
					                            argument_count += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3601,7 +3441,7 @@ void parse(Module* module)
 | 
				
			|||||||
                        Type* struct_type;
 | 
					                        Type* struct_type;
 | 
				
			||||||
                        if (forward_declaration)
 | 
					                        if (forward_declaration)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            trap_raw();
 | 
					                            struct_type = forward_declaration;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else
 | 
					                        else
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								tests/basic_bool_call.bbb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/basic_bool_call.bbb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					require = fn (ok: u1) void
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!ok) #trap();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bb_bool = fn (x: u8) void
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    require(#truncate(x));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[export] main = fn [cc(c)] () s32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bb_bool(1);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								tests/basic_shortcircuiting_if.bbb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/basic_shortcircuiting_if.bbb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					[export] main = fn [cc(c)] (argument_count: u32) s32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    >a: s32 = 0;
 | 
				
			||||||
 | 
					    if (argument_count != 3 and? argument_count != 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								tests/forward_declared_type.bbb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tests/forward_declared_type.bbb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					T = struct;
 | 
				
			||||||
 | 
					Foo = struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    t: &T,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					T = struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    f: Foo,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[export] main = fn [cc(c)] () s32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    >t: T = zero;
 | 
				
			||||||
 | 
					    t.f.t = &t;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								tests/self_referential_struct.bbb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/self_referential_struct.bbb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					S = struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    self: &S,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[export] main = fn [cc(c)] () s32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    >s: S = zero;
 | 
				
			||||||
 | 
					    s.self = &s;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user