Hello world string

This commit is contained in:
David Gonzalez Martin 2024-06-16 20:43:35 -05:00
parent 200cc7b76e
commit 610faec907
3 changed files with 391 additions and 49 deletions

View File

@ -670,23 +670,34 @@ const Parser = struct{
parser.skip_space(src); parser.skip_space(src);
const element_count = parser.parse_constant_expression(thread, file, null); if (src[parser.i] == ']') {
switch (element_count.sema.id) { // Slice
.constant_int => { parser.i += 1;
const constant_int = element_count.get_payload(.constant_int);
parser.skip_space(src);
parser.expect_character(src, ']');
parser.skip_space(src);
const element_type = parser.parse_type_expression(thread, file, current_scope); const element_type = parser.parse_type_expression(thread, file, current_scope);
const array_type = get_array_type(thread, .{ const slice_type = get_slice_type(thread, element_type);
.element_type = element_type, return slice_type;
.element_count = constant_int.n, } else {
}); // Array
return array_type; const element_count = parser.parse_constant_expression(thread, file, null);
}, switch (element_count.sema.id) {
else => |t| @panic(@tagName(t)), .constant_int => {
const constant_int = element_count.get_payload(.constant_int);
parser.skip_space(src);
parser.expect_character(src, ']');
parser.skip_space(src);
const element_type = parser.parse_type_expression(thread, file, current_scope);
const array_type = get_array_type(thread, .{
.element_type = element_type,
.element_count = constant_int.n,
});
return array_type;
},
else => |t| @panic(@tagName(t)),
}
} }
} }
const identifier = parser.parse_identifier(thread, src); const identifier = parser.parse_identifier(thread, src);
@ -858,6 +869,13 @@ const Parser = struct{
}; };
} }
fn get_escape_character(ch: u8) u8 {
return switch (ch) {
'n' => '\n',
else => unreachable,
};
}
fn parse_single_expression(parser: *Parser, analyzer: *Analyzer, thread: *Thread, file: *File, maybe_type: ?*Type, side: Side) *Value { fn parse_single_expression(parser: *Parser, analyzer: *Analyzer, thread: *Thread, file: *File, maybe_type: ?*Type, side: Side) *Value {
const src = file.source_code; const src = file.source_code;
const Unary = enum{ const Unary = enum{
@ -878,10 +896,7 @@ const Parser = struct{
parser.i += 1; parser.i += 1;
parser.expect_character(src, '\''); parser.expect_character(src, '\'');
const ch = switch (is_escape) { const ch = switch (is_escape) {
true => switch (potential_ch) { true => get_escape_character(potential_ch),
'n' => '\n',
else => unreachable,
},
false => potential_ch, false => potential_ch,
}; };
const character_literal = create_constant_int(thread, .{ const character_literal = create_constant_int(thread, .{
@ -890,6 +905,148 @@ const Parser = struct{
}); });
return &character_literal.value; return &character_literal.value;
}, },
'"' => {
// String literal
parser.i += 1;
const string_start = parser.i;
var hash: u64 = library.fnv_offset;
var escape_character_count: u64 = 0;
while (parser.i < src.len) {
if (src[parser.i] == '"') {
break;
}
const is_escape = src[parser.i] == '\\';
parser.i += @intFromBool(is_escape);
escape_character_count += @intFromBool(is_escape);
const potential_ch = src[parser.i];
parser.i += 1;
if (is_escape) {
hash ^= '\\';
hash *%= library.fnv_prime;
}
hash ^= potential_ch;
hash *%= library.fnv_prime;
}
const string_end = parser.i;
parser.i += 1;
const StringKind = enum{
array,
global,
};
const kind: StringKind = if (maybe_type) |ty| switch (ty.sema.id) {
// TODO: typecheck
.slice => .global,
else => |t| @panic(@tagName(t)),
} else .array;
switch (kind) {
.global => {
const truncated_hash: u32 = @truncate(hash);
const string = if (thread.global_strings.get_pointer(truncated_hash)) |string| string
else blk: {
const expected_length: u32 = @intCast((string_end + 1) - (string_start + escape_character_count));
const string_content = thread.string_buffer.add_slice(expected_length);
var source_index: usize = string_start;
var destination_index: usize = 0;
while (source_index < string_end) {
const is_escape = src[source_index] == '\\';
source_index += @intFromBool(is_escape);
const ch = switch (is_escape) {
true => get_escape_character(src[source_index]),
false => src[source_index],
};
string_content[destination_index] = ch;
destination_index += 1;
source_index += 1;
}
string_content[destination_index] = 0;
const string = thread.global_strings.put_no_clobber(truncated_hash, .{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .global_string_literal,
},
},
.content = string_content,
.source_file_hash = truncated_hash,
.emit = false,
});
break :blk string;
};
var values = PinnedArray(*Value){};
_ = values.append(&string.value);
_ = values.append(&create_constant_int(thread, .{
.n = string.content.len,
.type = &thread.integers[63].type,
}).value);
const constant_struct = thread.constant_structs.append(.{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .constant_struct,
},
},
.type = maybe_type orelse unreachable,
.values = values.const_slice(),
});
return &constant_struct.value;
},
.array => {
const truncated_hash: u32 = @truncate(hash);
if (thread.constant_strings.get_pointer(truncated_hash)) |string| {
return &string.value;
} else {
const expected_length: u32 = @intCast((string_end + 1) - (string_start + escape_character_count));
const string_content = thread.string_buffer.add_slice(expected_length);
var source_index: usize = string_start;
var destination_index: usize = 0;
while (source_index < string_end) {
const is_escape = src[source_index] == '\\';
source_index += @intFromBool(is_escape);
const ch = switch (is_escape) {
true => get_escape_character(src[source_index]),
false => src[source_index],
};
string_content[destination_index] = ch;
destination_index += 1;
source_index += 1;
}
string_content[destination_index] = 0;
const string = thread.constant_strings.put_no_clobber(truncated_hash, .{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .constant_string_literal,
},
},
.content = string_content,
.source_file_hash = truncated_hash,
.emit = false,
});
return &string.value;
}
},
}
},
'-' => block: { '-' => block: {
parser.i += 1; parser.i += 1;
break :block .negation; break :block .negation;
@ -1960,6 +2117,46 @@ const Parser = struct{
fail_term("Array access must only be 'length', got", array_field_access_id); fail_term("Array access must only be 'length', got", array_field_access_id);
} }
}, },
.slice => {
const slice_field_access_id = parser.parse_raw_identifier(src);
if (byte_equal(slice_field_access_id, "pointer")) {
const slice_type = ty.get_payload(.slice);
const load = emit_load(analyzer, thread, .{
.value = value,
.type = get_typed_pointer(thread, .{
.pointee = slice_type.element_type,
}),
.scope = analyzer.current_scope,
.line = 0,
.column = 0,
});
return &load.instruction.value;
} else if (byte_equal(slice_field_access_id, "length")) {
const gep = emit_gep(thread, analyzer, .{
.line = 0,
.column = 0,
.scope = analyzer.current_scope,
.pointer = value,
.index = &create_constant_int(thread, .{
.n = 1,
.type = &thread.integers[31].type,
}).value,
.aggregate_type = ty,
.type = &thread.integers[63].type,
.is_struct = true,
});
const load = emit_load(analyzer, thread, .{
.value = &gep.instruction.value,
.type = &thread.integers[63].type,
.scope = analyzer.current_scope,
.line = 0,
.column = 0,
});
return &load.instruction.value;
} else {
fail_term("Slice access must be either 'pointer' or 'length', got", slice_field_access_id);
}
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }
@ -2559,6 +2756,8 @@ const Value = struct {
global_symbol, global_symbol,
lazy_expression, lazy_expression,
local_lazy_expression, local_lazy_expression,
constant_string_literal,
global_string_literal,
undefined, undefined,
}; };
@ -2573,6 +2772,8 @@ const Value = struct {
.instruction = Instruction, .instruction = Instruction,
.lazy_expression = LazyExpression, .lazy_expression = LazyExpression,
.local_lazy_expression = LocalLazyExpression, .local_lazy_expression = LocalLazyExpression,
.constant_string_literal = String,
.global_string_literal = String,
.undefined = Undefined, .undefined = Undefined,
}); });
@ -2656,6 +2857,25 @@ const Value = struct {
const constant_struct = value.get_payload(.constant_struct); const constant_struct = value.get_payload(.constant_struct);
return constant_struct.type; return constant_struct.type;
}, },
.constant_string_literal => {
const string_literal = value.get_payload(.constant_string_literal);
const thread = &instance.threads[string_literal.value.sema.thread];
const array_type = get_array_type(thread, .{
.element_type = &thread.integers[8 - 1].type,
.element_count = string_literal.content.len,
});
return array_type;
},
.global_string_literal => {
unreachable;
// const string_literal = value.get_payload(.string_literal);
// const thread = &instance.threads[string_literal.value.sema.thread];
// const array_type = get_array_type(thread, .{
// .element_type = &thread.integers[8 - 1].type,
// .element_count = string_literal.content.len,
// });
// return array_type;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }
@ -2687,6 +2907,7 @@ const Type = struct {
@"struct", @"struct",
bitfield, bitfield,
anonymous_struct, anonymous_struct,
slice,
}; };
const Integer = struct { const Integer = struct {
@ -2751,6 +2972,11 @@ const Type = struct {
}; };
}; };
const Slice = struct{
type: Type,
element_type: *Type,
};
const id_to_type_map = std.EnumArray(Id, type).init(.{ const id_to_type_map = std.EnumArray(Id, type).init(.{
.unresolved = void, .unresolved = void,
.void = void, .void = void,
@ -2763,6 +2989,7 @@ const Type = struct {
.bitfield = Type.Bitfield, .bitfield = Type.Bitfield,
.typed_pointer = TypedPointer, .typed_pointer = TypedPointer,
.anonymous_struct = AnonymousStruct, .anonymous_struct = AnonymousStruct,
.slice = Slice,
}); });
fn get_payload(ty: *Type, comptime id: Id) *id_to_type_map.get(id) { fn get_payload(ty: *Type, comptime id: Id) *id_to_type_map.get(id) {
@ -2850,7 +3077,7 @@ const Type = struct {
result.llvm = null; result.llvm = null;
result.sema.thread = args.destination_thread.get_index(); result.sema.thread = args.destination_thread.get_index();
args.destination_thread.cloned_types.put_no_clobber(ty, result); _ = args.destination_thread.cloned_types.put_no_clobber(ty, result);
break :blk result; break :blk result;
}; };
@ -2873,7 +3100,7 @@ const Type = struct {
.bitfield, .bitfield,
=> =>
false, false,
.@"struct", .anonymous_struct => true, .@"struct", .anonymous_struct, .slice => true,
}; };
} }
@ -3555,6 +3782,16 @@ const DebugArgument = struct{
argument: *ArgumentSymbol, argument: *ArgumentSymbol,
}; };
const String = struct{
value: Value,
content: []const u8,
// This hash amounts to the source file bytes, not the actual string bytes
// in the final object
source_file_hash: u32,
null_terminate: bool = true,
emit: bool,
};
const Thread = struct{ const Thread = struct{
arena: *Arena = undefined, arena: *Arena = undefined,
functions: PinnedArray(Function) = .{}, functions: PinnedArray(Function) = .{},
@ -3599,6 +3836,7 @@ const Thread = struct{
array_type_map: PinnedHashMap(Type.Array.Descriptor, *Type) = .{}, array_type_map: PinnedHashMap(Type.Array.Descriptor, *Type) = .{},
typed_pointer_type_map: PinnedHashMap(Type.TypedPointer.Descriptor, *Type) = .{}, typed_pointer_type_map: PinnedHashMap(Type.TypedPointer.Descriptor, *Type) = .{},
array_types: PinnedArray(Type.Array) = .{}, array_types: PinnedArray(Type.Array) = .{},
slice_types: PinnedHashMap(*Type, Type.Slice) = .{},
typed_pointer_types: PinnedArray(Type.TypedPointer) = .{}, typed_pointer_types: PinnedArray(Type.TypedPointer) = .{},
structs: PinnedArray(Type.Struct) = .{}, structs: PinnedArray(Type.Struct) = .{},
anonymous_structs: PinnedArray(Type.AnonymousStruct) = .{}, anonymous_structs: PinnedArray(Type.AnonymousStruct) = .{},
@ -3606,6 +3844,9 @@ const Thread = struct{
fields: PinnedArray(Type.AggregateField) = .{}, fields: PinnedArray(Type.AggregateField) = .{},
bitfields: PinnedArray(Type.Bitfield) = .{}, bitfields: PinnedArray(Type.Bitfield) = .{},
cloned_types: PinnedHashMap(*Type, *Type) = .{}, cloned_types: PinnedHashMap(*Type, *Type) = .{},
constant_strings: PinnedHashMap(u32, String) = .{},
global_strings: PinnedHashMap(u32, String) = .{},
string_buffer: PinnedArray(u8) = .{},
analyzed_file_count: u32 = 0, analyzed_file_count: u32 = 0,
assigned_file_count: u32 = 0, assigned_file_count: u32 = 0,
llvm: struct { llvm: struct {
@ -3618,6 +3859,8 @@ const Thread = struct{
fixed_intrinsic_functions: std.EnumArray(LLVMFixedIntrinsic, *LLVM.Value.Constant.Function), fixed_intrinsic_functions: std.EnumArray(LLVMFixedIntrinsic, *LLVM.Value.Constant.Function),
intrinsic_id_map: PinnedHashMap([]const u8, LLVM.Value.IntrinsicID) = .{}, intrinsic_id_map: PinnedHashMap([]const u8, LLVM.Value.IntrinsicID) = .{},
intrinsic_function_map: PinnedHashMap(LLVMIntrinsic.Parameters, *LLVM.Value.Constant.Function) = .{}, intrinsic_function_map: PinnedHashMap(LLVMIntrinsic.Parameters, *LLVM.Value.Constant.Function) = .{},
pointer: *LLVM.Type,
slice: *LLVM.Type,
} = undefined, } = undefined,
integers: [128]Type.Integer = blk: { integers: [128]Type.Integer = blk: {
var integers: [128]Type.Integer = undefined; var integers: [128]Type.Integer = undefined;
@ -4683,7 +4926,7 @@ fn intern_identifier(pool: *PinnedHashMap(u32, []const u8), identifier: []const
const start_index = @intFromBool(identifier[0] == '"'); const start_index = @intFromBool(identifier[0] == '"');
const end_index = identifier.len - start_index; const end_index = identifier.len - start_index;
const hash = hash_bytes(identifier[start_index..end_index]); const hash = hash_bytes(identifier[start_index..end_index]);
pool.put(hash, identifier); _ = pool.put(hash, identifier);
return hash; return hash;
} }
@ -4993,6 +5236,9 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
module.setTargetMachineDataLayout(target_machine); module.setTargetMachineDataLayout(target_machine);
module.setTargetTriple(target_triple.ptr, target_triple.len); module.setTargetTriple(target_triple.ptr, target_triple.len);
const pointer_type = context.getPointerType(address_space);
const usize_type = context.getIntegerType(64);
const slice_types: []const *LLVM.Type = &.{pointer_type.toType(), usize_type.toType()};
thread.llvm = .{ thread.llvm = .{
.context = context, .context = context,
@ -5009,8 +5255,14 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
.types = &.{}, .types = &.{},
}), }),
}), }),
.slice = context.getStructType(slice_types.ptr, slice_types.len, false).toType(),
.pointer = pointer_type.toType(),
}; };
for (thread.global_strings.values()) |*string| {
string.value.llvm = builder.createGlobalString(string.content.ptr, string.content.len, string.content.ptr, string.content.len, address_space, module).toValue();
}
for (thread.external_functions.slice()) |*nat_function| { for (thread.external_functions.slice()) |*nat_function| {
llvm_emit_function_declaration(thread, nat_function); llvm_emit_function_declaration(thread, nat_function);
} }
@ -6264,6 +6516,10 @@ fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value {
const poison = ty.getPoison(); const poison = ty.getPoison();
break :b poison.toValue(); break :b poison.toValue();
}, },
.constant_string_literal => b: {
const string_literal = value.get_payload(.constant_string_literal);
break :b thread.llvm.context.getConstantString(string_literal.content.ptr, string_literal.content.len, false).toValue();
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -6482,6 +6738,55 @@ fn llvm_get_debug_type(thread: *Thread, builder: *LLVM.DebugInfo.Builder, ty: *T
builder.replaceCompositeTypes(struct_type, member_types.pointer, member_types.length); builder.replaceCompositeTypes(struct_type, member_types.pointer, member_types.length);
break :block struct_type.toType(); break :block struct_type.toType();
}, },
.slice => block: {
const nat_slice_type = ty.get_payload(.slice);
const file_struct = llvm_get_file(thread, 0);
const element_type = llvm_get_debug_type(thread, builder, nat_slice_type.element_type);
const usize_type = llvm_get_debug_type(thread, builder, &thread.integers[63].type);
const flags = LLVM.DebugInfo.Node.Flags{
.visibility = .none,
.forward_declaration = false,
.apple_block = false,
.block_by_ref_struct = false,
.virtual = false,
.artificial = false,
.explicit = false,
.prototyped = false,
.objective_c_class_complete = false,
.object_pointer = false,
.vector = false,
.static_member = false,
.lvalue_reference = false,
.rvalue_reference = false,
.reserved = false,
.inheritance = .none,
.introduced_virtual = false,
.bit_field = false,
.no_return = false,
.type_pass_by_value = false,
.type_pass_by_reference = false,
.enum_class = false,
.thunk = false,
.non_trivial = false,
.big_endian = false,
.little_endian = false,
.all_calls_described = false,
};
const file = file_struct.file;
const name = "[]";
const line = 0;
const bitsize = nat_slice_type.type.size * 8;
const alignment = nat_slice_type.type.alignment;
const pointer_name = "pointer";
const length_name = "length";
const members = [_]*LLVM.DebugInfo.Type{builder.createMemberType(null, pointer_name, pointer_name.len, null, line, 64, 8, 0, flags, element_type).toType(), builder.createMemberType(null, length_name, length_name.len, null, line, 64, 8, 0, flags, usize_type).toType()};
const struct_type = builder.createStructType(file.toScope(), name.ptr, name.len, file, line, bitsize, alignment, flags, null, &members, members.len, null);
break :block struct_type.toType();
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -6512,10 +6817,8 @@ fn llvm_get_type(thread: *Thread, ty: *Type) *LLVM.Type {
const array_type = LLVM.Type.Array.get(element_type, array_ty.descriptor.element_count); const array_type = LLVM.Type.Array.get(element_type, array_ty.descriptor.element_count);
break :b array_type.toType(); break :b array_type.toType();
}, },
.opaque_pointer, .typed_pointer => b: { .opaque_pointer, .typed_pointer => thread.llvm.pointer,
const pointer_type = thread.llvm.context.getPointerType(address_space); .slice => thread.llvm.slice,
break :b pointer_type.toType();
},
.function => b: { .function => b: {
const nat_function_type = ty.get_payload(.function); const nat_function_type = ty.get_payload(.function);
const return_type = llvm_get_type(thread, nat_function_type.abi.abi_return_type); const return_type = llvm_get_type(thread, nat_function_type.abi.abi_return_type);
@ -6593,13 +6896,11 @@ fn llvm_get_file(thread: *Thread, file_index: u32) *LLVMFile {
const sdk = ""; const sdk = "";
const compile_unit = builder.createCompileUnit(LLVM.DebugInfo.Language.c11, llvm_file, producer, producer.len, is_optimized, flags, flags.len, runtime_version, splitname, splitname.len, debug_info_kind, DWOId, split_debug_inlining, debug_info_for_profiling, name_table_kind, ranges_base_address, sysroot, sysroot.len, sdk, sdk.len); const compile_unit = builder.createCompileUnit(LLVM.DebugInfo.Language.c11, llvm_file, producer, producer.len, is_optimized, flags, flags.len, runtime_version, splitname, splitname.len, debug_info_kind, DWOId, split_debug_inlining, debug_info_for_profiling, name_table_kind, ranges_base_address, sysroot, sysroot.len, sdk, sdk.len);
thread.debug_info_file_map.put_no_clobber(file_index, .{ return thread.debug_info_file_map.put_no_clobber(file_index, .{
.file = llvm_file, .file = llvm_file,
.compile_unit = compile_unit, .compile_unit = compile_unit,
.builder = builder, .builder = builder,
}); });
return thread.debug_info_file_map.get_pointer(file_index).?;
} }
} }
@ -7902,7 +8203,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.initial_value = global_initial_value, .initial_value = global_initial_value,
}); });
file.scope.scope.declarations.put_no_clobber(global_name, &global_variable.global_symbol.global_declaration.declaration); _ = file.scope.scope.declarations.put_no_clobber(global_name, &global_variable.global_symbol.global_declaration.declaration);
}, },
'b' => { 'b' => {
const identifier = parser.parse_raw_identifier(src); const identifier = parser.parse_raw_identifier(src);
@ -7947,7 +8248,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.fields = &.{}, .fields = &.{},
.backing_type = backing_type, .backing_type = backing_type,
}); });
file.scope.scope.declarations.put_no_clobber(bitfield_name, &bitfield_type.declaration); _ = file.scope.scope.declarations.put_no_clobber(bitfield_name, &bitfield_type.declaration);
parser.skip_space(src); parser.skip_space(src);
@ -8692,7 +8993,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}, },
.entry_block = entry_block, .entry_block = entry_block,
}; };
file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration); _ = file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration);
var analyzer = Analyzer{ var analyzer = Analyzer{
.current_function = function, .current_function = function,
.current_basic_block = entry_block, .current_basic_block = entry_block,
@ -8905,7 +9206,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}; };
if (argument.name != 0) { if (argument.name != 0) {
analyzer.current_scope.declarations.put_no_clobber(argument.name, &argument_symbol.argument_declaration.declaration); _ = analyzer.current_scope.declarations.put_no_clobber(argument.name, &argument_symbol.argument_declaration.declaration);
if (thread.generate_debug_information) { if (thread.generate_debug_information) {
emit_debug_argument(&analyzer, thread, .{ emit_debug_argument(&analyzer, thread, .{
.argument_symbol = argument_symbol, .argument_symbol = argument_symbol,
@ -8957,7 +9258,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
function_declaration_data.global_symbol.id = .function_declaration; function_declaration_data.global_symbol.id = .function_declaration;
const function_declaration = thread.external_functions.append(function_declaration_data); const function_declaration = thread.external_functions.append(function_declaration_data);
file.scope.scope.declarations.put_no_clobber(function_declaration.global_symbol.global_declaration.declaration.name, &function_declaration.global_symbol.global_declaration.declaration); _ = file.scope.scope.declarations.put_no_clobber(function_declaration.global_symbol.global_declaration.declaration.name, &function_declaration.global_symbol.global_declaration.declaration);
}, },
else => fail_message("Unexpected character to close function declaration"), else => fail_message("Unexpected character to close function declaration"),
} }
@ -9013,8 +9314,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}); });
_ = import.files.append(file); _ = import.files.append(file);
_ = file.imports.append(import); _ = file.imports.append(import);
file.scope.scope.declarations.put_no_clobber(filename_without_extension_hash, &import.global_declaration.declaration); const global_declaration_reference: **GlobalDeclaration = @ptrCast(file.scope.scope.declarations.put_no_clobber(filename_without_extension_hash, &import.global_declaration.declaration));
const global_declaration_reference: **GlobalDeclaration = @ptrCast(file.scope.scope.declarations.get_pointer(filename_without_extension_hash) orelse unreachable);
const import_values = file.values_per_import.append(.{}); const import_values = file.values_per_import.append(.{});
const lazy_expression = thread.lazy_expressions.append(LazyExpression.init(global_declaration_reference, thread)); const lazy_expression = thread.lazy_expressions.append(LazyExpression.init(global_declaration_reference, thread));
_ = import_values.append(&lazy_expression.value); _ = import_values.append(&lazy_expression.value);
@ -9056,7 +9356,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}, },
.fields = &.{}, .fields = &.{},
}); });
file.scope.scope.declarations.put_no_clobber(struct_name, &struct_type.declaration); _ = file.scope.scope.declarations.put_no_clobber(struct_name, &struct_type.declaration);
parser.skip_space(src); parser.skip_space(src);
@ -9404,7 +9704,7 @@ fn emit_local_symbol(analyzer: *Analyzer, thread: *Thread, args: struct{
_ = analyzer.current_function.stack_slots.append(local_symbol); _ = analyzer.current_function.stack_slots.append(local_symbol);
if (args.name != 0) { if (args.name != 0) {
analyzer.current_scope.declarations.put_no_clobber(args.name, &local_symbol.local_declaration.declaration); _ = analyzer.current_scope.declarations.put_no_clobber(args.name, &local_symbol.local_declaration.declaration);
if (thread.generate_debug_information) { if (thread.generate_debug_information) {
emit_debug_local(analyzer, thread, .{ emit_debug_local(analyzer, thread, .{
.local_symbol = local_symbol, .local_symbol = local_symbol,
@ -9691,7 +9991,7 @@ fn get_typed_pointer(thread: *Thread, descriptor: Type.TypedPointer.Descriptor)
.descriptor = descriptor, .descriptor = descriptor,
}); });
thread.typed_pointer_type_map.put_no_clobber(descriptor, &typed_pointer_type.type); _ = thread.typed_pointer_type_map.put_no_clobber(descriptor, &typed_pointer_type.type);
return &typed_pointer_type.type; return &typed_pointer_type.type;
} }
} }
@ -9736,12 +10036,30 @@ fn get_anonymous_two_field_struct(thread: *Thread, types: [2]*Type) *Type {
.fields = fields, .fields = fields,
}; };
thread.two_struct_map.put_no_clobber(types, &anonymous_struct.type); _ = thread.two_struct_map.put_no_clobber(types, &anonymous_struct.type);
return &anonymous_struct.type; return &anonymous_struct.type;
} }
} }
fn get_slice_type(thread: *Thread, ty: *Type) *Type {
if (thread.slice_types.get_pointer(ty)) |slice_type| return &slice_type.type else {
const slice_type = thread.slice_types.put_no_clobber(ty, .{
.element_type = ty,
.type = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .slice,
},
.size = 2 * 8,
.bit_size = 2 * 8 * 8,
.alignment = 8,
},
});
return &slice_type.type;
}
}
fn get_array_type(thread: *Thread, descriptor: Type.Array.Descriptor) *Type { fn get_array_type(thread: *Thread, descriptor: Type.Array.Descriptor) *Type {
assert(descriptor.element_type.sema.resolved); assert(descriptor.element_type.sema.resolved);
if (thread.array_type_map.get(descriptor)) |result| return result else { if (thread.array_type_map.get(descriptor)) |result| return result else {
@ -9759,7 +10077,7 @@ fn get_array_type(thread: *Thread, descriptor: Type.Array.Descriptor) *Type {
.descriptor = descriptor, .descriptor = descriptor,
}); });
thread.array_type_map.put_no_clobber(descriptor, &array_type.type); _ = thread.array_type_map.put_no_clobber(descriptor, &array_type.type);
return &array_type.type; return &array_type.type;
} }
} }
@ -9817,7 +10135,7 @@ pub const LLVM = struct {
const create = bindings.NativityLLVMCreateContext; const create = bindings.NativityLLVMCreateContext;
const createBasicBlock = bindings.NativityLLVMCreateBasicBlock; const createBasicBlock = bindings.NativityLLVMCreateBasicBlock;
const getConstantInt = bindings.NativityLLVMContextGetConstantInt; const getConstantInt = bindings.NativityLLVMContextGetConstantInt;
const getConstString = bindings.NativityLLVMContextGetConstString; const getConstantString = bindings.NativityLLVMContextGetConstantString;
const getVoidType = bindings.NativityLLVMGetVoidType; const getVoidType = bindings.NativityLLVMGetVoidType;
const getIntegerType = bindings.NativityLLVMGetIntegerType; const getIntegerType = bindings.NativityLLVMGetIntegerType;
const getPointerType = bindings.NativityLLVMGetPointerType; const getPointerType = bindings.NativityLLVMGetPointerType;

View File

@ -258,11 +258,24 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type, comptim
return ptr; return ptr;
} }
pub fn add_many_with_capacity(array: *Array, count: u32) []T {
const index = array.length;
assert((index + count) * @sizeOf(T) < pinned_array_max_size);
array.length += count;
const ptr = array.pointer[index..][0..count];
return ptr;
}
pub fn add_one(array: *Array) *T{ pub fn add_one(array: *Array) *T{
array.ensure_capacity(1); array.ensure_capacity(1);
return array.add_one_with_capacity(); return array.add_one_with_capacity();
} }
pub fn add_slice(array: *Array, count: u32) []T {
array.ensure_capacity(count);
return array.add_many_with_capacity(count);
}
pub fn append_with_capacity(array: *Array, item: T) *T { pub fn append_with_capacity(array: *Array, item: T) *T {
const ptr = array.add_one_with_capacity(); const ptr = array.add_one_with_capacity();
ptr.* = item; ptr.* = item;
@ -359,9 +372,9 @@ fn JointEnum(comptime enums: []const type, comptime backing_type: ?type) type {
}); });
} }
pub const fnv_offset = 14695981039346656037;
pub const fnv_prime = 1099511628211;
pub fn my_hash(bytes: []const u8) u32 { pub fn my_hash(bytes: []const u8) u32 {
const fnv_offset = 14695981039346656037;
const fnv_prime = 1099511628211;
var result: u64 = fnv_offset; var result: u64 = fnv_offset;
for (bytes) |byte| { for (bytes) |byte| {
@ -466,28 +479,30 @@ pub fn PinnedHashMapAdvanced(comptime K: type, comptime V: type, comptime granul
} }
} }
pub fn put(map: *@This(), key: K, value: V) void { pub fn put(map: *@This(), key: K, value: V) *V {
if (map.get_pointer(key)) |value_pointer| { if (map.get_pointer(key)) |value_pointer| {
value_pointer.* = value; value_pointer.* = value;
return value_pointer;
} else { } else {
const len = map.length; const len = map.length;
map.ensure_capacity(len + 1); map.ensure_capacity(len + 1);
map.put_at_with_capacity(len, key, value); return map.put_at_with_capacity(len, key, value);
} }
} }
pub fn put_no_clobber(map: *@This(), key: K, value: V) void { pub fn put_no_clobber(map: *@This(), key: K, value: V) *V {
assert(map.get_pointer(key) == null); assert(map.get_pointer(key) == null);
const len = map.length; const len = map.length;
map.ensure_capacity(len + 1); map.ensure_capacity(len + 1);
map.put_at_with_capacity(len, key, value); return map.put_at_with_capacity(len, key, value);
} }
fn put_at_with_capacity(map: *@This(), index: u64, key: K, value: V) void { fn put_at_with_capacity(map: *@This(), index: u64, key: K, value: V) *V {
map.length += 1; map.length += 1;
assert(index < map.length); assert(index < map.length);
map.key_pointer[index] = key; map.key_pointer[index] = key;
map.value_pointer[index] = value; map.value_pointer[index] = value;
return &map.value_pointer[index];
} }
fn ensure_capacity(map: *Map, additional: u64) void { fn ensure_capacity(map: *Map, additional: u64) void {

View File

@ -0,0 +1,9 @@
fn [cc(.c)] write[extern](file_descriptor: s32, byte_pointer: *u8, byte_count: u64) s64;
fn[cc(.c)] main[export]() s32 {
>local_string = "Hello world from local string!\n";
write(1, local_string&, local_string.length);
>global_string: []u8 = "Hello world from global string!\n";
write(1, global_string.pointer, global_string.length);
return 0;
}