diff --git a/bootstrap/compiler.zig b/bootstrap/compiler.zig index 0baf711..6dd4d3d 100644 --- a/bootstrap/compiler.zig +++ b/bootstrap/compiler.zig @@ -869,6 +869,27 @@ const Parser = struct{ const unary: Unary = switch (src[parser.i]) { 'A'...'Z', 'a'...'z', '_' => Unary.none, '0'...'9' => Unary.none, + '\'' => { + // Character literal + parser.i += 1; + const is_escape = src[parser.i] == '\\'; + parser.i += @intFromBool(is_escape); + const potential_ch = src[parser.i]; + parser.i += 1; + parser.expect_character(src, '\''); + const ch = switch (is_escape) { + true => switch (potential_ch) { + 'n' => '\n', + else => unreachable, + }, + false => potential_ch, + }; + const character_literal = create_constant_int(thread, .{ + .n = ch, + .type = &thread.integers[8 - 1].type, + }); + return &character_literal.value; + }, '-' => block: { parser.i += 1; break :block .negation; @@ -1232,6 +1253,7 @@ const Parser = struct{ const ty = if (initial_type) |source_ty| if (maybe_type) |destination_ty| blk: { switch (typecheck(destination_ty, source_ty)) { .success => {}, + else => unreachable, } break :blk source_ty; } else source_ty @@ -1435,8 +1457,21 @@ const Parser = struct{ switch (argument_abi.kind) { .direct => { - assert(argument_value_type == argument_type); - _ = abi_argument_values.append(argument_value); + const v = switch (typecheck(argument_type, argument_value_type)) { + .success => argument_value, + .implicit_pointer_cast => b: { + const cast = emit_cast(analyzer, thread, .{ + .value = argument_value, + .type = argument_type, + .id = .implicit_pointer_cast, + .scope = analyzer.current_scope, + .line = 0, + .column = 0, + }); + break :b &cast.instruction.value; + }, + }; + _ = abi_argument_values.append(v); }, .direct_coerce => |coerced_type| { const coerced_value = emit_direct_coerce(analyzer, thread, .{ @@ -1724,6 +1759,7 @@ const Parser = struct{ if (maybe_type) |ty| { switch (typecheck(ty, pointer_load_type)) { .success => {}, + else => unreachable, } } @@ -1854,6 +1890,7 @@ const Parser = struct{ if (expected_type) |expected| { switch (typecheck(expected, result_type)) { .success => {}, + else => unreachable, } } @@ -1910,6 +1947,19 @@ const Parser = struct{ assert(result != value); return result; }, + .array => { + const array_field_access_id = parser.parse_raw_identifier(src); + if (byte_equal(array_field_access_id, "length")) { + const array_type = ty.get_payload(.array); + const constant = create_constant_int(thread, .{ + .n = array_type.descriptor.element_count, + .type = if (expected_type) |exp| exp else unreachable, + }); + return &constant.value; + } else { + fail_term("Array access must only be 'length', got", array_field_access_id); + } + }, else => |t| @panic(@tagName(t)), } } @@ -3428,6 +3478,7 @@ const Cast = struct{ int_from_bitfield, int_from_pointer, truncate, + implicit_pointer_cast, }; }; @@ -5375,7 +5426,9 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void { const cast = instruction.get_payload(.cast); const cast_value = llvm_get_value(thread, cast.value); const v = switch (cast.id) { - .int_from_bitfield => cast_value, + .int_from_bitfield, + .implicit_pointer_cast, + => cast_value, .truncate, .int_from_pointer => |cast_id| b: { const cast_type = llvm_get_type(thread, cast.type); const cast_i = builder.createCast(switch (cast_id) { @@ -9158,12 +9211,35 @@ fn try_resolve_file(thread: *Thread, file: *File) void { const TypecheckResult = enum{ success, + implicit_pointer_cast, }; fn typecheck(expected: *Type, have: *Type) TypecheckResult { if (expected == have) { return TypecheckResult.success; } else { + switch (expected.sema.id) { + .typed_pointer => { + const expected_pointer = expected.get_payload(.typed_pointer); + switch (have.sema.id) { + .typed_pointer => { + const have_pointer = have.get_payload(.typed_pointer); + switch (have_pointer.descriptor.pointee.sema.id) { + .array => { + const have_pointed_array_type = have_pointer.descriptor.pointee.get_payload(.array); + if (have_pointed_array_type.descriptor.element_type == expected_pointer.descriptor.pointee) { + return .implicit_pointer_cast; + } + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + fail(); } } diff --git a/retest/standalone/hello_world_array/main.nat b/retest/standalone/hello_world_array/main.nat new file mode 100644 index 0000000..1a62aba --- /dev/null +++ b/retest/standalone/hello_world_array/main.nat @@ -0,0 +1,6 @@ +fn [cc(.c)] write[extern](file_descriptor: s32, byte_pointer: *u8, byte_count: u64) s64; +fn [cc(.c)] main[export]() s32 { + >arr: [4]u8 = ['H', 'i', '!', '\n']; + write(1, arr&, arr.length); + return 0; +}