Implement basic tests and error unions

This commit is contained in:
David Gonzalez Martin 2024-02-24 11:46:27 -06:00
parent 3a78cfe11d
commit e9e5165345
58 changed files with 1668 additions and 513 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1180,7 +1180,13 @@ pub const LLVM = struct {
for (sema_function_prototype.argument_types) |argument_type_index| { for (sema_function_prototype.argument_types) |argument_type_index| {
switch (unit.types.get(argument_type_index).*) { switch (unit.types.get(argument_type_index).*) {
// TODO: ABI // TODO: ABI
.integer, .pointer, .@"enum", .@"struct", .slice, .bool, => try parameter_types.append(context.allocator, try llvm.getType(unit, context, argument_type_index)), .integer,
.pointer,
.@"enum",
.@"struct",
.slice,
.bool,
=> try parameter_types.append(context.allocator, try llvm.getType(unit, context, argument_type_index)),
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
// arg_types.appendAssumeCapacity(llvm_argument_type); // arg_types.appendAssumeCapacity(llvm_argument_type);
@ -1262,6 +1268,39 @@ pub const LLVM = struct {
const array_type = LLVM.Type.Array.get(element_type, array.count + @intFromBool(extra_element)) orelse return Type.Error.array; const array_type = LLVM.Type.Array.get(element_type, array.count + @intFromBool(extra_element)) orelse return Type.Error.array;
break :blk array_type.toType(); break :blk array_type.toType();
}, },
.error_union => |error_union| {
const error_type = try llvm.getType(unit, context, error_union.@"error");
const payload_type = try llvm.getType(unit, context, error_union.type);
const payload_type_size = unit.types.get(error_union.type).getBitSize(unit);
switch (payload_type_size) {
0 => {
const integer_type = llvm.context.getIntegerType(31) orelse unreachable;
const boolean_type = try llvm.getType(unit, context, .bool);
const types = [2]*LLVM.Type{ integer_type.toType(), boolean_type };
const is_packed = false;
const struct_type = llvm.context.getStructType(&types, types.len, is_packed) orelse return Type.Error.@"struct";
return struct_type.toType();
},
else => unreachable,
}
_ = error_type;
_ = payload_type;
unreachable;
},
.error_set => |error_set_index| b: {
const error_set = unit.error_sets.get(error_set_index);
if (error_set.values.items.len > 0) {
unreachable;
} else {
const integer_type = llvm.context.getIntegerType(32) orelse unreachable;
break :b integer_type.toType();
}
},
.@"error" => b: {
const integer_type = llvm.context.getIntegerType(31) orelse unreachable;
break :b integer_type.toType();
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -1327,7 +1366,13 @@ pub const LLVM = struct {
break :b name.items; break :b name.items;
} else { } else {
if (unit.type_declarations.get(sema_type_index)) |type_declaration| {
_ = type_declaration; // autofix
unreachable; unreachable;
} else {
// TODO: fix
break :b "anon_struct";
}
} }
}, },
// TODO: termination // TODO: termination
@ -2031,7 +2076,7 @@ pub const LLVM = struct {
} }
} }
fn emitComptimeRightValue(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, ct: Compilation.V.Comptime, type_index: Compilation.Type.Index) !*LLVM.Value.Constant { fn emitComptimeRightValue(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, ct: Compilation.V.Comptime, type_index: Compilation.Type.Index) anyerror!*LLVM.Value.Constant {
switch (ct) { switch (ct) {
.constant_int => |integer| { .constant_int => |integer| {
const integer_type = unit.types.get(type_index); const integer_type = unit.types.get(type_index);
@ -2083,21 +2128,7 @@ pub const LLVM = struct {
const constant_int = llvm.context.getConstantInt(backing_integer_type.bit_count, value, signed) orelse unreachable; const constant_int = llvm.context.getConstantInt(backing_integer_type.bit_count, value, signed) orelse unreachable;
return constant_int.toConstant(); return constant_int.toConstant();
}, },
.constant_struct => |constant_struct_index| { .constant_struct => |constant_struct_index| return try llvm.getConstantStruct(unit, context, constant_struct_index),
const constant_struct = unit.constant_structs.get(constant_struct_index);
var field_values = try ArrayList(*LLVM.Value.Constant).initCapacity(context.allocator, constant_struct.fields.len);
const sema_struct_type = unit.structs.get(unit.types.get(constant_struct.type).@"struct");
for (constant_struct.fields, sema_struct_type.fields.items) |field_value, field_index| {
const field = unit.struct_fields.get(field_index);
const constant = try llvm.emitComptimeRightValue(unit, context, field_value, field.type);
field_values.appendAssumeCapacity(constant);
}
const llvm_type = try llvm.getType(unit, context, constant_struct.type);
const struct_type = llvm_type.toStruct() orelse unreachable;
const const_struct = struct_type.getConstant(field_values.items.ptr, field_values.items.len) orelse unreachable;
return const_struct;
},
.undefined => { .undefined => {
const undefined_type = try llvm.getType(unit, context, type_index); const undefined_type = try llvm.getType(unit, context, type_index);
const poison = undefined_type.getPoison() orelse unreachable; const poison = undefined_type.getPoison() orelse unreachable;
@ -2130,6 +2161,13 @@ pub const LLVM = struct {
const constant_null_pointer = pointer_type.getNull(); const constant_null_pointer = pointer_type.getNull();
return constant_null_pointer.toConstant(); return constant_null_pointer.toConstant();
}, },
.error_value => |error_field_index| {
const error_field = unit.error_fields.get(error_field_index);
const signed = false;
const bit_count = 31;
const constant_int = llvm.context.getConstantInt(bit_count, error_field.value, signed) orelse unreachable;
return constant_int.toConstant();
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }
@ -2192,9 +2230,10 @@ pub const LLVM = struct {
const const_slice = unit.constant_slices.get(constant_slice_index); const const_slice = unit.constant_slices.get(constant_slice_index);
const const_slice_type = try llvm.getType(unit, context, const_slice.type); const const_slice_type = try llvm.getType(unit, context, const_slice.type);
const slice_struct_type = const_slice_type.toStruct() orelse unreachable; const slice_struct_type = const_slice_type.toStruct() orelse unreachable;
const ptr = llvm.global_variable_map.get(const_slice.ptr).?; const ptr = llvm.global_variable_map.get(const_slice.array).?;
const signed = false; const signed = false;
const len = llvm.context.getConstantInt(@bitSizeOf(usize), const_slice.len, signed) orelse unreachable; assert(const_slice.start == 0);
const len = llvm.context.getConstantInt(@bitSizeOf(usize), const_slice.end, signed) orelse unreachable;
const slice_fields = [2]*LLVM.Value.Constant{ const slice_fields = [2]*LLVM.Value.Constant{
ptr.toConstant(), ptr.toConstant(),
len.toConstant(), len.toConstant(),
@ -2223,6 +2262,7 @@ pub const LLVM = struct {
break :b constant_int.toConstant(); break :b constant_int.toConstant();
}, },
.constant_slice => |constant_slice_index| try llvm.getConstantSlice(unit, context, constant_slice_index), .constant_slice => |constant_slice_index| try llvm.getConstantSlice(unit, context, constant_slice_index),
.constant_struct => |constant_struct_index| try llvm.getConstantStruct(unit, context, constant_struct_index),
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
list.appendAssumeCapacity(value); list.appendAssumeCapacity(value);
@ -2232,6 +2272,22 @@ pub const LLVM = struct {
return result; return result;
} }
fn getConstantStruct(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, constant_struct_index: Compilation.V.Comptime.ConstantStruct.Index) !*LLVM.Value.Constant {
const constant_struct = unit.constant_structs.get(constant_struct_index);
var field_values = try ArrayList(*LLVM.Value.Constant).initCapacity(context.allocator, constant_struct.fields.len);
const sema_struct_type = unit.structs.get(unit.types.get(constant_struct.type).@"struct");
for (constant_struct.fields, sema_struct_type.fields.items) |field_value, field_index| {
const field = unit.struct_fields.get(field_index);
const constant = try llvm.emitComptimeRightValue(unit, context, field_value, field.type);
field_values.appendAssumeCapacity(constant);
}
const llvm_type = try llvm.getType(unit, context, constant_struct.type);
const struct_type = llvm_type.toStruct() orelse unreachable;
const const_struct = struct_type.getConstant(field_values.items.ptr, field_values.items.len) orelse unreachable;
return const_struct;
}
fn callIntrinsic(llvm: *LLVM, intrinsic_name: []const u8, intrinsic_parameter_types: []const *LLVM.Type, intrinsic_arguments: []const *LLVM.Value) !*LLVM.Value { fn callIntrinsic(llvm: *LLVM, intrinsic_name: []const u8, intrinsic_parameter_types: []const *LLVM.Type, intrinsic_arguments: []const *LLVM.Value) !*LLVM.Value {
const intrinsic_id = LLVM.lookupIntrinsic(intrinsic_name.ptr, intrinsic_name.len); const intrinsic_id = LLVM.lookupIntrinsic(intrinsic_name.ptr, intrinsic_name.len);
assert(intrinsic_id != .none); assert(intrinsic_id != .none);
@ -2354,7 +2410,6 @@ pub const LLVM = struct {
} }
} }
} }
}; };
fn getCallingConvention(calling_convention: Compilation.Function.CallingConvention) LLVM.Value.Constant.Function.CallingConvention { fn getCallingConvention(calling_convention: Compilation.Function.CallingConvention) LLVM.Value.Constant.Function.CallingConvention {
@ -2508,6 +2563,8 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
const entry_block_node = try llvm.createBasicBlock(context, function_definition.basic_blocks.items[0], "fn_entry"); const entry_block_node = try llvm.createBasicBlock(context, function_definition.basic_blocks.items[0], "fn_entry");
block_command_list.append(entry_block_node); block_command_list.append(entry_block_node);
var phis = AutoArrayHashMap(Compilation.Instruction.Index, *LLVM.Value.Instruction.PhiNode){};
while (block_command_list.len != 0) { while (block_command_list.len != 0) {
const block_node = block_command_list.first orelse unreachable; const block_node = block_command_list.first orelse unreachable;
const basic_block_index = block_node.data; const basic_block_index = block_node.data;
@ -2625,14 +2682,8 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
switch (unit.types.get(stack_slot.type).*) { switch (unit.types.get(stack_slot.type).*) {
.void, .noreturn, .type => unreachable, .void, .noreturn, .type => unreachable,
.comptime_int => unreachable, .comptime_int => unreachable,
.bool => {},
.@"struct" => {},
.@"enum" => {},
.function => unreachable, .function => unreachable,
.integer => {}, else => {},
.pointer => {},
.slice => {},
.array => {},
} }
const declaration_type = try llvm.getType(unit, context, stack_slot.type); const declaration_type = try llvm.getType(unit, context, stack_slot.type);
@ -2769,7 +2820,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
for (call.arguments, arguments) |argument_value, *argument| { for (call.arguments, arguments) |argument_value, *argument| {
argument.* = try llvm.emitRightValue(unit, context, argument_value); argument.* = try llvm.emitRightValue(unit, context, argument_value);
} }
@ -2883,15 +2933,8 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
switch (unit.types.get(argument_type_index).*) { switch (unit.types.get(argument_type_index).*) {
.void, .noreturn, .type => unreachable, .void, .noreturn, .type => unreachable,
.comptime_int => unreachable, .comptime_int => unreachable,
.bool => {},
// .bool => unreachable,
.@"struct" => {},
.@"enum" => {},
.function => unreachable, .function => unreachable,
.integer => {}, else => {},
.pointer => {},
.slice => {},
.array => {},
} }
const argument_type = argument.toValue().getType(); const argument_type = argument.toValue().getType();
const alloca_array_size: ?*LLVM.Value = null; const alloca_array_size: ?*LLVM.Value = null;
@ -3047,6 +3090,8 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
const not_taken_node = try llvm.createBasicBlock(context, branch.not_taken, "not_taken_block"); const not_taken_node = try llvm.createBasicBlock(context, branch.not_taken, "not_taken_block");
block_command_list.insertAfter(block_node, taken_node); block_command_list.insertAfter(block_node, taken_node);
block_command_list.insertAfter(taken_node, not_taken_node); block_command_list.insertAfter(taken_node, not_taken_node);
// block_command_list.append(taken_node);
// block_command_list.append(taken_node);
// TODO: make this fast // TODO: make this fast
const taken_block = llvm.llvm_block_map.get(taken_node.data).?; const taken_block = llvm.llvm_block_map.get(taken_node.data).?;
@ -3064,11 +3109,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
const phi_name = "phi"; const phi_name = "phi";
const phi_node = llvm.builder.createPhi(phi_type, reserved_value_count, phi_name, phi_name.len) orelse unreachable; const phi_node = llvm.builder.createPhi(phi_type, reserved_value_count, phi_name, phi_name.len) orelse unreachable;
for (phi.values.items, phi.basic_blocks.items) |sema_value, sema_block| { try phis.putNoClobber(context.allocator, instruction_index, phi_node);
const value = llvm.llvm_value_map.get(sema_value) orelse try llvm.emitRightValue(unit, context, sema_value);
const value_basic_block = llvm.llvm_block_map.get(sema_block).?;
phi_node.addIncoming(value, value_basic_block);
}
try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, phi_node.toValue()); try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, phi_node.toValue());
}, },
@ -3106,6 +3147,16 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
_ = block_command_list.popFirst(); _ = block_command_list.popFirst();
} }
for (phis.keys(), phis.values()) |instruction_index, phi| {
const instruction = unit.instructions.get(instruction_index);
const sema_phi = instruction.phi;
for (sema_phi.values.items, sema_phi.basic_blocks.items) |sema_value, sema_block| {
const value_basic_block = llvm.llvm_block_map.get(sema_block).?;
const value = llvm.llvm_value_map.get(sema_value) orelse try llvm.emitRightValue(unit, context, sema_value);
phi.addIncoming(value, value_basic_block);
}
}
if (!builder.isCurrentBlockTerminated()) { if (!builder.isCurrentBlockTerminated()) {
var message_len: usize = 0; var message_len: usize = 0;
const function_str = llvm.function.toString(&message_len); const function_str = llvm.function.toString(&message_len);

View File

@ -162,7 +162,6 @@ pub const ListType = enum{
pointer, pointer,
}; };
pub fn enumFromString(comptime E: type, string: []const u8) ?E { pub fn enumFromString(comptime E: type, string: []const u8) ?E {
return inline for (@typeInfo(E).Enum.fields) |enum_field| { return inline for (@typeInfo(E).Enum.fields) |enum_field| {
if (std.mem.eql(u8, string, enum_field.name)) { if (std.mem.eql(u8, string, enum_field.name)) {

View File

@ -15,7 +15,6 @@ const logln = Compilation.logln;
const Token = Compilation.Token; const Token = Compilation.Token;
const fs = @import("../fs.zig"); const fs = @import("../fs.zig");
// Needed information // Needed information
// Token: u8 // Token: u8
// line: u32 // line: u32
@ -281,7 +280,6 @@ pub fn analyze(allocator: Allocator, text: []const u8, token_buffer: *Token.Buff
}, },
else => break :blk .operator_bang, else => break :blk .operator_bang,
} }
}, },
'=' => blk: { '=' => blk: {
index += 1; index += 1;

View File

@ -187,6 +187,9 @@ pub const Node = struct {
test_declaration, test_declaration,
all_errors, all_errors,
error_union, error_union,
catch_expression,
try_expression,
error_type,
}; };
}; };
@ -307,7 +310,9 @@ const Analyzer = struct {
if (equal(u8, identifier_name, enum_field.name)) { if (equal(u8, identifier_name, enum_field.name)) {
const attribute = @field(Compilation.Debug.Declaration.Global.Attribute, enum_field.name); const attribute = @field(Compilation.Debug.Declaration.Global.Attribute, enum_field.name);
const attribute_node = switch (attribute) { const attribute_node = switch (attribute) {
.@"export", .@"extern", => try analyzer.addNode(.{ .@"export",
.@"extern",
=> try analyzer.addNode(.{
.id = @field(Node.Id, "symbol_attribute_" ++ @tagName(attribute)), .id = @field(Node.Id, "symbol_attribute_" ++ @tagName(attribute)),
.token = identifier, .token = identifier,
.left = .null, .left = .null,
@ -393,7 +398,8 @@ const Analyzer = struct {
if (equal(u8, identifier_name, enum_field.name)) { if (equal(u8, identifier_name, enum_field.name)) {
const attribute = @field(Compilation.Function.Attribute, enum_field.name); const attribute = @field(Compilation.Function.Attribute, enum_field.name);
const attribute_node = switch (attribute) { const attribute_node = switch (attribute) {
.naked, => try analyzer.addNode(.{ .naked,
=> try analyzer.addNode(.{
.id = @field(Node.Id, "function_attribute_" ++ @tagName(attribute)), .id = @field(Node.Id, "function_attribute_" ++ @tagName(attribute)),
.token = identifier, .token = identifier,
.left = .null, .left = .null,
@ -473,16 +479,17 @@ const Analyzer = struct {
const first_statement_token = analyzer.peekToken(); const first_statement_token = analyzer.peekToken();
logln(.parser, .block, "First statement token: {s}", .{@tagName(first_statement_token)}); logln(.parser, .block, "First statement token: {s}", .{@tagName(first_statement_token)});
const statement_index = switch (first_statement_token) { const statement_index = switch (first_statement_token) {
.identifier => switch (analyzer.peekTokenAhead(1)) {
.operator_colon => {
unreachable;
},
else => try analyzer.assignExpressionStatement(), else => try analyzer.assignExpressionStatement(),
}, // .identifier => switch (analyzer.peekTokenAhead(1)) {
.fixed_keyword_unreachable, // .operator_colon => {
.fixed_keyword_return, // unreachable;
.discard, // },
=> try analyzer.assignExpressionStatement(), // else => try analyzer.assignExpressionStatement(),
// },
// .fixed_keyword_unreachable,
// .fixed_keyword_return,
// .discard,
// => try analyzer.assignExpressionStatement(),
.fixed_keyword_while => try analyzer.whileExpression(), .fixed_keyword_while => try analyzer.whileExpression(),
.fixed_keyword_switch => try analyzer.switchExpression(), .fixed_keyword_switch => try analyzer.switchExpression(),
@ -491,17 +498,12 @@ const Analyzer = struct {
.fixed_keyword_const, .fixed_keyword_const,
.fixed_keyword_var, .fixed_keyword_var,
=> try analyzer.symbolDeclaration(), => try analyzer.symbolDeclaration(),
.fixed_keyword_break => b: { // .intrinsic => blk: {
const node_index = try analyzer.breakExpression(); // const intrinsic = try analyzer.compilerIntrinsic();
_ = try analyzer.expectToken(.operator_semicolon); // _ = try analyzer.expectToken(.operator_semicolon);
break :b node_index; // break :blk intrinsic;
}, // },
.intrinsic => blk: { // else => |t| @panic(@tagName(t)),
const intrinsic = try analyzer.compilerIntrinsic();
_ = try analyzer.expectToken(.operator_semicolon);
break :blk intrinsic;
},
else => |t| @panic(@tagName(t)),
}; };
const node = analyzer.nodes.get(statement_index); const node = analyzer.nodes.get(statement_index);
@ -783,7 +785,7 @@ const Analyzer = struct {
const left = try analyzer.expression(); const left = try analyzer.expression();
const expression_token = analyzer.token_i; const expression_token = analyzer.token_i;
const expression_id: Node.Id = switch (analyzer.peekToken()) { const expression_id: Node.Id = switch (analyzer.peekToken()) {
.operator_semicolon, .operator_comma => return left, .operator_semicolon, .operator_comma, .operator_right_brace, .identifier => return left,
.operator_assign => .assign, .operator_assign => .assign,
.operator_add_assign => .add_assign, .operator_add_assign => .add_assign,
.operator_sub_assign => .sub_assign, .operator_sub_assign => .sub_assign,
@ -951,6 +953,7 @@ const Analyzer = struct {
bit_or, bit_or,
shift_left, shift_left,
shift_right, shift_right,
@"catch",
}; };
const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{ const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{
@ -970,6 +973,7 @@ const Analyzer = struct {
.bit_or = 40, .bit_or = 40,
.shift_left = 50, .shift_left = 50,
.shift_right = 50, .shift_right = 50,
.@"catch" = 40,
}); });
const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{ const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{
@ -989,6 +993,7 @@ const Analyzer = struct {
.mod = .left, .mod = .left,
.shift_left = .left, .shift_left = .left,
.shift_right = .left, .shift_right = .left,
.@"catch" = .left,
}); });
const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{ const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{
@ -1008,6 +1013,7 @@ const Analyzer = struct {
.mod = .mod, .mod = .mod,
.shift_left = .shift_left, .shift_left = .shift_left,
.shift_right = .shift_right, .shift_right = .shift_right,
.@"catch" = .catch_expression,
}); });
fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index { fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index {
@ -1062,6 +1068,7 @@ const Analyzer = struct {
.operator_xor => .bit_xor, .operator_xor => .bit_xor,
.operator_shift_left => .shift_left, .operator_shift_left => .shift_left,
.operator_shift_right => .shift_right, .operator_shift_right => .shift_right,
.fixed_keyword_catch => .@"catch",
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -1114,6 +1121,7 @@ const Analyzer = struct {
}, },
.operator_bang => .boolean_not, .operator_bang => .boolean_not,
.operator_minus => .negation, .operator_minus => .negation,
.fixed_keyword_try => .try_expression,
// .tilde => |t| @panic(@tagName(t)), // .tilde => |t| @panic(@tagName(t)),
}; };
@ -1155,6 +1163,9 @@ const Analyzer = struct {
.discard, .discard,
.fixed_keyword_undefined, .fixed_keyword_undefined,
.operator_left_bracket, .operator_left_bracket,
.fixed_keyword_const,
.fixed_keyword_var,
.fixed_keyword_error,
=> try analyzer.curlySuffixExpression(), => try analyzer.curlySuffixExpression(),
.fixed_keyword_fn => try analyzer.function(), .fixed_keyword_fn => try analyzer.function(),
.fixed_keyword_return => try analyzer.addNode(.{ .fixed_keyword_return => try analyzer.addNode(.{
@ -1167,6 +1178,7 @@ const Analyzer = struct {
.left = try analyzer.expression(), .left = try analyzer.expression(),
.right = Node.Index.null, .right = Node.Index.null,
}), }),
.fixed_keyword_break => try analyzer.breakExpression(),
// todo:? // todo:?
.operator_left_brace => try analyzer.block(), .operator_left_brace => try analyzer.block(),
.fixed_keyword_if => try analyzer.ifExpression(), .fixed_keyword_if => try analyzer.ifExpression(),
@ -1384,34 +1396,40 @@ const Analyzer = struct {
} }
fn errorUnionExpression(analyzer: *Analyzer) !Node.Index { fn errorUnionExpression(analyzer: *Analyzer) !Node.Index {
if (analyzer.peekToken() == .operator_bang) { const initial = analyzer.token_i;
const error_union_token = try analyzer.expectToken(.operator_bang); if (analyzer.peekToken() == .operator_asterisk and analyzer.peekTokenAhead(1) == .operator_bang) {
if (analyzer.peekToken() == .operator_asterisk) { const asterisk = try analyzer.expectToken(.operator_asterisk);
analyzer.consumeToken(); analyzer.consumeToken();
// All errors const type_node = try analyzer.suffixExpression();
const all_errors_node = try analyzer.addNode(.{ const all_errors_node = try analyzer.addNode(.{
.id = .all_errors, .id = .all_errors,
.token = error_union_token, .token = asterisk,
.left = .null, .left = .null,
.right = .null, .right = .null,
}); });
const type_node = try analyzer.suffixExpression();
const error_union = try analyzer.addNode(.{ const error_union = try analyzer.addNode(.{
.id = .error_union, .id = .error_union,
.token = error_union_token, .token = asterisk,
// All errors
.left = all_errors_node, .left = all_errors_node,
.right = type_node, .right = type_node,
}); });
return error_union; return error_union;
} else {
unreachable;
}
} else { } else {
const suffix_expression = try analyzer.suffixExpression(); const suffix_expression = try analyzer.suffixExpression();
return switch (analyzer.peekToken()) { return switch (analyzer.peekToken()) {
.operator_bang => unreachable, .operator_bang => try analyzer.addNode(.{
.id = .error_union,
.token = blk: {
analyzer.consumeToken();
break :blk initial;
},
.left = suffix_expression,
.right = try analyzer.typeExpression(),
}),
else => suffix_expression, else => suffix_expression,
}; };
} }
@ -1600,6 +1618,7 @@ const Analyzer = struct {
fn processContainerType(analyzer: *Analyzer, maybe_token_id: ?Token.Id) !Node.Index { fn processContainerType(analyzer: *Analyzer, maybe_token_id: ?Token.Id) !Node.Index {
const token_i = if (maybe_token_id) |tid| try analyzer.expectToken(tid) else analyzer.token_i; const token_i = if (maybe_token_id) |tid| try analyzer.expectToken(tid) else analyzer.token_i;
assert(Token.unwrap(analyzer.token_i) < analyzer.token_buffer.tokens.len);
const token_id = maybe_token_id orelse .fixed_keyword_struct; const token_id = maybe_token_id orelse .fixed_keyword_struct;
const container_type: Compilation.ContainerType = switch (token_id) { const container_type: Compilation.ContainerType = switch (token_id) {
.fixed_keyword_struct => .@"struct", .fixed_keyword_struct => .@"struct",
@ -1608,8 +1627,8 @@ const Analyzer = struct {
}; };
const node_id: Node.Id = switch (token_id) { const node_id: Node.Id = switch (token_id) {
.fixed_keyword_struct => .@"struct_type", .fixed_keyword_struct => .struct_type,
.fixed_keyword_enum => .@"enum_type", .fixed_keyword_enum => .enum_type,
else => unreachable, else => unreachable,
}; };
@ -1726,7 +1745,16 @@ const Analyzer = struct {
fn testDeclaration(analyzer: *Analyzer) !Node.Index { fn testDeclaration(analyzer: *Analyzer) !Node.Index {
const test_token = try analyzer.expectToken(.fixed_keyword_test); const test_token = try analyzer.expectToken(.fixed_keyword_test);
const name_node: Node.Index = if (analyzer.peekToken() == .string_literal) try analyzer.identifierNode() else .null; const name_node: Node.Index = if (analyzer.peekToken() == .string_literal) try analyzer.addNode(.{
.id = .string_literal,
.token = b: {
const index = analyzer.token_i;
analyzer.consumeToken();
break :b index;
},
.left = .null,
.right = .null,
}) else .null;
const test_block = try analyzer.block(); const test_block = try analyzer.block();
return try analyzer.addNode(.{ return try analyzer.addNode(.{
.token = test_token, .token = test_token,
@ -1861,6 +1889,33 @@ const Analyzer = struct {
_ = try analyzer.expectToken(.operator_right_parenthesis); _ = try analyzer.expectToken(.operator_right_parenthesis);
break :blk expr; break :blk expr;
}, },
.fixed_keyword_error => blk: {
analyzer.consumeToken();
if (analyzer.peekToken() == .operator_left_brace) {
analyzer.consumeToken();
var list = ArrayList(Node.Index){};
while (analyzer.peekToken() != .operator_right_brace) {
const identifier = try analyzer.identifierNode();
try list.append(analyzer.allocator, identifier);
const comma = try analyzer.expectToken(.operator_comma);
_ = comma; // autofix
}
analyzer.consumeToken();
break :blk try analyzer.addNode(.{
.id = .error_type,
.token = token_i,
.left = try analyzer.nodeList(list),
.right = .null,
});
} else {
const t = analyzer.peekToken();
_ = t; // autofix
unreachable;
}
},
else => |t| switch (t) { else => |t| switch (t) {
.identifier => std.debug.panic("{s}: {s}", .{ @tagName(t), analyzer.bytes(token_i) }), .identifier => std.debug.panic("{s}: {s}", .{ @tagName(t), analyzer.bytes(token_i) }),
else => @panic(@tagName(t)), else => @panic(@tagName(t)),
@ -2031,7 +2086,6 @@ const Analyzer = struct {
} }
}; };
// Here it is assumed that left brace is consumed // Here it is assumed that left brace is consumed
pub fn analyze(allocator: Allocator, lexer_result: lexer.Result, source_file: []const u8, token_buffer: *Token.Buffer, node_list: *Node.List, node_lists: *ArrayList(ArrayList(Node.Index))) !Result { pub fn analyze(allocator: Allocator, lexer_result: lexer.Result, source_file: []const u8, token_buffer: *Token.Buffer, node_list: *Node.List, node_lists: *ArrayList(ArrayList(Node.Index))) !Result {
const start = std.time.Instant.now() catch unreachable; const start = std.time.Instant.now() catch unreachable;
@ -2065,5 +2119,3 @@ const Associativity = enum {
none, none,
left, left,
}; };

View File

@ -30,5 +30,5 @@ const panic = fn (reason: PanicReason) noreturn{
const TestFunction = struct{ const TestFunction = struct{
name: []const u8, name: []const u8,
function: &const fn () !*void, function: &const fn () *!void,
}; };

View File

@ -31,8 +31,8 @@ const start :: export = fn (argc_argv_address: usize) noreturn {
argument_address_iterator += #size(usize) * (argument_count + 1); argument_address_iterator += #size(usize) * (argument_count + 1);
environment_values = #cast(argument_address_iterator); environment_values = #cast(argument_address_iterator);
const env = environment_values; const env = environment_values;
const result = #import("main").main(); #import("root").main() catch std.os.exit(1);
std.os.exit(exit_code = result); std.os.exit(0);
} }
const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 { const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 {
@ -40,5 +40,6 @@ const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null
argument_count = argc_u; argument_count = argc_u;
argument_values = argv; argument_values = argv;
environment_values = env; environment_values = env;
return #import("main").main(); #import("root").main() catch return 1;
return 0;
} }

6
lib/test_runner.nat Normal file
View File

@ -0,0 +1,6 @@
const builtin = #import("builtin");
const main = fn () *!void {
for (builtin.test_functions) |test_function| {
try test_function.function();
}
}

View File

@ -1,3 +0,0 @@
const main = fn () s32 {
return 0;
}

View File

@ -2,7 +2,11 @@ const std = #import("std");
const assert = std.assert; const assert = std.assert;
const Executable = std.build.Executable; const Executable = std.build.Executable;
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const executable = Executable{ const executable = Executable{
.target = .{ .target = .{
.cpu = .x86_64, .cpu = .x86_64,
@ -10,13 +14,12 @@ const main = fn () s32 {
.abi = .gnu, .abi = .gnu,
}, },
.main_source_path = "src/main.nat", .main_source_path = "src/main.nat",
.name = "first", .name = "first_build",
}; };
if (executable.compile()) { if (executable.compile()) {
return 0;
} else { } else {
std.print(bytes = "Executable failed to compile!\n"); std.print(bytes = "Executable failed to compile!\n");
return 1; return Error.unexpected_result;
} }
} }

View File

@ -0,0 +1,2 @@
const main = fn () *!void {
}

View File

@ -2,7 +2,11 @@ const std = #import("std");
const assert = std.assert; const assert = std.assert;
const Executable = std.build.Executable; const Executable = std.build.Executable;
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const executable = Executable{ const executable = Executable{
.target = .{ .target = .{
.cpu = .x86_64, .cpu = .x86_64,
@ -15,9 +19,8 @@ const main = fn () s32 {
}; };
if (executable.compile()) { if (executable.compile()) {
return 0;
} else { } else {
std.print(bytes = "Executable failed to compile!\n"); std.print(bytes = "Executable failed to compile!\n");
return 1; return Error.unexpected_result;
} }
} }

View File

@ -1,3 +1,2 @@
const main = fn () s32 { const main = fn () *!void {
return 0;
} }

View File

@ -1,8 +1,14 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
const a: s32 = 1; const a: s32 = 1;
const b: s32 = 2; const b: s32 = 2;
const c: s32 = a + b; const c: s32 = a + b;
const d: s32 = 3; const d: s32 = 3;
const e: s32 = d - c; const e: s32 = d - c;
return e; if (e != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,6 +1,11 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var a: s32 = 5; var a: s32 = 5;
var b: s32 = 4; var b: s32 = 4;
var result = a & b; var result = a & b;
return result - b; if (result - b != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,10 +1,15 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const ch = 'a'; const ch = 'a';
var buffer: [1]u8 = undefined; var buffer: [1]u8 = undefined;
var ptr: &[1]u8 = buffer.&; var ptr: &[1]u8 = buffer.&;
var index: usize = 0; var index: usize = 0;
ptr[index] = ch; ptr[index] = ch;
const sub: u8 = ptr[index] - ch; const sub: u8 = ptr[index] - ch;
const result: u32 = sub; if (sub != 0) {
return #cast(result); return Error.unexpected_result;
}
} }

View File

@ -1,4 +1,8 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
var buffer: [2]u8 = undefined; var buffer: [2]u8 = undefined;
const expected = 'a'; const expected = 'a';
const index: usize = 1; const index: usize = 1;
@ -6,7 +10,9 @@ const main = fn () s32 {
const ch = buffer[index]; const ch = buffer[index];
const sub = expected - ch; const sub = expected - ch;
const result: u32 = sub; const result: u32 = sub;
return #cast(result); if (result != 0) {
return Error.unexpected_result;
}
} }
const foo = fn (buffer: &[2]u8, index: usize, ch: u8) void { const foo = fn (buffer: &[2]u8, index: usize, ch: u8) void {

View File

@ -1,9 +1,13 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const ch = 'a'; const ch = 'a';
var buffer: [1]u8 = undefined; var buffer: [1]u8 = undefined;
var index: usize = 0; var index: usize = 0;
buffer[index] = ch; buffer[index] = ch;
const sub: u8 = buffer[index] - ch; if (buffer[index] - ch != 0) {
const result: u32 = sub; return Error.unexpected_result;
return #cast(result); }
} }

View File

@ -1,10 +1,9 @@
const std = #import("std"); const std = #import("std");
const assert = std.assert; const assert = std.assert;
const main = fn() s32 { const main = fn() *!void {
assert(true); assert(true);
var a: s32 = 1; var a: s32 = 1;
const is_not_one = a != 1; const is_not_one = a != 1;
assert(!is_not_one); assert(!is_not_one);
return 0;
} }

View File

@ -8,7 +8,7 @@ const BitStruct = struct(u8) {
d: u5, d: u5,
}; };
const main = fn () s32 { const main = fn () *!void {
var bs = BitStruct{ var bs = BitStruct{
.a = false, .a = false,
.b = true, .b = true,
@ -26,5 +26,4 @@ const main = fn () s32 {
}; };
const bitcast_const_bs: u8 = #cast(const_bs); const bitcast_const_bs: u8 = #cast(const_bs);
assert(bitcast_const_bs == 5); assert(bitcast_const_bs == 5);
return 0;
} }

View File

@ -17,7 +17,7 @@ const transform = fn (a: A) B {
}; };
} }
const main = fn () s32 { const main = fn () *!void {
var a = A{ var a = A{
.a = 3, .a = 3,
.b = 8, .b = 8,
@ -26,6 +26,4 @@ const main = fn () s32 {
const b = transform(a); const b = transform(a);
assert(a.a == b.a); assert(a.a == b.a);
assert(a.b == b.b); assert(a.b == b.b);
return 0;
} }

View File

@ -1,4 +1,7 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var i: s32 = 0; var i: s32 = 0;
const j: s32 = 5; const j: s32 = 5;
for (0..10) |_| { for (0..10) |_| {
@ -8,5 +11,7 @@ const main = fn() s32 {
i += 1; i += 1;
} }
return i - j; if (i - j != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,7 +1,10 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
if (true) { if (true) {
return 0;
} else { } else {
return 1; return Error.unexpected_result;
} }
} }

View File

@ -1,8 +1,13 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
const dividend: s32 = 30; const dividend: s32 = 30;
const divisor: s32 = 6; const divisor: s32 = 6;
const div: s32 = dividend / divisor; const div: s32 = dividend / divisor;
const n: s32 = 5; const n: s32 = 5;
return n - div; if (n - div != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,13 +1,20 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = foo(5); const a = foo(5);
if (a != 123) { if (a != 123) {
return 1; return Error.unexpected_result;
} }
const b = foo(5); const b = foo(5);
if (b != 123) { if (b != 123) {
return 1; return Error.unexpected_result;
}
if (a - b != 0) {
return Error.unexpected_result;
} }
return a - b;
} }
const foo = fn (arg: s32) s32 { const foo = fn (arg: s32) s32 {

View File

@ -1,3 +1 @@
const main = fn() s32 { const main = fn() *!void { }
return 0;
}

View File

@ -1,4 +1,8 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var counter: s32 = 0; var counter: s32 = 0;
const loop = 10; const loop = 10;
@ -6,5 +10,7 @@ const main = fn() s32 {
counter += 1; counter += 1;
} }
return loop - counter; if (loop - counter != 0) {
return Error.unexpected_result;
}
} }

View File

@ -20,12 +20,17 @@ const print_values = fn(slice: []const u8) void {
} }
} }
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = [_]u8{1, 1, 4, 5, 6}; const a = [_]u8{1, 1, 4, 5, 6};
const b = [_]u8{1, 4, 6}; const b = [_]u8{1, 4, 6};
const expected_result: usize = a.len + b.len; const expected_result: usize = a.len + b.len;
const result = count_slice_byte_count(slices = .{a.&, b.&}.&); const result = count_slice_byte_count(slices = .{a.&, b.&}.&);
print_values(slice = a.&); print_values(slice = a.&);
const main_result: u32 = #cast(expected_result - result); if (expected_result - result != 0) {
return #cast(main_result); return Error.unexpected_result;
}
} }

View File

@ -1,16 +1,18 @@
const Error = error{
unexpected_result,
};
const std = #import("std"); const std = #import("std");
const main = fn() s32 { const main = fn() Error!void {
if (std.os.duplicate_process()) |pid| { if (std.os.duplicate_process()) |pid| {
if (pid == 0) { if (pid == 0) {
std.print(bytes = "Hello from child\n"); std.print(bytes = "Hello from child\n");
std.os.exit(exit_code = 0); std.os.exit(exit_code = 0);
} else { } else {
std.print(bytes = "Hello from parent\n"); std.print(bytes = "Hello from parent\n");
return 0;
} }
} else { } else {
std.print(bytes = "Unable to create child process\n"); std.print(bytes = "Unable to create child process\n");
return 1; return Error.unexpected_result;
} }
} }

View File

@ -1,18 +1,21 @@
const std = #import("std"); const std = #import("std");
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
if (std.os.duplicate_process()) |pid| { if (std.os.duplicate_process()) |pid| {
if (pid == 0) { if (pid == 0) {
std.print(bytes = "Hello from child\n"); std.print(bytes = "Hello from child\n");
const argv = [_:null] ?[&:0]const u8{"/usr/bin/ls"}; const argv = [_:null] ?[&:0]const u8{"/usr/bin/ls"};
_ = std.os.execute(path = "/usr/bin/ls", argv = argv.&, env = std.start.environment_values); _ = std.os.execute(path = "/usr/bin/ls", argv = argv.&, env = std.start.environment_values);
return 1; return Error.unexpected_result;
} else { } else {
std.print(bytes = "Hello from parent\n"); std.print(bytes = "Hello from parent\n");
return 0;
} }
} else { } else {
std.print(bytes = "Unable to create child process\n"); std.print(bytes = "Unable to create child process\n");
return 1; return Error.unexpected_result;
} }
} }

View File

@ -4,8 +4,14 @@ const foo = fn () s32 {
return expected_number; return expected_number;
} }
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
var function_pointer = foo.&; var function_pointer = foo.&;
const result = function_pointer(); const result = function_pointer();
return result - expected_number; if (result - expected_number != 0) {
return Error.unexpected_result;
}
} }

View File

@ -13,11 +13,17 @@ const Struct = struct{
} }
}; };
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
var s = Struct{ var s = Struct{
.a = expected_number, .a = expected_number,
.handler = Struct.handler_function.&, .handler = Struct.handler_function.&,
}; };
return s.handler(s.&) - expected_number; if (s.handler(s.&) - expected_number != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,6 +1,5 @@
const std = #import("std"); const std = #import("std");
const main = fn() s32 { const main = fn() *!void {
std.print(bytes = "Hello world!\n"); std.print(bytes = "Hello world!\n");
return 0;
} }

View File

@ -1,13 +1,18 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = foo(5); const a = foo(5);
if (a != 6) { if (a != 6) {
return 1; return Error.unexpected_result;
} }
const b = foo(5); const b = foo(5);
if (b != 6) { if (b != 6) {
return 1; return Error.unexpected_result;
}
if (a - b != 0) {
return Error.unexpected_result;
} }
return a - b;
} }
const foo = fn (arg: s32) s32 { const foo = fn (arg: s32) s32 {

View File

@ -1,13 +1,20 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
const a = foo(5); const a = foo(5);
if (a != 12412) { if (a != 12412) {
return 1; return Error.unexpected_result;
} }
const b = foo(5); const b = foo(5);
if (b != 12412) { if (b != 12412) {
return 1; return Error.unexpected_result;
}
if (a - b != 0) {
return Error.unexpected_result;
} }
return a - b;
} }
const foo = fn(arg: s32) s32 { const foo = fn(arg: s32) s32 {

View File

@ -1,5 +1,10 @@
const main = fn() s32 { const Error = error{
const a: s32 = 5; unexpected_result,
const b: s32 = 4; };
return a * b - a * b; const main = fn() Error!void {
var a: s32 = 5;
var b: s32 = 4;
if (a * b - a * b != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,4 +1,8 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var i: s32 = 0; var i: s32 = 0;
while (i < 10) { while (i < 10) {
i += 1; i += 1;
@ -7,5 +11,7 @@ const main = fn() s32 {
} }
} }
return i - 5; if (i - 5 != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,13 +1,19 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = foo(5142); const a = foo(5142);
if (a != 2501) { if (a != 2501) {
return 1; return Error.unexpected_result;
} }
const b = foo(5142); const b = foo(5142);
if (b != 2501) { if (b != 2501) {
return 1; return Error.unexpected_result;
}
if (a - b != 0) {
return Error.unexpected_result;
} }
return #cast(a - b);
} }
const foo = fn (arg: u32) u32 { const foo = fn (arg: u32) u32 {

View File

@ -1,7 +1,12 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = foo(5142); const a = foo(5142);
const b = foo(5142); const b = foo(5142);
return #cast(a - b); if (a - b != 0) {
return Error.unexpected_result;
}
} }
const foo = fn (arg: u32) u32 { const foo = fn (arg: u32) u32 {

View File

@ -1,7 +1,13 @@
const main = fn () s32 { const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a = foo(5); const a = foo(5);
const b = foo(5); const b = foo(5);
return a - b; if (a - b != 0) {
return Error.unexpected_result;
}
} }
const foo = fn (arg: s32) s32 { const foo = fn (arg: s32) s32 {

View File

@ -1,7 +1,6 @@
const std = #import("std"); const std = #import("std");
const assert = std.assert; const assert = std.assert;
const main = fn() s32 { const main = fn() *!void {
var foo = [2:null] ?[&:0]const u8 {"Hi", "Ho"}; var foo = [2:null] ?[&:0]const u8 {"Hi", "Ho"};
assert(foo[2] == null); assert(foo[2] == null);
return 0;
} }

View File

@ -1,8 +1,6 @@
const foo = fn(slice: []u8) ?[]u8 { const foo = fn(slice: []u8) ?[]u8 {
return slice[0..1]; return slice[0..1];
} }
const main = fn() s32 { const main = fn() *!void {
_ = foo(slice = .{ 0, 1, 2, 3 }.&); _ = foo(slice = .{ 0, 1, 2, 3 }.&);
return 0;
} }

View File

@ -1,7 +1,13 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
const a: u32 = 0xffff; const a: u32 = 0xffff;
const b: u32 = 0xffff0000; const b: u32 = 0xffff0000;
const c: u32 = 0xffffffff; const c: u32 = 0xffffffff;
const result = c - (a | b); const result = c - (a | b);
return #cast(result); if (result != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,14 +1,16 @@
const std = #import("std"); const std = #import("std");
const print = std.print; const print = std.print;
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var buffer: [std.os.max_path_byte_count:0]u8 = undefined; var buffer: [std.os.max_path_byte_count:0]u8 = undefined;
if (std.os.current_executable_path(buffer = buffer.&)) |bytes| { if (std.os.current_executable_path(buffer = buffer.&)) |bytes| {
print(bytes); print(bytes);
print(bytes = "\n"); print(bytes = "\n");
return 0;
} else { } else {
print(bytes = "Failed\n"); return Error.unexpected_result;
return 1;
} }
} }

View File

@ -1,7 +1,13 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var x: u32 = 1; var x: u32 = 1;
x = x << 5; x = x << 5;
x = x >> 5; x = x >> 5;
const b: u32 = 1; const b: u32 = 1;
return #cast(x - b); if (x - b != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,8 +1,10 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var false_boolean: bool = false; var false_boolean: bool = false;
if (false_boolean) { if (false_boolean) {
return 1; return Error.unexpected_result;
} else {
return 0;
} }
} }

View File

@ -1,6 +1,9 @@
const std = #import("std"); const Error = error{
const assert = std.assert; unexpected_result,
const main = fn () s32 { };
assert(#size(usize) == 8);
return 0; const main = fn () Error!void {
if (#size(usize) != 8) {
return Error.unexpected_result;
}
} }

View File

@ -1,4 +1,8 @@
const main = fn () s32{ const Error = error{
unexpected_result,
};
const main = fn () Error!void{
const a: [4]u8 = .{1, 2, 3, 4}; const a: [4]u8 = .{1, 2, 3, 4};
const b: []const []const u8 = .{a.&}.&; const b: []const []const u8 = .{a.&}.&;
@ -10,5 +14,7 @@ const main = fn () s32{
} }
} }
return #cast(sum - 10); if (sum - 10 != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,7 +1,12 @@
const main = fn () s32{ const Error = error{
unexpected_result,
};
const main = fn () Error!void {
const a: [4]u8 = .{1, 2, 3, 4}; const a: [4]u8 = .{1, 2, 3, 4};
const b: []const []const u8 = .{a.&}.&; const b: []const []const u8 = .{a.&}.&;
const c: u8 = b[0][0] - 1; const c: u8 = b[0][0] - 1;
const d: u32 = c; if (c != 0) {
return #cast(c); return Error.unexpected_result;
}
} }

View File

@ -1,6 +1,5 @@
const main = fn () s32 { const main = fn () *!void {
_ = foo(); _ = foo();
return 0;
} }
const foo = fn () []u8 { const foo = fn () []u8 {

View File

@ -1,12 +1,18 @@
const std = #import("std"); const std = #import("std");
const assert = std.assert; const assert = std.assert;
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var buffer: [65]u8 = undefined; var buffer: [65]u8 = undefined;
const slice = foo(5, buffer.&); const slice = foo(5, buffer.&);
assert(slice.len + 5 == buffer.len); assert(slice.len + 5 == buffer.len);
const result: u32 = #cast(slice.len + 5 - buffer.len); const result: u32 = #cast(slice.len + 5 - buffer.len);
return #cast(result); if (result != 0) {
return Error.unexpected_result;
}
} }
const foo = fn(n: usize, buffer: &[65]u8) []u8 { const foo = fn(n: usize, buffer: &[65]u8) []u8 {
return buffer[n..]; return buffer[n..];

View File

@ -1,4 +1,9 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var a : s32 = 0; var a : s32 = 0;
return a; if (a != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,6 +1,10 @@
const std = #import("std"); const std = #import("std");
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
const size = 0x1000; const size = 0x1000;
if (std.page_allocator.allocate(size, alignment = 12)) |result| { if (std.page_allocator.allocate(size, alignment = 12)) |result| {
@ -8,13 +12,12 @@ const main = fn() s32 {
std.print(bytes = "Allocation succeeded. Freeing...\n"); std.print(bytes = "Allocation succeeded. Freeing...\n");
if (std.page_allocator.free(bytes_ptr = result.ptr, bytes_len = result.len)) { if (std.page_allocator.free(bytes_ptr = result.ptr, bytes_len = result.len)) {
std.print(bytes = "Memory freed successfully\n"); std.print(bytes = "Memory freed successfully\n");
return 0;
} else { } else {
std.print(bytes = "Memory freed with errors\n"); std.print(bytes = "Memory freed with errors\n");
return 1; return Error.unexpected_result;
} }
} else { } else {
std.print(bytes = "Allocation failed!\n"); std.print(bytes = "Allocation failed!\n");
return 1; return Error.unexpected_result;
} }
} }

View File

@ -1,7 +1,13 @@
const main = fn() s32 { const Error = error{
unexpected_result,
};
const main = fn() Error!void {
var a: s32 = 561; var a: s32 = 561;
var b: s32 = 124; var b: s32 = 124;
var c: s32 = a ^ b; var c: s32 = a ^ b;
var d: s32 = a ^ b; var d: s32 = a ^ b;
return c ^ d; if (c ^ d != 0) {
return Error.unexpected_result;
}
} }

View File

@ -1,7 +1,6 @@
const std = #import("std"); const std = #import("std");
const assert = std.assert; const assert = std.assert;
const main = fn () s32 { const main = fn () *!void {
var a = [2:0]u8 {1, 2}; var a = [2:0]u8 {1, 2};
assert(a[2] == 0); assert(a[2] == 0);
return 0;
} }

View File

@ -0,0 +1,2 @@
test "First test" {
}

View File

@ -1,2 +0,0 @@
test {
}