implement shifts

This commit is contained in:
David Gonzalez Martin 2023-11-13 20:49:24 -06:00
parent 33eb057529
commit 4c358c2f89
10 changed files with 824 additions and 338 deletions

33
ci.sh
View File

@ -2,7 +2,7 @@
echo "Testing Nativity with Zig" echo "Testing Nativity with Zig"
echo "Compiling Nativity with Zig" echo "Compiling Nativity with Zig"
zig build -Doptimize=ReleaseSafe zig build
failed_test_count=0 failed_test_count=0
passed_test_count=0 passed_test_count=0
test_directory_name=test test_directory_name=test
@ -10,12 +10,17 @@ test_directory=$test_directory_name/*
total_test_count=$(ls 2>/dev/null -Ubad1 -- test/* | wc -l) total_test_count=$(ls 2>/dev/null -Ubad1 -- test/* | wc -l)
ran_test_count=0 ran_test_count=0
test_i=1 test_i=1
passed_compilation_count=0
failed_compilation_count=0
failed_compilations=()
failed_tests=()
for dir in $test_directory for dir in $test_directory
do do
MY_TESTNAME=${dir##*/} MY_TESTNAME=${dir##*/}
zig build run -Doptimize=ReleaseSafe -- $dir/main.nat zig build run -- $dir/main.nat
if [[ "$?" == "0" ]]; then if [[ "$?" == "0" ]]; then
passed_compilation_count=$(($passed_compilation_count + 1))
if [[ "$OSTYPE" == "linux-gnu"* ]]; then if [[ "$OSTYPE" == "linux-gnu"* ]]; then
nat/$MY_TESTNAME nat/$MY_TESTNAME
if [[ "$?" == "0" ]]; then if [[ "$?" == "0" ]]; then
@ -24,19 +29,39 @@ do
else else
failed_test_count=$(($failed_test_count + 1)) failed_test_count=$(($failed_test_count + 1))
result="FAILED" result="FAILED"
failed_tests+=("$test_i. $MY_TESTNAME")
fi fi
echo "[$test_i/$total_test_count] [$result] $MY_TESTNAME" echo "[$test_i/$total_test_count] [$result] $MY_TESTNAME"
ran_test_count=$(($ran_test_count + 1)) ran_test_count=$(($ran_test_count + 1))
fi fi
else else
"$MY_TESTNAME failed to compile" failed_compilation_count=$(($failed_compilation_count + 1))
echo "$MY_TESTNAME failed to compile"
failed_compilations+=("$test_i. $MY_TESTNAME")
fi fi
test_i=$(($test_i + 1)) test_i=$(($test_i + 1))
done done
echo "Ran $total_test_count compilations ($passed_compilation_count succeeded, $failed_compilation_count failed)."
echo "Ran $ran_test_count tests ($passed_test_count passed, $failed_test_count failed)." echo "Ran $ran_test_count tests ($passed_test_count passed, $failed_test_count failed)."
if [[ $failed_test_count == "0" ]]; then if [[ "$failed_compilation_count" != "0" ]]; then
echo "Failed compilations:"
for failed_compilation in "${failed_compilations[@]}"
do
echo "$failed_compilation"
done
fi
if [[ "$failed_test_count" != "0" ]]; then
echo "Failed tests:"
for failed_test in "${failed_tests[@]}"
do
echo "$failed_test"
done
fi
if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then
true true
else else
false false

View File

@ -546,7 +546,7 @@ pub const BinaryOperation = struct {
pub const Index = List.Index; pub const Index = List.Index;
pub const Allocation = List.Allocation; pub const Allocation = List.Allocation;
const Id = enum { pub const Id = enum {
add, add,
sub, sub,
logical_and, logical_and,
@ -554,6 +554,8 @@ pub const BinaryOperation = struct {
logical_or, logical_or,
multiply, multiply,
divide, divide,
shift_left,
shift_right,
}; };
}; };
@ -602,12 +604,13 @@ pub const Value = union(enum) {
} }
}; };
pub fn isComptime(value: Value) bool { pub fn isComptime(value: *Value, module: *Module) bool {
return switch (value) { return switch (value.*) {
.bool, .void, .undefined, .function, .type, .enum_field => true, .bool, .void, .undefined, .function, .type, .enum_field => true,
.integer => |integer| integer.type.eq(Type.comptime_int), .integer => |integer| integer.type.eq(Type.comptime_int),
.call => false, .call => false,
.binary_operation => false, .binary_operation => false,
.declaration_reference => |declaration_reference| module.declarations.get(declaration_reference.value).mutability == .@"const" and isComptime(module.values.get(module.declarations.get(declaration_reference.value).init_value), module),
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }

View File

@ -240,6 +240,8 @@ pub const BinaryOperation = struct {
logical_or, logical_or,
signed_multiply, signed_multiply,
signed_divide, signed_divide,
shift_left,
shift_right,
}; };
pub const List = BlockList(@This()); pub const List = BlockList(@This());
@ -749,7 +751,6 @@ pub const Builder = struct {
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
//.multiply,
.divide => switch (sema_type) { .divide => switch (sema_type) {
.integer => |integer| switch (integer.signedness) { .integer => |integer| switch (integer.signedness) {
.signed => .signed_divide, .signed => .signed_divide,
@ -757,7 +758,8 @@ pub const Builder = struct {
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
//.divide, .shift_left => .shift_left,
.shift_right => .shift_right,
}, },
.type = binary_operation_type, .type = binary_operation_type,
}); });
@ -917,6 +919,19 @@ pub const Builder = struct {
} }
}, },
.call => |sema_call_index| _ = try builder.processCall(sema_call_index), .call => |sema_call_index| _ = try builder.processCall(sema_call_index),
.assign => |sema_assignment_index| {
const sema_assignment = builder.ir.module.assignments.get(sema_assignment_index);
const sema_left = builder.ir.module.values.get(sema_assignment.store);
assert(sema_left.* == .declaration_reference);
const sema_declaration_index = sema_left.declaration_reference.value;
const stack = builder.currentFunction().stack_map.get(sema_declaration_index).?;
const value_index = try builder.emitDeclarationInitValue(sema_assignment.load);
const store_instruction = try builder.store(.{
.source = value_index,
.destination = stack,
});
_ = store_instruction;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }

View File

@ -2,7 +2,6 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const equal = std.mem.eql; const equal = std.mem.eql;
const print = std.debug.print;
const Compilation = @import("../Compilation.zig"); const Compilation = @import("../Compilation.zig");
@ -487,7 +486,7 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
_ = allocator; _ = allocator;
_ = descriptor; _ = descriptor;
const header: *const Header = @ptrCast(@alignCast(file.ptr)); const header: *const Header = @ptrCast(@alignCast(file.ptr));
print("Header : {}", .{header}); //print("Header : {}", .{header});
assert(header.magic == Header.magic); assert(header.magic == Header.magic);
var text_segment: LoadCommand.Segment64 = undefined; var text_segment: LoadCommand.Segment64 = undefined;
@ -503,69 +502,83 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
if (equal(u8, segment_load_command.name[0..text_segment_name.len], text_segment_name)) { if (equal(u8, segment_load_command.name[0..text_segment_name.len], text_segment_name)) {
text_segment = segment_load_command.*; text_segment = segment_load_command.*;
} }
print("SLC: {}", .{segment_load_command}); //print("SLC: {}", .{segment_load_command});
print("segment name: {s}", .{segment_load_command.name}); //print("segment name: {s}", .{segment_load_command.name});
const section_ptr: [*]const LoadCommand.Segment64.Section = @ptrFromInt(@intFromPtr(segment_load_command) + @sizeOf(LoadCommand.Segment64)); const section_ptr: [*]const LoadCommand.Segment64.Section = @ptrFromInt(@intFromPtr(segment_load_command) + @sizeOf(LoadCommand.Segment64));
const sections = section_ptr[0..segment_load_command.section_count]; const sections = section_ptr[0..segment_load_command.section_count];
for (sections) |section| { for (sections) |section| {
print("{}", .{section}); _ = section;
print("Section name: {s}. Segment name: {s}", .{ section.name, section.segment_name }); //print("{}", .{section});
//print("Section name: {s}. Segment name: {s}", .{ section.name, section.segment_name });
} }
}, },
.dyld_chained_fixups => { .dyld_chained_fixups => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.dyld_exports_trie => { .dyld_exports_trie => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.symbol_table => { .symbol_table => {
const command: *const LoadCommand.SymbolTable = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SymbolTable = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.symbol_table_information => { .symbol_table_information => {
const command: *const LoadCommand.SymbolTableInformation = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SymbolTableInformation = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.load_dylinker => { .load_dylinker => {
const command: *const LoadCommand.Dylinker = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Dylinker = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); //print("command: {}", .{command});
const name: [*:0]const u8 = @ptrFromInt(@intFromPtr(command) + command.name_offset); const name: [*:0]const u8 = @ptrFromInt(@intFromPtr(command) + command.name_offset);
print("Name: {s}", .{name}); _ = name;
//print("Name: {s}", .{name});
}, },
.uuid_number => { .uuid_number => {
const command: *const LoadCommand.Uuid = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Uuid = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.minimum_os_version => { .minimum_os_version => {
const command: *const LoadCommand.MinimumVersion = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.MinimumVersion = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.source_version => { .source_version => {
const command: *const LoadCommand.SourceVersion = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SourceVersion = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.dyld_main_entry_point => { .dyld_main_entry_point => {
const command: *const LoadCommand.EntryPoint = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.EntryPoint = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.load_dylib => { .load_dylib => {
const command: *const LoadCommand.Dylib = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Dylib = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
print("Dylib: {s}", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))}); //print("command: {}", .{command});
//print("Dylib: {s}", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))});
}, },
.function_starts => { .function_starts => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.data_in_code => { .data_in_code => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
.code_signature => { .code_signature => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}", .{command}); _ = command;
//print("command: {}", .{command});
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
@ -666,7 +679,8 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
writer.index = writer.segment_offset + @sizeOf(LoadCommand.Segment64); writer.index = writer.segment_offset + @sizeOf(LoadCommand.Segment64);
for (file[16384 + 56 ..][0..48]) |b| { for (file[16384 + 56 ..][0..48]) |b| {
print("0x{x}, ", .{b}); _ = b;
//print("0x{x}, ", .{b});
} }
const chained_fixup_bytes = &.{ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; const chained_fixup_bytes = &.{ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const print = std.debug.print;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const data_structures = @import("../data_structures.zig"); const data_structures = @import("../data_structures.zig");
@ -22,21 +21,23 @@ pub const Writer = struct {
} }
pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void { pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void {
print("File len: {}", .{writer.in_file.len}); //print("File len: {}", .{writer.in_file.len});
const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr)); const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr));
print("File address: {}", .{dos_header.file_address_of_new_exe_header}); //print("File address: {}", .{dos_header.file_address_of_new_exe_header});
print("File: {s}", .{writer.in_file[0x40..]}); //print("File: {s}", .{writer.in_file[0x40..]});
for (writer.in_file[0x40..], 0..) |byte, index| { for (writer.in_file[0x40..], 0..) |byte, index| {
_ = index;
if (byte == 'T') { if (byte == 'T') {
print("Index: {}", .{index}); //print("Index: {}", .{index});
break; break;
} }
} }
assert(dos_header.magic_number == ImageDosHeader.magic); assert(dos_header.magic_number == ImageDosHeader.magic);
// assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader)); // assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader));
print("{}", .{dos_header}); //print("{}", .{dos_header});
const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr)); const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr));
print("File header: {}", .{file_header}); _ = file_header;
//print("File header: {}", .{file_header});
writer.append(std.mem.asBytes(&ImageDosHeader{ writer.append(std.mem.asBytes(&ImageDosHeader{
.file_address_of_new_exe_header = 208, .file_address_of_new_exe_header = 208,

File diff suppressed because it is too large Load Diff

View File

@ -202,7 +202,7 @@ const Analyzer = struct {
const declaration_index = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local); const declaration_index = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local);
const declaration = analyzer.module.declarations.get(declaration_index); const declaration = analyzer.module.declarations.get(declaration_index);
const init_value = analyzer.module.values.get(declaration.init_value); const init_value = analyzer.module.values.get(declaration.init_value);
switch (init_value.isComptime() and declaration.mutability == .@"const") { switch (init_value.isComptime(analyzer.module) and declaration.mutability == .@"const") {
// Dont add comptime declaration statements // Dont add comptime declaration statements
true => continue, true => continue,
false => { false => {
@ -461,7 +461,7 @@ const Analyzer = struct {
fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value { fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
const node = analyzer.getScopeNode(scope_index, node_index); const node = analyzer.getScopeNode(scope_index, node_index);
assert(node.id == .assign); assert(node.id == .assign);
const assignment = switch (node.left.invalid) { switch (node.left.invalid) {
// In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result``` // In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result```
true => { true => {
var result = Value{ var result = Value{
@ -477,23 +477,25 @@ const Analyzer = struct {
false => { false => {
// const id = analyzer.tokenIdentifier(.token); // const id = analyzer.tokenIdentifier(.token);
// logln("id: {s}\n", .{id}); // logln("id: {s}\n", .{id});
// const left = try analyzer.expression(scope_index, ExpectType.none, statement_node.left); const left = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left);
const right = try analyzer.unresolvedAllocate(scope_index, ExpectType{
.type_index = left.ptr.getType(analyzer.module),
}, node.right);
// if (analyzer.module.values.get(left).isComptime() and analyzer.module.values.get(right).isComptime()) { if (left.ptr.isComptime(analyzer.module) and right.ptr.isComptime(analyzer.module)) {
// unreachable; unreachable;
// } else { } else {
// const assignment_index = try analyzer.module.assignments.append(analyzer.allocator, .{ const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
// .store = result.left, .store = left.index,
// .load = result.right, .load = right.index,
// }); });
// return assignment_index;
// } return Value{
unreachable; .assign = assignment.index,
};
}
}, },
}; }
_ = assignment;
unreachable;
} }
fn processReturn(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value { fn processReturn(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
@ -524,29 +526,46 @@ const Analyzer = struct {
fn processBinaryOperation(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value { fn processBinaryOperation(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
const node = analyzer.getScopeNode(scope_index, node_index); const node = analyzer.getScopeNode(scope_index, node_index);
const binary_operation_id: Compilation.BinaryOperation.Id = switch (node.id) {
.add => .add,
.sub => .sub,
.logical_and => .logical_and,
.logical_xor => .logical_xor,
.logical_or => .logical_or,
.multiply => .multiply,
.divide => .divide,
.shift_left => .shift_left,
.shift_right => .shift_right,
else => |t| @panic(@tagName(t)),
};
const right_expect_type: ExpectType = switch (binary_operation_id) {
.add,
.sub,
.logical_and,
.logical_xor,
.logical_or,
.multiply,
.divide,
=> expect_type,
.shift_left,
.shift_right,
=> ExpectType{
.type_index = Type.u8,
},
};
const left_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.left); const left_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.left);
const right_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.right); const right_allocation = try analyzer.unresolvedAllocate(scope_index, right_expect_type, node.right);
const left_type = left_allocation.ptr.getType(analyzer.module); const left_type = left_allocation.ptr.getType(analyzer.module);
const right_type = right_allocation.ptr.getType(analyzer.module); const right_type = right_allocation.ptr.getType(analyzer.module);
if (!left_type.eq(right_type)) { _ = right_type;
unreachable;
}
const binary_operation = try analyzer.module.binary_operations.append(analyzer.allocator, .{ const binary_operation = try analyzer.module.binary_operations.append(analyzer.allocator, .{
.left = left_allocation.index, .left = left_allocation.index,
.right = right_allocation.index, .right = right_allocation.index,
.type = left_type, .type = left_type,
.id = switch (node.id) { .id = binary_operation_id,
.add => .add,
.sub => .sub,
.logical_and => .logical_and,
.logical_xor => .logical_xor,
.logical_or => .logical_or,
.multiply => .multiply,
.divide => .divide,
else => |t| @panic(@tagName(t)),
},
}); });
return .{ return .{
@ -606,11 +625,11 @@ const Analyzer = struct {
} }
logln(.sema, .identifier, "Declaration resolved as: {}\n", .{init_value}); logln(.sema, .identifier, "Declaration resolved as: {}\n", .{init_value});
logln(.sema, .identifier, "Declaration mutability: {s}. Is comptime: {}\n", .{ @tagName(declaration.mutability), init_value.isComptime() }); logln(.sema, .identifier, "Declaration mutability: {s}. Is comptime: {}\n", .{ @tagName(declaration.mutability), init_value.isComptime(analyzer.module) });
const typecheck_result = try analyzer.typeCheck(expect_type, declaration.type); const typecheck_result = try analyzer.typeCheck(expect_type, declaration.type);
if (init_value.isComptime() and declaration.mutability == .@"const") { if (init_value.isComptime(analyzer.module) and declaration.mutability == .@"const") {
assert(!declaration.init_value.invalid); assert(!declaration.init_value.invalid);
assert(typecheck_result == .success); assert(typecheck_result == .success);
return declaration.init_value; return declaration.init_value;
@ -1017,6 +1036,8 @@ const Analyzer = struct {
.logical_or, .logical_or,
.multiply, .multiply,
.divide, .divide,
.shift_left,
.shift_right,
=> try analyzer.processBinaryOperation(scope_index, expect_type, node_index), => try analyzer.processBinaryOperation(scope_index, expect_type, node_index),
.expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable, .expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),

View File

@ -160,6 +160,8 @@ pub const Node = packed struct(u128) {
logical_or = 66, logical_or = 66,
multiply = 67, multiply = 67,
divide = 68, divide = 68,
shift_left = 69,
shift_right = 70,
}; };
}; };
@ -721,6 +723,8 @@ const Analyzer = struct {
logical_or, logical_or,
multiply, multiply,
divide, divide,
shift_left,
shift_right,
}; };
const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{ const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{
@ -733,6 +737,8 @@ const Analyzer = struct {
.logical_or = 40, .logical_or = 40,
.multiply = 70, .multiply = 70,
.divide = 70, .divide = 70,
.shift_left = 50,
.shift_right = 50,
}); });
const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{ const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{
@ -745,6 +751,8 @@ const Analyzer = struct {
.logical_or = .left, .logical_or = .left,
.multiply = .left, .multiply = .left,
.divide = .left, .divide = .left,
.shift_left = .left,
.shift_right = .left,
}); });
const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{ const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{
@ -757,6 +765,8 @@ const Analyzer = struct {
.logical_or = .logical_or, .logical_or = .logical_or,
.multiply = .multiply, .multiply = .multiply,
.divide = .divide, .divide = .divide,
.shift_left = .shift_left,
.shift_right = .shift_right,
}); });
fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index { fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index {
@ -825,6 +835,14 @@ const Analyzer = struct {
.equal => unreachable, .equal => unreachable,
else => .divide, else => .divide,
}, },
.less => switch (next_token_id) {
.less => .shift_left,
else => unreachable,
},
.greater => switch (next_token_id) {
.greater => .shift_right,
else => unreachable,
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} else { } else {
@ -845,7 +863,7 @@ const Analyzer = struct {
} }
const operator_token = analyzer.token_i; const operator_token = analyzer.token_i;
const extra_token = switch (operator) { const extra_tokens: u32 = switch (operator) {
.add, .add,
.sub, .sub,
.logical_and, .logical_and,
@ -853,13 +871,15 @@ const Analyzer = struct {
.logical_or, .logical_or,
.multiply, .multiply,
.divide, .divide,
=> false, => 0,
.compare_equal, .compare_equal,
.compare_not_equal, .compare_not_equal,
=> true, .shift_right,
.shift_left,
=> 1,
// else => |t| @panic(@tagName(t)), // else => |t| @panic(@tagName(t)),
}; };
analyzer.token_i += @as(u32, 1) + @intFromBool(extra_token); analyzer.token_i += @as(u32, 1) + extra_tokens;
// TODO: fix this // TODO: fix this
const right = try analyzer.expressionPrecedence(precedence + 1); const right = try analyzer.expressionPrecedence(precedence + 1);

View File

@ -1,5 +1,5 @@
const main = fn () s32 { const main = fn () s32 {
const a: s32 = 5; const a: s32 = 5;
const b: s32 = 4; const b: s32 = 4;
return 5 * 4 - a * b; return a * b - a * b;
} }

7
test/shifts/main.nat Normal file
View File

@ -0,0 +1,7 @@
const main = fn() s32 {
const x: u32 = 1;
x = x << 5;
x = x >> 5;
const b: u32 = 1;
return x - b;
}