From 68454de80952627ad7c66b0671c2a4140606abe2 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Sun, 21 Jul 2024 16:42:29 +0200 Subject: [PATCH] feat(language): Arrow notation goes from `->` to `=>` - It's more commonly expected - `->` is already used when unwrapping nullable in a if statement --- src/Codegen.zig | 4 ++- src/Parser.zig | 20 ++++++++----- src/Scanner.zig | 16 +++++++++- src/Token.zig | 1 + src/builtin/list.zig | 1 - src/lib/buzz_buffer.zig | 6 ++-- src/lib/ffi.buzz | 2 +- src/lib/serialize.buzz | 12 ++++---- src/lib/testing.buzz | 50 ++++++++++++++++---------------- src/obj.zig | 4 +-- tests/012-lambda.buzz | 8 ++--- tests/021-upvalues.buzz | 2 +- tests/029-default-arguments.buzz | 2 +- tests/032-debug.buzz | 2 +- tests/038-fibers.buzz | 6 ++-- tests/048-generics.buzz | 4 +-- tests/051-functional.buzz | 18 ++++++------ 17 files changed, 89 insertions(+), 69 deletions(-) diff --git a/src/Codegen.zig b/src/Codegen.zig index ff85cbcb..1b50e5ef 100644 --- a/src/Codegen.zig +++ b/src/Codegen.zig @@ -307,6 +307,8 @@ pub fn identifierConstant(self: *Self, name: []const u8) !u24 { // Unlocated error, should not be used fn reportError(self: *Self, error_type: Reporter.Error, message: []const u8) void { + @setCold(true); + if (self.reporter.panic_mode) { return; } @@ -388,7 +390,7 @@ fn endScope(self: *Self, node: Ast.Node.Index) Error!void { } } -inline fn generateNode(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj.ObjFunction { +fn generateNode(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj.ObjFunction { if (self.synchronize(node)) { return null; } diff --git a/src/Parser.zig b/src/Parser.zig index aed166c9..b58fbca5 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -402,6 +402,7 @@ const rules = [_]ParseRule{ .{ .prefix = null, .infix = binary, .precedence = .Comparison }, // LessEqual .{ .prefix = null, .infix = binary, .precedence = .NullCoalescing }, // QuestionQuestion .{ .prefix = null, .infix = null, .precedence = .None }, // Arrow + .{ .prefix = null, .infix = null, .precedence = .None }, // DoubleArrow .{ .prefix = literal, .infix = null, .precedence = .None }, // True .{ .prefix = literal, .infix = null, .precedence = .None }, // False .{ .prefix = literal, .infix = null, .precedence = .None }, // Null @@ -530,7 +531,8 @@ pub fn deinit(self: *Self) void { self.ffi.deinit(); } -inline fn reportErrorAtCurrent(self: *Self, error_type: Reporter.Error, message: []const u8) void { +fn reportErrorAtCurrent(self: *Self, error_type: Reporter.Error, message: []const u8) void { + @setCold(true); self.reporter.reportErrorAt( error_type, self.ast.tokens.get(self.current_token.?), @@ -538,7 +540,8 @@ inline fn reportErrorAtCurrent(self: *Self, error_type: Reporter.Error, message: ); } -pub inline fn reportError(self: *Self, error_type: Reporter.Error, message: []const u8) void { +pub fn reportError(self: *Self, error_type: Reporter.Error, message: []const u8) void { + @setCold(true); self.reporter.reportErrorAt( error_type, self.ast.tokens.get(if (self.current_token.? > 0) self.current_token.? - 1 else 0), @@ -546,7 +549,8 @@ pub inline fn reportError(self: *Self, error_type: Reporter.Error, message: []co ); } -inline fn reportErrorFmt(self: *Self, error_type: Reporter.Error, comptime fmt: []const u8, args: anytype) void { +fn reportErrorFmt(self: *Self, error_type: Reporter.Error, comptime fmt: []const u8, args: anytype) void { + @setCold(true); self.reporter.reportErrorFmt( error_type, self.ast.tokens.get(if (self.current_token.? > 0) self.current_token.? - 1 else 0), @@ -2241,7 +2245,7 @@ fn parseVariable( ); } -inline fn markInitialized(self: *Self) void { +fn markInitialized(self: *Self) void { if (self.current.?.scope_depth == 0) { // assert(!self.globals.items[self.globals.items.len - 1].initialized); self.globals.items[self.globals.items.len - 1].initialized = true; @@ -4930,7 +4934,7 @@ fn inlineIf(self: *Self, _: bool) Error!Ast.Node.Index { return try self.@"if"(false, null); } -inline fn isAs(self: *Self, left: Ast.Node.Index, is_expr: bool) Error!Ast.Node.Index { +fn isAs(self: *Self, left: Ast.Node.Index, is_expr: bool) Error!Ast.Node.Index { const start_location = self.ast.nodes.items(.location)[left]; const constant = try self.parseTypeDef(null, true); const type_def = self.ast.nodes.items(.type_def)[constant].?; @@ -5370,7 +5374,7 @@ fn function( const end_token: Token.Type = if (function_type.canOmitBody()) .Semicolon else .LeftBrace; - while (!self.check(end_token) and !self.check(.Arrow) and !self.check(.Eof)) { + while (!self.check(end_token) and !self.check(.DoubleArrow) and !self.check(.Eof)) { const error_type_node = try self.parseTypeDef( self.ast.nodes.items(.type_def)[function_node].?.resolved_type.?.Function.generic_types, true, @@ -5384,7 +5388,7 @@ fn function( self.reportError(.error_type, "Error type can't be optional"); } - if (!self.check(end_token) and !self.check(.Arrow)) { + if (!self.check(end_token) and !self.check(.DoubleArrow)) { try self.consume(.Comma, "Expected `,` after error type"); } } @@ -5397,7 +5401,7 @@ fn function( self.ast.nodes.items(.components)[function_signature].FunctionType.error_types = error_types.items; // Parse body - if (try self.match(.Arrow)) { + if (try self.match(.DoubleArrow)) { function_typedef.resolved_type.?.Function.lambda = true; self.ast.nodes.items(.components)[function_signature].FunctionType.lambda = true; const expr = try self.expression(false); diff --git a/src/Scanner.zig b/src/Scanner.zig index e93f5c27..a01e7f46 100644 --- a/src/Scanner.zig +++ b/src/Scanner.zig @@ -115,7 +115,20 @@ pub fn scanToken(self: *Self) !Token { self.makeToken(.DoubleColon, null, null, null) else self.makeToken(.Colon, null, null, null), - '=' => self.makeToken(if (self.match('=')) .EqualEqual else .Equal, null, null, null), + '=' => if (self.match('>')) + self.makeToken( + .DoubleArrow, + null, + null, + null, + ) + else + self.makeToken( + if (self.match('=')) .EqualEqual else .Equal, + null, + null, + null, + ), '"' => self.string(false), '`' => self.string(true), '\'' => self.byte(), @@ -682,6 +695,7 @@ pub fn highlight(self: *Self, out: anytype, true_color: bool) void { .Colon, .DoubleColon, .Arrow, + .DoubleArrow, .Ampersand, .Spread, => if (true_color) Color.punctuation else Color.bright_white, diff --git a/src/Token.zig b/src/Token.zig index 1bf93cfc..478eedc0 100644 --- a/src/Token.zig +++ b/src/Token.zig @@ -103,6 +103,7 @@ pub const Type = enum { LessEqual, // <= QuestionQuestion, // ?? Arrow, // -> + DoubleArrow, // => True, // true False, // false Null, // null diff --git a/src/builtin/list.zig b/src/builtin/list.zig index e8f34754..fd39bc18 100644 --- a/src/builtin/list.zig +++ b/src/builtin/list.zig @@ -1,5 +1,4 @@ const builtin = @import("builtin"); -const is_wasm = builtin.cpu.arch.isWasm(); const std = @import("std"); const _obj = @import("../obj.zig"); const ObjString = _obj.ObjString; diff --git a/src/lib/buzz_buffer.zig b/src/lib/buzz_buffer.zig index 0b30177a..a4f49afb 100644 --- a/src/lib/buzz_buffer.zig +++ b/src/lib/buzz_buffer.zig @@ -501,7 +501,7 @@ pub export fn BufferAt(ctx: *api.NativeCtx) c_int { return 1; } -inline fn rawWriteZ( +fn rawWriteZ( ctx: *api.NativeCtx, buffer: *Buffer, ztype: []const u8, @@ -584,7 +584,7 @@ pub export fn BufferWriteZAt(ctx: *api.NativeCtx) c_int { )) -1 else 0; } -inline fn rawWriteStruct( +fn rawWriteStruct( vm: *api.VM, buffer: *Buffer, at: usize, @@ -666,7 +666,7 @@ pub export fn BufferWriteStructAt(ctx: *api.NativeCtx) c_int { )) -1 else 0; } -inline fn rawReadStruct( +fn rawReadStruct( vm: *api.VM, buffer: *Buffer, at: ?usize, diff --git a/src/lib/ffi.buzz b/src/lib/ffi.buzz index d03f3737..53a9b0b0 100644 --- a/src/lib/ffi.buzz +++ b/src/lib/ffi.buzz @@ -1,6 +1,6 @@ namespace ffi; -export fun cstr(str string) -> "{string}\0"; +export fun cstr(str string) => "{string}\0"; export object FFITypeMismatchError { str message = "Provided buzz value type does not match expected FFI type", diff --git a/src/lib/serialize.buzz b/src/lib/serialize.buzz index f38471c3..478af85d 100644 --- a/src/lib/serialize.buzz +++ b/src/lib/serialize.buzz @@ -64,17 +64,17 @@ export object Boxed { } || @return wrapped data string value or empty string if not a string - fun stringValue() > str -> this.string() ?? "" + fun stringValue() > str => this.string() ?? "" || @return wrapped data boolean value or `false` if not a boolean - fun booleanValue() > bool -> this.boolean() ?? false + fun booleanValue() > bool => this.boolean() ?? false || @return wrapped data number value or `0` if not an integer - fun integerValue() > int -> this.integer() ?? 0 + fun integerValue() > int => this.integer() ?? 0 || @return wrapped data number value or `0` if not a float - fun floatingValue() > float -> this.floating() ?? 0.0 + fun floatingValue() > float => this.floating() ?? 0.0 || @return wrapped data map value or empty map if not a map - fun mapValue() > {str: Boxed} -> this.map() ?? {} + fun mapValue() > {str: Boxed} => this.map() ?? {} || @return wrapped data list value or empty list if not a list - fun listValue() > [Boxed] -> this.list() ?? [] + fun listValue() > [Boxed] => this.list() ?? [] || Query the json element at `path`, if nothing matches return `Boxed{}` || @param path Path to query diff --git a/src/lib/testing.buzz b/src/lib/testing.buzz index e76d4f52..5dc1e8b6 100644 --- a/src/lib/testing.buzz +++ b/src/lib/testing.buzz @@ -38,28 +38,28 @@ export fun color(str text, Color color, bool reset = true) > str { return "\27[{color.value}m{text}{if (reset) "\27[0m" else ""}"; } -export fun bright(str text) -> color(text, color: Color.bright); -export fun dim(str text) -> color(text, color: Color.dim); -export fun underscore(str text) -> color(text, color: Color.underscore); -export fun blink(str text) -> color(text, color: Color.blink); -export fun reverse(str text) -> color(text, color: Color.reverse); -export fun hidden(str text) -> color(text, color: Color.hidden); -export fun black(str text) -> color(text, color: Color.black); -export fun red(str text) -> color(text, color: Color.red); -export fun green(str text) -> color(text, color: Color.green); -export fun yellow(str text) -> color(text, color: Color.yellow); -export fun blue(str text) -> color(text, color: Color.blue); -export fun magenta(str text) -> color(text, color: Color.magenta); -export fun cyan(str text) -> color(text, color: Color.cyan); -export fun white(str text) -> color(text, color: Color.white); -export fun onblack(str text) -> color(text, color: Color.onblack); -export fun onred(str text) -> color(text, color: Color.onred); -export fun ongreen(str text) -> color(text, color: Color.ongreen); -export fun onyellow(str text) -> color(text, color: Color.onyellow); -export fun onblue(str text) -> color(text, color: Color.onblue); -export fun onmagenta(str text) -> color(text, color: Color.onmagenta); -export fun oncyan(str text) -> color(text, color: Color.oncyan); -export fun onwhite(str text) -> color(text, color: Color.onwhite); +export fun bright(str text) => color(text, color: Color.bright); +export fun dim(str text) => color(text, color: Color.dim); +export fun underscore(str text) => color(text, color: Color.underscore); +export fun blink(str text) => color(text, color: Color.blink); +export fun reverse(str text) => color(text, color: Color.reverse); +export fun hidden(str text) => color(text, color: Color.hidden); +export fun black(str text) => color(text, color: Color.black); +export fun red(str text) => color(text, color: Color.red); +export fun green(str text) => color(text, color: Color.green); +export fun yellow(str text) => color(text, color: Color.yellow); +export fun blue(str text) => color(text, color: Color.blue); +export fun magenta(str text) => color(text, color: Color.magenta); +export fun cyan(str text) => color(text, color: Color.cyan); +export fun white(str text) => color(text, color: Color.white); +export fun onblack(str text) => color(text, color: Color.onblack); +export fun onred(str text) => color(text, color: Color.onred); +export fun ongreen(str text) => color(text, color: Color.ongreen); +export fun onyellow(str text) => color(text, color: Color.onyellow); +export fun onblue(str text) => color(text, color: Color.onblue); +export fun onmagenta(str text) => color(text, color: Color.onmagenta); +export fun oncyan(str text) => color(text, color: Color.oncyan); +export fun onwhite(str text) => color(text, color: Color.onwhite); export object Tester { [bool] tests = [], @@ -99,7 +99,7 @@ export object Tester { fun failedAsserts() > int { return this.asserts.reduce::( fun (int _, bool success, int accumulator) - -> accumulator + if (success) 0 else 1, + => accumulator + if (success) 0 else 1, initial: 0, ); } @@ -107,7 +107,7 @@ export object Tester { fun failedTests() > int { return this.tests.reduce::( fun (int _, bool success, int accumulator) - -> accumulator + if (success) 0 else 1, + => accumulator + if (success) 0 else 1, initial: 0, ); } @@ -115,7 +115,7 @@ export object Tester { fun succeededTests() > int { return this.tests.reduce::( fun (int _, bool success, int accumulator) - -> accumulator + if (success) 1 else 0, + => accumulator + if (success) 1 else 0, initial: 0, ); } diff --git a/src/obj.zig b/src/obj.zig index 439439b7..4e4fb4ee 100644 --- a/src/obj.zig +++ b/src/obj.zig @@ -62,7 +62,7 @@ pub const Obj = struct { is_dirty: bool = false, node: ?*std.DoublyLinkedList(*Obj).Node = null, - pub inline fn cast(obj: *Obj, comptime T: type, obj_type: ObjType) ?*T { + pub fn cast(obj: *Obj, comptime T: type, obj_type: ObjType) ?*T { if (obj.obj_type != obj_type) { return null; } @@ -70,7 +70,7 @@ pub const Obj = struct { return @alignCast(@fieldParentPtr("obj", obj)); } - pub inline fn access(obj: *Obj, comptime T: type, obj_type: ObjType, gc: *GarbageCollector) ?*T { + pub fn access(obj: *Obj, comptime T: type, obj_type: ObjType, gc: *GarbageCollector) ?*T { if (BuildOptions.gc_debug_access) { gc.debugger.?.accessed(obj, gc.where); } diff --git a/tests/012-lambda.buzz b/tests/012-lambda.buzz index 3db08b71..b7627e92 100644 --- a/tests/012-lambda.buzz +++ b/tests/012-lambda.buzz @@ -1,7 +1,7 @@ import "std"; test "Lambda/Anonymous functions" { - Function(int n) > int mul = fun (int n) > int -> n * 2; + Function(int n) > int mul = fun (int n) > int => n * 2; std.assert(mul(1) == 2, message: "called a lambda function"); } @@ -12,11 +12,11 @@ fun callThis(Function(int n) > int fn, int arg) > int { test "Function as arguments" { std.assert((fun (int n) > int { return n * n; })(10) == 100, message: "called anonymous function"); - std.assert((fun (int n) > int -> n * n)(10) == 100, message: "called lambda function"); - std.assert(callThis(fun (int n) > int -> n * 2, arg: 2) == 4, message: "called a function from a function"); + std.assert((fun (int n) > int => n * n)(10) == 100, message: "called lambda function"); + std.assert(callThis(fun (int n) > int => n * 2, arg: 2) == 4, message: "called a function from a function"); } -fun mul(int a, int b) > int -> a * b; +fun mul(int a, int b) > int => a * b; test "Any function can be an arrow function" { std.assert(mul(a: 2, b: 2) == 4, message: "arrow function"); diff --git a/tests/021-upvalues.buzz b/tests/021-upvalues.buzz index 27da336d..a7345214 100644 --- a/tests/021-upvalues.buzz +++ b/tests/021-upvalues.buzz @@ -4,7 +4,7 @@ fun upvals() > Function() { int upvalue = 12; str up = "up"; - return fun () > void -> std.print("{upvalue} {up}"); + return fun () > void => std.print("{upvalue} {up}"); } test "Upvalues" { diff --git a/tests/029-default-arguments.buzz b/tests/029-default-arguments.buzz index 6c46613d..ccbc6284 100644 --- a/tests/029-default-arguments.buzz +++ b/tests/029-default-arguments.buzz @@ -1,7 +1,7 @@ import "std"; fun hey(str name = "Joe", int age = 12, str? father, int fourth = 1) > str - -> "Hello {name} you're {age} {father} {fourth}"; + => "Hello {name} you're {age} {father} {fourth}"; test "function default arguments" { std.assert(hey("John") == "Hello John you're 12 null 1", message: "Could reorder or omit argument"); diff --git a/tests/032-debug.buzz b/tests/032-debug.buzz index d5276338..ab47a6c0 100644 --- a/tests/032-debug.buzz +++ b/tests/032-debug.buzz @@ -6,7 +6,7 @@ import "debug"; | str source = debug.ast(` | import \"std\"; | -| fun main([str] _) > void -> std.print(\"hello world\"); +| fun main([str] _) > void => std.print(\"hello world\"); | `, scriptName: "test"); | | Boxed jsonAST = jsonDecode(source); diff --git a/tests/038-fibers.buzz b/tests/038-fibers.buzz index 45286dd5..ac107d7c 100644 --- a/tests/038-fibers.buzz +++ b/tests/038-fibers.buzz @@ -54,13 +54,13 @@ test "Throw inside a fiber" { fun closedUpvalue() > Function() > str { str upvalue = "joe"; - return fun () > str -> "hello {upvalue}"; + return fun () > str => "hello {upvalue}"; } test "Opened upvalue in fiber" { str upvalue = "world"; - Function() > str fiberFn = fun () > str -> "hello {upvalue}"; + Function() > str fiberFn = fun () > str => "hello {upvalue}"; std.assert(resolve &fiberFn() == "hello world", message: "Fiber could use an opened upvalue"); } @@ -71,7 +71,7 @@ test "Closed upvalue in fiber" { test "Wrapping call inside complex expressions" { {str: Function() > str} map = { - "hello": fun () > str -> "hello world", + "hello": fun () > str => "hello world", }; std.assert(resolve &map["hello"]?() == "hello world", message:"Could warp function call in a complex expression"); diff --git a/tests/048-generics.buzz b/tests/048-generics.buzz index e5f68f99..181c1eea 100644 --- a/tests/048-generics.buzz +++ b/tests/048-generics.buzz @@ -47,7 +47,7 @@ test "Generic within anonymous object and map" { } fun countShuffleGenerics::() > Function([A] a, [B] b) > int { - return fun ([A] a, [B] b) > int -> a.len() + b.len(); + return fun ([A] a, [B] b) > int => a.len() + b.len(); } test "Generic in lambda function definition" { @@ -101,7 +101,7 @@ fun doubleGeneric::(Function::() > int lambda) > int { test "Generic with generic lambda parameter" { std.assert( doubleGeneric::( - fun::() > int -> 12 + fun::() > int => 12 ) == 12, message: "could defined multiple generics" ); diff --git a/tests/051-functional.buzz b/tests/051-functional.buzz index 1f9606b5..05710807 100644 --- a/tests/051-functional.buzz +++ b/tests/051-functional.buzz @@ -14,7 +14,7 @@ test "list.forEach" { test "list.map" { [int] data = [1, 2, 3, 4]; - [str] mapped = data.map::(fun (int _, int element) -> "{element}"); + [str] mapped = data.map::(fun (int _, int element) => "{element}"); std.assert(mapped.join(", ") == "1, 2, 3, 4", message: "could use map"); } @@ -22,7 +22,7 @@ test "list.map" { test "list.filter" { [int] data = [1, 2, 3, 4]; - [int] odd = data.filter(fun (int _, int element) -> element % 2 != 0); + [int] odd = data.filter(fun (int _, int element) => element % 2 != 0); std.assert(odd.join(", ") == "1, 3", message: "could use filter"); } @@ -31,7 +31,7 @@ test "list.reduce" { [int] data = [1, 2, 3, 4]; int sum = data.reduce::( - fun (int _, int element, int accumulator) -> accumulator + element, + fun (int _, int element, int accumulator) => accumulator + element, initial: 0 ); @@ -41,7 +41,7 @@ test "list.reduce" { test "list.sort" { [int] data = [10, 3, 12, 0, 1, -3]; - _ = data.sort(fun (int left, int right) -> left < right); + _ = data.sort(fun (int left, int right) => left < right); foreach (int i, int value in [-3, 0, 1, 3, 10, 12]) { std.assert(data[i] == value, message: "list is not ordered"); @@ -58,7 +58,7 @@ test "map.forEach" { int sum = 0; map.forEach( - fun (str _, int value) > void -> sum = sum + value + fun (str _, int value) > void => sum = sum + value ); std.assert(sum == 11, message: "could use map.forEach"); @@ -74,7 +74,7 @@ test "map.map" { | fun map(, Function(str key, int value) > obj{ K key, V value }) > {K, V} {int: str} inverted = map.map::( - fun (str key, int value) -> .{ key = value, value = key }, + fun (str key, int value) => .{ key = value, value = key }, ); foreach (str key, int value in map) { @@ -91,7 +91,7 @@ test "map.filter" { }; {str: int} filtered = map.filter( - fun (str _, int value) -> value % 2 != 0 + fun (str _, int value) => value % 2 != 0 ); std.assert(filtered["two"] == null, message: "Could use map.filter"); @@ -106,7 +106,7 @@ test "map.reduce" { }; int sum = map.reduce::( - fun (str _, int value, int accumulator) -> accumulator + value, + fun (str _, int value, int accumulator) => accumulator + value, initial: 0 ); @@ -123,7 +123,7 @@ test "map.sort" { _ = map.sort( - fun (str lhs, str rhs) -> map[lhs]! < map[rhs]! + fun (str lhs, str rhs) => map[lhs]! < map[rhs]! ); [str] ordered = [ "one", "two", "three", "five" ];