diff --git a/build.zig b/build.zig index 6447c07..c33547b 100644 --- a/build.zig +++ b/build.zig @@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void { all = b.option(bool, "all", "All") orelse false; const target = b.standardTargetOptions(.{}); const optimization = b.standardOptimizeOption(.{}); - const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true; + const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse false; const exe = b.addExecutable(.{ .name = "nativity", .root_source_file = .{ .path = "src/main.zig" }, diff --git a/ci.sh b/ci.sh index 56f8e23..9c9c55e 100755 --- a/ci.sh +++ b/ci.sh @@ -2,7 +2,7 @@ echo "Testing Nativity with Zig" echo "Compiling Nativity with Zig" -nativity_use_llvm=false +nativity_use_llvm=true zig build -Duse_llvm=$nativity_use_llvm failed_test_count=0 passed_test_count=0 diff --git a/lib/std/os.nat b/lib/std/os.nat index 4aced36..4b4ffd3 100644 --- a/lib/std/os.nat +++ b/lib/std/os.nat @@ -7,8 +7,8 @@ const system = switch (current) { const write = fn (file_descriptor: FileDescriptor, bytes_ptr: [@]const u8, bytes_len: usize) ssize { switch (current) { - .linux => return #syscall(1, file_descriptor, bytes_ptr, bytes_len), - .macos => return macos.write(file_descriptor, bytes_ptr, bytes_len), + .linux => return #syscall(1, file_descriptor, #cast(bytes_ptr), bytes_len), + .macos => return macos.write(file_descriptor, #cast(bytes_ptr), bytes_len), .windows => { var written_bytes: u32 = 0; if (windows.WriteFile(file_descriptor, bytes_ptr, bytes_len, @written_bytes, false) != 0) { diff --git a/src/Compilation.zig b/src/Compilation.zig index 3226105..dd705ac 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -21,6 +21,7 @@ const syntactic_analyzer = @import("frontend/syntactic_analyzer.zig"); const Node = syntactic_analyzer.Node; const semantic_analyzer = @import("frontend/semantic_analyzer.zig"); const intermediate_representation = @import("backend/intermediate_representation.zig"); +const c_transpiler = @import("backend/c_transpiler.zig"); const emit = @import("backend/emit.zig"); test { @@ -120,7 +121,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor { const arg = arguments[i]; if (std.mem.eql(u8, arg, "true")) { transpile_to_c = true; - } else if (std.mem.equal(u8, arg, "false")) { + } else if (std.mem.eql(u8, arg, "false")) { transpile_to_c = false; } else { unreachable; @@ -301,6 +302,18 @@ pub const Type = union(enum) { .bit_count = 8, .signedness = .unsigned, }); + pub const @"u16" = Type.Integer.getIndex(.{ + .bit_count = 16, + .signedness = .unsigned, + }); + pub const @"u32" = Type.Integer.getIndex(.{ + .bit_count = 32, + .signedness = .unsigned, + }); + pub const @"u64" = Type.Integer.getIndex(.{ + .bit_count = 64, + .signedness = .unsigned, + }); }; // Each time an enum is added here, a corresponding insertion in the initialization must be made @@ -308,6 +321,7 @@ pub const Intrinsic = enum { @"error", import, syscall, + cast, }; pub const FixedTypeKeyword = enum { @@ -479,8 +493,8 @@ const Unresolved = struct { }; pub const Assignment = struct { - store: Value.Index, - load: Value.Index, + destination: Value.Index, + source: Value.Index, pub const List = BlockList(@This()); pub const Index = List.Index; @@ -600,6 +614,7 @@ pub const Value = union(enum) { zero_extend: Cast.Index, binary_operation: BinaryOperation.Index, branch: Branch.Index, + cast: Cast.Index, pub const List = BlockList(@This()); pub const Index = List.Index; @@ -740,6 +755,7 @@ pub const Module = struct { string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{}, array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{}, entry_point: Function.Index = Function.Index.invalid, + descriptor: Descriptor, pub const Descriptor = struct { main_package_path: []const u8, @@ -972,6 +988,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) ! }; break :blk result; }, + .descriptor = descriptor, }; const std_package_dir = "lib/std"; @@ -1074,10 +1091,15 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) ! try semantic_analyzer.initialize(compilation, module, packages[0], value_allocation.ptr); - const ir = try intermediate_representation.initialize(compilation, module); - - switch (descriptor.target.cpu.arch) { - inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor), + if (descriptor.transpile_to_c) { + try c_transpiler.initialize(compilation, module, descriptor); + } else { + unreachable; + // const ir = try intermediate_representation.initialize(compilation, module); + // + // switch (descriptor.target.cpu.arch) { + // inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor), + // } } } @@ -1159,6 +1181,7 @@ const LoggerScope = enum { sema, ir, codegen, + c, }; const Logger = enum { @@ -1177,6 +1200,7 @@ fn getLoggerScopeType(comptime logger_scope: LoggerScope) type { .sema => semantic_analyzer, .ir => intermediate_representation, .codegen => emit, + .c => c_transpiler, }; } } diff --git a/src/backend/c_transpiler.zig b/src/backend/c_transpiler.zig new file mode 100644 index 0000000..916aa56 --- /dev/null +++ b/src/backend/c_transpiler.zig @@ -0,0 +1,383 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; + +const Compilation = @import("../Compilation.zig"); +const Module = Compilation.Module; +const data_structures = @import("../data_structures.zig"); +const ArrayList = data_structures.ArrayList; +const AutoArrayHashMap = data_structures.AutoArrayHashMap; +const StringArrayHashMap = data_structures.StringArrayHashMap; + +pub const Logger = enum { + g, + + pub var bitset = std.EnumSet(Logger).initMany(&.{ + .g, + }); +}; + +pub const TranslationUnit = struct { + string_literals: ArrayList(u8) = .{}, + type_declarations: ArrayList(u8) = .{}, + function_declarations: ArrayList(u8) = .{}, + function_definitions: ArrayList(u8) = .{}, + syscall_bitset: SyscallBitset = SyscallBitset.initEmpty(), + const SyscallBitset = std.StaticBitSet(6); + + fn create(module: *Module, allocator: Allocator) !TranslationUnit { + var unit = TranslationUnit{}; + try unit.type_declarations.appendSlice(allocator, + \\typedef unsigned char u8; + \\typedef unsigned short u16; + \\typedef unsigned int u32; + \\typedef unsigned long u64; + \\typedef u64 usize; + \\static_assert(sizeof(u8) == 1); + \\static_assert(sizeof(u16) == 2); + \\static_assert(sizeof(u32) == 4); + \\static_assert(sizeof(u64) == 8); + \\typedef signed char s8; + \\typedef signed short s16; + \\typedef signed int s32; + \\typedef signed long s64; + \\typedef s64 ssize; + \\static_assert(sizeof(s8) == 1); + \\static_assert(sizeof(s16) == 2); + \\static_assert(sizeof(s32) == 4); + \\static_assert(sizeof(s64) == 8); + \\ + \\ + ); + + { + var function_definitions = module.function_definitions.iterator(); + while (function_definitions.nextIndex()) |function_definition_index| { + const function_definition = module.function_definitions.get(function_definition_index); + try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition_index); + try unit.writeFunctionHeader(module, &unit.function_definitions, allocator, function_definition_index); + try unit.function_declarations.appendSlice(allocator, ";\n\n"); + try unit.function_definitions.append(allocator, ' '); + try unit.writeBlock(module, &unit.function_definitions, allocator, function_definition.body, 1); + try unit.function_definitions.append(allocator, '\n'); + } + } + + return unit; + } + + fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, indentation: usize) !void { + try list.appendSlice(allocator, "{\n"); + const block = module.blocks.get(block_index); + for (block.statements.items) |statement_index| { + try list.appendNTimes(allocator, ' ', indentation * 4); + + const statement = module.values.get(statement_index); + switch (statement.*) { + .declaration => |declaration_index| { + const declaration = module.declarations.get(declaration_index); + if (declaration.mutability == .@"const") { + try list.appendSlice(allocator, "const "); + } + try unit.writeType(module, list, allocator, declaration.type); + + try list.append(allocator, ' '); + + const declaration_name = module.getName(declaration.name).?; + try list.appendSlice(allocator, declaration_name); + + try list.appendSlice(allocator, " = "); + + try unit.writeValue(module, list, allocator, declaration.init_value, indentation); + try list.append(allocator, ';'); + }, + .assign => |assignment_index| { + const assignment = module.assignments.get(assignment_index); + try unit.writeValue(module, list, allocator, assignment.destination, indentation); + try list.appendSlice(allocator, " = "); + try unit.writeValue(module, list, allocator, assignment.source, indentation); + try list.append(allocator, ';'); + }, + .@"return" => |return_index| { + const return_expr = module.returns.get(return_index); + try list.appendSlice(allocator, "return "); + try unit.writeValue(module, list, allocator, return_expr.value, indentation); + try list.append(allocator, ';'); + }, + .syscall => |syscall_index| { + try unit.writeSyscall(module, list, allocator, syscall_index, indentation); + try list.append(allocator, ';'); + }, + .@"unreachable" => { + try writeUnreachable(list, allocator); + try list.append(allocator, ';'); + }, + .call => |call_index| { + try unit.writeCall(module, list, allocator, call_index, indentation); + try list.append(allocator, ';'); + }, + .branch => |branch_index| { + const branch = module.branches.get(branch_index); + try list.appendSlice(allocator, "if ("); + try unit.writeValue(module, list, allocator, branch.condition, indentation); + try list.appendSlice(allocator, ") "); + try unit.writeValue(module, list, allocator, branch.true_expression, indentation); + if (!branch.false_expression.invalid) { + try list.appendSlice(allocator, " else "); + try unit.writeValue(module, list, allocator, branch.false_expression, indentation); + } + }, + else => |t| @panic(@tagName(t)), + } + + try list.append(allocator, '\n'); + } + + try list.appendSlice(allocator, "}\n"); + } + + fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_index: Compilation.Function.Index) !void { + const function_definition = module.function_definitions.get(function_index); + const function_prototype_type = module.types.get(function_definition.prototype); + const function_prototype = module.function_prototypes.get(function_prototype_type.function); + try unit.writeType(module, list, allocator, function_prototype.return_type); + try list.append(allocator, ' '); + const function_name_hash = module.function_name_map.get(function_index).?; + const function_name = module.getName(function_name_hash).?; + try list.appendSlice(allocator, function_name); + + try list.append(allocator, '('); + if (function_prototype.arguments) |function_arguments| { + for (function_arguments) |argument_index| { + const arg_declaration = module.declarations.get(argument_index); + try unit.writeType(module, list, allocator, arg_declaration.type); + try list.append(allocator, ' '); + const arg_name = module.getName(arg_declaration.name).?; + try list.appendSlice(allocator, arg_name); + try list.append(allocator, ','); + } + _ = list.pop(); + } + try list.appendSlice(allocator, ")"); + } + + fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Compilation.Type.Index) !void { + const sema_type = module.types.get(type_index); + switch (sema_type.*) { + .void => try list.appendSlice(allocator, "void"), + .noreturn => try list.appendSlice(allocator, "[[noreturn]] void"), + .bool => try list.appendSlice(allocator, "bool"), + .integer => |integer| { + try list.append(allocator, switch (integer.signedness) { + .signed => 's', + .unsigned => 'u', + }); + try list.writer(allocator).print("{}", .{integer.bit_count}); + }, + .pointer => |pointer| { + if (pointer.@"const") { + try list.appendSlice(allocator, "const "); + } + try unit.writeType(module, list, allocator, pointer.element_type); + try list.append(allocator, '*'); + }, + else => |t| @panic(@tagName(t)), + } + } + + fn writeSyscall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, syscall_index: Compilation.Syscall.Index, indentation: usize) !void { + const syscall = module.syscalls.get(syscall_index); + const arguments = syscall.getArguments(); + if (!unit.syscall_bitset.isSet(arguments.len)) { + try unit.function_declarations.appendSlice(allocator, "static __inline u64 syscall"); + try unit.function_declarations.writer(allocator).print("{}(", .{arguments.len}); + try unit.function_declarations.appendSlice(allocator, "u64 n, "); + for (0..arguments.len) |arg_i| { + try unit.function_declarations.writer(allocator).print("u64 arg{}, ", .{arg_i}); + } + _ = unit.function_declarations.pop(); + _ = unit.function_declarations.pop(); + try unit.function_declarations.appendSlice(allocator, + \\) { + \\ unsigned long ret; + \\ __asm__ __volatile__("syscall" + \\ : "=a"(ret) + \\ : "a"(n), + ); + + const argument_registers = [_]u8{ 'D', 'S', 'd' }; + if (arguments.len <= 3) { + for (0..arguments.len, argument_registers[0..arguments.len]) |arg_i, arg_register| { + try unit.function_declarations.writer(allocator).print("\"{c}\"(arg{}), ", .{ arg_register, arg_i }); + } + } else { + unreachable; + } + _ = unit.function_declarations.pop(); + _ = unit.function_declarations.pop(); + try unit.function_declarations.appendSlice(allocator, + \\ + \\ : "rcx", "r11", "memory" + \\ ); + \\ return ret; + \\} + \\ + \\ + ); + + unit.syscall_bitset.set(arguments.len); + } + + try list.writer(allocator).print("syscall{}(", .{arguments.len}); + + try unit.writeValue(module, list, allocator, syscall.number, indentation); + try list.appendSlice(allocator, ", "); + + for (arguments) |argument_index| { + try unit.writeValue(module, list, allocator, argument_index, indentation); + try list.appendSlice(allocator, ", "); + } + + _ = list.pop(); + _ = list.pop(); + try list.append(allocator, ')'); + } + + fn writeUnreachable(list: *ArrayList(u8), allocator: Allocator) !void { + try list.appendSlice(allocator, "__builtin_unreachable()"); + } + + fn writeCall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, call_index: Compilation.Call.Index, indentation: usize) !void { + const call = module.calls.get(call_index); + const call_value = module.values.get(call.value); + const callable_name = switch (call_value.*) { + .function_definition => |function_definition_index| module.getName(module.function_name_map.get(function_definition_index).?).?, + else => |t| @panic(@tagName(t)), + }; + try list.writer(allocator).print("{s}(", .{callable_name}); + + if (!call.arguments.invalid) { + const argument_list = module.argument_lists.get(call.arguments); + for (argument_list.array.items) |argument_index| { + try unit.writeValue(module, list, allocator, argument_index, indentation); + try list.appendSlice(allocator, ", "); + } + _ = list.pop(); + _ = list.pop(); + } + + try list.append(allocator, ')'); + } + + fn writeValue(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, value_index: Compilation.Value.Index, indentation: usize) anyerror!void { + const value = module.values.get(value_index); + switch (value.*) { + .integer => |integer| { + try list.writer(allocator).print("{}", .{integer.value}); + }, + .declaration_reference => |declaration_reference| { + const declaration = module.declarations.get(declaration_reference.value); + const declaration_name = module.getName(declaration.name).?; + try list.appendSlice(allocator, declaration_name); + }, + .binary_operation => |binary_operation_index| { + const binary_operation = module.binary_operations.get(binary_operation_index); + try unit.writeValue(module, list, allocator, binary_operation.left, indentation); + try list.append(allocator, ' '); + switch (binary_operation.id) { + .add => try list.append(allocator, '+'), + .sub => try list.append(allocator, '-'), + .logical_and => try list.append(allocator, '&'), + .logical_or => try list.append(allocator, '|'), + .logical_xor => try list.append(allocator, '^'), + .multiply => try list.append(allocator, '*'), + .divide => try list.append(allocator, '/'), + .shift_left => try list.appendSlice(allocator, "<<"), + .shift_right => try list.appendSlice(allocator, ">>"), + .compare_equal => try list.appendSlice(allocator, "=="), + } + try list.append(allocator, ' '); + try unit.writeValue(module, list, allocator, binary_operation.right, indentation); + }, + .sign_extend => |cast_index| { + const sign_extend = module.casts.get(cast_index); + try unit.writeValue(module, list, allocator, sign_extend.value, indentation); + }, + .cast => |cast_index| { + const cast = module.casts.get(cast_index); + try list.append(allocator, '('); + try unit.writeType(module, list, allocator, cast.type); + try list.append(allocator, ')'); + try unit.writeValue(module, list, allocator, cast.value, indentation); + }, + .string_literal => |string_literal_hash| { + try list.appendSlice(allocator, "(const u8*)"); + const string_literal = module.string_literals.getValue(string_literal_hash).?; + try list.append(allocator, '"'); + try list.appendSlice(allocator, string_literal); + try list.append(allocator, '"'); + }, + .@"unreachable" => try writeUnreachable(list, allocator), + .call => |call_index| try unit.writeCall(module, list, allocator, call_index, indentation), + .syscall => |syscall_index| try unit.writeSyscall(module, list, allocator, syscall_index, indentation), + .bool => |boolean| try list.appendSlice(allocator, if (boolean) "true" else "false"), + .block => |block_index| try unit.writeBlock(module, list, allocator, block_index, indentation + 1), + else => |t| @panic(@tagName(t)), + } + } +}; + +// fn writeDeclarationReference(module: *Module, list: *ArrayList(u8), allocator: Allocator, declaration_reference: Compilation.Declaration.Reference) !void { +// _ = module; +// _ = list; +// _ = allocator; +// _ = declaration_reference; +// } + +pub fn initialize(compilation: *Compilation, module: *Module, descriptor: Compilation.Module.Descriptor) !void { + const allocator = compilation.base_allocator; + const unit = try TranslationUnit.create(module, allocator); + const c_source_file_path = try std.mem.concat(allocator, u8, &.{ descriptor.executable_path, ".c" }); + const c_source_file = try std.fs.cwd().createFile(c_source_file_path, .{}); + + var offset: u64 = 0; + const slices = [_][]const u8{ unit.type_declarations.items, unit.function_declarations.items, unit.string_literals.items, unit.function_definitions.items }; + for (slices) |slice| { + try c_source_file.pwriteAll(slice, offset); + offset += slice.len; + } + + c_source_file.close(); + const c_source_file_realpath = try std.fs.cwd().realpathAlloc(allocator, c_source_file_path); + const c_flags = [_][]const u8{ + "-std=c2x", + "-g", + }; + + var zig_command_line = ArrayList([]const u8){}; + try zig_command_line.append(allocator, "zig"); + try zig_command_line.append(allocator, "build-exe"); + try zig_command_line.append(allocator, try std.mem.concat(allocator, u8, &.{ "-femit-bin=", descriptor.executable_path })); + try zig_command_line.append(allocator, "-cflags"); + for (c_flags) |c_flag| { + try zig_command_line.append(allocator, c_flag); + } + try zig_command_line.append(allocator, "--"); + try zig_command_line.append(allocator, c_source_file_realpath); + + const run_result = try std.ChildProcess.run(.{ + .allocator = allocator, + .argv = zig_command_line.items, + }); + switch (run_result.term) { + .Exited => |exit_code| { + if (exit_code != 0) { + for (zig_command_line.items) |arg| { + std.debug.print("{s} ", .{arg}); + } + std.debug.panic("\nZig command exited with code {}:\n{s}", .{ exit_code, run_result.stderr }); + } + }, + else => |t| @panic(@tagName(t)), + } +} diff --git a/src/backend/emit.zig b/src/backend/emit.zig index 799dab6..c38e066 100644 --- a/src/backend/emit.zig +++ b/src/backend/emit.zig @@ -151,7 +151,7 @@ pub const Result = struct { target: std.Target, pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result { - var result = Result{ + const result = Result{ .section_manager = section_manager, .target = target, .entry_point = entry_point_index, diff --git a/src/backend/intermediate_representation.zig b/src/backend/intermediate_representation.zig index 0dd7532..3430e43 100644 --- a/src/backend/intermediate_representation.zig +++ b/src/backend/intermediate_representation.zig @@ -608,11 +608,11 @@ const Builder = struct { .assign => |sema_assignment_index| { const sema_assignment = builder.ir.module.assignments.get(sema_assignment_index); const current_function = builder.ir.function_definitions.get(builder.current_function_index); - const sema_declaration = builder.ir.module.values.get(sema_assignment.store).declaration_reference.value; + const sema_declaration = builder.ir.module.values.get(sema_assignment.destination).declaration_reference.value; const destination = current_function.stack_map.get(sema_declaration).?; _ = try builder.emitAssignment(.{ .destination = destination, - .sema_source = sema_assignment.load, + .sema_source = sema_assignment.source, }); }, else => |t| @panic(@tagName(t)), diff --git a/src/backend/x86_64.zig b/src/backend/x86_64.zig index fee1c5b..6f69a25 100644 --- a/src/backend/x86_64.zig +++ b/src/backend/x86_64.zig @@ -1413,8 +1413,6 @@ const InstructionSelection = struct { } var gp_i: u8 = 0; - var fp_i: u8 = 0; - _ = fp_i; for (ir_arguments) |ir_argument_instruction_index| { const ir_argument_instruction = mir.ir.instructions.get(ir_argument_instruction_index); @@ -4803,7 +4801,6 @@ pub const MIR = struct { register_allocator.used_in_instruction = RegisterBitset.initEmpty(); var physical_register_use = false; - var register_mask = false; var virtual_register_definition = false; var register_definition = false; var early_clobber = false; @@ -4906,9 +4903,9 @@ pub const MIR = struct { } } - if (register_mask) { - unreachable; - } + // if (register_mask) { + // unreachable; + // } // Physical register use if (physical_register_use) { @@ -4935,8 +4932,6 @@ pub const MIR = struct { } } - var undef_use = false; - _ = undef_use; var rearranged_implicit_operands = true; while (rearranged_implicit_operands) { rearranged_implicit_operands = false; diff --git a/src/frontend/semantic_analyzer.zig b/src/frontend/semantic_analyzer.zig index e4ef3cd..62466d6 100644 --- a/src/frontend/semantic_analyzer.zig +++ b/src/frontend/semantic_analyzer.zig @@ -387,8 +387,6 @@ const Analyzer = struct { const enum_field_name = analyzer.module.getName(e_field.name); _ = enum_field_name; - var else_case_index: ?usize = null; - _ = else_case_index; var existing_enums = ArrayList(u32){}; var switch_case_groups = try ArrayList(ArrayList(u32)).initCapacity(analyzer.allocator, switch_case_node_list.len); @@ -551,8 +549,8 @@ const Analyzer = struct { unreachable; } else { const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{ - .store = left.index, - .load = right.index, + .destination = left.index, + .source = right.index, }); return Value{ @@ -898,6 +896,37 @@ const Analyzer = struct { } unreachable; }, + .cast => { + assert(node.id == .compiler_intrinsic_one); + const value_to_cast = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left); + const value_type = value_to_cast.ptr.getType(analyzer.module); + assert(expect_type != .none); + const cast_result = try analyzer.canCast(expect_type, value_type); + if (cast_result == .success) { + const cast = try analyzer.module.casts.append(analyzer.allocator, .{ + .value = value_to_cast.index, + .type = switch (expect_type) { + .none => unreachable, + .flexible_integer => |flexible_integer| if (flexible_integer.sign) |sign| switch (sign) { + else => unreachable, + } else switch (flexible_integer.byte_count) { + 1 => Type.u8, + 2 => Type.u16, + 4 => Type.u32, + 8 => Type.u64, + else => unreachable, + }, + else => unreachable, + }, + }); + + break :blk .{ + .cast = cast.index, + }; + } else { + std.debug.panic("Can't cast", .{}); + } + }, } unreachable; }, @@ -1140,11 +1169,17 @@ const Analyzer = struct { const string_literal_node = analyzer.getScopeNode(scope_index, node_index); assert(string_literal_node.id == .string_literal); const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token); - const string_literal = for (original_string_literal) |ch| { - if (ch == '\\') { - break try fixupStringLiteral(analyzer.allocator, original_string_literal); + const string_literal = blk: { + if (!analyzer.module.descriptor.transpile_to_c) { + for (original_string_literal) |ch| { + if (ch == '\\') { + break :blk try fixupStringLiteral(analyzer.allocator, original_string_literal); + } + } } - } else original_string_literal; + + break :blk original_string_literal; + }; const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal); return string_key; } @@ -1298,7 +1333,7 @@ const Analyzer = struct { var function_prototype = try analyzer.processSimpleFunctionPrototype(scope_index, function_prototype_node.left); const function_prototype_attribute_list_node = analyzer.getScopeNode(scope_index, function_prototype_node.right); const attribute_node_list = analyzer.getScopeNodeList(scope_index, function_prototype_attribute_list_node); - var calling_convention: ?Compilation.CallingConvention = null; + const calling_convention: ?Compilation.CallingConvention = null; for (attribute_node_list.items) |attribute_node_index| { const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index); @@ -1569,6 +1604,21 @@ const Analyzer = struct { sign_extend, }; + fn canCast(analyzer: *Analyzer, expect_type: ExpectType, source: Type.Index) !TypeCheckResult { + return switch (expect_type) { + .none => unreachable, + .flexible_integer => |flexible_integer| blk: { + _ = flexible_integer; + const source_type = analyzer.module.types.get(source); + break :blk switch (source_type.*) { + .pointer => .success, + else => |t| @panic(@tagName(t)), + }; + }, + else => |t| @panic(@tagName(t)), + }; + } + fn typeCheck(analyzer: *Analyzer, expect_type: ExpectType, source: Type.Index) !TypeCheckResult { return switch (expect_type) { .none => TypeCheckResult.success, diff --git a/test/shifts/main.nat b/test/shifts/main.nat index 83cf8e7..dfc8fdd 100644 --- a/test/shifts/main.nat +++ b/test/shifts/main.nat @@ -1,5 +1,5 @@ const main = fn() s32 { - const x: u32 = 1; + var x: u32 = 1; x = x << 5; x = x >> 5; const b: u32 = 1;