From 48d438246e970535fa2d29494d487f2dcf11cd96 Mon Sep 17 00:00:00 2001 From: bgk- Date: Mon, 26 Feb 2024 19:39:56 -0800 Subject: [PATCH] Fix up enum refactor --- docs/syntax.md | 10 ++++++++++ src/bytecode.zig | 4 ++-- src/compiler.test.zig | 2 +- src/parser.zig | 8 ++++++-- src/token.zig | 3 +++ src/values.zig | 23 ++++++++++------------- src/vm.test.zig | 19 ++++++++++--------- src/vm.zig | 8 +++++--- 8 files changed, 47 insertions(+), 30 deletions(-) diff --git a/docs/syntax.md b/docs/syntax.md index 21ca348..dee1c06 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -425,6 +425,16 @@ const fib = |n| { } ``` +## Return Void + +If you want to return out of a function early you have to specify `return void` and not just `return` like most langauges. + +```topi +const early = || { + if (true) return void +} +``` + ### Enums Enums are pretty standard diff --git a/src/bytecode.zig b/src/bytecode.zig index abde312..f4419c9 100644 --- a/src/bytecode.zig +++ b/src/bytecode.zig @@ -207,8 +207,8 @@ pub const Bytecode = struct { } }, .prong => { - const index = std.mem.readVarInt(u16, instructions[i..(i + 2)], .little); - i += 2; + const index = std.mem.readVarInt(u32, instructions[i..(i + 4)], .little); + i += 4; writer.print("{d: >8}", .{index}); const count = instructions[i]; i += 1; diff --git a/src/compiler.test.zig b/src/compiler.test.zig index 29fdae7..d4f3c62 100644 --- a/src/compiler.test.zig +++ b/src/compiler.test.zig @@ -784,7 +784,7 @@ test "Functions" { }, }, .{ - .input = "|| { 5 + 10 return }", + .input = "|| { 5 + 10 return void }", .instructions = [_]u8{ @intFromEnum(OpCode.closure), 2 + cl, diff --git a/src/parser.zig b/src/parser.zig index ba46b02..73d346e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -360,7 +360,7 @@ pub const Parser = struct { fn returnStatement(self: *Parser) Error!Statement { const start_token = self.current_token; self.next(); - if (self.currentIsOneOf(&[_]TokenType{ .eof, .right_brace })) { + if (self.currentIs(.void)) { return .{ .token = start_token, .type = .return_void, @@ -518,7 +518,8 @@ pub const Parser = struct { // if no braces used will parse a single statement into a list fn block(self: *Parser) Error![]const Statement { var list = std.ArrayList(Statement).init(self.allocator); - if (!self.currentIs(.left_brace)) { + const has_brace = self.currentIs(.left_brace); + if (!has_brace) { try list.append(try self.statement()); return try list.toOwnedSlice(); } @@ -527,6 +528,9 @@ pub const Parser = struct { try list.append(try self.statement()); self.next(); } + if (has_brace and self.currentIs(.eof)) { + return self.fail("Missing closing brace", self.current_token, .{}); + } return try list.toOwnedSlice(); } diff --git a/src/token.zig b/src/token.zig index c8bac59..a0b86bb 100644 --- a/src/token.zig +++ b/src/token.zig @@ -77,6 +77,7 @@ pub const TokenType = enum { @"switch", true, @"var", + void, @"while", bough, @@ -113,6 +114,7 @@ pub const Keywords = std.ComptimeStringMap(TokenType, .{ .{ "switch", .@"switch" }, .{ "true", .true }, .{ "var", .@"var" }, + .{ "void", .void }, .{ "while", .@"while" }, }); @@ -181,6 +183,7 @@ pub fn toString(token_type: TokenType) []const u8 { .@"switch" => "switch", .true => "true", .@"var" => "var", + .void => "void", .@"while" => "while", .bough => "bough", diff --git a/src/values.zig b/src/values.zig index 745ffab..c71a208 100644 --- a/src/values.zig +++ b/src/values.zig @@ -117,7 +117,11 @@ pub const Value = union(Type) { pub fn destroy(allocator: std.mem.Allocator, obj: *Obj) void { switch (obj.data) { .string => |s| allocator.free(s), - .@"enum" => {}, + .@"enum" => |e| { + allocator.free(e.name); + for (e.values) |val| allocator.free(val); + allocator.free(e.values); + }, .list => |l| l.deinit(), .map => obj.data.map.deinit(), .set => obj.data.set.deinit(), @@ -323,7 +327,7 @@ pub const Value = union(Type) { }, .enum_value => { const index = try reader.readByte(); - return .{ .enum_value = .{ .index = index, .base = undefined }}; + return .{ .enum_value = .{ .index = index, .base = undefined } }; }, .obj => { const data_type: Obj.DataType = @enumFromInt(try reader.readByte()); @@ -404,15 +408,7 @@ pub const Value = union(Type) { try reader.readNoEof(name_buf); const values_length = try reader.readByte(); const obj = try allocator.create(Value.Obj); - obj.* = .{ - .data = .{ - .@"enum" = .{ - .allocator = allocator, - .name = name_buf, - .values = try allocator.alloc([]const u8, values_length) - } - } - }; + obj.* = .{ .data = .{ .@"enum" = .{ .allocator = allocator, .name = name_buf, .values = try allocator.alloc([]const u8, values_length) } } }; for (0..values_length) |i| { const value_name_length = try reader.readByte(); const value_name_buf = try allocator.alloc(u8, value_name_length); @@ -434,7 +430,7 @@ pub const Value = union(Type) { .bool => |b| writer.print("{}", .{b}), .nil => writer.print("nil", .{}), .visit => |v| writer.print("{d}", .{v}), - .enum_value => |e| writer.print("{s}.{s}", .{e.base.name, e.base.values[e.index]}), + .enum_value => |e| writer.print("{s}.{s}", .{ e.base.name, e.base.values[e.index] }), .obj => |o| { switch (o.data) { .string => |s| writer.print("{s}", .{s}), @@ -495,7 +491,7 @@ pub const Value = union(Type) { }, .@"enum" => |e| { writer.print("{s}{{", .{e.name}); - for(e.values, 0..) |val, i| { + for (e.values, 0..) |val, i| { writer.print("{s}", .{val}); if (i != e.values.len - 1) writer.print(", ", .{}); @@ -575,6 +571,7 @@ pub const Value = union(Type) { .bool => |bl| bl == b.bool, .nil => b == .nil, .visit => |v| v == b.visit, + .enum_value => |e| e.base == b.enum_value.base and e.index == b.enum_value.index, .obj => |o| { const b_data = b.obj.data; if (@intFromEnum(o.data) != @intFromEnum(b_data)) diff --git a/src/vm.test.zig b/src/vm.test.zig index 369a2c4..a42cb0b 100644 --- a/src/vm.test.zig +++ b/src/vm.test.zig @@ -806,23 +806,24 @@ test "Enums" { \\ Night \\ } \\ - \\ switch (5) { - \\ 0..4: print(TimeOfDay.Night), - \\ 5..11: print(TimeOfDay.Morning), - \\ 12..16: print(TimeOfDay.Afternoon), - \\ 16..21: print(TimeOfDay.Evening), - \\ 22..24: print(TimeOfDay.Night), - \\ else: print(TimeOfDay.Morning) + \\ const timeOfDay = |hour| { + \\ switch (hour) { + \\ 0..4: return TimeOfDay.Night, + \\ 5..11: return TimeOfDay.Morning, + \\ 12..16: return TimeOfDay.Afternoon, + \\ 16..21: return TimeOfDay.Evening, + \\ 22..24: return TimeOfDay.Night, \\ } + \\ } \\ \\ print(timeOfDay(5)) \\ -; + ; var mod = Module.create(allocator); defer mod.deinit(); defer mod.entry.source_loaded = false; - var vm = try initTestVm(input, &mod, true); + var vm = try initTestVm(input, &mod, false); defer vm.deinit(); defer vm.bytecode.free(testing.allocator); try vm.interpret(); diff --git a/src/vm.zig b/src/vm.zig index d0cbc0b..a4183b1 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -713,13 +713,15 @@ pub const Vm = struct { return self.fail("Can only query instance fields by string name, not {s}", .{@tagName(index)}); if (index.obj.data != .string) return self.fail("Can only query instance fields by string name, not {s}", .{@tagName(index.obj.data)}); + var found = false; + std.debug.print("\n", .{}); for (e.values, 0..) |name, i| { if (std.mem.eql(u8, name, index.obj.data.string)) { - try self.push(.{ .enum_value = .{ .index = @intCast(i), .base = &e }}); - continue; + try self.push(.{ .enum_value = .{ .index = @intCast(i), .base = &e } }); + found = true; } } - return self.fail("Unknown value \"{s}\" on enum {s}", .{ index.obj.data.string, e.name }); + if (!found) return self.fail("Unknown value \"{s}\" on enum {s}", .{ index.obj.data.string, e.name }); }, else => return self.fail("Unknown target type {s} to index. Only lists, maps, sets, or instances can be indexed.", .{@tagName(target)}), },