diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d4396bc..44d49b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Unreleased +## Major syntax changes +- Types are now specified *after* the identifier + `:`. This includes: + - Variable declarations + - Function argument definitions + - Catch clauses + - `if (...: type as ...)` +- Arrow function use `=>` instead of `->` +- Comments and docblocks must now be prefixed by `//` and `///` instead of `|` and `||` +- Bitwise or operator is `|` instead of `\` +- Function type now use `fun` keyword instead of `Function` +- If a function type has multiple error types, they must be put them in parenthesis +- Namespace can now be multiple `\` separated identifiers +- Qualified name now use `\` separator instead of `.` + ## Added - Object can have `const` properties (https://github.com/buzz-language/buzz/issues/13). A object with only `const` properties is considered itself `const`. Although we don't do anything yet with that concept. https://github.com/buzz-language/buzz/issues/114 is the objective but it requires being able to build objects and instances at compile time which is not yet possible. - `rg.subsetOf`, `rg.intersect`, `rg.union` @@ -22,7 +36,6 @@ list[?10] == null; ## Modified - Enum can now have `rg`, `ud`, `void`, `pat` has value type -- `var` can be used for key and/or value type in `for` and `foreach` loop - Anonymous object can also omit property name when initial value is a named variable ## Fixed diff --git a/README.md b/README.md index 5fe43ba5..ab3ec90b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ A small/lightweight statically typed scripting language written in Zig ## How to build and install -_Latest zig version supported: 0.14.0-dev.121+ab4c461b7_ +_Latest zig version supported: 0.14.0-dev.121+ab4c461b7 (https://github.com/ziglang/zig/issues/20847 prevents us from upgrading further)_ ### Requirements - Since this is built with Zig, you should be able to build buzz on a wide variety of architectures even though this has only been tested on x86/M1. diff --git a/example.png b/example.png index 26aea7ca..62a69847 100644 Binary files a/example.png and b/example.png differ diff --git a/examples/2048.buzz b/examples/2048.buzz index ac8773a9..dbb288a3 100644 --- a/examples/2048.buzz +++ b/examples/2048.buzz @@ -1,63 +1,62 @@ -| The rules are that on each turn the player must choose a direction (up, down, -| left or right) and all tiles move as far as possible in that direction, some -| more than others. Two adjacent tiles (in that direction only) with matching -| numbers combine into one bearing the sum of those numbers. A move is valid -| when at least one tile can be moved, if only by combination. A new tile with -| the value of 2 is spawned at the end of each turn at a randomly chosen empty -| square, if there is one. To win the player must create a tile with the number -| 2048. The player loses if no valid moves are possible. -| -| The name comes from the popular open-src implementation of this game -| mechanic: https://gabrielecirulli.github.io/2048/. -| -| Requirements: -| - "Non-greedy" movement. The tiles that were created by combining other tiles -| should not be combined again during the same turn (move). That is to say that -| moving the tile row of [2][2][2][2] to the right should result in -| ......[4][4] and not .........[8] -| - "Move direction priority". If more than one variant of combining is -| possible, move direction shows one that will take effect. For example, moving -| the tile row of ...[2][2][2] to the right should result in ......[2][4] and -| not ......[4][2] -| - Adding a new tile on a blank space. Most of the time new "2" is to be added -| and occasionally (10% of the time) - "4" -| - Check for valid moves. The player shouldn't be able to skip their turn by -| trying a move that doesn't change the board. -| - Win condition. -| - Lose condition. - +// The rules are that on each turn the player must choose a direction (up, down, +// left or right) and all tiles move as far as possible in that direction, some +// more than others. Two adjacent tiles (in that direction only) with matching +// numbers combine into one bearing the sum of those numbers. A move is valid +// when at least one tile can be moved, if only by combination. A new tile with +// the value of 2 is spawned at the end of each turn at a randomly chosen empty +// square, if there is one. To win the player must create a tile with the number +// 2048. The player loses if no valid moves are possible. +// +// The name comes from the popular open-src implementation of this game +// mechanic: https://gabrielecirulli.github.io/2048/. +// +// Requirements: +// - "Non-greedy" movement. The tiles that were created by combining other tiles +// should not be combined again during the same turn (move). That is to say that +// moving the tile row of [2][2][2][2] to the right should result in +// ......[4][4] and not .........[8] +// - "Move direction priority". If more than one variant of combining is +// possible, move direction shows one that will take effect. For example, moving +// the tile row of ...[2][2][2] to the right should result in ......[2][4] and +// not ......[4][2] +// - Adding a new tile on a blank space. Most of the time new "2" is to be added +// and occasionally (10% of the time) - "4" +// - Check for valid moves. The player shouldn't be able to skip their turn by +// trying a move that doesn't change the board. +// - Win condition. +// - Lose condition. import "std"; import "io"; import "errors"; import "os"; object Pair { - int srcX, - int srcY, - int srcValue, + srcX: int, + srcY: int, + srcValue: int, - int destX, - int destY, - int destValue, + destX: int, + destY: int, + destValue: int, } object Game { - [[int]] board = [<[int]>], - int size = 4, - int goal = 2048, - int score = 0, - bool invalidMove = false, + board: [[int]] = [<[int]>], + size: int = 4, + goal: int = 2048, + score: int = 0, + invalidMove: bool = false, - static fun init(int size = 4, int goal = 2048) > Game { + static fun init(size: int = 4, goal: int = 2048) > Game { const game = Game{ size, goal }; - foreach (int x in 0..game.size) { + foreach (x in 0..game.size) { game.board.append([]); - foreach (int _ in 0..game.size) { + foreach (_ in 0..game.size) { game.board[x].append(0); } } @@ -68,14 +67,14 @@ object Game { fun reset() > void { this.score = 0; - foreach (int x in 0..this.size) { - foreach (int y in 0..this.size) { + foreach (x in 0..this.size) { + foreach (y in 0..this.size) { this.board[x][y] = 0; } } } - | Add new tile at a random free sp + // Add new tile at a random free sp fun addNewTile() > void { const free = this.freeSpots(); @@ -83,19 +82,19 @@ object Game { return; } - const spot = free[std.random(min: 0, max: free.len() - 1)]; - this.board[spot.x][spot.y] = if (std.random(min: 0, max: 9) == 0) + const spot = free[std\random(min: 0, max: free.len() - 1)]; + this.board[spot.x][spot.y] = if (std\random(min: 0, max: 9) == 0) 4 else 2; } - | Return list of free spots - fun freeSpots() > [obj{ int x, int y }] { - [obj{ int x, int y}] spots = []; + // Return list of free spots + fun freeSpots() > [obj{ x: int, y: int }] { + var spots = []; - foreach (int x, [int] row in this.board) { - foreach (int y, int value in row) { + foreach (x, row in this.board) { + foreach (y, value in row) { if (value == 0) { spots.append(.{ x = x, y = y }); } @@ -105,60 +104,60 @@ object Game { return spots; } - | Render board + // Render board fun render() > void { try { - io.stdout.write("\27\91H\27\91J╭{"─".repeat(this.size * 7)}╮\n"); + io\stdout.write("\27\91H\27\91J╭{"─".repeat(this.size * 7)}╮\n"); - foreach (int x, [int] row in this.board) { - io.stdout.write("│ "); + foreach (x, row in this.board) { + io\stdout.write("│ "); - foreach (int y, int value in row) { + foreach (y, value in row) { if (value != 0) { - | TODO: we need formatting to be available in buzz + // TODO: we need formatting to be available in buzz if (value < 10) { - io.stdout.write(" {value} "); + io\stdout.write(" {value} "); } else if (value < 100) { - io.stdout.write(" {value} "); + io\stdout.write(" {value} "); } else if (value < 1000) { - io.stdout.write(" {value} "); + io\stdout.write(" {value} "); } else { - io.stdout.write(" {value} "); + io\stdout.write(" {value} "); } } else { - io.stdout.write(" "); + io\stdout.write(" "); } if (y < this.size - 1) { - io.stdout.write("│"); + io\stdout.write("│"); } } - io.stdout.write("│\n"); + io\stdout.write("│\n"); if (x < this.size - 1) { - io.stdout.write("├{"─".repeat(this.size * 7)}┤\n"); + io\stdout.write("├{"─".repeat(this.size * 7)}┤\n"); } } - io.stdout.write("╰{"─".repeat(this.size * 7)}╯\n"); + io\stdout.write("╰{"─".repeat(this.size * 7)}╯\n"); - io.stdout.write("Score: {this.score} / {this.goal}\n"); + io\stdout.write("Score: {this.score} / {this.goal}\n"); if (this.invalidMove) { this.invalidMove = false; - io.stdout.write("Invalid move, try again\n"); + io\stdout.write("Invalid move, try again\n"); } } catch { - io.stderr.write("Error while rendering board\n") catch void; + io\stderr.write("Error while rendering board\n") catch void; } } - fun iterate(bool axis, int direction) > [Pair] { - [Pair] result = []; + fun iterate(axis: bool, direction: int) > [Pair] { + var result = []; - foreach (int x in 0..this.size) { - foreach (int y in 0..this.size) { + foreach (x in 0..this.size) { + foreach (y in 0..this.size) { const pair = Pair{ srcX = x, srcY = y, @@ -186,13 +185,13 @@ object Game { return result; } - fun shift(bool axis, int direction) > int { + fun shift(axis: bool, direction: int) > int { var totalDone = 0; - foreach (int _ in 0..this.size) { + foreach (_ in 0..this.size) { var done = 0; - foreach (Pair pair in this.iterate(axis, direction)) { + foreach (pair in this.iterate(axis, direction)) { if (pair.destValue == 0 and pair.srcValue != 0) { this.board[pair.destX][pair.destY] = pair.srcValue; this.board[pair.srcX][pair.srcY] = 0; @@ -210,10 +209,10 @@ object Game { return totalDone; } - fun merge(bool axis, int direction) > int { + fun merge(axis: bool, direction: int) > int { var done = 0; - foreach (Pair pair in this.iterate(axis, direction)) { + foreach (pair in this.iterate(axis, direction)) { if (pair.destValue != 0 and pair.destValue == pair.srcValue) { this.board[pair.srcX][pair.srcY] = this.board[pair.srcX][pair.srcY] + pair.destValue; this.board[pair.destX][pair.destY] = 0; @@ -227,11 +226,11 @@ object Game { } fun move() > bool { - io.stdout.write("(wasd to move, q to quit, r to restart)\n> ") catch void; - const command = io.stdin.read(1) catch void; + io\stdout.write("(wasd to move, q to quit, r to restart)\n> ") catch void; + const command = io\stdin.read(1) catch void; if (command == "q") { - os.exit(0); + os\exit(0); } if (command == "r") { @@ -254,16 +253,16 @@ object Game { direction = 1; axis = true; } else { - io.stderr.write("Invalid command\n") catch void; + io\stderr.write("Invalid command\n") catch void; return false; } var done = 0; - | Shift in that direction + // Shift in that direction done = done + this.shift(axis, direction); - | Merge equal numbers in opposite direction + // Merge equal numbers in opposite direction done = done + this.merge(axis, direction: direction * -1); - | Shift merged numebrs in that direction + // Shift merged numebrs in that direction done = done + this.shift(axis, direction); return done > 0; @@ -276,25 +275,25 @@ object Game { this.addNewTile(); } else { if (this.freeSpots().len() == 0) { - io.stderr.write("No move left, you lost.\n") catch void; - os.exit(0); + io\stderr.write("No move left, you lost.\n") catch void; + os\exit(0); } else { this.invalidMove = true; } } - | Did we win? - foreach (int x in 0..this.size) { - foreach (int y in 0..this.size) { + // Did we win? + foreach (x in 0..this.size) { + foreach (y in 0..this.size) { if (this.board[x][y] == this.goal) { - io.stdout.write("YOU WON!\n") catch void; + io\stdout.write("YOU WON!\n") catch void; } } } } } -fun main([str] _) > void { +fun main(_: [str]) > void { const game = Game.init(); game.addNewTile(); @@ -303,4 +302,4 @@ fun main([str] _) > void { while (true) { game.step(); } -} \ No newline at end of file +} diff --git a/examples/brownian-tree.buzz b/examples/brownian-tree.buzz index 8da9a99d..2dcee781 100644 --- a/examples/brownian-tree.buzz +++ b/examples/brownian-tree.buzz @@ -1,24 +1,24 @@ import "std"; import "examples/sdl-wrapped" as _; -fun seed([[bool]] canvas) > void { - foreach (int i in 0..canvas.len()) { +fun seed(canvas: [[bool]]) > void { + foreach (i in 0..canvas.len()) { canvas[0][i] = true; canvas[canvas.len() - 1][i] = true; } - foreach (int i in 0..canvas.len()) { + foreach (i in 0..canvas.len()) { canvas[i][0] = true; canvas[i][canvas[0].len() - 1] = true; } } -fun setParticle([[bool]] canvas) > obj{ int x, int y } { +fun setParticle(canvas: [[bool]]) > obj{ x: int, y: int } { var posX = 0; var posY = 0; do { - posX = std.random(min: 0, max: canvas.len() - 1); - posY = std.random(min: 0, max: canvas[0].len() - 1); + posX = std\random(min: 0, max: canvas.len() - 1); + posY = std\random(min: 0, max: canvas[0].len() - 1); } until (!canvas[posX][posY]) return .{ @@ -27,13 +27,13 @@ fun setParticle([[bool]] canvas) > obj{ int x, int y } { }; } -fun iterate([[bool]] canvas, int numParticles) { - foreach (int _ in 0..numParticles) { +fun iterate(canvas: [[bool]], numParticles: int) { + foreach (_ in 0..numParticles) { const pos = setParticle(canvas); while (true) { - const dx = std.random(min: 0, max: 5) - 3; - const dy = std.random(min: 0, max: 5) - 3; + const dx = std\random(min: 0, max: 5) - 3; + const dy = std\random(min: 0, max: 5) - 3; if (pos.x + dx >= 0 and pos.x + dx < canvas.len() and pos.y + dy >= 0 and pos.y + dy < canvas[0].len()) { if (canvas[pos.x + dx][pos.y + dy]) { @@ -48,9 +48,9 @@ fun iterate([[bool]] canvas, int numParticles) { } } -fun draw([[bool]] canvas, Renderer renderer) > void !> SDLError { - foreach (int x in 0..canvas.len()) { - foreach (int y in 0..canvas[0].len()) { +fun draw(canvas: [[bool]], renderer: Renderer) > void !> SDLError { + foreach (x in 0..canvas.len()) { + foreach (y in 0..canvas[0].len()) { renderer.setRenderDrawColor( if (canvas[x][y]) Color{ @@ -71,16 +71,16 @@ fun draw([[bool]] canvas, Renderer renderer) > void !> SDLError { } } -fun main([str] _) > void !> SDLError { +fun main(_: [str]) > void !> SDLError { const sizeX = 200; const sizeY = 200; const numParticles = 16000; - [[bool]] canvas = []; - foreach (int i in 0..sizeX) { + var canvas: [[bool]] = []; + foreach (i in 0..sizeX) { canvas.append([]); - foreach (int _ in 0..sizeY) { + foreach (_ in 0..sizeY) { canvas[i].append(false); } } @@ -131,4 +131,4 @@ fun main([str] _) > void !> SDLError { } sdl.quit(); -} \ No newline at end of file +} diff --git a/examples/fibonacci.buzz b/examples/fibonacci.buzz index 556a1cd5..2ce91310 100644 --- a/examples/fibonacci.buzz +++ b/examples/fibonacci.buzz @@ -1,11 +1,11 @@ import "std"; -fun fibonacci(int n) > void *> int? { +fun fibonacci(n: int) > void *> int? { var n1 = 0; var n2 = 1; - int? next = null; + var next: int? = null; - foreach (var _ in 0..n) { + foreach (_ in 0..n) { _ = yield n1; next = n1 + n2; n1 = n2; @@ -13,10 +13,10 @@ fun fibonacci(int n) > void *> int? { } } -fun main([str] args) > void { - const N = std.parseInt(args[?0] ?? "10") ?? 10; +fun main(args: [str]) > void { + const N = std\parseInt(args[?0] ?? "10") ?? 10; - foreach (var n in &fibonacci(N)) { - std.print("{n}"); + foreach (n in &fibonacci(N)) { + std\print("{n}"); } } diff --git a/examples/fizzbuzz.buzz b/examples/fizzbuzz.buzz new file mode 100644 index 00000000..0219b9fb --- /dev/null +++ b/examples/fizzbuzz.buzz @@ -0,0 +1,40 @@ +namespace examples\fizzbuzz; + +import "std"; + +fun fizzBuzz(n: int) > str { + const fizz = n % 3 == 0; + const buzz = n % 5 == 0; + + if (fizz and buzz) { + return "FizzBuzz"; + } else if (fizz) { + return "Fizz"; + } else if (buzz) { + return "Buzz"; + } + + return "{n}"; +} + +fun main(args: [str]) > void { + const limit = std\parseInt(args[?0] ?? "10") ?? 10; + + foreach (n in 0..limit) { + std\print("{n}: {fizzBuzz(n)}"); + } +} + +test "FizzBuzz" { + std\assert(fizzBuzz(1) == "1"); + std\assert(fizzBuzz(7) == "7"); + + std\assert(fizzBuzz(3) == "Fizz"); + std\assert(fizzBuzz(9) == "Fizz"); + + std\assert(fizzBuzz(5) == "Buzz"); + std\assert(fizzBuzz(20) == "Buzz"); + + std\assert(fizzBuzz(15) == "FizzBuzz"); + std\assert(fizzBuzz(45) == "FizzBuzz"); +} \ No newline at end of file diff --git a/examples/game-of-life.buzz b/examples/game-of-life.buzz index 3335fe48..a6e39b30 100644 --- a/examples/game-of-life.buzz +++ b/examples/game-of-life.buzz @@ -2,7 +2,7 @@ import "std"; import "io"; import "examples/sdl-wrapped" as _; -| buzz -L/path/to/SDL2.dylib/so/dll examples/game-of-life.buzz +// buzz -L/path/to/SDL2.dylib/so/dll examples/game-of-life.buzz object World { int width, int height, @@ -16,7 +16,7 @@ object World { }; for (int i = 0; i < width * height; i = i + 1) { - world.cells.append(std.random(max: 5) == 1); + world.cells.append(std\random(max: 5) == 1); } return world; @@ -52,14 +52,14 @@ object World { fun dump() > void { for (int y = 0; y < this.height; y = y + 1) { for (int x = 0; x < this.width; x = x + 1) { - io.stdout.write( + io\stdout.write( if (this.cells[y * this.width + x]) "x" else "." ) catch void; } - io.stdout.write("\n") catch void; + io\stdout.write("\n") catch void; } } @@ -154,8 +154,8 @@ fun main([str] args) > void !> SDLError { height: 600, ); - int? width = if (args.len() > 0) std.parseInt(args[0]) else null; - int? height = if (args.len() > 1) std.parseInt(args[1]) else null; + int? width = if (args.len() > 0) std\parseInt(args[0]) else null; + int? height = if (args.len() > 1) std\parseInt(args[1]) else null; var world = World.init( width: width ?? 10, diff --git a/examples/sdl-wrapped.buzz b/examples/sdl-wrapped.buzz index 7730402d..5a80bd4d 100644 --- a/examples/sdl-wrapped.buzz +++ b/examples/sdl-wrapped.buzz @@ -149,7 +149,7 @@ export enum(int) Subsystem { Sensor = 0x8000, } -| Those don't seem to fit in i32 +// Those don't seem to fit in i32 export enum(int) PixelFormat { UNKNOWN = 0, INDEX1LSB = 286261504, @@ -203,19 +203,19 @@ export enum(int) TextureAccess { } export object SDLError { - str message, + message: str, } export object SDL { - SDL_Event event, + event: SDL_Event, - static fun init([Subsystem] subsystems) > SDL !> SDLError { - int flags = 0; - foreach (Subsystem subsystem in subsystems) { - flags = flags \ subsystem.value; + static fun init(subsystems: [Subsystem]) > SDL !> SDLError { + var flags = 0; + foreach (subsystem in subsystems) { + flags = flags | subsystem.value; } - if (SDL_Init(std.toFloat(flags)) != 0) { + if (SDL_Init(std\toFloat(flags)) != 0) { throw SDLError{ message = "SDL_Init error: {SDL_GetError()}", }; @@ -224,7 +224,7 @@ export object SDL { return SDL{ event = SDL_Event{ @"type" = 0.0, - | Would be useful to define default values in zig and get them back in buzz + // Would be useful to define default values in zig and get them back in buzz pad01 = 0, pad02 = 0, pad03 = 0, @@ -254,7 +254,7 @@ export object SDL { return null; } - fun delay(float ms) > void { + fun delay(ms: float) > void { SDL_Delay(ms); } @@ -264,7 +264,7 @@ export object SDL { } export object Texture { - SDL_Texture texture, + texture: SDL_Texture , fun collect() > void { SDL_DestroyTexture(this.texture); @@ -272,31 +272,31 @@ export object Texture { } export object Rect { - int x, - int y, - int width, - int height, + x: int, + y: int, + width: int, + height: int, } export object Color { - int red, - int green, - int blue, - int alpha = 0xff, + red: int, + green: int, + blue: int, + alpha: int= 0xff, } export object Renderer { - SDL_Renderer renderer, + renderer: SDL_Renderer, fun createTexture( - PixelFormat format, - TextureAccess access, - int width, - int height + format: PixelFormat, + access: TextureAccess, + width: int, + height: int ) > Texture !> SDLError { - const SDL_Texture? texture = SDL_CreateTexture( + const texture = SDL_CreateTexture( this.renderer, - format: std.toFloat(format.value), + format: std\toFloat(format.value), access: access.value, w: width, h: height, @@ -313,13 +313,10 @@ export object Renderer { }; } - fun setRenderTarget(Texture? texture) > void !> SDLError { + fun setRenderTarget(texture: Texture?) > void !> SDLError { const result = SDL_SetRenderTarget( this.renderer, - texture: if (texture != null) - texture!.texture - else - null + texture: texture?.texture ); if (result != 0) { @@ -329,7 +326,7 @@ export object Renderer { } } - fun setRenderDrawColor(Color color) > void !> SDLError { + fun setRenderDrawColor(color: Color) > void !> SDLError { const result = SDL_SetRenderDrawColor( this.renderer, r: color.red, @@ -345,7 +342,7 @@ export object Renderer { } } - fun fillRect(Rect rect) > void !> SDLError { + fun fillRect(rect: Rect) > void !> SDLError { const result = SDL_RenderFillRect( this.renderer, rect: SDL_Rect{ @@ -363,7 +360,7 @@ export object Renderer { } } - fun drawPoint(int x, int y) > void !> SDLError { + fun drawPoint(x: int, y: int) > void !> SDLError { const result = SDL_RenderDrawPoint( this.renderer, x, y, @@ -376,24 +373,24 @@ export object Renderer { } } - fun renderCopy(Texture texture, Rect? srcRect = null, Rect? dstRect = null) > void !> SDLError { + fun renderCopy(texture: Texture, srcRect: Rect? = null, dstRect: Rect? = null) > void !> SDLError { const result = SDL_RenderCopy( this.renderer, texture: texture.texture, - srcrect: if (srcRect != null) + srcrect: if (srcRect -> rect) SDL_Rect{ - x = srcRect!.x, - y = srcRect!.y, - w = srcRect!.width, - h = srcRect!.height, + x = rect.x, + y = rect.y, + w = rect.width, + h = rect.height, } else null, - dstrect: if (dstRect != null) + dstrect: if (dstRect -> rect) SDL_Rect{ - x = dstRect!.x, - y = dstRect!.y, - w = dstRect!.width, - h = dstRect!.height, + x = rect.x, + y = rect.y, + w = rect.width, + h = rect.height, } else null, ); @@ -415,28 +412,28 @@ export object Renderer { } export object Window { - SDL_Window window, + window: SDL_Window, static fun init( - str name, - int x = 0x2FFF0000, - int y = 0x2FFF0000, - int width, - int height, - [WindowFlag] flags + name: str, + x: int= 0x2FFF0000, + y: int= 0x2FFF0000, + width: int, + height: int, + flags: [WindowFlag] ) > Window !> SDLError { - int windowFlags = 0; - foreach (WindowFlag flag in flags) { - windowFlags = windowFlags \ flag.value; + var windowFlags = 0; + foreach (flag in flags) { + windowFlags = windowFlags | flag.value; } - const SDL_Window? window = SDL_CreateWindow( - ffi.cstr(name), + const window = SDL_CreateWindow( + ffi\cstr(name), x, y, w: width, h: height, - flags: std.toFloat(windowFlags), + flags: std\toFloat(windowFlags), ); if (window -> unwrapped) { @@ -451,18 +448,18 @@ export object Window { } fun createRenderer( - int index, - [RendererFlag] flags + index: int, + flags: [RendererFlag] ) > Renderer !> SDLError { - int rendererFlags = 0; - foreach (RendererFlag flag in flags) { - rendererFlags = rendererFlags \ flag.value; + var rendererFlags = 0; + foreach (flag in flags) { + rendererFlags = rendererFlags | flag.value; } - const SDL_Renderer? renderer = SDL_CreateRenderer( + const renderer = SDL_CreateRenderer( this.window, index: index, - flags: std.toFloat(rendererFlags), + flags: std\toFloat(rendererFlags), ); if (renderer -> unwrapped) { @@ -479,4 +476,4 @@ export object Window { fun collect() > void { SDL_DestroyWindow(this.window); } -} \ No newline at end of file +} diff --git a/examples/sdl.buzz b/examples/sdl.buzz index 32dc1862..d1fae7e8 100644 --- a/examples/sdl.buzz +++ b/examples/sdl.buzz @@ -1,22 +1,22 @@ import "examples/sdl-wrapped" as _; -| buzz -L/path/to/SDL2.dylib/so/dll examples/sdl.buzz -fun main([str] _) > int !> SDLError { - SDL sdl = SDL.init([Subsystem.Video]); +// buzz -L/path/to/SDL2.dylib/so/dll examples/sdl.buzz +fun main(_: [str]) > int !> SDLError { + const sdl = SDL.init([Subsystem.Video]); - Window window = Window.init( + const window = Window.init( "SDL FFI test", width: 800, height: 600, flags: [WindowFlag.OpenGL, WindowFlag.AllowHighDPI], ); - Renderer renderer = window.createRenderer( + const renderer = window.createRenderer( index: -1, flags: [RendererFlag.Accelerated, RendererFlag.TargetTexture], ); - Texture texture = renderer.createTexture( + const texture = renderer.createTexture( format: PixelFormat.RGBA8888, access: TextureAccess.Target, width: 800, diff --git a/examples/sqlite.buzz b/examples/sqlite.buzz index c6ab35f6..6f7db6d5 100644 --- a/examples/sqlite.buzz +++ b/examples/sqlite.buzz @@ -9,7 +9,7 @@ zdef("sqlite3", ` fn sqlite3_initialize() c_int; fn sqlite3_shutdown() c_int; // Right now we can't express a ptr to an opaque struct because we need to know its size - fn sqlite3_open_v2(filename: [*:0]const u8, ppDb: **anyopaque, flags: c_int, zVfs: ?[*:0]const u8) c_int; + fn sqlite3_open_v2(filename: [*:0]const u8, ppDb: **anyopaque, flags: c_int, zVfs\ ?[*:0]const u8) c_int; fn sqlite3_close_v2(db: *anyopaque) c_int; fn sqlite3_errmsg(db: *anyopaque) [*:0]const u8; fn sqlite3_prepare_v2(db: *anyopaque, zSql: [*:0]const u8, nBytes: c_int, ppStmt: **anyopaque, pzTail: ?*[*]const u8) c_int; @@ -26,37 +26,37 @@ zdef("sqlite3", ` `); enum(int) ResultCode { - Ok = 0, | Successful result - Error = 1, | Generic error - Internal = 2, | Internal logic error in SQLite - Perm = 3, | Access permission denied - Abort = 4, | Callback routine requested an abort - Busy = 5, | The database file is locked - Locked = 6, | A table in the database is locked - NoMem = 7, | A malloc() failed - Readonly = 8, | Attempt to write a readonly database - Interrupt = 9, | Operation terminated by sqlite3_interrupt( - IoErr = 10, | Some kind of disk I/O error occurred - Corrupt = 11, | The database disk image is malformed - NotFound = 12, | Unknown opcode in sqlite3_file_control() - Full = 13, | Insertion failed because database is full - CantOpen = 14, | Unable to open the database file - Protocol = 15, | Database lock protocol error - Empty = 16, | Internal use only - Schema = 17, | The database schema changed - TooBig = 18, | String or BLOB exceeds size limit - Constraint = 19, | Abort due to constraint violation - Mismatch = 20, | Data type mismatch - Misuse = 21, | Library used incorrectly - NoLfs = 22, | Uses OS features not supported on host - Auth = 23, | Authorization denied - Format = 24, | Not used - Range = 25, | 2nd parameter to sqlite3_bind out of range - NotADB = 26, | File opened that is not a database file - Notice = 27, | Notifications from sqlite3_log() - Warning = 28, | Warnings from sqlite3_log() - Row = 100, | sqlite3_step() has another row ready - Done = 101, | sqlite3_step() has finished executing + Ok = 0, // Successful result + Error = 1, // Generic error + Internal = 2, // Internal logic error in SQLite + Perm = 3, // Access permission denied + Abort = 4, // Callback routine requested an abort + Busy = 5, // The database file is locked + Locked = 6, // A table in the database is locked + NoMem = 7, // A malloc() failed + Readonly = 8, // Attempt to write a readonly database + Interrupt = 9, // Operation terminated by sqlite3_interrupt( + IoErr = 10, // Some kind of disk I/O error occurred + Corrupt = 11, // The database disk image is malformed + NotFound = 12, // Unknown opcode in sqlite3_file_control() + Full = 13, // Insertion failed because database is full + CantOpen = 14, // Unable to open the database file + Protocol = 15, // Database lock protocol error + Empty = 16, // Internal use only + Schema = 17, // The database schema changed + TooBig = 18, // String or BLOB exceeds size limit + Constraint = 19, // Abort due to constraint violation + Mismatch = 20, // Data type mismatch + Misuse = 21, // Library used incorrectly + NoLfs = 22, // Uses OS features not supported on host + Auth = 23, // Authorization denied + Format = 24, // Not used + Range = 25, // 2nd parameter to sqlite3_bind out of range + NotADB = 26, // File opened that is not a database file + Notice = 27, // Notifications from sqlite3_log() + Warning = 28, // Warnings from sqlite3_log() + Row = 100, // sqlite3_step() has another row ready + Done = 101, // sqlite3_step() has finished executing } export object SQLiteError { @@ -153,7 +153,7 @@ export object Statement { ud stmt, fun execute() > [[Boxed]] *> [Boxed]? !> SQLiteError { - std.print("Executing query `{this.query}`"); + std\print("Executing query `{this.query}`"); ResultCode code = ResultCode.Ok; [[Boxed]] rows = [<[Boxed]>]; @@ -223,14 +223,14 @@ export object Database { fun prepareRaw(str query) > Statement !> SQLiteError { Buffer buffer = Buffer.init(); - buffer.writeUserData(std.toUd(0)) catch void; + buffer\writeUserData(std\toUd(0)) catch void; const ResultCode code = ResultCode( sqlite3_prepare_v2( db: this.db, - zSql: ffi.cstr(query), + zSql: ffi\cstr(query), nBytes: -1, - ppStmt: buffer.ptr(), + ppStmt: buffer\ptr(), pzTail: null, ) ) ?? ResultCode.Error; @@ -243,7 +243,7 @@ export object Database { return Statement{ query = query, - stmt = buffer.readUserData()!, + stmt = buffer\readUserData()!, db = this.db, }; } @@ -263,7 +263,7 @@ export object SQLite { } static fun escape(str string) > str { - return sqlite3_mprintf(ffi.cstr(string)) ?? ""; + return sqlite3_mprintf(ffi\cstr(string)) ?? ""; } fun collect() > void { @@ -273,18 +273,18 @@ export object SQLite { fun open(str filename, [OpenFlag] flags) > Database !> SQLiteError { int cFlags = 0; foreach (OpenFlag flag in flags) { - cFlags = cFlags \ flag.value; + cFlags = cFlags | flag.value; } Buffer buffer = Buffer.init(); - buffer.writeUserData(std.toUd(0)) catch void; + buffer\writeUserData(std\toUd(0)) catch void; const ResultCode code = ResultCode( sqlite3_open_v2( - filename: ffi.cstr(filename), - ppDb: buffer.ptr(), + filename: ffi\cstr(filename), + ppDb: buffer\ptr(), flags: cFlags, - zVfs: null + zVfs\ null ) ) ?? ResultCode.Error; @@ -295,10 +295,10 @@ export object SQLite { }; } - std.print("Database `{filename}` opened"); + std\print("Database `{filename}` opened"); return Database { - db = buffer.readUserData()!, + db = buffer\readUserData()!, }; } } @@ -329,6 +329,6 @@ test "Testing sqlite" { .prepare(database); foreach ([Boxed] row in &select.execute()) { - std.print("{row[0].integerValue()}: {row[1].stringValue()}"); + std\print("{row[0].integerValue()}: {row[1].stringValue()}"); } } \ No newline at end of file diff --git a/examples/voronoi-diagram.buzz b/examples/voronoi-diagram.buzz index 95122e9c..98b5de5d 100644 --- a/examples/voronoi-diagram.buzz +++ b/examples/voronoi-diagram.buzz @@ -3,7 +3,7 @@ import "examples/sdl-wrapped" as _; import "math"; fun hypot(int x, int y) > int { - return std.toInt(math.sqrt(std.toFloat(x * x + y * y))); + return std\toInt(math\sqrt(std\toFloat(x * x + y * y))); } fun generateVoronoi(Renderer renderer, int width, int height, int numCells) > void !> SDLError { @@ -12,12 +12,12 @@ fun generateVoronoi(Renderer renderer, int width, int height, int numCells) > vo [Color] colors = []; foreach (int _ in 0..numCells) { - nx.append(std.random(min: 0, max: width)); - ny.append(std.random(min: 0, max: height)); + nx.append(std\random(min: 0, max: width)); + ny.append(std\random(min: 0, max: height)); colors.append(Color{ - red = std.random(min: 0, max: 255), - green = std.random(min: 0, max: 255), - blue = std.random(min: 0, max: 255) + red = std\random(min: 0, max: 255), + green = std\random(min: 0, max: 255), + blue = std\random(min: 0, max: 255) }); } diff --git a/src/Ast.zig b/src/Ast.zig index 816312f3..10082f37 100644 --- a/src/Ast.zig +++ b/src/Ast.zig @@ -191,7 +191,7 @@ pub const Node = struct { ListType: ListType, Map: Map, MapType: MapType, - Namespace: TokenIndex, + Namespace: []const TokenIndex, NamedVariable: NamedVariable, Null: void, ObjectDeclaration: ObjectDeclaration, @@ -449,7 +449,7 @@ pub const Enum = struct { }; pub const Export = struct { - identifier: ?TokenIndex, + name: ?[]const TokenIndex, alias: ?TokenIndex, declaration: ?Node.Index, }; @@ -553,7 +553,7 @@ pub const If = struct { pub const Import = struct { imported_symbols: []const TokenIndex, - prefix: ?TokenIndex, + prefix: ?[]const TokenIndex, path: TokenIndex, import: ?Parser.ScriptImport, }; @@ -598,7 +598,7 @@ pub const SlotType = enum(u8) { pub const Slot = u32; pub const NamedVariable = struct { - identifier: TokenIndex, + name: []const TokenIndex, value: ?Node.Index, slot: Slot, slot_type: SlotType, @@ -690,7 +690,7 @@ pub const Unwrap = struct { }; pub const UserType = struct { - identifier: TokenIndex, + name: []const TokenIndex, generic_resolve: ?Node.Index, }; diff --git a/src/Codegen.zig b/src/Codegen.zig index b1d8bf70..ac15d669 100644 --- a/src/Codegen.zig +++ b/src/Codegen.zig @@ -2074,10 +2074,13 @@ fn generateForEach(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?* }, .String => { if (value_type_def.def_type != .String) { - self.reporter.reportErrorAt( + self.reporter.reportTypeCheck( .foreach_value_type, + self.ast.tokens.get(locations[components.iterable]), + self.gc.type_registry.str_type, self.ast.tokens.get(locations[components.value]), - "Expected `str`.", + value_type_def, + "Bad value type", ); } }, @@ -2226,6 +2229,7 @@ fn generateFunction(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!? // If function is a test block and we're not testing/checking/etc. don't waste time generating the node if (self.flavor == .Run and function_type == .Test) { + try self.emitOpCode(locations[node], .OP_NULL); return null; } diff --git a/src/FFI.zig b/src/FFI.zig index 1f88c497..4948e2d9 100644 --- a/src/FFI.zig +++ b/src/FFI.zig @@ -650,7 +650,20 @@ fn identifier(self: *Self, decl_index: Ast.Node.Index) anyerror!*Zdef { null; if ((type_def == null or zig_type == null) and self.state.?.parser != null) { - const global_idx = try self.state.?.parser.?.resolveGlobal(null, id); + // FIXME: should this account for the current namespace? + const global_idx = glb: { + for (self.state.?.parser.?.globals.items, 0..) |global, idx| { + if (std.mem.eql( + u8, + id, + self.state.?.parser.?.ast.tokens.items(.lexeme)[global.name[global.name.len - 1]], + )) { + break :glb idx; + } + } + break :glb null; + }; + const global = if (global_idx) |idx| self.state.?.parser.?.globals.items[idx] else diff --git a/src/Parser.zig b/src/Parser.zig index 7968ff88..e5cdf0fa 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -166,31 +166,27 @@ pub const CompileError = error{ }; pub const Local = struct { - name: *obj.ObjString, - name_token: Ast.TokenIndex, - location: Ast.TokenIndex, + name: Ast.TokenIndex, type_def: *obj.ObjTypeDef, depth: i32, is_captured: bool, constant: bool, referenced: bool = false, - pub fn isReferenced(self: Local) bool { + pub fn isReferenced(self: Local, ast: Ast) bool { + const lexemes = ast.tokens.items(.lexeme); return self.referenced or self.type_def.def_type == .Void or self.type_def.def_type == .Placeholder or - self.name.string[0] == '$' or - (self.name.string[0] == '_' and self.name.string.len == 1); + lexemes[self.name][0] == '$' or + (lexemes[self.name][0] == '_' and lexemes[self.name].len == 1); } }; pub const Global = struct { - prefix: ?[]const u8, - name: *obj.ObjString, - name_token: Ast.TokenIndex, - location: Ast.TokenIndex, + name: []const Ast.TokenIndex, type_def: *obj.ObjTypeDef, - export_alias: ?[]const u8 = null, + export_alias: ?Ast.TokenIndex = null, imported_from: ?[]const u8 = null, initialized: bool = false, @@ -199,7 +195,8 @@ pub const Global = struct { constant: bool, referenced: bool = false, - pub fn isReferenced(self: Global) bool { + pub fn isReferenced(self: Global, ast: Ast) bool { + const lexemes = ast.tokens.items(.lexeme); const function_type = if (self.type_def.def_type == .Function) self.type_def.resolved_type.?.Function.function_type else @@ -209,10 +206,36 @@ pub const Global = struct { self.type_def.def_type == .Void or self.type_def.def_type == .Placeholder or (function_type != null and (function_type == .Extern or function_type == .Abstract or function_type == .EntryPoint or function_type == .ScriptEntryPoint or function_type != .Repl)) or - self.name.string[0] == '$' or - (self.name.string[0] == '_' and self.name.string.len == 1) or + lexemes[self.name[self.name.len - 1]][0] == '$' or + (lexemes[self.name[self.name.len - 1]][0] == '_' and lexemes[self.name[self.name.len - 1]].len == 1) or self.exported; } + + fn match(self: Global, ast: Ast, qualified: []const Ast.TokenIndex, name: ?Ast.TokenIndex) bool { + if (self.name.len != qualified.len + 1) { + return false; + } + + const lexemes = ast.tokens.items(.lexeme); + + if (qualified.len > 0) { + for (qualified[0 .. qualified.len - 1], 0..) |name_token, i| { + if (!std.mem.eql(u8, lexemes[name_token], lexemes[self.name[i]])) { + return false; + } + } + } + + return name == null or std.mem.eql(u8, lexemes[name.?], lexemes[self.name[self.name.len - 1]]); + } + + pub fn matchName(self: Global, ast: Ast, namespace: []const Ast.TokenIndex, name: Ast.TokenIndex) bool { + return self.match(ast, namespace, name); + } + + pub fn matchNamespace(self: Global, ast: Ast, namespace: []const Ast.TokenIndex) bool { + return self.match(ast, namespace, null); + } }; pub const UpValue = struct { @@ -389,6 +412,7 @@ const rules = [_]ParseRule{ .{ .prefix = unary, .infix = binary, .precedence = .Term }, // Minus .{ .prefix = null, .infix = binary, .precedence = .Factor }, // Star .{ .prefix = null, .infix = binary, .precedence = .Factor }, // Slash + .{ .prefix = null, .infix = null, .precedence = .None }, // AntiSlash .{ .prefix = null, .infix = binary, .precedence = .Factor }, // Percent .{ .prefix = null, .infix = gracefulUnwrap, .precedence = .Call }, // Question .{ .prefix = unary, .infix = forceUnwrap, .precedence = .Call }, // Bang @@ -492,7 +516,7 @@ test_count: u64 = 0, current: ?*Frame = null, current_object: ?ObjectFrame = null, globals: std.ArrayList(Global), -namespace: ?[]const u8 = null, +namespace: ?[]const Ast.TokenIndex = null, flavor: RunFlavor, ffi: FFI, reporter: Reporter, @@ -523,6 +547,9 @@ pub fn init( } pub fn deinit(self: *Self) void { + // for (self.globals.items) |global| { + // self.gc.allocator.free(global.name); + // } self.globals.deinit(); self.script_imports.deinit(); if (self.opt_jumps) |jumps| { @@ -856,48 +883,28 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { try self.advancePastEof(); while (!(try self.match(.Eof))) { - if (function_type == .Repl) { - // When running in REPL, global scope is allowed to run statements since the global scope becomes procedural - if (self.declarationOrStatement(null) catch |err| { - if (BuildOptions.debug) { - io.print("Parsing failed with error {}\n", .{err}); - } - return null; - }) |decl| { - var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( - self.gc.allocator, - @constCast(self.ast.nodes.items(.components)[body_node].Block), - ); - defer statements.shrinkAndFree(statements.items.len); - - try statements.append(decl); - - self.ast.nodes.items(.components)[body_node].Block = statements.items; + if (self.declarationOrStatement(null) catch |err| { + if (function_type != .Repl and err == error.ReachedMaximumMemoryUsage) { + return err; } - } else { - if (self.declaration() catch |err| { - if (err == error.ReachedMaximumMemoryUsage) { - return err; - } - if (BuildOptions.debug) { - io.print("Parsing failed with error {}\n", .{err}); - } - return null; - }) |decl| { - var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( - self.gc.allocator, - @constCast(self.ast.nodes.items(.components)[body_node].Block), - ); - defer statements.shrinkAndFree(statements.items.len); + if (BuildOptions.debug) { + io.print("Parsing failed with error {}\n", .{err}); + } + return null; + }) |decl| { + var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( + self.gc.allocator, + @constCast(self.ast.nodes.items(.components)[body_node].Block), + ); + defer statements.shrinkAndFree(statements.items.len); - try statements.append(decl); + try statements.append(decl); - self.ast.nodes.items(.components)[body_node].Block = statements.items; - } else { - self.reportError(.syntax, "Expected statement"); - break; - } + self.ast.nodes.items(.components)[body_node].Block = statements.items; + } else { + self.reportError(.syntax, "Expected statement"); + break; } } @@ -905,9 +912,14 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { // Then put any exported globals on the stack if (function_type == .ScriptEntryPoint) { for (self.globals.items, 0..) |global, index| { - if (std.mem.eql(u8, global.name.string, "main") and !global.hidden and (self.namespace == null or global.prefix == null or std.mem.eql(u8, global.prefix.?, self.namespace.?))) { + if (std.mem.eql(u8, self.ast.tokens.items(.lexeme)[global.name[global.name.len - 1]], "main") and + !global.hidden and + (self.namespace == null or + global.name.len == 1 or + global.matchNamespace(self.ast, self.namespace.?))) + { entry.main_slot = index; - entry.main_location = global.location; + entry.main_location = global.name[global.name.len - 1]; break; } } @@ -919,7 +931,7 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { for (self.globals.items, 0..) |global, index| { if (global.type_def.def_type == .Function and global.type_def.resolved_type.?.Function.function_type == .Test) { try test_slots.append(index); - try test_locations.append(global.location); + try test_locations.append(global.name[0]); } } @@ -982,7 +994,7 @@ fn beginFrame(self: *Self, function_type: obj.ObjFunction.FunctionType, function } // First local is reserved for an eventual `this` or cli arguments - var local: *Local = &self.current.?.locals[self.current.?.local_count]; + var local = &self.current.?.locals[self.current.?.local_count]; self.current.?.local_count += 1; local.depth = 0; local.is_captured = false; @@ -1012,14 +1024,23 @@ fn beginFrame(self: *Self, function_type: obj.ObjFunction.FunctionType, function }, } - const name: []const u8 = switch (function_type) { - .Method => "this", - .EntryPoint => "$args", - .ScriptEntryPoint => "$args", - else => "_", - }; + var location = Token.identifier( + switch (function_type) { + .Method => "this", + .EntryPoint => "$args", + .ScriptEntryPoint => "$args", + else => "_", + }, + ); + location.source = self.scanner.?.source; + location.script_name = self.script_name; - local.name = try self.gc.copyString(name); + if (self.current_token != null) { + local.name = try self.insertUtilityToken(location); + } else { + local.name = try self.ast.appendToken(location); + _ = try self.advance(); + } } fn endFrame(self: *Self) Ast.Node.Index { @@ -1028,13 +1049,13 @@ fn endFrame(self: *Self) Ast.Node.Index { const local = self.current.?.locals[i]; // Check discarded locals - if (self.flavor != .Repl and !local.isReferenced()) { + if (self.flavor != .Repl and !local.isReferenced(self.ast)) { const type_def_str = local.type_def.toStringAlloc(self.gc.allocator) catch unreachable; defer type_def_str.deinit(); self.reporter.warnFmt( .unused_argument, - self.ast.tokens.get(local.location), + self.ast.tokens.get(local.name), "Unused local of type `{s}`", .{ type_def_str.items, @@ -1047,13 +1068,13 @@ fn endFrame(self: *Self) Ast.Node.Index { const function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; if (function_type == .Script or function_type == .ScriptEntryPoint) { for (self.globals.items) |global| { - if (!global.isReferenced()) { + if (!global.isReferenced(self.ast)) { const type_def_str = global.type_def.toStringAlloc(self.gc.allocator) catch unreachable; defer type_def_str.deinit(); self.reporter.warnFmt( .unused_argument, - self.ast.tokens.get(global.location), + self.ast.tokens.get(global.name[0]), "Unused global of type `{s}`", .{ type_def_str.items, @@ -1092,13 +1113,13 @@ fn endScope(self: *Self) ![]Chunk.OpCode { } // Check discarded locals - if (self.flavor != .Repl and !local.isReferenced()) { + if (self.flavor != .Repl and !local.isReferenced(self.ast)) { const type_def_str = local.type_def.toStringAlloc(self.gc.allocator) catch unreachable; defer type_def_str.deinit(); self.reporter.warnFmt( .unused_argument, - self.ast.tokens.get(local.location), + self.ast.tokens.get(local.name), "Unused local of type `{s}`", .{ type_def_str.items, @@ -1252,6 +1273,21 @@ fn simpleType(self: *Self, def_type: obj.ObjTypeDef.Type) Error!Ast.Node.Index { ); } +fn simpleTypeFromToken(token: Token.Type) ?obj.ObjTypeDef.Type { + return switch (token) { + .Pat => .Pattern, + .Ud => .UserData, + .Str => .String, + .Int => .Integer, + .Float => .Float, + .Bool => .Bool, + .Range => .Range, + .Type => .Type, + .Any => .Any, + else => null, + }; +} + fn declaration(self: *Self) Error!?Ast.Node.Index { const global_scope = self.current.?.scope_depth == 0; @@ -1260,291 +1296,202 @@ fn declaration(self: *Self) Error!?Ast.Node.Index { else null; - if (try self.match(.Extern)) { - const node = try self.funDeclaration(); - - self.ast.nodes.items(.docblock)[node] = docblock; + const node = if (try self.match(.Object)) + try self.objectDeclaration() + else if (try self.match(.Protocol)) + try self.protocolDeclaration() + else if (try self.match(.Enum)) + try self.enumDeclaration() + else if ((try self.match(.Fun)) or (global_scope and try self.match(.Extern))) + try self.funDeclaration() + else if ((try self.match(.Const)) or + (try self.match(.Var) or + (self.check(.Identifier) and std.mem.eql(u8, "_", self.ast.tokens.items(.lexeme)[self.current_token.?])))) + variable: { + const constant = self.current_token.? > 0 and self.ast.tokens.items(.tag)[self.current_token.? - 1] == .Const; + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; - return node; - } else if ((self.current_token == 0 or self.ast.tokens.items(.tag)[self.current_token.? - 1] != .Export) and try self.match(.Export)) { - return try self.exportStatement(); - } else { - const constant: bool = try self.match(.Const); - - var node = if (global_scope and !constant and try self.match(.Object)) - try self.objectDeclaration() - else if (global_scope and !constant and try self.match(.Protocol)) - try self.protocolDeclaration() - else if (global_scope and !constant and try self.match(.Enum)) - try self.enumDeclaration() - else if (!constant and try self.match(.Fun)) - try self.funDeclaration() - else if (!constant and try self.match(.Var)) - try self.varDeclaration( - false, + // Type omitted? + if (!(try self.match(.Colon))) { + break :variable try self.varDeclaration( + identifier, null, .Semicolon, - false, - true, - false, - ) - else if (try self.match(.Pat)) - try self.varDeclaration( - false, - try self.simpleType(.Pattern), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Ud)) - try self.varDeclaration( - false, - try self.simpleType(.UserData), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Str)) - try self.varDeclaration( - false, - try self.simpleType(.String), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Int)) - try self.varDeclaration( - false, - try self.simpleType(.Integer), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Float)) - try self.varDeclaration( - false, - try self.simpleType(.Float), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Bool)) - try self.varDeclaration( - false, - try self.simpleType(.Bool), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Range)) - try self.varDeclaration( - false, - try self.simpleType(.Range), - .Semicolon, constant, true, false, - ) - else if (try self.match(.Type)) - try self.varDeclaration( - false, - try self.simpleType(.Type), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Any)) - try self.varDeclaration( - false, - try self.simpleType(.Any), + ); + } + + // Simple types + for ([_]Token.Type{ .Pat, .Ud, .Str, .Int, .Float, .Bool, .Range, .Type, .Any }) |token| { + if (try self.match(token)) { + break :variable try self.varDeclaration( + identifier, + try self.simpleType(simpleTypeFromToken(token).?), + .Semicolon, + constant, + true, + false, + ); + } + } + + // Complex types + if (try self.match(.Fib)) + break :variable try self.varDeclaration( + identifier, + try self.parseFiberType(null), .Semicolon, constant, true, false, ) - else if (self.current_token.? > 0 and self.current_token.? - 1 < self.ast.tokens.len - 1 and - self.ast.tokens.items(.tag)[self.current_token.?] == .Identifier and - self.ast.tokens.items(.lexeme)[self.current_token.?].len == 1 and - self.ast.tokens.items(.lexeme)[self.current_token.?][0] == '_') - try self.varDeclaration( - false, - try self.simpleType(.Any), + else if (try self.match(.Obj)) + break :variable try self.varDeclaration( + identifier, + try self.parseObjType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.Fib)) - try self.varDeclaration( - false, - try self.parseFiberType(null), + else if (try self.match(.LeftBracket)) + break :variable try self.varDeclaration( + identifier, + try self.parseListType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.Obj)) - try self.varDeclaration( - false, - try self.parseObjType(null), + else if (try self.match(.LeftBrace)) + break :variable try self.varDeclaration( + identifier, + try self.parseMapType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.LeftBracket)) - try self.listDeclaration(constant) - else if (try self.match(.LeftBrace)) - try self.mapDeclaration(constant) - else if (!constant and try self.match(.Test)) - try self.testStatement() - else if (try self.match(.Function)) - try self.varDeclaration( - false, + else if (try self.match(.Fun)) + break :variable try self.varDeclaration( + identifier, try self.parseFunctionType(null), .Semicolon, constant, true, false, ) - else if (global_scope and try self.match(.Import)) - try self.importStatement() - else if (global_scope and try self.match(.Zdef)) - try self.zdefStatement() - else if (global_scope and !constant and try self.match(.Export)) - try self.exportStatement() - else if (self.check(.Identifier)) user_decl: { - if ( // As of now this is the only place where we need to check more than one token ahead - // Note that we would not have to do this if type were given **after** the identifier. But changing this is a pretty big left turn. - // `Type variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Identifier }, 2) or - // `prefix.Type variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Identifier }, 4) or - // `prefix.Type? variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Question, .Identifier }, 5) or - // `Type? variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Question, .Identifier }, 3) or - // `Type::<...> variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .DoubleColon, .Less, null, .Greater, .Identifier }, 255 * 2) or - // - Type::<...>? variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .DoubleColon, .Less, null, .Greater, .Question, .Identifier }, 255 * 2) or - // - prefix.Type::<...> variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .DoubleColon, .Less, null, .Greater, .Identifier }, 255 * 2) or - // - prefix.Type::<...>? variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .DoubleColon, .Less, null, .Greater, .Question, .Identifier }, 255 * 2)) - { - _ = try self.advance(); // consume first identifier - break :user_decl try self.userVarDeclaration(false, constant); - } - - break :user_decl null; - } else if (global_scope and !constant and try self.match(.Export)) - try self.exportStatement() - else if (global_scope and !constant and try self.match(.Namespace)) - try self.namespaceStatement() - else - null; - - if (node == null and constant) { - node = try self.varDeclaration( - false, - null, - .Semicolon, - true, - true, - false, + else if (try self.match(.Identifier)) { + break :variable try self.userVarDeclaration( + identifier, + constant, ); } - if (node != null and docblock != null) { - if (self.ast.nodes.items(.tag)[node.?] == .FunDeclaration) { - const components = self.ast.nodes.items(.components); - components[components[node.?].FunDeclaration.function].Function.docblock = docblock; - } - self.ast.nodes.items(.docblock)[node.?] = docblock; - } + break :variable null; + } else null; - if (self.reporter.panic_mode) { - try self.synchronize(); + if (node != null and docblock != null) { + if (self.ast.nodes.items(.tag)[node.?] == .FunDeclaration) { + const components = self.ast.nodes.items(.components); + components[components[node.?].FunDeclaration.function].Function.docblock = docblock; } + self.ast.nodes.items(.docblock)[node.?] = docblock; + } - return node; + if (self.reporter.panic_mode) { + try self.synchronize(); } + + return node; } + fn declarationOrStatement(self: *Self, loop_scope: ?LoopScope) !?Ast.Node.Index { return try self.declaration() orelse try self.statement(false, loop_scope); } // When a break statement, will return index of jump to patch fn statement(self: *Self, hanging: bool, loop_scope: ?LoopScope) !?Ast.Node.Index { - if (try self.match(.If)) { - std.debug.assert(!hanging); - return try self.ifStatement(loop_scope); - } else if (try self.match(.For)) { - std.debug.assert(!hanging); - return try self.forStatement(); - } else if (try self.match(.ForEach)) { - std.debug.assert(!hanging); - return try self.forEachStatement(); - } else if (try self.match(.While)) { - std.debug.assert(!hanging); - return try self.whileStatement(); - } else if (try self.match(.Do)) { - std.debug.assert(!hanging); - return try self.doUntilStatement(); - } else if (try self.match(.Return)) { - std.debug.assert(!hanging); - return try self.returnStatement(); - } else if (try self.match(.Try)) { - std.debug.assert(!hanging); - return try self.tryStatement(); - } else if (try self.match(.Break)) { - std.debug.assert(!hanging); - return try self.breakStatement(loop_scope); - } else if (try self.match(.Continue)) { - std.debug.assert(!hanging); - return try self.continueStatement(loop_scope); - } else if (try self.match(.Import)) { - std.debug.assert(!hanging); - return try self.importStatement(); - } else if (try self.match(.Out)) { - std.debug.assert(!hanging); - return try self.outStatement(); - } else if (try self.match(.Namespace)) { - std.debug.assert(!hanging); - return try self.namespaceStatement(); - } else if (try self.match(.Throw)) { - const start_location = self.current_token.? - 1; - // For now we don't care about the type. Later if we have `Error` type of data, we'll type check this - const error_value = try self.expression(false); + const global_scope = self.current.?.scope_depth == 0; + const statement_allowed = self.flavor == .Repl or !global_scope; - try self.consume(.Semicolon, "Expected `;` after statement."); + if (statement_allowed) { + if (try self.match(.If)) { + std.debug.assert(!hanging); + return try self.ifStatement(loop_scope); + } else if (try self.match(.For)) { + std.debug.assert(!hanging); + return try self.forStatement(); + } else if (try self.match(.ForEach)) { + std.debug.assert(!hanging); + return try self.forEachStatement(); + } else if (try self.match(.While)) { + std.debug.assert(!hanging); + return try self.whileStatement(); + } else if (try self.match(.Do)) { + std.debug.assert(!hanging); + return try self.doUntilStatement(); + } else if (!global_scope and try self.match(.Return)) { + std.debug.assert(!hanging); + return try self.returnStatement(); + } else if (try self.match(.Try)) { + std.debug.assert(!hanging); + return try self.tryStatement(); + } else if (!global_scope and try self.match(.Break)) { + std.debug.assert(!hanging); + return try self.breakStatement(loop_scope); + } else if (!global_scope and try self.match(.Continue)) { + std.debug.assert(!hanging); + return try self.continueStatement(loop_scope); + } else if (try self.match(.Out)) { + std.debug.assert(!hanging); + return try self.outStatement(); + } else if (try self.match(.Throw)) { + const start_location = self.current_token.? - 1; + // For now we don't care about the type. Later if we have `Error` type of data, we'll type check this + const error_value = try self.expression(false); - return try self.ast.appendNode( - .{ - .tag = .Throw, - .location = start_location, - .end_location = self.current_token.? - 1, - .components = .{ - .Throw = .{ - .expression = error_value, - .unconditional = self.current.?.scope_depth == 1, + try self.consume(.Semicolon, "Expected `;` after statement."); + + return try self.ast.appendNode( + .{ + .tag = .Throw, + .location = start_location, + .end_location = self.current_token.? - 1, + .components = .{ + .Throw = .{ + .expression = error_value, + .unconditional = self.current.?.scope_depth == 1, + }, }, }, - }, - ); - } else { - return try self.expressionStatement(hanging); + ); + } } - return null; + if (global_scope) { + if (try self.match(.Import)) { + std.debug.assert(!hanging); + return try self.importStatement(); + } else if (try self.match(.Namespace)) { + std.debug.assert(!hanging); + return try self.namespaceStatement(); + } else if (try self.match(.Test)) { + std.debug.assert(!hanging); + return try self.testStatement(); + } else if (try self.match(.Zdef)) { + std.debug.assert(!hanging); + return try self.zdefStatement(); + } else if (try self.match(.Export)) { + std.debug.assert(!hanging); + return try self.exportStatement(); + } + } + + return try self.expressionStatement(hanging); } fn addLocal(self: *Self, name: Ast.TokenIndex, local_type: *obj.ObjTypeDef, constant: bool) Error!usize { @@ -1553,12 +1500,9 @@ fn addLocal(self: *Self, name: Ast.TokenIndex, local_type: *obj.ObjTypeDef, cons return 0; } - const name_lexeme = self.ast.tokens.items(.lexeme)[name]; const function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; self.current.?.locals[self.current.?.local_count] = Local{ - .name = try self.gc.copyString(name_lexeme), - .name_token = name, - .location = name, + .name = name, .depth = -1, .is_captured = false, .type_def = local_type, @@ -1574,11 +1518,11 @@ fn addLocal(self: *Self, name: Ast.TokenIndex, local_type: *obj.ObjTypeDef, cons fn addGlobal(self: *Self, name: Ast.TokenIndex, global_type: *obj.ObjTypeDef, constant: bool) Error!usize { const lexemes = self.ast.tokens.items(.lexeme); - // Search for an existing placeholder global with the same name for (self.globals.items, 0..) |*global, index| { if (global.type_def.def_type == .Placeholder and - std.mem.eql(u8, lexemes[name], global.name.string)) + (self.namespace == null or global.matchNamespace(self.ast, self.namespace.?)) and + std.mem.eql(u8, lexemes[global.name[global.name.len - 1]], lexemes[name])) { global.exported = self.exporting; @@ -1595,12 +1539,16 @@ fn addGlobal(self: *Self, name: Ast.TokenIndex, global_type: *obj.ObjTypeDef, co return 0; } + var qualified_name = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + if (self.namespace) |namespace| { + try qualified_name.appendSlice(namespace); + } + try qualified_name.append(name); + qualified_name.shrinkAndFree(qualified_name.items.len); + try self.globals.append( .{ - .prefix = self.namespace, - .name_token = name, - .name = try self.gc.copyString(lexemes[name]), - .location = name, + .name = qualified_name.items, .type_def = global_type, .constant = constant, .exported = self.exporting, @@ -1622,7 +1570,8 @@ fn resolveLocal(self: *Self, frame: *Frame, name: Ast.TokenIndex) !?usize { return null; } - const lexeme = self.ast.tokens.items(.lexeme)[name]; + const lexemes = self.ast.tokens.items(.lexeme); + const lexeme = lexemes[name]; if (std.mem.eql(u8, lexeme, "_")) { return null; @@ -1631,7 +1580,7 @@ fn resolveLocal(self: *Self, frame: *Frame, name: Ast.TokenIndex) !?usize { var i: usize = frame.local_count - 1; while (i >= 0) : (i -= 1) { var local = &frame.locals[i]; - if (std.mem.eql(u8, lexeme, local.name.string)) { + if (std.mem.eql(u8, lexeme, lexemes[local.name])) { if (local.depth == -1) { self.reportErrorFmt( .local_initializer, @@ -1651,12 +1600,13 @@ fn resolveLocal(self: *Self, frame: *Frame, name: Ast.TokenIndex) !?usize { } // Will consume tokens if find a prefixed identifier -pub fn resolveGlobal(self: *Self, prefix: ?[]const u8, name: []const u8) Error!?usize { +pub fn resolveGlobal(self: *Self, name: []const Ast.TokenIndex) Error!?usize { if (self.globals.items.len == 0) { return null; } - if (std.mem.eql(u8, name, "_")) { + const lexemes = self.ast.tokens.items(.lexeme); + if (name.len == 1 and std.mem.eql(u8, lexemes[name[name.len - 1]], "_")) { return null; } @@ -1664,18 +1614,23 @@ pub fn resolveGlobal(self: *Self, prefix: ?[]const u8, name: []const u8) Error!? while (i >= 0) : (i -= 1) { const global: *Global = &self.globals.items[i]; - if ((global.prefix == null or // Not prefixed - (prefix != null and std.mem.eql(u8, prefix.?, global.prefix.?)) or // Same prefix as provided - (self.namespace != null and std.mem.eql(u8, global.prefix.?, self.namespace.?)) // Prefix is the current namespace + if (global.matchName( + self.ast, + if (name.len > 1) + name[0 .. name.len - 1] + else + self.namespace orelse &[_]Ast.TokenIndex{}, + name[name.len - 1], ) and - std.mem.eql(u8, name, global.name.string) and !global.hidden) { if (!global.initialized) { self.reportErrorFmt( .global_initializer, "Can't read global `{s}` variable in its own initializer.", - .{global.name.string}, + .{ + lexemes[global.name[global.name.len - 1]], + }, ); } @@ -1683,18 +1638,6 @@ pub fn resolveGlobal(self: *Self, prefix: ?[]const u8, name: []const u8) Error!? return i; // Is it an import prefix? - } else if (global.prefix != null and std.mem.eql(u8, name, global.prefix.?)) { - const had_error = self.reporter.last_error != null; - - try self.consume(.Dot, "Expected `.` after import prefix."); - try self.consume(.Identifier, "Expected identifier after import prefix."); - - // Avoid infinite recursion - if (!had_error and self.reporter.last_error != null) { - return null; - } - - return try self.resolveGlobal(global.prefix.?, self.ast.tokens.items(.lexeme)[self.current_token.? - 1]); } if (i == 0) break; @@ -1719,7 +1662,7 @@ fn resolvePlaceholderWithRelation( .{ @intFromPtr(resolved_type), @intFromPtr(child), - if (child_placeholder.name) |name| name.string else "unknown", + self.ast.tokens.items(.lexeme)[child_placeholder.where], child_placeholder.parent_relation.?, }, ); @@ -1774,10 +1717,13 @@ fn resolvePlaceholderWithRelation( .Call => { // Can we call the parent? if (resolved_type.def_type != .Function) { - self.reporter.reportErrorAt( + self.reporter.reportErrorFmt( .callable, self.ast.tokens.get(child_placeholder.where), - "Can't be called", + "`{s}` can't be called", + .{ + (try resolved_type.toStringAlloc(self.gc.allocator)).items, + }, ); return; } @@ -1791,10 +1737,13 @@ fn resolvePlaceholderWithRelation( .Yield => { // Can we call the parent? if (resolved_type.def_type != .Function) { - self.reporter.reportErrorAt( + self.reporter.reportErrorFmt( .callable, self.ast.tokens.get(child_placeholder.where), - "Can't be called", + "`{s}` can't be called", + .{ + (try resolved_type.toStringAlloc(self.gc.allocator)).items, + }, ); return; } @@ -1813,17 +1762,24 @@ fn resolvePlaceholderWithRelation( } else if (resolved_type.def_type == .String) { try self.resolvePlaceholder(child, self.gc.type_registry.str_type, false); } else { - self.reporter.reportErrorAt( - .subscriptable, + self.reporter.reportErrorFmt( + .map_key_type, self.ast.tokens.get(child_placeholder.where), - "Can't be subscripted", + "`{s}` can't be subscripted", + .{ + (try resolved_type.toStringAlloc(self.gc.allocator)).items, + }, ); return; } }, .Key => { if (resolved_type.def_type == .Map) { - try self.resolvePlaceholder(child, resolved_type.resolved_type.?.Map.key_type, false); + try self.resolvePlaceholder( + child, + resolved_type.resolved_type.?.Map.key_type, + false, + ); } else if (resolved_type.def_type == .List or resolved_type.def_type == .String) { try self.resolvePlaceholder( child, @@ -1831,10 +1787,13 @@ fn resolvePlaceholderWithRelation( false, ); } else { - self.reporter.reportErrorAt( + self.reporter.reportErrorFmt( .map_key_type, self.ast.tokens.get(child_placeholder.where), - "Can't be a key", + "`{s}` can't be subscripted", + .{ + (try resolved_type.toStringAlloc(self.gc.allocator)).items, + }, ); return; } @@ -1998,10 +1957,13 @@ fn resolvePlaceholderWithRelation( } }, else => { - self.reporter.reportErrorAt( + self.reporter.reportErrorFmt( .field_access, self.ast.tokens.get(child_placeholder.where), - "Doesn't support field access", + "`{s}` can't be field accessed", + .{ + (try resolved_type.toStringAlloc(self.gc.allocator)).items, + }, ); return; }, @@ -2035,7 +1997,7 @@ pub fn resolvePlaceholder(self: *Self, placeholder: *obj.ObjTypeDef, resolved_ty if (BuildOptions.debug_placeholders) { io.print("Attempts to resolve @{} ({s}) with @{} a {}({})\n", .{ @intFromPtr(placeholder), - if (placeholder.resolved_type.?.Placeholder.name) |name| name.string else "unknown", + self.ast.tokens.items(.lexeme)[placeholder.resolved_type.?.Placeholder.where], @intFromPtr(resolved_type), resolved_type.def_type, resolved_type.optional, @@ -2049,9 +2011,9 @@ pub fn resolvePlaceholder(self: *Self, placeholder: *obj.ObjTypeDef, resolved_ty "Replaced linked placeholder @{} ({s}) with rooted placeholder @{} ({s})\n", .{ @intFromPtr(placeholder), - if (placeholder.resolved_type.?.Placeholder.name != null) placeholder.resolved_type.?.Placeholder.name.?.string else "unknown", + self.ast.tokens.items(.lexeme)[placeholder.resolved_type.?.Placeholder.where], @intFromPtr(resolved_type), - if (resolved_type.resolved_type.?.Placeholder.name != null) resolved_type.resolved_type.?.Placeholder.name.?.string else "unknown", + self.ast.tokens.items(.lexeme)[resolved_type.resolved_type.?.Placeholder.where], }, ); } @@ -2088,7 +2050,7 @@ pub fn resolvePlaceholder(self: *Self, placeholder: *obj.ObjTypeDef, resolved_ty "Resolved placeholder @{} {s}({}) with @{}.{}({})\n", .{ @intFromPtr(placeholder), - if (placeholder.resolved_type.?.Placeholder.name != null) placeholder.resolved_type.?.Placeholder.name.?.string else "unknown", + self.ast.tokens.items(.lexeme)[placeholder.resolved_type.?.Placeholder.where], placeholder.optional, @intFromPtr(resolved_type), resolved_type.def_type, @@ -2165,9 +2127,9 @@ fn resolveUpvalue(self: *Self, frame: *Frame, name: Ast.TokenIndex) Error!?usize return null; } -fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast.TokenIndex, constant: bool, check_name: bool) Error!usize { - const name = name_token orelse self.current_token.? - 1; - const name_lexeme = self.ast.tokens.items(.lexeme)[name]; +fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name: Ast.TokenIndex, constant: bool, check_name: bool) Error!usize { + const lexemes = self.ast.tokens.items(.lexeme); + const name_lexeme = lexemes[name]; if (self.current.?.scope_depth > 0) { // Check a local with the same name doesn't exists @@ -2180,11 +2142,14 @@ fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast break; } - if (!std.mem.eql(u8, name_lexeme, "_") and !std.mem.startsWith(u8, name_lexeme, "$") and std.mem.eql(u8, name_lexeme, local.name.string)) { + if (!std.mem.eql(u8, name_lexeme, "_") and + !std.mem.startsWith(u8, name_lexeme, "$") and + std.mem.eql(u8, name_lexeme, lexemes[local.name])) + { self.reporter.reportWithOrigin( .variable_already_exists, self.ast.tokens.get(name), - self.ast.tokens.get(local.location), + self.ast.tokens.get(local.name), "A variable named `{s}` already exists", .{name_lexeme}, null, @@ -2200,14 +2165,16 @@ fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast if (check_name) { // Check a global with the same name doesn't exists for (self.globals.items, 0..) |*global, index| { - if (!std.mem.eql(u8, name_lexeme, "_") and std.mem.eql(u8, name_lexeme, global.name.string) and !global.hidden) { + if (!std.mem.eql(u8, name_lexeme, "_") and + global.matchName( + self.ast, + self.namespace orelse &[_]Ast.TokenIndex{}, + name, + ) and + !global.hidden) + { // If we found a placeholder with that name, try to resolve it with `variable_type` - if (global.type_def.def_type == .Placeholder and - std.mem.eql( - u8, - name_lexeme, - self.ast.tokens.items(.lexeme)[global.type_def.resolved_type.?.Placeholder.where], - )) { + if (global.type_def.def_type == .Placeholder) { // A function declares a global with an incomplete typedef so that it can handle recursion // The placeholder resolution occurs after we parsed the functions body in `funDeclaration` if (variable_type.resolved_type != null or @intFromEnum(variable_type.def_type) < @intFromEnum(obj.ObjTypeDef.Type.ObjectInstance)) { @@ -2229,7 +2196,7 @@ fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast global.referenced = true; return index; - } else if (global.prefix == null) { + } else { self.reportError(.variable_already_exists, "A global with the same name already exists."); } } @@ -2242,18 +2209,18 @@ fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast fn parseVariable( self: *Self, - identifier_consumed: bool, + identifier: ?Ast.TokenIndex, variable_type: *obj.ObjTypeDef, constant: bool, error_message: []const u8, ) !usize { - if (!identifier_consumed) { + if (identifier == null) { try self.consume(.Identifier, error_message); } return try self.declareVariable( variable_type, - null, + identifier orelse self.current_token.? - 1, constant, true, ); @@ -2546,7 +2513,7 @@ fn parseTypeDef( return self.parseListType(generic_types); } else if (try self.match(.LeftBrace)) { return self.parseMapType(generic_types); - } else if (try self.match(.Function) or try self.match(.Extern)) { + } else if (try self.match(.Fun) or try self.match(.Extern)) { return try self.parseFunctionType(generic_types); } else if (try self.match(.Fib)) { return try self.parseFiberType(generic_types); @@ -2744,12 +2711,12 @@ fn parseFunctionType(self: *Self, parent_generic_types: ?std.AutoArrayHashMap(*o const start_location = self.current_token.? - 1; const tag = self.ast.tokens.items(.tag)[start_location]; - std.debug.assert(tag == .Function or tag == .Extern); + std.debug.assert(tag == .Fun or tag == .Extern); const is_extern = tag == .Extern; if (is_extern) { - try self.consume(.Function, "Expected `Function` after `extern`."); + try self.consume(.Fun, "Expected `fun` after `extern`."); } var name_token: ?Ast.TokenIndex = null; @@ -2847,21 +2814,23 @@ fn parseFunctionType(self: *Self, parent_generic_types: ?std.AutoArrayHashMap(*o if (!self.check(.RightParen)) { while (true) { arity += 1; - if (arity > 255) { + if (arity > std.math.maxInt(u8)) { self.reportErrorAtCurrent(.arguments_count, "Can't have more than 255 arguments."); } + try self.consume(.Identifier, "Expected argument name"); + + const arg_name_token = self.current_token.? - 1; + const arg_name = self.ast.tokens.items(.lexeme)[self.current_token.? - 1]; + + try self.consume(.Colon, "Expected `:`"); + const arg_type = try self.parseTypeDef( merged_generic_types, true, ); const arg_type_def = self.ast.nodes.items(.type_def)[arg_type]; - try self.consume(.Identifier, "Expected argument name"); - - const arg_name_token = self.current_token.? - 1; - const arg_name = self.ast.tokens.items(.lexeme)[self.current_token.? - 1]; - var default: ?Ast.Node.Index = null; if (try self.match(.Equal)) { const expr = try self.expression(false); @@ -2928,6 +2897,8 @@ fn parseFunctionType(self: *Self, parent_generic_types: ?std.AutoArrayHashMap(*o var error_types = std.ArrayList(*obj.ObjTypeDef).init(self.gc.allocator); defer error_types.shrinkAndFree(error_types.items.len); if (try self.match(.BangGreater)) { + const expects_multiple_error_types = try self.match(.LeftParen); + while (!self.check(.Eof)) { const error_type = try self.parseTypeDef(generic_types, true); const error_type_def = self.ast.nodes.items(.type_def)[error_type].?; @@ -2938,10 +2909,14 @@ fn parseFunctionType(self: *Self, parent_generic_types: ?std.AutoArrayHashMap(*o self.reportError(.error_type, "Error type can't be optional"); } - if (!self.check(.Comma)) { + if (!expects_multiple_error_types or !(try self.match(.Comma))) { break; } } + + if (expects_multiple_error_types) { + try self.consume(.RightParen, "Expected `)`"); + } } var function_typedef: obj.ObjTypeDef = .{ @@ -3029,8 +3004,6 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString while (!self.check(.RightBrace) and !self.check(.Eof)) : (property_idx += 1) { const constant = try self.match(.Const); - const property_type = try self.parseTypeDef(generic_types, true); - const is_tuple = !(try self.match(.Identifier)); const property_name = if (!is_tuple) self.current_token.? - 1 @@ -3048,6 +3021,9 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString ); const property_name_lexeme = self.ast.tokens.items(.lexeme)[property_name]; + try self.consume(.Colon, "Expected `:`"); + const property_type = try self.parseTypeDef(generic_types, true); + if (is_tuple) { obj_is_tuple = true; @@ -3108,6 +3084,8 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString try self.consume(.RightBrace, "Expected `}` after object body."); + object_type.optional = try self.match(.Question); + return try self.ast.appendNode( .{ .tag = .AnonymousObjectType, @@ -3124,12 +3102,12 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString } fn parseUserType(self: *Self, instance: bool) Error!Ast.Node.Index { - const user_type_name = self.current_token.? - 1; + const user_type_name = try self.qualifiedName(); var var_type: ?*obj.ObjTypeDef = null; var global_slot: ?usize = null; // Search for a global with that name - if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[user_type_name])) |slot| { + if (try self.resolveGlobal(user_type_name)) |slot| { const global = self.globals.items[slot]; var_type = global.type_def; @@ -3154,12 +3132,16 @@ fn parseUserType(self: *Self, instance: bool) Error!Ast.Node.Index { .{ .def_type = .Placeholder, .resolved_type = .{ - .Placeholder = obj.PlaceholderDef.init(self.gc.allocator, user_type_name), + .Placeholder = obj.PlaceholderDef.init( + self.gc.allocator, + user_type_name[user_type_name.len - 1], + ), }, }, ); - global_slot = try self.declarePlaceholder(user_type_name, var_type.?); + std.debug.assert(user_type_name.len == 1); + global_slot = try self.declarePlaceholder(user_type_name[user_type_name.len - 1], var_type.?); } // Concrete generic types list @@ -3224,7 +3206,7 @@ fn parseUserType(self: *Self, instance: bool) Error!Ast.Node.Index { return try self.ast.appendNode( .{ .tag = .UserType, - .location = user_type_name, + .location = user_type_name[0], .end_location = self.current_token.? - 1, .type_def = if (instance) try var_type.?.toInstance(self.gc.allocator, &self.gc.type_registry) @@ -3233,7 +3215,7 @@ fn parseUserType(self: *Self, instance: bool) Error!Ast.Node.Index { .components = .{ .UserType = .{ .generic_resolve = generic_resolve, - .identifier = user_type_name, + .name = user_type_name, }, }, }, @@ -4863,8 +4845,9 @@ fn @"if"(self: *Self, is_statement: bool, loop_scope: ?LoopScope) Error!Ast.Node var unwrapped_identifier: ?Ast.TokenIndex = null; var casted_type: ?Ast.Node.Index = null; if (try self.match(.Arrow)) { // if (opt -> unwrapped) + try self.consume(.Identifier, "Expected identifier"); _ = try self.parseVariable( - false, + self.current_token.? - 1, try condition_type_def.?.cloneNonOptional(&self.gc.type_registry), true, "Expected optional unwrap identifier", @@ -4873,10 +4856,12 @@ fn @"if"(self: *Self, is_statement: bool, loop_scope: ?LoopScope) Error!Ast.Node unwrapped_identifier = self.current_token.? - 1; } else if (try self.match(.As)) { // if (expr as casted) + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; + try self.consume(.Colon, "Expected `:`"); casted_type = try self.parseTypeDef(null, true); - _ = try self.parseVariable( - false, + identifier, try self.ast.nodes.items(.type_def)[casted_type.?].?.toInstance(self.gc.allocator, &self.gc.type_registry), true, "Expected casted identifier", @@ -5029,46 +5014,62 @@ fn string(self: *Self, _: bool) Error!Ast.Node.Index { return string_node; } -fn namedVariable(self: *Self, name: Ast.TokenIndex, can_assign: bool) Error!Ast.Node.Index { +fn namedVariable(self: *Self, name: []const Ast.TokenIndex, can_assign: bool) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; var var_def: ?*obj.ObjTypeDef = null; var slot: usize = undefined; var slot_type: Ast.SlotType = undefined; var slot_constant = false; - if (try self.resolveLocal(self.current.?, name)) |uslot| { - var_def = self.current.?.locals[uslot].type_def; - slot = uslot; - slot_type = .Local; - slot_constant = self.current.?.locals[uslot].constant; - } else if (try self.resolveUpvalue(self.current.?, name)) |uslot| { - var_def = self.current.?.enclosing.?.locals[self.current.?.upvalues[uslot].index].type_def; - slot = uslot; - slot_type = .UpValue; - slot_constant = self.current.?.enclosing.?.locals[self.current.?.upvalues[uslot].index].constant; - } else if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[name])) |uslot| { - const global = self.globals.items[uslot]; - - var_def = global.type_def; - slot = uslot; - slot_type = .Global; - slot_constant = global.constant; + if (name.len == 1) { + if (try self.resolveLocal(self.current.?, name[0])) |uslot| { + var_def = self.current.?.locals[uslot].type_def; + slot = uslot; + slot_type = .Local; + slot_constant = self.current.?.locals[uslot].constant; + } else if (try self.resolveUpvalue(self.current.?, name[0])) |uslot| { + var_def = self.current.?.enclosing.?.locals[self.current.?.upvalues[uslot].index].type_def; + slot = uslot; + slot_type = .UpValue; + slot_constant = self.current.?.enclosing.?.locals[self.current.?.upvalues[uslot].index].constant; + } + } - if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { - const imported_from = global.imported_from.?; + if (var_def == null) { + if (try self.resolveGlobal(name)) |uslot| { + const global = self.globals.items[uslot]; - try self.script_imports.put( - imported_from, - .{ - .location = self.script_imports.get(imported_from).?.location, - .referenced = true, - }, - ); + var_def = global.type_def; + slot = uslot; + slot_type = .Global; + slot_constant = global.constant; + + if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { + const imported_from = global.imported_from.?; + + try self.script_imports.put( + imported_from, + .{ + .location = self.script_imports.get(imported_from).?.location, + .referenced = true, + }, + ); + } + } else { + slot = try self.declarePlaceholder(name[0], null); + var_def = self.globals.items[slot].type_def; + slot_type = .Global; + + if (name.len > 1) { + self.reportErrorFmt( + .syntax, + "`{s}` does not exists in that namespace or namespace does not exists", + .{ + self.ast.tokens.items(.lexeme)[name[0]], + }, + ); + } } - } else { - slot = try self.declarePlaceholder(name, null); - var_def = self.globals.items[slot].type_def; - slot_type = .Global; } const value = if (can_assign and try self.match(.Equal)) @@ -5088,7 +5089,7 @@ fn namedVariable(self: *Self, name: Ast.TokenIndex, can_assign: bool) Error!Ast. .type_def = var_def, .components = .{ .NamedVariable = .{ - .identifier = name, + .name = name, .value = value, .slot = @intCast(slot), .slot_type = slot_type, @@ -5099,8 +5100,29 @@ fn namedVariable(self: *Self, name: Ast.TokenIndex, can_assign: bool) Error!Ast. ); } +/// Will parse qualified name too: identifier or A\B\C\identifier +fn qualifiedName(self: *Self) Error![]const Ast.TokenIndex { + // Assumes one identifier has already been consumed + std.debug.assert(self.ast.tokens.items(.tag)[self.current_token.? - 1] == .Identifier); + + var name = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + + try name.append(self.current_token.? - 1); + while ((try self.match(.AntiSlash)) and !self.check(.Eof)) { + try self.consume(.Identifier, "Expected identifier"); + + try name.append(self.current_token.? - 1); + } + name.shrinkAndFree(name.items.len); + + return name.items; +} + fn variable(self: *Self, can_assign: bool) Error!Ast.Node.Index { - return try self.namedVariable(self.current_token.? - 1, can_assign); + return try self.namedVariable( + try self.qualifiedName(), + can_assign, + ); } fn fun(self: *Self, _: bool) Error!Ast.Node.Index { @@ -5259,13 +5281,17 @@ fn function( if (!self.check(.RightParen)) { while (true) { arity += 1; - if (arity > 255) { + if (arity > std.math.maxInt(u8)) { self.reportErrorAtCurrent( .arguments_count, "Can't have more than 255 arguments.", ); } + try self.consume(.Identifier, "Expected argument name"); + const identifier = self.current_token.? - 1; + try self.consume(.Colon, "Expected `:`"); + const argument_type_node = try self.parseTypeDef( function_typedef.resolved_type.?.Function.generic_types, true, @@ -5281,7 +5307,7 @@ fn function( const argument_type = self.ast.nodes.items(.type_def)[argument_type_node].?; const slot = try self.parseVariable( - false, + identifier, argument_type, true, // function arguments are constant "Expected argument name", @@ -5290,7 +5316,10 @@ fn function( std.debug.assert(self.current.?.scope_depth > 0); const local = self.current.?.locals[slot]; - try function_typedef.resolved_type.?.Function.parameters.put(local.name, local.type_def); + try function_typedef.resolved_type.?.Function.parameters.put( + try self.gc.copyString(self.ast.tokens.items(.lexeme)[local.name]), + local.type_def, + ); self.markInitialized(); @@ -5312,7 +5341,7 @@ fn function( break :value expr; } else if (argument_type.optional) { try function_typedef.resolved_type.?.Function.defaults.put( - local.name, + try self.gc.copyString(self.ast.tokens.items(.lexeme)[local.name]), Value.Null, ); } @@ -5324,7 +5353,7 @@ fn function( try arguments.append( .{ - .name = local.name_token, + .name = local.name, .type = argument_type_node, .default = default, }, @@ -5332,7 +5361,7 @@ fn function( if (default) |dft| { try function_typedef.resolved_type.?.Function.defaults.put( - local.name, + try self.gc.copyString(self.ast.tokens.items(.lexeme)[local.name]), try self.ast.toValue(dft, self.gc), ); } @@ -6022,7 +6051,9 @@ fn funDeclaration(self: *Self) Error!Ast.Node.Index { const name_token = self.current_token.? - 1; const current_function_type_def = self.ast.nodes.items(.type_def)[self.current.?.function_node]; - const is_main = std.mem.eql(u8, self.ast.tokens.items(.lexeme)[name_token], "main") and current_function_type_def != null and current_function_type_def.?.resolved_type.?.Function.function_type == .ScriptEntryPoint; + const is_main = std.mem.eql(u8, self.ast.tokens.items(.lexeme)[name_token], "main") and + current_function_type_def != null and + current_function_type_def.?.resolved_type.?.Function.function_type == .ScriptEntryPoint; if (is_main) { if (function_type == .Extern) { @@ -6105,12 +6136,14 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { self.reportError(.syntax, "A exporting script must provide a namespace"); } - if (self.check(.Identifier) and (try self.checkAhead(.Semicolon, 0) or try self.checkAhead(.As, 0) or try self.checkAhead(.Dot, 0))) { - try self.consume(.Identifier, "Expected identifier after `export`."); - const identifier = self.current_token.? - 1; + if (self.check(.Identifier) and + (try self.checkAhead(.Semicolon, 0) or try self.checkAhead(.As, 0) or try self.checkAhead(.AntiSlash, 0))) + { + try self.consume(.Identifier, "Expected identifier"); + const qualified_name = try self.qualifiedName(); // Search for a global with that name - if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[identifier])) |slot| { + if (try self.resolveGlobal(qualified_name)) |slot| { const global = &self.globals.items[slot]; global.referenced = true; @@ -6131,12 +6164,18 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { if (try self.match(.As)) { try self.consume(.Identifier, "Expected identifier after `as`."); - global.export_alias = self.ast.tokens.items(.lexeme)[self.current_token.? - 1]; + global.export_alias = self.current_token.? - 1; alias = self.current_token.? - 1; } - // If we're exporting an imported global, overwrite is prefix - global.prefix = self.namespace; + // If we're exporting an imported global, overwrite its namespace + const name = global.name[global.name.len - 1]; + // self.gc.allocator.free(global.name); + var new_global_name = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + try new_global_name.appendSlice(self.namespace orelse &[_]Ast.TokenIndex{}); + try new_global_name.append(name); + new_global_name.shrinkAndFree(new_global_name.items.len); + global.name = new_global_name.items; try self.consume(.Semicolon, "Expected `;` after statement."); @@ -6148,7 +6187,7 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { .type_def = global.type_def, .components = .{ .Export = .{ - .identifier = identifier, + .name = qualified_name, .alias = alias, .declaration = null, }, @@ -6159,8 +6198,8 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { } else { self.exporting = true; if (try self.declaration()) |decl| { - self.globals.items[self.globals.items.len - 1].referenced = true; - + const global = &self.globals.items[self.globals.items.len - 1]; + global.referenced = true; self.exporting = false; return try self.ast.appendNode( @@ -6171,7 +6210,7 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { .type_def = self.ast.nodes.items(.type_def)[decl], .components = .{ .Export = .{ - .identifier = null, + .name = null, .alias = null, .declaration = decl, }, @@ -6192,7 +6231,7 @@ fn exportStatement(self: *Self) Error!Ast.Node.Index { .type_def = null, .components = .{ .Export = .{ - .identifier = self.current_token.? - 1, + .name = &[_]Ast.TokenIndex{self.current_token.? - 1}, .alias = null, .declaration = null, }, @@ -6251,7 +6290,7 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index { const object_name = self.ast.tokens.get(object_name_token).clone(); // Qualified name to avoid cross script collision - const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "."); + const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "\\"); defer self.gc.allocator.free(qualifier); var qualified_object_name = std.ArrayList(u8).init(self.gc.allocator); defer qualified_object_name.deinit(); @@ -6445,13 +6484,15 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index { try properties_type.put(method_name, self.ast.nodes.items(.type_def)[method_node].?); } else { const constant = try self.match(.Const); - const property_type = try self.parseTypeDef(null, true); - const property_type_def = self.ast.nodes.items(.type_def)[property_type]; try self.consume(.Identifier, "Expected property name."); const property_token = self.current_token.? - 1; const property_name = self.ast.tokens.get(property_token); + try self.consume(.Colon, "Expected `:`"); + const property_type = try self.parseTypeDef(null, true); + const property_type_def = self.ast.nodes.items(.type_def)[property_type]; + if (fields.get(property_name.lexeme) != null) { self.reportError(.property_already_exists, "A member with that name already exists."); } @@ -6944,7 +6985,7 @@ fn enumDeclaration(self: *Self) Error!Ast.Node.Index { fn varDeclaration( self: *Self, - identifier_consumed: bool, + identifier: ?Ast.TokenIndex, parsed_type: ?Ast.Node.Index, terminator: DeclarationTerminator, constant: bool, @@ -6960,7 +7001,7 @@ fn varDeclaration( self.gc.type_registry.any_type; const slot: usize = try self.parseVariable( - identifier_consumed, + identifier, var_type, constant, "Expected variable name.", @@ -7077,42 +7118,6 @@ fn implicitVarDeclaration(self: *Self, name: Ast.TokenIndex, parsed_type: *obj.O ); } -fn listDeclaration(self: *Self, constant: bool) Error!Ast.Node.Index { - const current_function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; - - if (self.check(.Less) and (self.current.?.scope_depth > 0 or current_function_type == .Repl)) { - // Its a list expression - return try self.expressionStatement(true); - } - - return try self.varDeclaration( - false, - try self.parseListType(null), - .Semicolon, - constant, - true, - false, - ); -} - -fn mapDeclaration(self: *Self, constant: bool) Error!Ast.Node.Index { - const current_function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; - - if (self.check(.Less) and (self.current.?.scope_depth > 0 or current_function_type == .Repl)) { - // Its a map expression - return try self.expressionStatement(true); - } - - return try self.varDeclaration( - false, - try self.parseMapType(null), - .Semicolon, - constant, - true, - false, - ); -} - // `test` is just like a function but we don't parse arguments and we don't care about its return type fn testStatement(self: *Self) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; @@ -7489,7 +7494,7 @@ fn importScript( self: *Self, path_token: Ast.TokenIndex, file_name: []const u8, - prefix: ?[]const u8, + prefix: ?[]const Ast.TokenIndex, imported_symbols: *std.StringHashMap(Ast.Node.Index), ) Error!?ScriptImport { var import = self.imports.get(file_name); @@ -7515,6 +7520,7 @@ fn importScript( // We need to share the token and node list with the import so TokenIndex and Node.Index are usable parser.ast = self.ast; parser.current_token = self.current_token; + const token_before_import = self.ast.tokens.get(self.current_token.?); const previous_root = self.ast.root; if (try parser.parse(source_and_path.?[0], file_name)) |ast| { @@ -7532,7 +7538,19 @@ fn importScript( global.exported = false; if (global.export_alias) |export_alias| { - global.name = try self.gc.copyString(export_alias); + const previous_name = global.name; + var new_name = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + try new_name.appendSlice( + if (global.name.len > 1) + global.name[0 .. global.name.len - 1] + else + &[_]Ast.TokenIndex{}, + ); + try new_name.append(export_alias); + new_name.shrinkAndFree(new_name.items.len); + self.gc.allocator.free(previous_name); // TODO: will this free be an issue? + + global.name = new_name.items; global.export_alias = null; } } else { @@ -7555,39 +7573,36 @@ fn importScript( self.ast.root = previous_root; // Last token of imported script is Eof, we discard it // Move scanned token just after import statement to replace the imported script Eof - // FIXME: this is letting in place the token just before the import list of tokens - self.ast.tokens.set(parser.current_token.?, self.ast.tokens.get(self.current_token.?)); + self.ast.tokens.set(parser.current_token.?, token_before_import); self.current_token = parser.current_token; } if (import) |imported| { const selective_import = imported_symbols.count() > 0; + const lexemes = self.ast.tokens.items(.lexeme); for (imported.globals.items) |imported_global| { var global = imported_global; if (!global.hidden) { - if (imported_symbols.get(global.name.string) != null) { - _ = imported_symbols.remove(global.name.string); + if (imported_symbols.get(lexemes[global.name[global.name.len - 1]]) != null) { + _ = imported_symbols.remove(lexemes[global.name[global.name.len - 1]]); } else if (selective_import) { global.hidden = true; } - // Search for name collision - if ((try self.resolveGlobal(prefix, global.name.string)) != null) { - self.reporter.reportWithOrigin( - .shadowed_global, - self.ast.tokens.get(self.current_token.? - 1), - self.ast.tokens.get(global.location), - "Shadowed global `{s}`", - .{global.name.string}, - null, - ); - } + // If requalified, overwrite namespace + var imported_name = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + try imported_name.appendSlice( + if (prefix != null and prefix.?.len == 1 and std.mem.eql(u8, lexemes[prefix.?[0]], "_")) + &[_]Ast.TokenIndex{} // With a `_` override, we erase the namespace + else + prefix orelse global.name[0 .. global.name.len - 1], // override or take initial namespace + ); + try imported_name.append(global.name[global.name.len - 1]); + imported_name.shrinkAndFree(imported_name.items.len); + // self.gc.allocator.free(global.name); - global.prefix = if (prefix != null and std.mem.eql(u8, "_", prefix.?)) - null // import "..." as _; | Erased prefix so the imported global are in the importer script namespace - else - prefix orelse global.prefix; + global.name = imported_name.items; } global.imported_from = file_name; @@ -7752,7 +7767,7 @@ fn importStatement(self: *Self) Error!Ast.Node.Index { } } - var prefix: ?Ast.TokenIndex = null; + var prefix: ?[]const Ast.TokenIndex = null; if (imported_symbols.count() > 0) { try self.consume(.From, "Expected `from` after import identifier list."); } @@ -7780,7 +7795,7 @@ fn importStatement(self: *Self) Error!Ast.Node.Index { if (imported_symbols.count() == 0 and try self.match(.As)) { try self.consume(.Identifier, "Expected identifier after `as`."); - prefix = self.current_token.? - 1; + prefix = try self.qualifiedName(); } try self.consume(.Semicolon, "Expected `;` after statement."); @@ -7789,10 +7804,7 @@ fn importStatement(self: *Self) Error!Ast.Node.Index { try self.importScript( path_token, file_name, - if (prefix) |pr| - self.ast.tokens.items(.lexeme)[pr] - else - null, + prefix, &imported_symbols, ) else @@ -7966,129 +7978,131 @@ fn zdefStatement(self: *Self) Error!Ast.Node.Index { } // FIXME: this is almost the same as parseUserType! -fn userVarDeclaration(self: *Self, _: bool, constant: bool) Error!Ast.Node.Index { +fn userVarDeclaration(self: *Self, identifier: Ast.TokenIndex, constant: bool) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; - const identifier = self.current_token.? - 1; var var_type: ?*obj.ObjTypeDef = null; - const inferred_declaration = self.check(.Equal) and constant; var generic_resolve: ?Ast.Node.Index = null; // If next token is `=`, means the identifier wasn't a user type but the variable name // and the type needs to be inferred - if (!inferred_declaration) { - const user_type_name = self.current_token.? - 1; - - // Is it a generic type defined in enclosing functions or object? - if (self.resolveGeneric(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { + const user_type_name = try self.qualifiedName(); + + // Is it a generic type defined in enclosing functions or object? + if (self.resolveGeneric(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { + var_type = generic_type; + } else if (self.current.?.generics != null) { + // Is it generic type defined in a function signature being parsed? + if (self.current.?.generics.?.get(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { var_type = generic_type; - } else if (self.current.?.generics != null) { - // Is it generic type defined in a function signature being parsed? - if (self.current.?.generics.?.get(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { - var_type = generic_type; - } } + } - // Search for a global with that name - if (var_type == null) { - if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[user_type_name])) |slot| { - const global = self.globals.items[slot]; + // Search for a global with that name + if (var_type == null) { + if (try self.resolveGlobal(user_type_name)) |slot| { + const global = self.globals.items[slot]; - var_type = global.type_def; + var_type = global.type_def; - if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { - const imported_from = global.imported_from.?; + if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { + const imported_from = global.imported_from.?; - try self.script_imports.put( - imported_from, - .{ - .location = self.script_imports.get(imported_from).?.location, - .referenced = true, - }, - ); - } + try self.script_imports.put( + imported_from, + .{ + .location = self.script_imports.get(imported_from).?.location, + .referenced = true, + }, + ); } } + } - // If none found, create a placeholder - if (var_type == null) { - var_type = try self.gc.type_registry.getTypeDef( - .{ - .def_type = .Placeholder, - .resolved_type = .{ - // TODO: token is wrong but what else can we put here? - .Placeholder = obj.PlaceholderDef.init(self.gc.allocator, user_type_name), - }, + // If none found, create a placeholder + if (var_type == null) { + var_type = try self.gc.type_registry.getTypeDef( + .{ + .def_type = .Placeholder, + .resolved_type = .{ + // TODO: token is wrong but what else can we put here? + .Placeholder = obj.PlaceholderDef.init( + self.gc.allocator, + user_type_name[user_type_name.len - 1], + ), }, - ); + }, + ); - _ = try self.declarePlaceholder(user_type_name, var_type); - } + _ = try self.declarePlaceholder( + user_type_name[user_type_name.len - 1], + var_type, + ); + } - // Concrete generic types list - generic_resolve = if (try self.match(.DoubleColon)) gn: { - const generic_start = self.current_token.? - 1; + // Concrete generic types list + generic_resolve = if (try self.match(.DoubleColon)) gn: { + const generic_start = self.current_token.? - 1; - try self.consume(.Less, "Expected generic types list after `::`"); + try self.consume(.Less, "Expected generic types list after `::`"); - var resolved_generics = std.ArrayList(*obj.ObjTypeDef).init(self.gc.allocator); - defer resolved_generics.shrinkAndFree(resolved_generics.items.len); - var generic_nodes = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); - defer generic_nodes.shrinkAndFree(generic_nodes.items.len); - var i: usize = 0; - while (!self.check(.Greater) and !self.check(.Eof)) : (i += 1) { - try generic_nodes.append( - try self.parseTypeDef( - if (self.current.?.generics) |generics| - generics.* - else - null, - true, - ), - ); + var resolved_generics = std.ArrayList(*obj.ObjTypeDef).init(self.gc.allocator); + defer resolved_generics.shrinkAndFree(resolved_generics.items.len); + var generic_nodes = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); + defer generic_nodes.shrinkAndFree(generic_nodes.items.len); + var i: usize = 0; + while (!self.check(.Greater) and !self.check(.Eof)) : (i += 1) { + try generic_nodes.append( + try self.parseTypeDef( + if (self.current.?.generics) |generics| + generics.* + else + null, + true, + ), + ); - try resolved_generics.append( - self.ast.nodes.items(.type_def)[generic_nodes.items[generic_nodes.items.len - 1]].?, - ); + try resolved_generics.append( + self.ast.nodes.items(.type_def)[generic_nodes.items[generic_nodes.items.len - 1]].?, + ); - if (!self.check(.Greater)) { - try self.consume(.Comma, "Expected `,` between generic types"); - } + if (!self.check(.Greater)) { + try self.consume(.Comma, "Expected `,` between generic types"); } + } - try self.consume(.Greater, "Expected `>` after generic types list"); + try self.consume(.Greater, "Expected `>` after generic types list"); - if (resolved_generics.items.len == 0) { - self.reportErrorAtCurrent(.generic_type, "Expected at least one type"); - } + if (resolved_generics.items.len == 0) { + self.reportErrorAtCurrent(.generic_type, "Expected at least one type"); + } - // Shouldn't we populate only in codegen? - var_type = try var_type.?.populateGenerics( - self.current_token.? - 1, - var_type.?.resolved_type.?.Object.id, - resolved_generics.items, - &self.gc.type_registry, - null, - ); + // Shouldn't we populate only in codegen? + var_type = try var_type.?.populateGenerics( + self.current_token.? - 1, + var_type.?.resolved_type.?.Object.id, + resolved_generics.items, + &self.gc.type_registry, + null, + ); - break :gn try self.ast.appendNode( - .{ - .tag = .GenericResolveType, - .location = generic_start, - .end_location = self.current_token.? - 1, - .type_def = var_type, - .components = .{ - .GenericResolveType = .{ - .resolved_types = generic_nodes.items, - }, + break :gn try self.ast.appendNode( + .{ + .tag = .GenericResolveType, + .location = generic_start, + .end_location = self.current_token.? - 1, + .type_def = var_type, + .components = .{ + .GenericResolveType = .{ + .resolved_types = generic_nodes.items, }, }, - ); - } else null; + }, + ); + } else null; - if (try self.match(.Question)) { - var_type = try var_type.?.cloneOptional(&self.gc.type_registry); - } + if (try self.match(.Question)) { + var_type = try var_type.?.cloneOptional(&self.gc.type_registry); } const user_type_node = try self.ast.appendNode( @@ -8099,7 +8113,7 @@ fn userVarDeclaration(self: *Self, _: bool, constant: bool) Error!Ast.Node.Index .type_def = var_type, .components = .{ .UserType = .{ - .identifier = identifier, + .name = user_type_name, .generic_resolve = generic_resolve, }, }, @@ -8107,7 +8121,7 @@ fn userVarDeclaration(self: *Self, _: bool, constant: bool) Error!Ast.Node.Index ); return try self.varDeclaration( - inferred_declaration, + identifier, user_type_node, .Semicolon, constant, @@ -8127,13 +8141,16 @@ fn forStatement(self: *Self) Error!Ast.Node.Index { var init_declarations = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); defer init_declarations.shrinkAndFree(init_declarations.items.len); while (!self.check(.Semicolon) and !self.check(.Eof)) { + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; + try init_declarations.append( try self.varDeclaration( - false, - if (try self.match(.Var)) - null + identifier, + if (try self.match(.Colon)) + try self.parseTypeDef(null, true) else - try self.parseTypeDef(null, true), + null, .Nothing, false, true, @@ -8215,32 +8232,30 @@ fn forEachStatement(self: *Self) Error!Ast.Node.Index { try self.beginScope(null); - const infer_key_type = try self.match(.Var); + try self.consume(.Identifier, "Expected identifier"); + const key_identifier = self.current_token.? - 1; var key = try self.varDeclaration( - false, - if (infer_key_type) - null - else - try self.parseTypeDef(null, true), + key_identifier, + null, .Nothing, false, false, - infer_key_type, + true, ); const key_omitted = !(try self.match(.Comma)); - const infer_value_type = !key_omitted and try self.match(.Var); + if (!key_omitted) { + try self.consume(.Identifier, "Expected identifier"); + } + const value_identifier = self.current_token.? - 1; var value = if (!key_omitted) try self.varDeclaration( - false, - if (infer_value_type) - null - else - try self.parseTypeDef(null, true), + value_identifier, + null, .Nothing, false, false, - infer_value_type, + true, ) else null; @@ -8284,35 +8299,73 @@ fn forEachStatement(self: *Self) Error!Ast.Node.Index { self.current.?.locals[iterable_slot].type_def = iterable_type_def; // Infer key/value type - if (infer_key_type and !key_omitted) { - const key_type = switch (iterable_type_def.def_type) { - .List, .String => self.gc.type_registry.int_type, - .Map => iterable_type_def.resolved_type.?.Map.key_type, - else => - // Other type don't have key type - self.current.?.locals[self.ast.nodes.items(.components)[key].VarDeclaration.slot].type_def, - }; + const key_type = switch (iterable_type_def.def_type) { + .List, .String => self.gc.type_registry.int_type, + .Map => iterable_type_def.resolved_type.?.Map.key_type, + .Placeholder => placeholder: { + const placeholder = try self.gc.type_registry.getTypeDef( + .{ + .def_type = .Placeholder, + .resolved_type = .{ + .Placeholder = obj.PlaceholderDef.init( + self.gc.allocator, + self.ast.nodes.items(.location)[if (key_omitted) iterable else key], + ), + }, + }, + ); - self.current.?.locals[self.ast.nodes.items(.components)[key].VarDeclaration.slot].type_def = key_type; - self.ast.nodes.items(.type_def)[key] = key_type; - } - - if (infer_value_type or (infer_key_type and key_omitted)) { - const value_type = switch (iterable_type_def.def_type) { - .List => iterable_type_def.resolved_type.?.List.item_type, - .Range => self.gc.type_registry.int_type, - // .String => self.gc.type_registry.str_type, - .Map => iterable_type_def.resolved_type.?.Map.value_type, - .Enum => try iterable_type_def.toInstance(self.gc.allocator, &self.gc.type_registry), - .Fiber => iterable_type_def.resolved_type.?.Fiber.yield_type, - else => - // Other type are invalid and will be caught at codegen - self.current.?.locals[self.ast.nodes.items(.components)[value.?].VarDeclaration.slot].type_def, - }; + try obj.PlaceholderDef.link( + iterable_type_def, + placeholder, + .Key, + ); - self.current.?.locals[self.ast.nodes.items(.components)[value.?].VarDeclaration.slot].type_def = value_type; - self.ast.nodes.items(.type_def)[value.?] = value_type; - } + break :placeholder placeholder; + }, + else => + // Other type don't have key type + self.current.?.locals[self.ast.nodes.items(.components)[key].VarDeclaration.slot].type_def, + }; + + self.current.?.locals[self.ast.nodes.items(.components)[key].VarDeclaration.slot].type_def = key_type; + self.ast.nodes.items(.type_def)[key] = key_type; + + const value_type = switch (iterable_type_def.def_type) { + .List => iterable_type_def.resolved_type.?.List.item_type, + .Range => self.gc.type_registry.int_type, + .String => self.gc.type_registry.str_type, + .Map => iterable_type_def.resolved_type.?.Map.value_type, + .Enum => try iterable_type_def.toInstance(self.gc.allocator, &self.gc.type_registry), + .Fiber => iterable_type_def.resolved_type.?.Fiber.yield_type, + .Placeholder => placeholder: { + const placeholder = try self.gc.type_registry.getTypeDef( + .{ + .def_type = .Placeholder, + .resolved_type = .{ + .Placeholder = obj.PlaceholderDef.init( + self.gc.allocator, + self.ast.nodes.items(.location)[value.?], + ), + }, + }, + ); + + try obj.PlaceholderDef.link( + iterable_type_def, + placeholder, + .Subscript, + ); + + break :placeholder placeholder; + }, + else => + // Other type are invalid and will be caught at codegen + self.current.?.locals[self.ast.nodes.items(.components)[value.?].VarDeclaration.slot].type_def, + }; + + self.current.?.locals[self.ast.nodes.items(.components)[value.?].VarDeclaration.slot].type_def = value_type; + self.ast.nodes.items(.type_def)[value.?] = value_type; self.markInitialized(); @@ -8539,10 +8592,19 @@ fn namespaceStatement(self: *Self) Error!Ast.Node.Index { self.reportError(.syntax, "`namespace` should be the first statement"); } - try self.consume(.Identifier, "Expected namespace identifier"); + var namespace = std.ArrayList(Ast.TokenIndex).init(self.gc.allocator); + while (!self.check(.Semicolon) and !self.check(.Eof)) { + try self.consume(.Identifier, "Expected namespace identifier"); - const identifier = self.current_token.? - 1; - self.namespace = self.ast.tokens.items(.lexeme)[identifier]; + try namespace.append(self.current_token.? - 1); + + if (!try self.match(.AntiSlash)) { + break; + } + } + namespace.shrinkAndFree(namespace.items.len); + + self.namespace = namespace.items; try self.consume(.Semicolon, "Expected `;` after statement."); @@ -8552,7 +8614,7 @@ fn namespaceStatement(self: *Self) Error!Ast.Node.Index { .location = start_location, .end_location = self.current_token.? - 1, .components = .{ - .Namespace = identifier, + .Namespace = namespace.items, }, }, ); @@ -8585,16 +8647,18 @@ fn tryStatement(self: *Self) Error!Ast.Node.Index { try self.beginScope(null); + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; + try self.consume(.Colon, "Expected `:`"); const type_def = try self.parseTypeDef(null, true); _ = try self.parseVariable( - false, + identifier, self.ast.nodes.items(.type_def)[type_def].?, true, // function arguments are constant "Expected error identifier", ); - const identifier = self.current_token.? - 1; self.markInitialized(); try self.consume(.RightParen, "Expected `)` after error identifier"); diff --git a/src/Scanner.zig b/src/Scanner.zig index a01e7f46..2488be5f 100644 --- a/src/Scanner.zig +++ b/src/Scanner.zig @@ -51,9 +51,7 @@ pub fn scanToken(self: *Self) !Token { const char: u8 = self.advance(); return try switch (char) { - 'b' => self.identifier(), - 'a', 'c'...'z', 'A'...'Z' => self.identifier(), - // `_` identifier is used to discard expressions or locals, but we don't allow identifiers starting with `_`, so we stop there + 'a'...'z', 'A'...'Z' => self.identifier(), '_' => self.makeToken( .Identifier, self.source[self.current.start..self.current.offset], @@ -94,7 +92,7 @@ pub fn scanToken(self: *Self) !Token { self.makeToken(.Less, null, null, null), '~' => self.makeToken(.Bnot, null, null, null), '^' => self.makeToken(.Xor, null, null, null), - '\\' => self.makeToken(.Bor, null, null, null), + '|' => self.makeToken(.Bor, null, null, null), '+' => self.makeToken(.Plus, null, null, null), '-' => if (self.match('>')) self.makeToken(.Arrow, null, null, null) @@ -102,7 +100,10 @@ pub fn scanToken(self: *Self) !Token { self.makeToken(.Minus, null, null, null), '&' => self.makeToken(.Ampersand, null, null, null), '*' => self.makeToken(.Star, null, null, null), - '/' => self.makeToken(.Slash, null, null, null), + '/' => if (self.match('/')) + self.docblock() + else + self.makeToken(.Slash, null, null, null), '%' => self.makeToken(.Percent, null, null, null), '?' => self.makeToken(if (self.match('?')) .QuestionQuestion else .Question, null, null, null), '!' => if (self.match('=')) @@ -133,10 +134,15 @@ pub fn scanToken(self: *Self) !Token { '`' => self.string(true), '\'' => self.byte(), '@' => self.atIdentifier(), - '|' => self.docblock(), '$' => self.pattern(), + '\\' => self.makeToken(.AntiSlash, null, null, null), - else => self.makeToken(.Error, "Unexpected character.", null, null), + else => self.makeToken( + .Error, + "Unexpected character.", + null, + null, + ), }; } @@ -160,9 +166,14 @@ fn skipWhitespaces(self: *Self) void { return; } }, - '|' => { - // It's a docblock, we don't skip it - if (self.peekNext() == '|') { + '/' => { + // It's a / operator + if (self.peekNext() != '/') { + return; + } + + // It's a docblock + if (self.peekNextNext() == '/') { return; } @@ -184,7 +195,7 @@ fn isLetter(char: u8) bool { } fn docblock(self: *Self) !Token { - _ = self.advance(); // Skip second `|` + _ = self.advance(); // Skip third `/` var block = std.ArrayList(u8).init(self.allocator); @@ -208,11 +219,12 @@ fn docblock(self: *Self) !Token { self.skipWhitespaces(); - if (self.peek() != '|' or self.peekNext() != '|') { + if (self.peek() != '/' or self.peekNext() != '/' or self.peekNextNext() != '/') { break; } else { _ = self.advance(); _ = self.advance(); + _ = self.advance(); } } @@ -533,6 +545,14 @@ fn peekNext(self: *Self) u8 { return self.source[self.current.offset + 1]; } +fn peekNextNext(self: *Self) u8 { + if (self.current.offset + 2 >= self.source.len) { + return '\x00'; + } + + return self.source[self.current.offset + 2]; +} + fn advance(self: *Self) u8 { const char = self.source[self.current.offset]; @@ -612,6 +632,7 @@ pub fn highlight(self: *Self, out: anytype, true_color: bool) void { .Minus, .Star, .Slash, + .AntiSlash, .Percent, .Equal, .EqualEqual, diff --git a/src/Token.zig b/src/Token.zig index 478eedc0..eaee8e91 100644 --- a/src/Token.zig +++ b/src/Token.zig @@ -90,6 +90,7 @@ pub const Type = enum { Minus, // - Star, // * Slash, // / + AntiSlash, // \ Percent, // % Question, // ? Bang, // ! diff --git a/src/buzz_api.zig b/src/buzz_api.zig index ea11ef5a..6119611f 100644 --- a/src/buzz_api.zig +++ b/src/buzz_api.zig @@ -229,12 +229,12 @@ fn valueDump(value: Value, vm: *VM, seen: *std.AutoHashMap(*_obj.Obj, void), dep if (!field.method) { io.print( - "{s}{s}{s} {s}", + "{s}{s}{s}: {s}", .{ if (field.static) "static" else "", if (field.constant) "const" else "", - field_type_str.items, field.name, + field_type_str.items, }, ); diff --git a/src/disassembler.zig b/src/disassembler.zig index 4ee95bdf..eae2fbf8 100644 --- a/src/disassembler.zig +++ b/src/disassembler.zig @@ -587,12 +587,12 @@ pub const DumpState = struct { if (!field.method) { out.print( - " {s}{s}{s} {s}", + " {s}{s}{s}: {s}", .{ if (kv.value_ptr.*.static) "static " else "", if (kv.value_ptr.*.constant) "const " else "", - field_type_str.items, kv.key_ptr.*, + field_type_str.items, }, ) catch unreachable; diff --git a/src/lib/buffer.buzz b/src/lib/buffer.buzz index 7221479f..b8cd24fc 100644 --- a/src/lib/buffer.buzz +++ b/src/lib/buffer.buzz @@ -5,213 +5,213 @@ import "ffi"; export object WriteWhileReadingError {} export object OutOfBoundError {} -|| @private -extern fun BufferNew(int capacity) > ud; -|| @private -extern fun BufferDeinit(ud userdata) > void; -|| @private -extern fun BufferRead(ud userdata, int n) > str?; -|| @private -extern fun BufferWrite(ud userdata, str bytes) > void !> WriteWhileReadingError; -|| @private -extern fun BufferReadBoolean(ud userdata) > bool?; -|| @private -extern fun BufferWriteBoolean(ud userdata, bool b) > void !> WriteWhileReadingError; -|| @private -extern fun BufferWriteInt(ud userdata, int n) > void !> WriteWhileReadingError; -|| @private -extern fun BufferReadInt(ud userdata) > int?; -|| @private -extern fun BufferWriteUserData(ud userdata, ud ptr) > void !> WriteWhileReadingError; -|| @private -extern fun BufferReadUserData(ud userdata) > ud?; -|| @private -extern fun BufferWriteFloat(ud userdata, float n) > void !> WriteWhileReadingError; -|| @private -extern fun BufferReadFloat(ud userdata) > float?; -|| @private -extern fun BufferLen(ud userdata, int align) > int; -|| @private -extern fun BufferCursor(ud userdata) > int; -|| @private -extern fun BufferBuffer(ud userdata) > str; -|| @private -extern fun BufferPtr(ud userdata, int at, int alignment) > ud; -|| @private -extern fun BufferEmpty(ud userdata) > void; -|| @private -extern fun BufferAt(ud userdata, int index) > int; -|| @private -extern fun BufferSetAt(ud userdata, int index, int value) > void; -|| @private -extern fun BufferWriteZ(ud userdata, str zigType, [any] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; -|| @private -extern fun BufferWriteZAt(ud userdata, int at, str zigType, [any] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; -|| @private -extern fun BufferReadZ::(ud userdata, str zigType) > T !> ffi.FFITypeMismatchError; -|| @private -extern fun BufferReadZAt::(ud userdata, int at, str zigType) > T !> ffi.FFITypeMismatchError; -|| @private -extern fun BufferWriteStruct::(ud userdata, type structType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; -|| @private -extern fun BufferWriteStructAt::(ud userdata, type structType, int at, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; -|| @private -extern fun BufferReadStruct::(ud userdata, type structType) > T !> ffi.FFITypeMismatchError; -|| @private -extern fun BufferReadStructAt::(ud userdata, type structType, int at) > T !> ffi.FFITypeMismatchError; - -|| Read and write data to a string buffer +/// @private +extern fun BufferNew(capacity: int) > ud; +/// @private +extern fun BufferDeinit(userdata: ud) > void; +/// @private +extern fun BufferRead(userdata: ud, n: int) > str?; +/// @private +extern fun BufferWrite(userdata: ud, bytes: str) > void !> WriteWhileReadingError; +/// @private +extern fun BufferReadBoolean(userdata: ud) > bool?; +/// @private +extern fun BufferWriteBoolean(userdata: ud, b: bool) > void !> WriteWhileReadingError; +/// @private +extern fun BufferWriteInt(userdata: ud, n: int) > void !> WriteWhileReadingError; +/// @private +extern fun BufferReadInt(userdata: ud) > int?; +/// @private +extern fun BufferWriteUserData(userdata: ud, ptr: ud) > void !> WriteWhileReadingError; +/// @private +extern fun BufferReadUserData(userdata: ud) > ud?; +/// @private +extern fun BufferWriteFloat(userdata: ud, n: float) > void !> WriteWhileReadingError; +/// @private +extern fun BufferReadFloat(userdata: ud) > float?; +/// @private +extern fun BufferLen(userdata: ud, align: int) > int; +/// @private +extern fun BufferCursor(userdata: ud) > int; +/// @private +extern fun BufferBuffer(userdata: ud) > str; +/// @private +extern fun BufferPtr(userdata: ud, at: int, alignment: int) > ud; +/// @private +extern fun BufferEmpty(userdata: ud) > void; +/// @private +extern fun BufferAt(userdata: ud, index: int) > int; +/// @private +extern fun BufferSetAt(userdata: ud, index: int, value:int ) > void; +/// @private +extern fun BufferWriteZ(userdata: ud, zigType: str, values: [any]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError; +/// @private +extern fun BufferWriteZAt(userdata: ud, at: int, zigType: str, values: [any]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError; +/// @private +extern fun BufferReadZ::(userdata: ud, zigType: str) > T !> ffi\FFITypeMismatchError; +/// @private +extern fun BufferReadZAt::(userdata: ud, at: int, zigType: str) > T !> ffi\FFITypeMismatchError; +/// @private +extern fun BufferWriteStruct::(userdata: ud, structType: type, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError; +/// @private +extern fun BufferWriteStructAt::(userdata: ud, structType: type, at: int, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError; +/// @private +extern fun BufferReadStruct::(userdata: ud, structType: type) > T !> ffi\FFITypeMismatchError; +/// @private +extern fun BufferReadStructAt::(userdata: ud, structType: type, at: int) > T !> ffi\FFITypeMismatchError; + +/// Read and write data to a string buffer export object Buffer { - || @private - ud buffer, - || @private - bool released = false, + /// @private + buffer: ud, + /// @private + released: bool = false, - || @return A new `Buffer` - static fun init(int capacity = 0) > Buffer { + /// @return A new `Buffer` + static fun init(capacity: int = 0) > Buffer { return Buffer{ buffer = BufferNew(capacity) }; } - static fun fromStr(str string) > Buffer { - Buffer buffer = Buffer.init(); + static fun fromStr(string: str) > Buffer { + const buffer = Buffer.init(); - | We're sure we did not read this buffer before + // We're sure we did not read this buffer before buffer.write(string) catch void; return buffer; } - || Frees the buffer + /// Frees the buffer fun collect() > void { - | Avoid double free + // Avoid double free if (!this.released) { this.released = true; BufferDeinit(this.buffer); } } - || Reads `n` bytes - || @return Read bytes or `null` if nothing to read - fun read(int n = 1) > str? { + /// Reads `n` bytes + /// @return Read bytes or `null` if nothing to read + fun read(n: int = 1) > str? { return BufferRead(this.buffer, n: n); } - || Writes a string - || @param bytes Bytes to write - fun write(str bytes) > void !> WriteWhileReadingError { + /// Writes a string + /// @param bytes Bytes to write + fun write(bytes: str) > void !> WriteWhileReadingError { BufferWrite(this.buffer, bytes: bytes); } - fun writeZ::(str zigType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeZ::(zigType: str, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError { BufferWriteZ(this.buffer, zigType: zigType, values: values); } - fun writeZAt::(int at, str zigType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeZAt::(at: int, zigType: str, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError { BufferWriteZAt(this.buffer, at: at, zigType: zigType, values: values); } - fun readZ::(str zigType) > T !> ffi.FFITypeMismatchError { + fun readZ::(zigType: str) > T !> ffi\FFITypeMismatchError { return BufferReadZ::(this.buffer, zigType: zigType); } - fun readZAt::(int at, str zigType) > T !> ffi.FFITypeMismatchError { + fun readZAt::(at: int, zigType: str) > T !> ffi\FFITypeMismatchError { return BufferReadZAt::(this.buffer, at: at, zigType: zigType); } - fun writeStruct::(type structType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeStruct::(structType: type, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError { BufferWriteStruct::(this.buffer, structType: structType, values: values); } - fun writeStructAt::(type structType, int at, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeStructAt::(structType: type, at: int, values: [T]) > void !> WriteWhileReadingError, ffi\FFITypeMismatchError { BufferWriteStructAt::(this.buffer, structType: structType, at: at, values: values); } - fun readStruct::(type structType) > T !> ffi.FFITypeMismatchError { + fun readStruct::(structType: type) > T !> ffi\FFITypeMismatchError { return BufferReadStruct::(this.buffer, structType: structType); } - fun readStructAt::(type structType, int at) > T !> ffi.FFITypeMismatchError { + fun readStructAt::(structType: type, at: int) > T !> ffi\FFITypeMismatchError { return BufferReadStructAt::(this.buffer, structType: structType, at: at); } - || Reads a boolean - || @return Boolean we read or `null` if nothing to read + /// Reads a boolean + /// @return Boolean we read or `null` if nothing to read fun readBoolean() > bool? { return BufferReadBoolean(this.buffer); } - || Writes a boolean - || @param boolean Boolean to write - fun writeBoolean(bool boolean) > void !> WriteWhileReadingError { + /// Writes a boolean + /// @param boolean Boolean to write + fun writeBoolean(boolean: bool) > void !> WriteWhileReadingError { BufferWriteBoolean(this.buffer, b: boolean); } - || Reads an integer - || @return Read integer or `null` if nothing to read + /// Reads an integer + /// @return Read integer or `null` if nothing to read fun readInt() > int? { return BufferReadInt(this.buffer); } - || Writes an integer - || @param number Integer to write - fun writeInt(int number) > void !> WriteWhileReadingError { + /// Writes an integer + /// @param number Integer to write + fun writeInt(number: int) > void !> WriteWhileReadingError { BufferWriteInt(this.buffer, n: number); } - || Reads an ud - || @return Read ud or `null` if nothing to read + /// Reads an ud + /// @return Read ud or `null` if nothing to read fun readUserData() > ud? { return BufferReadUserData(this.buffer); } - || Writes an ud - || @param number UserDataeger to write - fun writeUserData(ud userdata) > void !> WriteWhileReadingError { + /// Writes an ud + /// @param number UserDataeger to write + fun writeUserData(userdata: ud) > void !> WriteWhileReadingError { BufferWriteUserData(this.buffer, ptr: userdata); } - || Reads a float - || @return Read float or `null` if nothing to read + /// Reads a float + /// @return Read float or `null` if nothing to read fun readFloat() > float? { return BufferReadFloat(this.buffer); } - || Writes a float - || @param number Float to write - fun writeFloat(float number) > void !> WriteWhileReadingError { + /// Writes a float + /// @param number Float to write + fun writeFloat(number: float) > void !> WriteWhileReadingError { BufferWriteFloat(this.buffer, n: number); } - || @return Length of the buffer - fun len(int align = 1) > int { + /// @return Length of the buffer + fun len(align: int = 1) > int { return BufferLen(this.buffer, align: align); } - || @return Position of the reading cursor + /// @return Position of the reading cursor fun cursor() > int { return BufferCursor(this.buffer); } - || Empties the buffer + /// Empties the buffer fun empty() > void { BufferEmpty(this.buffer); } - || Get buffer as string + /// Get buffer as string fun toString() > str { return BufferBuffer(this.buffer); } - || Get buffer's ptr - fun ptr(int at = 0, int align = 1) > ud { + /// Get buffer's ptr + fun ptr(at: int = 0, align: int = 1) > ud { return BufferPtr(this.buffer, at: at, alignment: align); } - || Get byte at `index` - fun at(int index) > int !> OutOfBoundError { + /// Get byte at `index` + fun at(index: int) > int !> OutOfBoundError { if (index < this.len()) { return BufferAt(this.buffer, index: index); } @@ -219,8 +219,8 @@ export object Buffer { throw OutOfBoundError{}; } - || Set byte at `index` - fun setAt(int index, int value) > void !> WriteWhileReadingError, OutOfBoundError { + /// Set byte at `index` + fun setAt(index: int, value: int) > void !> WriteWhileReadingError, OutOfBoundError { if (index < this.len()) { BufferSetAt(this.buffer, index: index, value: value); diff --git a/src/lib/crypto.buzz b/src/lib/crypto.buzz index 494f07c1..d1210ec8 100644 --- a/src/lib/crypto.buzz +++ b/src/lib/crypto.buzz @@ -1,6 +1,6 @@ namespace crypto; -|| Hash algorithms +/// Hash algorithms export enum HashAlgorithm { Md5, Sha1, @@ -17,8 +17,8 @@ export enum HashAlgorithm { Sha3512, } -|| Returns hash of data using given algorithm -|| @param algo Hash algorithm to use -|| @param data Data to hash -|| @return Hash of data has hex string -export extern fun hash(HashAlgorithm algo, str data) > str; +/// Returns hash of data using given algorithm +/// @param algo Hash algorithm to use +/// @param data Data to hash +/// @return Hash of data has hex string +export extern fun hash(algo: HashAlgorithm, data: str) > str; diff --git a/src/lib/debug.buzz b/src/lib/debug.buzz index 1dcaf2c0..0164edb7 100644 --- a/src/lib/debug.buzz +++ b/src/lib/debug.buzz @@ -1,11 +1,11 @@ namespace debug; -|| Dump any value to stdout -export extern fun dump(any value) > void; +/// Dump any value to stdout +export extern fun dump(value: any) > void; -| Parse `source` and return the abstract syntax tree in JSON -| @param source the buzz source -| @param script name (used to fetch eventual extern functions) -| @return AST as JSON -| TODO: reactivate -| export extern fun ast(str source, str scriptName) > str !> CompileError; \ No newline at end of file +// Parse `source` and return the abstract syntax tree in JSON +// @param source the buzz source +// @param script name (used to fetch eventual extern functions) +// @return AST as JSON +// TODO: reactivate +// export extern fun ast(source: str, scriptName: str) > str !> CompileError; diff --git a/src/lib/errors.buzz b/src/lib/errors.buzz index 460500a7..f1873ff7 100644 --- a/src/lib/errors.buzz +++ b/src/lib/errors.buzz @@ -110,23 +110,23 @@ export enum ReadWriteError { } export object CompileError { - str message = "CompileError", + message: str = "CompileError", } export object InterpretError { - str message = "InterpretError", + message: str = "InterpretError", } export object InvalidArgumentError { - str message = "InvalidArgumentError", + message: str = "InvalidArgumentError", } export object NotYetImplementedError { - str message = "NotYetImplementedError", + message: str = "NotYetImplementedError", } export object OverflowError { - str message = "OverflowError", + message: str = "OverflowError", } export object UnderflowError { - str message = "UnderflowError", + message: str = "UnderflowError", } export object UnexpectedError { - str message = "UnexpectedError", + message: str = "UnexpectedError", } diff --git a/src/lib/ffi.buzz b/src/lib/ffi.buzz index 53a9b0b0..8a4c15ea 100644 --- a/src/lib/ffi.buzz +++ b/src/lib/ffi.buzz @@ -1,19 +1,19 @@ namespace ffi; -export fun cstr(str string) => "{string}\0"; +export fun cstr(string: str) => "{string}\0"; export object FFITypeMismatchError { - str message = "Provided buzz value type does not match expected FFI type", + message: str = "Provided buzz value type does not match expected FFI type", } export object FFIZigTypeParseError { - str message = "Could not parse zig type", + message: str = "Could not parse zig type", } -export extern fun alignOf(str zigType) > int; +export extern fun alignOf(zigType: str) > int; -export extern fun sizeOf(str zigType) > int; +export extern fun sizeOf(zigType: str) > int; -export extern fun sizeOfStruct(type structType) > int; +export extern fun sizeOfStruct(structType: type) > int; -export extern fun alignOfStruct(type structType) > int; \ No newline at end of file +export extern fun alignOfStruct(structType: type) > int; diff --git a/src/lib/fs.buzz b/src/lib/fs.buzz index 06295db4..eff3d897 100644 --- a/src/lib/fs.buzz +++ b/src/lib/fs.buzz @@ -3,37 +3,37 @@ namespace fs; import "os"; import "errors"; -|| Returns current directory absolute path -|| @return current directory -export fun currentDirectory() > str !> errors.FileSystemError, errors.InvalidArgumentError { - if (os.env("PWD") -> dir) { +/// Returns current directory absolute path +/// @return current directory +export fun currentDirectory() > str !> errors\FileSystemError, errors\InvalidArgumentError { + if (os\env("PWD") -> dir) { return dir; } else { - throw errors.FileSystemError.BadPathName; + throw errors\FileSystemError.BadPathName; } - | TODO: should not be required since there's throw in the else branch + // TODO: should not be required since there's throw in the else branch return ""; } -|| Creates directory path -|| @param path directory to create -export extern fun makeDirectory(str path) > void !> errors.FileSystemError, errors.UnexpectedError; +/// Creates directory path +/// @param path directory to create +export extern fun makeDirectory(path: str) > void !> errors\FileSystemError, errors\UnexpectedError; -|| Deletes directory or file at path -|| @param path direcotry/file to delete -export extern fun delete(str path) > void !> errors.FileSystemError, errors.UnexpectedError; +/// Deletes directory or file at path +/// @param path direcotry/file to delete +export extern fun delete(path: str) > void !> errors\FileSystemError, errors\UnexpectedError; -|| Moves/renames file -|| @param source file to move -|| @param destination where to move it -export extern fun move(str source, str destination) > void !> errors.FileSystemError, errors.UnexpectedError; +/// Moves/renames file +/// @param source file to move +/// @param destination where to move it +export extern fun move(source: str, destination: str) > void !> errors\FileSystemError, errors\UnexpectedError; -|| List files under path -|| @param path directory to list -export extern fun list(str path) > [str] !> errors.FileSystemError, errors.UnexpectedError; +/// List files under path +/// @param path directory to list +export extern fun list(path: str) > [str] !> errors\FileSystemError, errors\UnexpectedError; -|| Returns true if path exists -|| @param path directory/file to test -|| @return wether file exists -export extern fun exists(str path) > bool !> errors.FileSystemError; \ No newline at end of file +/// Returns true if path exists +/// @param path directory/file to test +/// @return wether file exists +export extern fun exists(path: str) > bool !> errors\FileSystemError; diff --git a/src/lib/gc.buzz b/src/lib/gc.buzz index 8fa58478..40775cfa 100644 --- a/src/lib/gc.buzz +++ b/src/lib/gc.buzz @@ -1,11 +1,11 @@ namespace gc; -|| Error occured while collecting +/// Error occured while collecting object CollectError {} -|| Returns the number of allocated bytes -|| @return allocated bytes +/// Returns the number of allocated bytes +/// @return allocated bytes export extern fun allocated() > int; -|| Triggers a GC sweep +/// Triggers a GC sweep export extern fun collect() > void !> CollectError; \ No newline at end of file diff --git a/src/lib/http.buzz b/src/lib/http.buzz index f6e7b44b..3c4357a5 100644 --- a/src/lib/http.buzz +++ b/src/lib/http.buzz @@ -49,7 +49,7 @@ export enum HttpError { RequestCollected, } -| https://datatracker.ietf.org/doc/html/rfc2616 +// https://datatracker.ietf.org/doc/html/rfc2616 export enum(str) Method { GET, @@ -63,18 +63,18 @@ export enum(str) Method { PATCH, } -|| @private +/// @private extern fun HttpClientNew() > ud; -|| @private -extern fun HttpClientDeinit(ud client) > void; -|| @private -extern fun HttpClientSend(ud client, Method method, str uri, {str: str} headers) > ud !> HttpError; -|| @private -extern fun HttpRequestWait(ud request) > void !> HttpError; -|| @private -extern fun HttpRequestRead(ud request) > Response !> HttpError; -|| @private -extern fun HttpRequestDeinit(ud request) > void; +/// @private +extern fun HttpClientDeinit(client: ud) > void; +/// @private +extern fun HttpClientSend(client: ud, method: Method, uri: str, headers: {str: str}) > ud !> HttpError; +/// @private +extern fun HttpRequestWait(request: ud) > void !> HttpError; +/// @private +extern fun HttpRequestRead(request: ud) > Response !> HttpError; +/// @private +extern fun HttpRequestDeinit(request: ud) > void; const {int: str} reasons = { 100: "Continue", @@ -147,19 +147,19 @@ const {int: str} reasons = { }; export object HttpParseError{ - str? message = null, + message: str? = null, } object Connection { - || @private - ud connection, + /// @private + connection: ud, } export object Client { - || @private - ud client, - || @private - bool collected = false, + /// @private + client: ud, + /// @private + collected: bool = false, static fun init() > Client { return Client{ @@ -167,7 +167,7 @@ export object Client { }; } - fun send(Request request) > Response *> void !> HttpError, errors.InvalidArgumentError, HttpParseError { + fun send(request: Request) > Response *> void !> HttpError, errors\InvalidArgumentError, HttpParseError { _ = this.start(request); yield void; @@ -175,7 +175,7 @@ export object Client { return request.wait(); } - fun start(Request request) > Request !> HttpError { + fun start(request: Request) > Request !> HttpError { if (this.collected) { throw HttpError.ClientCollected; } @@ -188,7 +188,7 @@ export object Client { ); request.request = requestPtr; - | In case we're reusing the request object + // In case we're reusing the request object request.response = null; return request; @@ -204,21 +204,21 @@ export object Client { } export object Request { - ud? request = null, - Response? response = null, - Method method, - {str: str} headers = {}, - str uri = "/", - str? body = null, - bool collected = false, - - fun wait() > Response !> HttpError, errors.InvalidArgumentError, HttpParseError { + request: ud? = null, + response: Response? = null, + method: Method, + headers: {str: str} = {}, + uri: str = "/", + body: str? = null, + collected: bool = false, + + fun wait() > Response !> HttpError, errors\InvalidArgumentError, HttpParseError { if (this.collected) { throw HttpError.RequestCollected; } if (this.response != null) { - throw errors.InvalidArgumentError{}; + throw errors\InvalidArgumentError{}; } if (this.request -> request) { @@ -226,9 +226,9 @@ export object Request { const response = HttpRequestRead(request); - | - we don't need the request anymore - | - also this allows to properly reuse the Request object - | - finally the client can't be collected if there's opened connections + // - we don't need the request anymore + // - also this allows to properly reuse the Request object + // - finally the client can't be collected if there's opened connections HttpRequestDeinit(request); this.request = null; @@ -237,12 +237,12 @@ export object Request { return response; } - throw errors.InvalidArgumentError{}; + throw errors\InvalidArgumentError{}; } fun toString() > str { try { - var result = buffer.Buffer.init(); + var result = buffer\Buffer.init(); result.write("{this.method.value} {this.uri} HTTP/1.1\r\n"); foreach (str key, str value in this.headers) { @@ -251,24 +251,22 @@ export object Request { result.write("{this.body ?? ""}\r\n"); - str strResult = result.toString(); - - return strResult; + return result.toString(); } catch {} return ""; } } -| Don't change proeprties order +// Don't change proeprties order export object Response { - int status = 200, - {str: str} headers = {}, - str? body = null, + status: int = 200, + headers: {str: str} = {}, + body: str? = null, fun toString() > str { try { - var result = buffer.Buffer.init(); + var result = buffer\Buffer.init(); result.write("HTTP/1.1 {this.status} {reasons[this.status]}\r\n"); foreach (str key, str value in this.headers) { @@ -277,9 +275,7 @@ export object Response { result.write("\r\n{this.body ?? ""}\r\n"); - str strResult = result.toString(); - - return strResult; + return result.toString(); } catch {} return "HTTP/1.1 500 Internal Server Error"; diff --git a/src/lib/io.buzz b/src/lib/io.buzz index 135de88e..59e5b956 100644 --- a/src/lib/io.buzz +++ b/src/lib/io.buzz @@ -2,44 +2,44 @@ namespace io; import "errors"; -|| @private -extern fun FileOpen(str filename, int mode) > int !> errors.FileSystemError, errors.UnexpectedError; -|| @private -extern fun FileClose(int fd) > void; -|| @private -extern fun FileReadAll(int fd, int? maxSize) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; -|| @private -extern fun FileReadLine(int fd, int? maxSize) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; -|| @private -extern fun FileRead(int fd, int n) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError; -|| @private -extern fun FileWrite(int fd, str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; -|| @private +/// @private +extern fun FileOpen(filename: str, mode: int) > int !> errors\FileSystemError, errors\UnexpectedError; +/// @private +extern fun FileClose(fd: int) > void; +/// @private +extern fun FileReadAll(fd: int, maxSize: int?) > str !> errors\ReadWriteError, errors\FileSystemError, errors\UnexpectedError; +/// @private +extern fun FileReadLine(fd: int, maxSize: int?) > str? !> errors\ReadWriteError, errors\FileSystemError, errors\UnexpectedError; +/// @private +extern fun FileRead(fd: int, n: int) > str? !> errors\ReadWriteError, errors\FileSystemError, errors\InvalidArgumentError, errors\UnexpectedError; +/// @private +extern fun FileWrite(fd: int, bytes: str) > void !> errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError; +/// @private extern fun getStdIn() > int; -|| @private +/// @private extern fun getStdOut() > int; -|| @private +/// @private extern fun getStdErr() > int; -|| @private -extern fun FileIsTTY(int fd) > bool; +/// @private +extern fun FileIsTTY(fd: int) > bool; -|| File mode with which you can open a file +/// File mode with which you can open a file export enum FileMode { read, write, update, } -|| Object to manipulate an opened file +/// Object to manipulate an opened file export object File { - || File descriptor - int fd, + /// File descriptor + fd: int, - || Open file - || @param filename Path of file to open - || @param mode Mode with which to open it - || @return opened file - static fun open(str filename, FileMode mode) > File !> errors.FileSystemError, errors.UnexpectedError { + /// Open file + /// @param filename Path of file to open + /// @param mode Mode with which to open it + /// @return opened file + static fun open(filename: str, mode: FileMode) > File !> errors\FileSystemError, errors\UnexpectedError { return File { fd = FileOpen(filename, mode: mode.value), }; @@ -49,49 +49,49 @@ export object File { this.close(); } - || Close file + /// Close file fun close() > void { FileClose(this.fd); } - || Reads file until `EOF` - || @return Read data - fun readAll(int? maxSize) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { + /// Reads file until `EOF` + /// @return Read data + fun readAll(maxSize: int?) > str !> errors\ReadWriteError, errors\FileSystemError, errors\UnexpectedError { return FileReadAll(this.fd, maxSize); } - || Reads next line, returns null if nothing to read - || @return Read data - fun readLine(int? maxSize) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { + /// Reads next line, returns null if nothing to read + /// @return Read data + fun readLine(maxSize: int?) > str? !> errors\ReadWriteError, errors\FileSystemError, errors\UnexpectedError { return FileReadLine(this.fd, maxSize); } - || Reads `n` bytes, returns null if nothing to read - || @param n how many bytes to read - || @return Read data - fun read(int n) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError { + /// Reads `n` bytes, returns null if nothing to read + /// @param n how many bytes to read + /// @return Read data + fun read(n: int) > str? !> errors\ReadWriteError, errors\FileSystemError, errors\InvalidArgumentError, errors\UnexpectedError { return FileRead(this.fd, n: n); } - || Write bytes - || @param bytes string to write - fun write(str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + /// Write bytes + /// @param bytes string to write + fun write(bytes: str) > void !> errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError { FileWrite(this.fd, bytes: bytes); } - || @return true if file is TTY + /// @return true if file is TTY fun isTTY() > bool { return FileIsTTY(this.fd); } } -|| stdin -export const File stdin = File{ fd = getStdIn() }; -|| stdout -export const File stdout = File{ fd = getStdOut() }; -|| stderr -export const File stderr = File{ fd = getStdErr() }; +/// stdin +export const stdin = File{ fd = getStdIn() }; +/// stdout +export const stdout = File{ fd = getStdOut() }; +/// stderr +export const stderr = File{ fd = getStdErr() }; -|| Run a buzz file -|| @param filename path to buzz file -export extern fun runFile(str filename) > void !> errors.CompileError, errors.InterpretError, errors.FileSystemError, errors.ReadWriteError; \ No newline at end of file +/// Run a buzz file +/// @param filename path to buzz file +export extern fun runFile(filename: str) > void !> errors\CompileError, errors\InterpretError, errors\FileSystemError, errors\ReadWriteError; diff --git a/src/lib/math.buzz b/src/lib/math.buzz index e4ba2370..ce2aacb2 100644 --- a/src/lib/math.buzz +++ b/src/lib/math.buzz @@ -2,69 +2,69 @@ namespace math; import "errors"; -|| @return absolute value of n -extern fun abs(float n) > float; +/// @return absolute value of n +extern fun abs(n: float) > float; -|| @return acos of n -extern fun acos(float n) > float; +/// @return acos of n +extern fun acos(n: float) > float; -|| @return asin of n -extern fun asin(float n) > float; +/// @return asin of n +extern fun asin(n: float) > float; -|| @return atan of n -extern fun atan(float n) > float; +/// @return atan of n +extern fun atan(n: float) > float; -|| @return ceiled n -extern fun bzceil(float n) > int; +/// @return ceiled n +extern fun bzceil(n: float) > int; -|| @return cos of n -extern fun bzcos(float n) > float; +/// @return cos of n +extern fun bzcos(n: float) > float; -|| π constant -const float pi = 3.1415926535898; +/// π constant +const pi: float = 3.1415926535898; -|| Convert radian to degree -fun deg(float n) > float { +/// Convert radian to degree +fun deg(n: float) > float { return n * 180.0 / pi; } -|| @return exp of n -extern fun bzexp(float n) > float; +/// @return exp of n +extern fun bzexp(n: float) > float; -|| @returned floored n -extern fun bzfloor(float n) > int; +/// @returned floored n +extern fun bzfloor(n: float) > int; -|| @return log(base) of n -extern fun bzlog(float base, float n) > float; +/// @return log(base) of n +extern fun bzlog(base: float, n: float) > float; -|| @return max of a and b -extern fun maxFloat(float a, float b) > float; +/// @return max of a and b +extern fun maxFloat(a: float, b: float) > float; -|| @return min of a and b -extern fun minFloat(float a, float b) > float; +/// @return min of a and b +extern fun minFloat(a: float, b: float) > float; -|| @return max of a and b -extern fun maxInt(int a, int b) > int; +/// @return max of a and b +extern fun maxInt(a: int, b: int) > int; -|| @return min of a and b -extern fun minInt(int a, int b) > int; +/// @return min of a and b +extern fun minInt(a: int, b: int) > int; -|| Convert degree to radian -fun rad(float n) > float { +/// Convert degree to radian +fun rad(n: float) > float { return n * pi / 180.0; } -|| @return sin of n -extern fun bzsin(float n) > float; +/// @return sin of n +extern fun bzsin(n: float) > float; -|| @return square root of n -extern fun bzsqrt(float n) > float; +/// @return square root of n +extern fun bzsqrt(n: float) > float; -|| @return tan of n -extern fun bztan(float n) > float; +/// @return tan of n +extern fun bztan(n: float) > float; -|| @return `x`^`y` -extern fun pow(float x, float y) > float !> errors.OverflowError, errors.UnderflowError; +/// @return `x`^`y` +extern fun pow(x: float, y: float) > float !> errors\OverflowError, errors\UnderflowError; export abs; export acos; @@ -85,4 +85,4 @@ export pi; export rad; export bzsin as sin; export bztan as tan; -export pow; \ No newline at end of file +export pow; diff --git a/src/lib/os.buzz b/src/lib/os.buzz index ee01fea1..aa092b9a 100644 --- a/src/lib/os.buzz +++ b/src/lib/os.buzz @@ -2,121 +2,121 @@ namespace os; import "errors"; -|| Sleep for the given amount of ms -export extern fun sleep(float ms) > void; +/// Sleep for the given amount of ms +export extern fun sleep(ms: float) > void; -|| @return epoch time in ms +/// @return epoch time in ms export extern fun time() > float; -|| Returns environment variable under `key` -|| @param key environment variable name -export extern fun env(str key) > str?; +/// Returns environment variable under `key` +/// @param key environment variable name +export extern fun env(key: str) > str?; -|| @return path to system temp directory +/// @return path to system temp directory export extern fun tmpDir() > str; -|| @param prefix prefix to the temp file name -|| @return a temporary file name in system tmp dir -export extern fun tmpFilename(str? prefix) > str; +/// @param prefix prefix to the temp file name +/// @return a temporary file name in system tmp dir +export extern fun tmpFilename(prefix: str?) > str; -|| Exit program with `exitCode` -|| @param exitCode exit code -extern fun buzzExit(int exitCode) > void; +/// Exit program with `exitCode` +/// @param exitCode exit code +extern fun buzzExit(exitCode: int) > void; export buzzExit as exit; -|| Execute command and return its exit code -|| @param command command to execute -|| @return exit code of the command -export extern fun execute([str] command) > int !> errors.FileSystemError, errors.UnexpectedError; - -|| @private -extern fun SocketConnect(str address, int port, int netProtocol) > int !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError; -|| @private -extern fun SocketClose(int fd) > void; -|| @private -extern fun SocketRead(int fd, int n) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; -|| @private -extern fun SocketWrite(int fd, str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; -|| @private -extern fun SocketServerStart(str address, int port, bool reuseAddr, bool reusePort) > int !> errors.InvalidArgumentError, errors.SocketError, errors.UnexpectedError, errors.FileSystemError; -|| @private -extern fun SocketServerAccept(int fd) > int !> errors.SocketError, errors.UnexpectedError; -|| @private -extern fun SocketReadLine(int fd, int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; -|| @private -extern fun SocketReadAll(int fd, int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; - -|| Protocols supported over a socket +/// Execute command and return its exit code +/// @param command command to execute +/// @return exit code of the command +export extern fun execute(command: [str]) > int !> errors\FileSystemError, errors\UnexpectedError; + +/// @private +extern fun SocketConnect(address: str, port: int, netProtocol: int) > int !> errors\InvalidArgumentError, errors\SocketError, errors\NotYetImplementedError; +/// @private +extern fun SocketClose(fd: int) > void; +/// @private +extern fun SocketRead(fd: int, n: int) > str? !> errors\InvalidArgumentError, errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError; +/// @private +extern fun SocketWrite(fd: int, bytes: str) > void !> errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError; +/// @private +extern fun SocketServerStart(address: str, port: int, reuseAddr: bool, reusePort: bool) > int !> errors\InvalidArgumentError, errors\SocketError, errors\UnexpectedError, errors\FileSystemError; +/// @private +extern fun SocketServerAccept(fd: int) > int !> errors\SocketError, errors\UnexpectedError; +/// @private +extern fun SocketReadLine(fd: int, maxSize: int?) > str? !> errors\FileSystemError, errors\UnexpectedError, errors\ReadWriteError; +/// @private +extern fun SocketReadAll(fd: int, maxSize: int?) > str? !> errors\FileSystemError, errors\UnexpectedError, errors\ReadWriteError; + +/// Protocols supported over a socket export enum SocketProtocol { tcp, udp, ipc, } -|| A socket +/// A socket export object Socket { - || @private - int fd, - - || Opens a socket - || @param address A string containing either a IPv4, IPv6 or path to a socket file (IPC) - || @param port Port to which to connect - || @param protocol Protocol to use - || @return A new `Socket` opened and ready to use - static fun connect(str address, int port = 0, SocketProtocol netProtocol) > Socket !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError { + /// @private + fd: int, + + /// Opens a socket + /// @param address A string containing either a IPv4, IPv6 or path to a socket file (IPC) + /// @param port Port to which to connect + /// @param protocol Protocol to use + /// @return A new `Socket` opened and ready to use + static fun connect(address: str, port: int = 0, netProtocol: SocketProtocol) > Socket !> errors\InvalidArgumentError, errors\SocketError, errors\NotYetImplementedError { return Socket{ fd = SocketConnect(address, port: port, netProtocol: netProtocol.value), }; } - || Close the socket + /// Close the socket fun close() > void { SocketClose(this.fd); } - || Receive at most `n` bytes from the socket - || @param n How many bytes we're prepare to receive - || @return The bytes received or null if nothing to read - fun receive(int n) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + /// Receive at most `n` bytes from the socket + /// @param n How many bytes we're prepare to receive + /// @return The bytes received or null if nothing to read + fun receive(n: int) > str? !> errors\InvalidArgumentError, errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError { return SocketRead(this.fd, n: n); } - || Receive from socket until it's closed or a linefeed is received - || @return The bytes received or null if nothing to read - fun receiveLine(int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { + /// Receive from socket until it's closed or a linefeed is received + /// @return The bytes received or null if nothing to read + fun receiveLine(maxSize: int?) > str? !> errors\FileSystemError, errors\UnexpectedError, errors\ReadWriteError { return SocketReadLine(this.fd, maxSize); } - || Receive from socket until it's closed - || @return The bytes received or null if nothing to read - fun receiveAll(int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { + /// Receive from socket until it's closed + /// @return The bytes received or null if nothing to read + fun receiveAll(maxSize: int?) > str? !> errors\FileSystemError, errors\UnexpectedError, errors\ReadWriteError { return SocketReadAll(this.fd, maxSize); } - || Send bytes on the socket - || @param bytes Bytes to send - fun send(str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + /// Send bytes on the socket + /// @param bytes Bytes to send + fun send(bytes: str) > void !> errors\FileSystemError, errors\ReadWriteError, errors\UnexpectedError { SocketWrite(this.fd, bytes: bytes); } } -|| A TCP Server +/// A TCP Server export object TcpServer { - || @private - Socket serverSocket, - || @private - bool reuseAddr, - || @private - bool reusePort, - - || Starts a TCP server - || @param address Address to listen on - || @param port Port to listen on - || @param reuseAddr Wether we want to accept multiple connections - || @param reusePort Wether we want to accept multiple connections - || @return New `TcpServer` bound to `
:` - static fun init(str address, int port, bool reuseAddr, bool reusePort) > TcpServer !> errors.SocketError, errors.UnexpectedError, errors.InvalidArgumentError, errors.FileSystemError { + /// @private + serverSocket: Socket, + /// @private + reuseAddr: bool, + /// @private + reusePort: bool, + + /// Starts a TCP server + /// @param address Address to listen on + /// @param port Port to listen on + /// @param reuseAddr Wether we want to accept multiple connections + /// @param reusePort Wether we want to accept multiple connections + /// @return New `TcpServer` bound to `
:` + static fun init(address: str, port: int, reuseAddr: bool, reusePort: bool) > TcpServer !> errors\SocketError, errors\UnexpectedError, errors\InvalidArgumentError, errors\FileSystemError { return TcpServer{ serverSocket = Socket{ fd = SocketServerStart(address, port: port, reuseAddr: reuseAddr, reusePort: reusePort), @@ -126,15 +126,15 @@ export object TcpServer { }; } - || Accept a new connection - || @return Socket opened with the client - fun accept() > Socket !> errors.SocketError, errors.UnexpectedError { + /// Accept a new connection + /// @return Socket opened with the client + fun accept() > Socket !> errors\SocketError, errors\UnexpectedError { return Socket{ fd = SocketServerAccept(this.serverSocket.fd), }; } - || Close server + /// Close server fun close() > void { this.serverSocket.close(); } @@ -142,4 +142,4 @@ export object TcpServer { export SocketProtocol; export Socket; -export TcpServer; \ No newline at end of file +export TcpServer; diff --git a/src/lib/serialize.buzz b/src/lib/serialize.buzz index 478af85d..8486897e 100644 --- a/src/lib/serialize.buzz +++ b/src/lib/serialize.buzz @@ -3,42 +3,42 @@ namespace serialize; import "buffer"; import "std"; -|| Utility object to manage deserialized data from, for example, decoded JSON +/// Utility object to manage deserialized data from, for example, decoded JSON export object Boxed { - any data = null, + data: any = null, - static fun init(any data) > Boxed !> CircularReference, NotSerializable { + static fun init(data: any) > Boxed !> CircularReference, NotSerializable { return Boxed{ data = serializeValue(data), }; } - || When wrapped data is a string + /// When wrapped data is a string fun string() > str? { return this.data as? str; } - || When wrapped data is a boolean + /// When wrapped data is a boolean fun boolean() > bool? { return this.data as? bool; } - || When wrapped data is a int + /// When wrapped data is a int fun integer() > int? { return this.data as? int; } - || When wrapped data is a float + /// When wrapped data is a float fun floating() > float? { return this.data as? float; } - || When wrapped data is an object, object property values are themselves wrapped in a `Boxed` + /// When wrapped data is an object, object property values are themselves wrapped in a `Boxed` fun map() > {str: Boxed}? { if (this.data as? {str: any} -> dataMap) { - {str: Boxed} boxedMap = {}; + var boxedMap = {}; - foreach (str key, any value in dataMap) { + foreach (key, value in dataMap) { boxedMap[key] = Boxed{ data = value }; } @@ -48,12 +48,12 @@ export object Boxed { return null; } - || When wrapped data is a list, list elements are themselves warpped in a `Boxed` + /// When wrapped data is a list, list elements are themselves warpped in a `Boxed` fun list() > [Boxed]? { if (this.data as? [any] -> dataList) { - [Boxed] boxedList = []; + var boxedList = []; - foreach (any element in dataList) { + foreach (element in dataList) { boxedList.append(Boxed{ data = element }); } @@ -63,23 +63,23 @@ export object Boxed { return null; } - || @return wrapped data string value or empty string if not a string + /// @return wrapped data string value or empty string if not a string fun stringValue() > str => this.string() ?? "" - || @return wrapped data boolean value or `false` if not a boolean + /// @return wrapped data boolean value or `false` if not a boolean fun booleanValue() > bool => this.boolean() ?? false - || @return wrapped data number value or `0` if not an integer + /// @return wrapped data number value or `0` if not an integer fun integerValue() > int => this.integer() ?? 0 - || @return wrapped data number value or `0` if not a float + /// @return wrapped data number value or `0` if not a float fun floatingValue() > float => this.floating() ?? 0.0 - || @return wrapped data map value or empty map if not a map + /// @return wrapped data map value or empty map if not a map fun mapValue() > {str: Boxed} => this.map() ?? {} - || @return wrapped data list value or empty list if not a list + /// @return wrapped data list value or empty list if not a list fun listValue() > [Boxed] => this.list() ?? [] - || Query the json element at `path`, if nothing matches return `Boxed{}` - || @param path Path to query - || @return Found `Boxed` or `Boxed{}` (which is `null`) - fun q([str] path) > Boxed { + /// Query the json element at `path`, if nothing matches return `Boxed{}` + /// @param path Path to query + /// @return Found `Boxed` or `Boxed{}` (which is `null`) + fun q(path: [str]) > Boxed { if (this.map() -> map) { if (path.len() > 1) { return (map[path[0]] ?? Boxed{}).q(path.sub(1)); @@ -95,33 +95,33 @@ export object Boxed { } export object CircularReference { - str message = "Circular reference", + message: str = "Circular reference", } export object NotSerializable { - str message = "Not serializable", + message: str = "Not serializable", } -export extern fun serializeValue(any value) > any !> CircularReference, NotSerializable; +export extern fun serializeValue(value: any) > any !> CircularReference, NotSerializable; export object JsonParseError { - str? message = null, + message: str? = null, } -|| Parse JSON string into a `Json` tree -|| @private +/// Parse JSON string into a `Json` tree +/// @private object JsonParser { - | TODO: comform to https://datatracker.ietf.org/doc/html/rfc8259 + // TODO: comform to https://datatracker.ietf.org/doc/html/rfc8259 - str source, - int offset = 0, + source: str, + offset: int = 0, fun advance() > str? { if (this.offset >= this.source.len()) { return null; } - str char = this.source[this.offset]; + var char = this.source[this.offset]; this.offset = this.offset + 1; @@ -136,7 +136,7 @@ object JsonParser { return this.source[this.offset]; } - fun match(str expected) > bool { + fun match(expected: str) > bool { if (this.offset > this.source.len() or this.source[this.offset] != expected) { return false; } @@ -146,7 +146,7 @@ object JsonParser { return true; } - fun consume(str expected) > void !> JsonParseError { + fun consume(expected: str) > void !> JsonParseError { if (!this.match(expected)) { throw JsonParseError{ message = "Could not parse JSON: expected `{expected}` got `{this.peek()}` at offset {this.offset}" }; } @@ -154,7 +154,7 @@ object JsonParser { fun skipWhitespaces() > void { while (true) { - const str? char = this.peek(); + const char = this.peek(); if (char == " " or char == "\r" or char == "\t" or char == "\n") { _ = this.advance(); @@ -164,15 +164,15 @@ object JsonParser { } } - fun next() > any !> JsonParseError, buffer.WriteWhileReadingError { + fun next() > any !> JsonParseError, buffer\WriteWhileReadingError { this.skipWhitespaces(); if (this.offset >= this.source.len()) { throw JsonParseError{ message = "Could not parse JSON: end of string" }; } - const str char = this.advance() ?? ""; - const int byte = char.byte(0); + const char = this.advance() ?? ""; + const byte = char.byte(0); if (char == "[") { return this.array(); } else if (char == "\{") { @@ -195,8 +195,8 @@ object JsonParser { throw JsonParseError{ message = "Could not parse JSON: unexpected character `{char}` at offset {this.offset}" }; } - fun array() > [any] !> JsonParseError, buffer.WriteWhileReadingError { - [any] array = []; + fun array() > [any] !> JsonParseError, buffer\WriteWhileReadingError { + var array = []; while (true) { this.skipWhitespaces(); @@ -219,8 +219,8 @@ object JsonParser { return array; } - fun map() > {str: any} !> JsonParseError, buffer.WriteWhileReadingError { - {str: any} map = {}; + fun map() > {str: any} !> JsonParseError, buffer\WriteWhileReadingError { + var map = {}; while (true) { this.skipWhitespaces(); @@ -230,7 +230,7 @@ object JsonParser { } this.consume("\""); - const str key = this.string(); + const key = this.string(); this.skipWhitespaces(); @@ -252,12 +252,12 @@ object JsonParser { return map; } - fun number(str parsed) > any !> JsonParseError { - str number = parsed; + fun number(parsed: str) > any !> JsonParseError { + var number = parsed; - bool isFloat = false; - while (std.parseInt(this.peek() ?? "NaN") != null or this.peek() == ".") { - str? char = this.advance(); + var isFloat = false; + while (std\parseInt(this.peek() ?? "NaN") != null or this.peek() == ".") { + var char = this.advance(); if (char == null) { break; @@ -271,19 +271,19 @@ object JsonParser { } if (isFloat) { - if (std.parseFloat(number) -> floating) { + if (std\parseFloat(number) -> floating) { return floating; } - } else if (std.parseInt(number) -> integer) { + } else if (std\parseInt(number) -> integer) { return integer; } throw JsonParseError{ message = "Could not parse JSON: `{number}` is not a number" }; } - fun string() > str !> buffer.WriteWhileReadingError { - str? char = this.advance(); - var string = buffer.Buffer.init(); + fun string() > str !> buffer\WriteWhileReadingError { + var char = this.advance(); + var string = buffer\Buffer.init(); while (char != null and char != "\"") { if (char == "\\") { @@ -305,15 +305,15 @@ object JsonParser { char = this.advance(); } - str result = string.toString(); + var result = string.toString(); return result; } } -|| Encode to a JSON string -|| @return the JSON string -export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { +/// Encode to a JSON string +/// @return the JSON string +export fun jsonEncode(data: Boxed) > str !> CircularReference, NotSerializable { if (data.string() -> string) { return "\"{string}\""; } else if (data.boolean() -> boolean) { @@ -323,10 +323,10 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { } else if (data.floating() -> floating) { return "{floating}"; } else if (data.map() -> map) { - str json = "\{"; - const int size = map.size(); - int count = 0; - foreach (str key, Boxed value in map) { + var json = "\{"; + const size = map.size(); + var count = 0; + foreach (key, value in map) { json = json + "\"{key}\":{jsonEncode(value)}"; if (count < size - 1) { @@ -337,10 +337,10 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { } return json + "}"; } else if (data.list() -> list) { - str json = "["; + var json = "["; - const int len = list.len(); - foreach (int i, Boxed value in list) { + const len = list.len(); + foreach (i, value in list) { json = json + jsonEncode(value); if (i < len - 1) { @@ -354,13 +354,13 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { return "null"; } -|| Decode string into a Json instance -|| @param str json The JSON string -|| @return Boxed -export fun jsonDecode(str json) > Boxed !> JsonParseError, buffer.WriteWhileReadingError { +/// Decode string into a Json instance +/// @param str json The JSON string +/// @return Boxed +export fun jsonDecode(json: str) > Boxed !> JsonParseError, buffer\WriteWhileReadingError { return Boxed{ data = JsonParser{ source = json }.next() }; -} \ No newline at end of file +} diff --git a/src/lib/std.buzz b/src/lib/std.buzz index 2dd16f29..949ffcb2 100644 --- a/src/lib/std.buzz +++ b/src/lib/std.buzz @@ -1,58 +1,58 @@ namespace std; -|| If condition is false print message and exit program -|| @param condition assert condition -|| @param message message printed if `condition` is false -export extern fun assert(bool condition, str? message = null) > void; - -|| Prints value on stdout -|| @param value value to print -export extern fun print(str value) > void; - -|| Parse integer, returns false if string does not represent a integer -|| @param string string to parse -|| @return integer parsed or null -export extern fun parseInt(str string) > int?; - -|| Parse float, returns false if string does not represent a float -|| @param string string to parse -|| @return float parsed or null -export extern fun parseFloat(str string) > float?; - -|| Cast integer to a float value -|| @param n value to cast -|| @return casted value -export extern fun toInt(float n) > int; - -|| Cast float to a integer value -|| @param n value to cast -|| @return casted value -export extern fun toFloat(int n) > float; - -| FIXME: once we have type composition this might be more elegant -|| Cast float or integer to userdata -|| @param n value to cast -|| @return casted value or 0 if value provided is not a number -export extern fun toUd(any n) > ud; - -|| Parse ud, returns false if string does not represent a ud (u64) -|| @param string string to parse -|| @return ud parsed or null -export extern fun parseUd(str string) > ud?; - -|| Return ascii char for given byte -export extern fun char(int byte) > str; - -|| Return evenly distributed random number between `min` and `max` -|| @param min Minimum value, if omitted `0` -|| @param max Maximum value, if omitted `min + 1` -|| @return Random value -export extern fun random(int? min = null, int? max = null) > int; - -|| @return Current fiber +/// If condition is false print message and exit program +/// @param condition assert condition +/// @param message message printed if `condition` is false +export extern fun assert(condition: bool, message: str? = null) > void; + +/// Prints value on stdout +/// @param value value to print +export extern fun print(value: str) > void; + +/// Parse integer, returns false if string does not represent a integer +/// @param string string to parse +/// @return integer parsed or null +export extern fun parseInt(string: str) > int?; + +/// Parse float, returns false if string does not represent a float +/// @param string string to parse +/// @return float parsed or null +export extern fun parseFloat(string: str) > float?; + +/// Cast integer to a float value +/// @param n value to cast +/// @return casted value +export extern fun toInt(n: float) > int; + +/// Cast float to a integer value +/// @param n value to cast +/// @return casted value +export extern fun toFloat(n: int) > float; + +// FIXME: once we have type composition this might be more elegant +/// Cast float or integer to userdata +/// @param n value to cast +/// @return casted value or 0 if value provided is not a number +export extern fun toUd(n: any) > ud; + +/// Parse ud, returns false if string does not represent a ud (u64) +/// @param string string to parse +/// @return ud parsed or null +export extern fun parseUd(string: str) > ud?; + +/// Return ascii char for given byte +export extern fun char(byte: int) > str; + +/// Return evenly distributed random number between `min` and `max` +/// @param min Minimum value, if omitted `0` +/// @param max Maximum value, if omitted `min + 1` +/// @return Random value +export extern fun random(min: int? = null, max: int? = null) > int; + +/// @return Current fiber export extern fun currentFiber() > fib; -|| Print message and exit program -extern fun buzzPanic(str message) > void; +/// Print message and exit program +extern fun buzzPanic(message: str) > void; export buzzPanic as panic; diff --git a/src/lib/testing.buzz b/src/lib/testing.buzz index 5dc1e8b6..f517f67a 100644 --- a/src/lib/testing.buzz +++ b/src/lib/testing.buzz @@ -4,7 +4,7 @@ import "os"; import "io"; export enum(int) Color { - | attributes + // attributes reset = 0, bright = 1, dim = 2, @@ -13,7 +13,7 @@ export enum(int) Color { reverse = 7, hidden = 8, - | foreground + // foreground black = 30, red = 31, green = 32, @@ -23,7 +23,7 @@ export enum(int) Color { cyan = 36, white = 37, - | background + // background onblack = 40, onred = 41, ongreen = 42, @@ -34,47 +34,47 @@ export enum(int) Color { onwhite = 47, } -export fun color(str text, Color color, bool reset = true) > str { +export fun color(text: str, color: Color, reset: bool = 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(text: str) => color(text, color: Color.bright); +export fun dim(text: str) => color(text, color: Color.dim); +export fun underscore(text: str) => color(text, color: Color.underscore); +export fun blink(text: str) => color(text, color: Color.blink); +export fun reverse(text: str) => color(text, color: Color.reverse); +export fun hidden(text: str) => color(text, color: Color.hidden); +export fun black(text: str) => color(text, color: Color.black); +export fun red(text: str) => color(text, color: Color.red); +export fun green(text: str) => color(text, color: Color.green); +export fun yellow(text: str) => color(text, color: Color.yellow); +export fun blue(text: str) => color(text, color: Color.blue); +export fun magenta(text: str) => color(text, color: Color.magenta); +export fun cyan(text: str) => color(text, color: Color.cyan); +export fun white(text: str) => color(text, color: Color.white); +export fun onblack(text: str) => color(text, color: Color.onblack); +export fun onred(text: str) => color(text, color: Color.onred); +export fun ongreen(text: str) => color(text, color: Color.ongreen); +export fun onyellow(text: str) => color(text, color: Color.onyellow); +export fun onblue(text: str) => color(text, color: Color.onblue); +export fun onmagenta(text: str) => color(text, color: Color.onmagenta); +export fun oncyan(text: str) => color(text, color: Color.oncyan); +export fun onwhite(text: str) => color(text, color: Color.onwhite); export object Tester { - [bool] tests = [], - [bool] asserts = [], - float elapsed = 0.0, - Function(Tester t) > void? beforeAll, - Function(Tester t) > void? beforeEach, - Function(Tester t) > void? afterAll, - Function(Tester t) > void? afterEach, + tests: [bool] = [], + asserts: [bool] = [], + elapsed: float = 0.0, + beforeAll: fun (t: Tester) > void?, + beforeEach: fun (t: Tester) > void?, + afterAll: fun (t: Tester) > void?, + afterEach: fun (t: Tester) > void?, static fun init( - Function(Tester t) > void? beforeAll, - Function(Tester t) > void? beforeEach, - Function(Tester t) > void? afterAll, - Function(Tester t) > void? afterEach + beforeAll: fun (t: Tester) > void?, + beforeEach: fun (t: Tester) > void?, + afterAll: fun (t: Tester) > void?, + afterEach: fun (t: Tester) > void? ) > Tester { var t = Tester{ beforeAll = beforeAll, @@ -98,7 +98,7 @@ export object Tester { fun failedAsserts() > int { return this.asserts.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 0 else 1, initial: 0, ); @@ -106,7 +106,7 @@ export object Tester { fun failedTests() > int { return this.tests.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 0 else 1, initial: 0, ); @@ -114,22 +114,22 @@ export object Tester { fun succeededTests() > int { return this.tests.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 1 else 0, initial: 0, ); } - fun it(str message, Function() > void fn) > void { - float startTime = os.time(); + fun it(message: str, fn: fun () > void) > void { + var startTime = os\time(); - io.stdout.write(yellow("▶ Test: {message}\n")) catch void; + io\stdout.write(yellow("▶ Test: {message}\n")) catch void; if (this.beforeEach -> beforeEach) { beforeEach(this); } - int previousFailCount = this.failedAsserts(); + var previousFailCount = this.failedAsserts(); fn(); if (this.afterEach -> afterEach) { @@ -138,7 +138,7 @@ export object Tester { this.tests.append(previousFailCount == this.failedAsserts()); - this.elapsed = this.elapsed + (os.time() - startTime); + this.elapsed = this.elapsed + (os\time() - startTime); } fun summary() > void { @@ -148,17 +148,17 @@ export object Tester { const failed = this.failedTests(); - io.stdout.write("\n") catch void; + io\stdout.write("\n") catch void; - foreach (bool testStatus in this.tests) { + foreach (testStatus in this.tests) { if (testStatus) { - io.stdout.write(green("●")) catch void; + io\stdout.write(green("●")) catch void; } else { - io.stdout.write(yellow("●")) catch void; + io\stdout.write(yellow("●")) catch void; } } - io.stdout.write( + io\stdout.write( green("\n{this.succeededTests()}") + dim(" successes, ") + yellow("{failed}") @@ -168,15 +168,15 @@ export object Tester { ) catch void; if (failed > 0) { - os.exit(1); + os\exit(1); } } - fun report(str? error, str? message) > void { - io.stderr.write(red(" Assert failed: {message ?? ""}") + dim("\n {error}\n")) catch void; + fun report(error: str?, message: str?) > void { + io\stderr.write(red(" Assert failed: {message ?? ""}") + dim("\n {error}\n")) catch void; } - fun assert(bool condition, str? error, str? message) > void { + fun assert(condition: bool, error: str?, message: str?) > void { if (!condition) { this.report(error, message: message); @@ -186,7 +186,7 @@ export object Tester { } } - fun assertEqual::(T actual, T expected, str? message) > void { + fun assertEqual::(actual: T, expected: T, message: str?) > void { this.assert( actual == expected, error: "expected `{expected}` got `{actual}`", @@ -194,7 +194,7 @@ export object Tester { ); } - fun assertNotEqual::(T actual, T expected, str? message) > void { + fun assertNotEqual::(actual: T, expected: T, message: str?) > void { this.assert( actual != expected, error: "expected `{expected}` got `{actual}`", @@ -202,14 +202,14 @@ export object Tester { ); } - fun assertAreEqual::([T] values, str? message) > void { + fun assertAreEqual::(values: [T], message: str?) > void { if (values.len() < 2) { return; } - bool equal = true; - T previous = values[0]; - foreach (T value in values) { + var equal = true; + var previous = values[0]; + foreach (value in values) { if (value != previous) { equal = false; break; @@ -225,14 +225,14 @@ export object Tester { ); } - fun assertAreNotEqual::([T] values, str? message) > void { + fun assertAreNotEqual::(values: [T], message: str?) > void { if (values.len() < 2) { return; } - bool equal = true; - T previous = values[0]; - foreach (int i, T value in values) { + var equal = true; + var previous = values[0]; + foreach (i, value in values) { if (i > 0 and value == previous) { equal = false; break; @@ -248,7 +248,7 @@ export object Tester { ); } - fun assertOfType::(any value, str? message) > void { + fun assertOfType::(value: any, message: str?) > void { this.assert( !(value is T), error: "`{value}` type is `{typeof value}`", @@ -256,10 +256,10 @@ export object Tester { ); } - fun assertThrows::(Function() > void !> T fn, str? message) > void { + fun assertThrows::(fn: fun () > void !> T, message: str?) > void { try { fn(); - } catch (any error) { + } catch (error: any) { this.assertOfType::(error, message: message); return; } @@ -267,10 +267,10 @@ export object Tester { this.assert(false, error: "Did not throw", message: message); } - fun assertDoesNotThrow::(Function() > void fn, str? message) > void { + fun assertDoesNotThrow::(fn: fun () > void, message: str?) > void { try { fn(); - } catch (any error) { + } catch (error: any) { if (error is T) { this.assert(false, error: "Did throw", message: message); return; diff --git a/src/memory.zig b/src/memory.zig index 598baa09..3ac7bb0d 100644 --- a/src/memory.zig +++ b/src/memory.zig @@ -300,10 +300,13 @@ pub const GarbageCollector = struct { if (BuildOptions.gc_debug) { io.print( - "Allocated @{} {}\n", + "Allocated @{} {} for {} (now {}/{})\n", .{ - std.fmt.fmtIntSizeDec(@intFromPtr(allocated)), + @intFromPtr(allocated), T, + std.fmt.fmtIntSizeDec(@sizeOf(T)), + std.fmt.fmtIntSizeDec(self.bytes_allocated), + std.fmt.fmtIntSizeDec(self.next_gc), }, ); } @@ -606,6 +609,7 @@ pub const GarbageCollector = struct { } self.obj_collected = obj; + defer self.obj_collected = null; self.allocator.destroy(obj.node.?); @@ -759,8 +763,6 @@ pub const GarbageCollector = struct { free(self, ObjRange, ObjRange.cast(obj).?); }, } - - self.obj_collected = null; } pub fn markValue(self: *Self, value: Value) !void { @@ -1024,7 +1026,7 @@ pub const GarbageCollector = struct { @intFromPtr(vm.current_fiber), @intFromPtr(vm.currentFrame().?.closure), @intFromPtr(vm.currentFrame().?.closure.function), - vm.currentFrame().?.closure.function.name.string, + vm.currentFrame().?.closure.function.type_def.resolved_type.?.Function.name.string, }, ); } diff --git a/src/obj.zig b/src/obj.zig index 4e4fb4ee..f5527038 100644 --- a/src/obj.zig +++ b/src/obj.zig @@ -715,9 +715,9 @@ pub const ObjFiber = struct { }; pub const members_typedef = [_][]const u8{ - "extern Function cancel() > void", - "extern Function isMain() > bool", - "extern Function over() > bool", + "extern fun cancel() > void", + "extern fun isMain() > bool", + "extern fun over() > bool", }; pub const members_name = std.StaticStringMap(usize).initComptime( @@ -835,15 +835,15 @@ pub const ObjPattern = struct { const members_typedef = if (!is_wasm) [_][]const u8{ - "extern Function match(str subject) > [str]?", - "extern Function matchAll(str subject) > [[str]]?", - "extern Function replace(str subject, str with) > str", - "extern Function replaceAll(str subject, str with) > str", + "extern fun match(subject: str) > [str]?", + "extern fun matchAll(subject: str) > [[str]]?", + "extern fun replace(subject: str, with: str) > str", + "extern fun replaceAll(subject: str, with: str) > str", } else [_][]const u8{ - "extern Function replace(str subject, str with) > str", - "extern Function replaceAll(str subject, str with) > str", + "extern fun replace(subject: str, with: str) > str", + "extern fun replaceAll(subject: str, with: str) > str", }; pub const members_name = std.StaticStringMap(usize).initComptime( @@ -1006,25 +1006,25 @@ pub const ObjString = struct { }; pub const members_typedef = [_][]const u8{ - "extern Function bin() > str", - "extern Function byte(int at = 0) > int", - "extern Function decodeBase64() > str", - "extern Function encodeBase64() > str", - "extern Function endsWith(str needle) > bool", - "extern Function hex() > str", - "extern Function indexOf(str needle) > int?", - "extern Function len() > int", - "extern Function lower() > str", - "extern Function repeat(int n) > str", - "extern Function replace(str needle, str with) > str", - "extern Function split(str separator) > [str]", - "extern Function startsWith(str needle) > bool", - "extern Function sub(int start, int? len) > str", - "extern Function trim() > str", - "extern Function upper() > str", - "extern Function utf8Codepoints() > [str]", - "extern Function utf8Len() > int", - "extern Function utf8Valid() > bool", + "extern fun bin() > str", + "extern fun byte(at: int = 0) > int", + "extern fun decodeBase64() > str", + "extern fun encodeBase64() > str", + "extern fun endsWith(needle: str) > bool", + "extern fun hex() > str", + "extern fun indexOf(needle: str) > int?", + "extern fun len() > int", + "extern fun lower() > str", + "extern fun repeat(n: int) > str", + "extern fun replace(needle: str, with: str) > str", + "extern fun split(separator: str) > [str]", + "extern fun startsWith(needle: str) > bool", + "extern fun sub(start: int, len: int?) > str", + "extern fun trim() > str", + "extern fun upper() > str", + "extern fun utf8Codepoints() > [str]", + "extern fun utf8Len() > int", + "extern fun utf8Valid() > bool", }; pub const members_name = std.StaticStringMap(usize).initComptime( @@ -1295,13 +1295,25 @@ pub const ObjFunction = struct { pub fn mark(self: *Self, gc: *GarbageCollector) !void { try gc.markObj(@constCast(self.type_def.toObj())); if (BuildOptions.gc_debug) { - io.print("MARKING CONSTANTS OF FUNCTION @{} {s}\n", .{ @intFromPtr(self), self.name.string }); + io.print( + "MARKING CONSTANTS OF FUNCTION @{} {s}\n", + .{ + @intFromPtr(self), + self.type_def.resolved_type.?.Function.name.string, + }, + ); } for (self.chunk.constants.items) |constant| { try gc.markValue(constant); } if (BuildOptions.gc_debug) { - io.print("DONE MARKING CONSTANTS OF FUNCTION @{} {s}\n", .{ @intFromPtr(self), self.name.string }); + io.print( + "DONE MARKING CONSTANTS OF FUNCTION @{} {s}\n", + .{ + @intFromPtr(self), + self.type_def.resolved_type.?.Function.name.string, + }, + ); } } @@ -2835,14 +2847,14 @@ pub const ObjRange = struct { }; const members_typedef = [_][]const u8{ - "extern Function high() > int", - "extern Function intersect(rg other) > rg", - "extern Function invert() > rg", - "extern Function len() > int", - "extern Function low() > int", - "extern Function subsetOf(rg other) > bool", - "extern Function toList() > [int]", - "extern Function union(rg other) > rg", + "extern fun high() > int", + "extern fun intersect(other: rg) > rg", + "extern fun invert() > rg", + "extern fun len() > int", + "extern fun low() > int", + "extern fun subsetOf(other: rg) > bool", + "extern fun toList() > [int]", + "extern fun union(other: rg) > rg", }; pub const members_name = std.StaticStringMap(usize).initComptime( @@ -4075,13 +4087,13 @@ pub const ObjTypeDef = struct { type_registry, visited_ptr, ), - .yield_type = try self.resolved_type.?.Fiber.yield_type.populateGenerics( + .yield_type = try (try self.resolved_type.?.Fiber.yield_type.populateGenerics( where, origin, generics, type_registry, visited_ptr, - ), + )).cloneOptional(type_registry), }; const resolved = ObjTypeDef.TypeUnion{ .Fiber = new_fiber_def }; @@ -4286,14 +4298,17 @@ pub const ObjTypeDef = struct { generics, type_registry, visited_ptr, - )).toInstance(type_registry.gc.allocator, type_registry), - .yield_type = try (try old_fun_def.yield_type.populateGenerics( + )) + .toInstance(type_registry.gc.allocator, type_registry), + .yield_type = try (try (try old_fun_def.yield_type.populateGenerics( where, origin, generics, type_registry, visited_ptr, - )).toInstance(type_registry.gc.allocator, type_registry), + )) + .toInstance(type_registry.gc.allocator, type_registry)) + .cloneOptional(type_registry), .error_types = if (error_types) |types| types.items else null, .parameters = parameters, .defaults = old_fun_def.defaults, @@ -4430,8 +4445,8 @@ pub const ObjTypeDef = struct { const count = object_def.fields.count(); var i: usize = 0; while (it.next()) |kv| { + try writer.print("{s}: ", .{kv.key_ptr.*}); try kv.value_ptr.*.type_def.toStringRaw(writer, qualified); - try writer.print(" {s}", .{kv.key_ptr.*}); if (i < count - 1) { try writer.writeAll(", "); @@ -4496,8 +4511,8 @@ pub const ObjTypeDef = struct { const count = object_def.fields.count(); var i: usize = 0; while (it.next()) |kv| { + try writer.print("{s}: ", .{kv.key_ptr.*}); try kv.value_ptr.*.type_def.toStringRaw(writer, qualified); - try writer.print(" {s}", .{kv.key_ptr.*}); if (i < count - 1) { try writer.writeAll(", "); @@ -4612,9 +4627,9 @@ pub const ObjTypeDef = struct { var i: usize = 0; var it = function_def.parameters.iterator(); while (it.next()) |kv| : (i = i + 1) { - try kv.value_ptr.*.toStringRaw(writer, qualified); - try writer.writeAll(" "); try writer.writeAll(kv.key_ptr.*.string); + try writer.writeAll(": "); + try kv.value_ptr.*.toStringRaw(writer, qualified); if (i < size - 1) { try writer.writeAll(", "); @@ -4840,7 +4855,11 @@ pub const ObjTypeDef = struct { // Compare two type definitions pub fn eql(expected: *Self, actual: *Self) bool { - if (expected == actual or (expected.optional and actual.def_type == .Void) or expected.def_type == .Any) { + if (expected == actual or + (expected.optional and actual.def_type == .Void) or + (actual.optional and expected.def_type == .Void) or + expected.def_type == .Any) + { return true; } @@ -5006,21 +5025,21 @@ pub const PlaceholderDef = struct { return; } - if (child.resolved_type.?.Placeholder.parent != null) { - if (BuildOptions.debug_placeholders) { - io.print( - ">>> Placeholder @{} ({s}) has already a {} relation with @{} ({s})\n", - .{ - @intFromPtr(child), - if (child.resolved_type.?.Placeholder.name) |name| name.string else "unknown", - child.resolved_type.?.Placeholder.parent_relation.?, - @intFromPtr(child.resolved_type.?.Placeholder.parent.?), - if (child.resolved_type.?.Placeholder.parent.?.resolved_type.?.Placeholder.name) |name| name.string else "unknown", - }, - ); - } - return; - } + // if (child.resolved_type.?.Placeholder.parent != null) { + // if (BuildOptions.debug_placeholders) { + // io.print( + // ">>> Placeholder @{} ({s}) has already a {} relation with @{} ({s})\n", + // .{ + // @intFromPtr(child), + // if (child.resolved_type.?.Placeholder.name) |name| name.string else "unknown", + // child.resolved_type.?.Placeholder.parent_relation.?, + // @intFromPtr(child.resolved_type.?.Placeholder.parent.?), + // if (child.resolved_type.?.Placeholder.parent.?.resolved_type.?.Placeholder.name) |name| name.string else "unknown", + // }, + // ); + // } + // return; + // } child.resolved_type.?.Placeholder.parent = parent; try parent.resolved_type.?.Placeholder.children.append(child); diff --git a/src/vm.zig b/src/vm.zig index 13c97665..0a2c30a0 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -4577,7 +4577,7 @@ pub const VM = struct { else " ╰─", if (unext.closure.function.type_def.resolved_type.?.Function.function_type == .Test) - function_name[(std.mem.indexOfScalar(u8, function_name, ' ').? + 1)..] + function_name //[(std.mem.indexOfScalar(u8, function_name, ' ') orelse 0 + 1)..] else function_name, if (frame.call_site) |call_site| @@ -4605,13 +4605,15 @@ pub const VM = struct { } if (frame.call_site) |call_site| { - writer.print( - ":{d}:{d}", - .{ - self.current_ast.tokens.items(.line)[call_site] + 1, - self.current_ast.tokens.items(.column)[call_site], - }, - ) catch @panic("Could not report error"); + if (frame.closure.function.type_def.resolved_type.?.Function.function_type != .ScriptEntryPoint) { + writer.print( + ":{d}:{d}", + .{ + self.current_ast.tokens.items(.line)[call_site] + 1, + self.current_ast.tokens.items(.column)[call_site], + }, + ) catch @panic("Could not report error"); + } } notes.append( @@ -4627,7 +4629,9 @@ pub const VM = struct { .error_type = .runtime, .items = &[_]Reporter.ReportItem{ .{ - .location = self.current_ast.tokens.get(error_site orelse stack[0].call_site.?), + .location = self.current_ast.tokens.get( + error_site orelse stack[0].call_site.?, + ), .kind = .@"error", .message = message, }, @@ -5245,7 +5249,10 @@ pub const VM = struct { self.currentFrame().?.ip = hotspot_call_start; if (BuildOptions.debug) { - disassembler.disassembleChunk(chunk, self.currentFrame().?.closure.function.name.string); + disassembler.disassembleChunk( + chunk, + self.currentFrame().?.closure.function.type_def.resolved_type.?.Function.name.string, + ); } } }; diff --git a/tests/001-basic-types.buzz b/tests/001-basic-types.buzz index a5c01ca7..c4cfe086 100644 --- a/tests/001-basic-types.buzz +++ b/tests/001-basic-types.buzz @@ -1,40 +1,40 @@ import "std"; test "Basic types" { - str _ = "hello world"; - float _ = 3.14; - int _ = 3; - bool _ = true; + const _: str = "hello world"; + const _: float = 3.14; + const _: int = 3; + const _: bool = true; } test "Underscore on number literals" { - int a = 100_000; + const a: int = 100_000; - std.assert(a == 100000, message: "Could use an underscore on an int"); + std\assert(a == 100000, message: "Could use an underscore on an int"); - float b = 3.1_4; + const b = 3.1_4; - std.assert(b == 3.14, message: "Could use an underscore on a float"); + std\assert(b == 3.14, message: "Could use an underscore on a float"); - int bin = 0b1_0001; + const bin = 0b1_0001; - std.assert(bin == 17, message: "Clould use an underscore on a binary int"); + std\assert(bin == 17, message: "Clould use an underscore on a binary int"); - int h = 0xF_FFF; + const h = 0xF_FFF; - std.assert(h == 65535, message: "Clould use an underscore on a hex int"); + std\assert(h == 65535, message: "Clould use an underscore on a hex int"); } test "Char literal" { - int char = 'A'; + const char = 'A'; - std.assert(char == 65, message: "Could use char literal"); + std\assert(char == 65, message: "Could use char literal"); - int quote = '\''; + const quote = '\''; - std.assert(quote == 39, message: "Could escape ' in char literal"); + std\assert(quote == 39, message: "Could escape ' in char literal"); - int slash = '\\'; + const slash = '\\'; - std.assert(slash == 92, message: "Could escape \\ in char literal"); + std\assert(slash == 92, message: "Could escape \\ in char literal"); } diff --git a/tests/002-operators.buzz b/tests/002-operators.buzz index 9d1ba565..ba8b58ff 100644 --- a/tests/002-operators.buzz +++ b/tests/002-operators.buzz @@ -1,38 +1,38 @@ import "std"; test "Binary operators" { - std.assert(12 == 12, message: "equality (number)"); - std.assert(12 + 12 == 24, message: "addition"); - std.assert(12 - 12 == 0, message: "substraction"); - std.assert(12 * 12 == 144, message: "multiplication"); - std.assert(12 / 12 == 1, message: "division"); - std.assert(12 % 12 == 0, message: "modulo"); - std.assert(12 != 13, message: "inequality"); - std.assert(12 >= 12, message: "greater or equal"); - std.assert(12 <= 12, message: "less or equal"); - std.assert(12 > 11, message: "greater"); - std.assert(12 < 13, message: "less"); - std.assert(12 > 3 and 5 < 12, message: "and"); - std.assert(12 > 3 or 12 < 5, message: "or"); + std\assert(12 == 12, message: "equality (number)"); + std\assert(12 + 12 == 24, message: "addition"); + std\assert(12 - 12 == 0, message: "substraction"); + std\assert(12 * 12 == 144, message: "multiplication"); + std\assert(12 / 12 == 1, message: "division"); + std\assert(12 % 12 == 0, message: "modulo"); + std\assert(12 != 13, message: "inequality"); + std\assert(12 >= 12, message: "greater or equal"); + std\assert(12 <= 12, message: "less or equal"); + std\assert(12 > 11, message: "greater"); + std\assert(12 < 13, message: "less"); + std\assert(12 > 3 and 5 < 12, message: "and"); + std\assert(12 > 3 or 12 < 5, message: "or"); } test "Binary operators for strings" { - std.assert("hello " + "world" == "hello world", message: "string concat"); - std.assert("hello" == "hello", message: "equality (string"); + std\assert("hello " + "world" == "hello world", message: "string concat"); + std\assert("hello" == "hello", message: "equality (string"); } test "Unary operators (constant folded)" { - std.assert(-12 < 0, message: "negate operator"); - std.assert(!false, message: "not operator"); - std.assert(~15 == -16, message: "~"); + std\assert(-12 < 0, message: "negate operator"); + std\assert(!false, message: "not operator"); + std\assert(~15 == -16, message: "~"); } test "Unary operators" { - int a = 12; - bool b = false; - int c = 15; + const a = 12; + const b = false; + const c = 15; - std.assert(-a < 0, message: "negate operator"); - std.assert(!b, message: "not operator"); - std.assert(~c == -16, message: "~"); -} \ No newline at end of file + std\assert(-a < 0, message: "negate operator"); + std\assert(!b, message: "not operator"); + std\assert(~c == -16, message: "~"); +} diff --git a/tests/003-control-flow.buzz b/tests/003-control-flow.buzz index c067e2f7..13968663 100644 --- a/tests/003-control-flow.buzz +++ b/tests/003-control-flow.buzz @@ -2,63 +2,63 @@ import "std"; test "if statement" { if (2 > 1) { - std.assert(true, message: "if"); + std\assert(true, message: "if"); } else { - std.assert(false, message: "else"); + std\assert(false, message: "else"); } if (2 < 1) { - std.assert(false, message: "if"); + std\assert(false, message: "if"); } else { - std.assert(true, message: "else"); + std\assert(true, message: "else"); } } test "if statement with placeholder" { if (ahead == "wat") { - std.assert(true, message: "works with a placeholder"); + std\assert(true, message: "works with a placeholder"); } else { - std.assert(false, message: "if failed with placeholder"); + std\assert(false, message: "if failed with placeholder"); } - | if (objAhead.name == "joe") { - | std.assert(true, message: "works with a placeholder"); - | } else { - | std.assert(false, message: "if failed with placeholder"); - | } + // if (objAhead.name == "joe") { + // std\assert(true, message: "works with a placeholder"); + // } else { + // std\assert(false, message: "if failed with placeholder"); + // } } test "while statement" { - int i = 0; + var i = 0; while (i < 10) { i = i + 1; } - std.assert(i == 10, message: "while"); + std\assert(i == 10, message: "while"); } -| test "while statement with placeholder" { -| while (objAhead.age < 10) { -| objAhead.age = objAhead.age + 1; -| } +// test "while statement with placeholder" { +// while (objAhead.age < 10) { +// objAhead.age = objAhead.age + 1; +// } -| std.assert(objAhead.age == 10, message: "while with placeholder"); -| } +// std\assert(objAhead.age == 10, message: "while with placeholder"); +// } test "do-until statement" { - int i = 10; + var i = 10; do { i = i - 1; } until (i == 0) - std.assert(i == 0, message: "do until"); + std\assert(i == 0, message: "do until"); } -str ahead = "wat"; +const ahead = "wat"; -| object Ahead { -| str name = "joe", -| int age = 0 -| } +// object Ahead { +// str name = "joe", +// int age = 0 +// } -| Ahead objAhead = Ahead{}; \ No newline at end of file +// Ahead objAhead = Ahead{}; diff --git a/tests/004-lists.buzz b/tests/004-lists.buzz index 4257d437..5886bbd7 100644 --- a/tests/004-lists.buzz +++ b/tests/004-lists.buzz @@ -1,80 +1,80 @@ import "std"; test "Lists" { - [int] list = [1, 2, 3, 4]; + const list = [1, 2, 3, 4]; - std.assert(list.len() == 4, message: "len"); + std\assert(list.len() == 4, message: "len"); - [str] strList = ["hello", "world"]; - std.assert(strList[0] == "hello", message: "subscript"); + const strList = ["hello", "world"]; + std\assert(strList[0] == "hello", message: "subscript"); - | A lone list expression - _ = ["hello", "world"]; - _ = [["hello"], ["world"]]; + // A lone list expression + const _ = ["hello", "world"]; + const _ = [["hello"], ["world"]]; - [[str]] nestedList = [["hello"], ["world"]]; + const nestedList = [["hello"], ["world"]]; - std.assert(nestedList[0][0] == "hello", message: "nested list"); + std\assert(nestedList[0][0] == "hello", message: "nested list"); strList[1] = "yolo"; - std.assert(strList[1] == "yolo", message: "list assignment"); + std\assert(strList[1] == "yolo", message: "list assignment"); strList.append("dojo"); - std.assert(strList[strList.len() - 1] == "dojo", message: "append to list"); + std\assert(strList[strList.len() - 1] == "dojo", message: "append to list"); - str? removed = strList.remove(1); - std.assert(strList.len() == 2, message: "removed element form list"); - std.assert(strList[0] == "hello" and strList[1] == "dojo", message: "item were properly shifted"); - std.assert(removed == "yolo", message: "removed element has the correct value"); + const removed = strList.remove(1); + std\assert(strList.len() == 2, message: "removed element form list"); + std\assert(strList[0] == "hello" and strList[1] == "dojo", message: "item were properly shifted"); + std\assert(removed == "yolo", message: "removed element has the correct value"); - std.assert(strList.remove(12) == null, message: "returns null when removing non existent index"); + std\assert(strList.remove(12) == null, message: "returns null when removing non existent index"); } test "list.sub" { - [int] list = [1, 2, 3, 4]; - [int] sub = list.sub(1, len: 2); + const list = [1, 2, 3, 4]; + const sub = list.sub(1, len: 2); - std.assert(sub.len() == 2 and sub[0] == 2 and sub[1] == 3, message: "list.sub"); + std\assert(sub.len() == 2 and sub[0] == 2 and sub[1] == 3, message: "list.sub"); } test "list.indexOf" { - std.assert([0, 1, 2, 3].indexOf(2) == 2, message: "list.indexOf"); + std\assert([0, 1, 2, 3].indexOf(2) == 2, message: "list.indexOf"); } test "list.join" { - std.assert([1, 2, 3, 4].join(",") == "1,2,3,4", message: "list.join"); + std\assert([1, 2, 3, 4].join(",") == "1,2,3,4", message: "list.join"); } test "list concat" { - std.assert(([1, 2, 3] + [4, 5, 6]).join(",") == "1,2,3,4,5,6", message: "list concat"); + std\assert(([1, 2, 3] + [4, 5, 6]).join(",") == "1,2,3,4,5,6", message: "list concat"); } test "list.clone" { - [int] list = [1, 2, 3]; - [int] copy = list.clone(); + const list = [1, 2, 3]; + const copy = list.clone(); - std.assert(list.len() == copy.len(), message: "Could clone list"); - foreach (int i, int el in copy) { - std.assert(list[i] == el, message: "Could clone list"); + std\assert(list.len() == copy.len(), message: "Could clone list"); + foreach (i, el in copy) { + std\assert(list[i] == el, message: "Could clone list"); } } test "empty list type inferring" { - var list = []; + const list = []; - std.assert(typeof list == <[any]>); + std\assert(typeof list == <[any]>); - [str] slist = []; + const slist: [str] = []; - std.assert(typeof slist == <[str]>); + std\assert(typeof slist == <[str]>); } test "list.fill" { const list = (0..3).toList().fill(42); - std.assert(list[0] == 42 and list[1] == 42 and list[2] == 42); + std\assert(list[0] == 42 and list[1] == 42 and list[2] == 42); const another = (0..10).toList().fill(42, start: 2, len: 3); - std.assert(another[2] == 42 and another[3] == 42 and another[4] == 42 and another[1] != 42 and another[5] != 42); + std\assert(another[2] == 42 and another[3] == 42 and another[4] == 42 and another[1] != 42 and another[5] != 42); } diff --git a/tests/005-maps.buzz b/tests/005-maps.buzz index 232f66fb..bef1ec9b 100644 --- a/tests/005-maps.buzz +++ b/tests/005-maps.buzz @@ -1,96 +1,96 @@ import "std"; test "Maps" { - {str: int} map = { + const map = { "hello": 1, "bye": 2, }; - _ = {1: true, 2: false}; + const _ = {1: true, 2: false}; - std.assert(map["bye"] is int?, message: "yeah"); + std\assert(map["bye"] is int?, message: "yeah"); - std.assert(map["bye"] == 2, message: "map subscript"); - std.assert(({1: true, 2: false})[2] == false, message: "map expression subscript"); + std\assert(map["bye"] == 2, message: "map subscript"); + std\assert(({1: true, 2: false})[2] == false, message: "map expression subscript"); - std.assert(map.remove("hello") == 1, message: "removed element"); - | std.assert(map["hello"] == null, message: "removed element"); - std.assert(map.size() == 1, message: "map size"); + std\assert(map.remove("hello") == 1, message: "removed element"); + // std\assert(map["hello"] == null, message: "removed element"); + std\assert(map.size() == 1, message: "map size"); } test "map merge" { - {str: int} map = {"one": 1, "two": 22} + {"three": 3, "two": 2}; + const map = {"one": 1, "two": 22} + {"three": 3, "two": 2}; - std.assert(map["two"] == 2, message: "map merge"); - std.assert(map.size() == 3, message: "map merge"); + std\assert(map["two"] == 2, message: "map merge"); + std\assert(map.size() == 3, message: "map merge"); } test "map.keys" { - std.assert({"one": 1, "two": 2, "three": 3}.keys().join(",") == "one,two,three", message: "map.keys"); + std\assert({"one": 1, "two": 2, "three": 3}.keys().join(",") == "one,two,three", message: "map.keys"); } test "map.values" { - std.assert({"one": 1, "two": 2, "three": 3}.values().join(",") == "1,2,3", message: "map.values"); + std\assert({"one": 1, "two": 2, "three": 3}.values().join(",") == "1,2,3", message: "map.values"); - std.assert({}.keys().len() == 0, message: "yo empty map"); + std\assert({}.keys().len() == 0, message: "yo empty map"); } test "map.diff" { - {str: int} first = { + const first = { "one": 1, "two": 2, "three": 3, }; - {str: int} second = { + const second = { "two": 22, "three": 33, "four": 4, }; - {str: int} diff = first.diff(second); + const diff = first.diff(second); - std.assert(diff.size() == 1 and diff["one"] != null, message: "Could use map.diff"); + std\assert(diff.size() == 1 and diff["one"] != null, message: "Could use map.diff"); } test "map.intersect" { - {str: int} first = { + const first = { "one": 1, "two": 2, "five": 5, }; - {str: int} second = { + const second = { "two": 22, "three": 33, "four": 4, }; - {str: int} intersect = first.intersect(second); + const intersect = first.intersect(second); - std.assert(intersect.size() == 1 and intersect["two"] != null, message: "Could use map.intersect"); + std\assert(intersect.size() == 1 and intersect["two"] != null, message: "Could use map.intersect"); } test "map.clone" { - {str: int} first = { + const first = { "one": 1, "two": 2, "five": 5, }; - {str: int} copy = first.clone(); + const copy = first.clone(); - std.assert(copy.size() == first.size(), message: "Could clone map"); - foreach (str key, int value in copy) { - std.assert(first[key] == value, message: "Could clone map"); + std\assert(copy.size() == first.size(), message: "Could clone map"); + foreach (key, value in copy) { + std\assert(first[key] == value, message: "Could clone map"); } } test "empty map type inferring" { - var map = {}; + const map = {}; - std.assert(typeof map == <{any: any}>); + std\assert(typeof map == <{any: any}>); - {str: int} smap = {}; + const smap: {str: int} = {}; - std.assert(typeof smap == <{str: int}>); -} \ No newline at end of file + std\assert(typeof smap == <{str: int}>); +} diff --git a/tests/006-enums.buzz b/tests/006-enums.buzz index d9081d0f..2a63a916 100644 --- a/tests/006-enums.buzz +++ b/tests/006-enums.buzz @@ -10,7 +10,7 @@ enum(int) IntEnum { one = 1, two = 2, three = 3, - | wat = "wat", + // wat = "wat", } enum NaturalEnum { @@ -19,32 +19,32 @@ enum NaturalEnum { two, } -fun getValue(NaturalEnum case = NaturalEnum.zero) > int { +fun getValue(case: NaturalEnum = NaturalEnum.zero) > int { return case.value; } object Natural { - NaturalEnum natural = NaturalEnum.zero, + natural: NaturalEnum = NaturalEnum.zero, } test "Enums" { - std.assert(StrEnum.one.value == "one", message: "str enum"); + std\assert(StrEnum.one.value == "one", message: "str enum"); - std.assert(IntEnum.one.value == 1, message: "int enum"); + std\assert(IntEnum.one.value == 1, message: "int enum"); - std.assert(NaturalEnum.zero.value == 0, message: "natural enum"); + std\assert(NaturalEnum.zero.value == 0, message: "natural enum"); - NaturalEnum myCase = NaturalEnum.two; + const myCase = NaturalEnum.two; - std.assert(myCase.value == 2, message: "enum instance"); + std\assert(myCase.value == 2, message: "enum instance"); - NaturalEnum? fromValue = NaturalEnum(0); - std.assert(fromValue != null, message: "Could get enum instance from value"); - std.assert(fromValue?.value == 0, message: "Could get correct enum instance from value"); + const fromValue = NaturalEnum(0); + std\assert(fromValue != null, message: "Could get enum instance from value"); + std\assert(fromValue?.value == 0, message: "Could get correct enum instance from value"); } test "Enum case as default value" { - std.assert(getValue() == 0, message: "Could use enum case as function argument default value"); + std\assert(getValue() == 0, message: "Could use enum case as function argument default value"); - std.assert(Natural{}.natural == NaturalEnum.zero, message: "Could use enum case as object field default value"); -} \ No newline at end of file + std\assert(Natural{}.natural == NaturalEnum.zero, message: "Could use enum case as object field default value"); +} diff --git a/tests/007-objects.buzz b/tests/007-objects.buzz index f28f40b1..1063579b 100644 --- a/tests/007-objects.buzz +++ b/tests/007-objects.buzz @@ -1,32 +1,32 @@ import "std"; object First { - str name = "Joe", - int age = 10, + name: str = "Joe", + age: int = 10, fun sayHello() > void { - std.print("hello"); - std.print(this.name); + std\print("hello"); + std\print(this.name); } } test "Objects" { - First first = First { + const first = First { name = "John", }; - std.assert(first.name == "John", message: "object instance, field access"); + std\assert(first.name == "John", message: "object instance, field access"); first.age = 21; - std.assert(first.age == 21, message: "field assignment"); + std\assert(first.age == 21, message: "field assignment"); first.sayHello(); } object Second { - static int nextId = -1; + static nextId: int = -1; - int id, + id: int, static fun init() > Second { Second.nextId = Second.nextId + 1; @@ -38,7 +38,7 @@ object Second { } test "Object with static fields" { - Second second = Second.init(); + const second = Second.init(); - std.assert(second.id == Second.nextId, message: "could use static fields"); -} \ No newline at end of file + std\assert(second.id == Second.nextId, message: "could use static fields"); +} diff --git a/tests/008-inline-catch.buzz b/tests/008-inline-catch.buzz index 04cd3406..642a2610 100644 --- a/tests/008-inline-catch.buzz +++ b/tests/008-inline-catch.buzz @@ -10,9 +10,9 @@ fun willFailVoid() > void !> str { } test "Inline catch clauses" { - std.assert((willFail() catch 0) == 0, message: "error or default value"); + std\assert((willFail() catch 0) == 0, message: "error or default value"); } test "Inline catch void" { willFailVoid() catch void; -} \ No newline at end of file +} diff --git a/tests/009-gc.buzz b/tests/009-gc.buzz index 94f7cddd..2bce546c 100644 --- a/tests/009-gc.buzz +++ b/tests/009-gc.buzz @@ -1,10 +1,10 @@ import "std"; import "gc"; -bool collectorCalled = false; +var collectorCalled = false; object Kill { - int yo = -1, + yo: int = -1, fun collect() > void { collectorCalled = true; @@ -12,18 +12,18 @@ object Kill { } test "GC, collecting unreferenced objects" { - int i = 0; - _ = Kill{}; | Should be kept longer - while (i < 100) { - _ = Kill{ yo = i }; | Should be collected since not referenced anywhere + var i = 0; + const _ = Kill{}; // Should be kept longer + while (i < 1000) { + const _ = Kill{ yo = i }; // Should be collected since not referenced anywhere i = i + 1; } - const int before = gc.allocated(); + const before = gc\allocated(); - gc.collect(); + gc\collect(); - std.assert(gc.allocated() <= before, message: "Garbage was collected"); - std.assert(collectorCalled, message: "Object collector was called"); -} \ No newline at end of file + std\assert(gc\allocated() <= before, message: "Garbage was collected"); + std\assert(collectorCalled, message: "Object collector was called"); +} diff --git a/tests/010-placeholder-cycle.buzz b/tests/010-placeholder-cycle.buzz index 8374d15d..aa702c42 100644 --- a/tests/010-placeholder-cycle.buzz +++ b/tests/010-placeholder-cycle.buzz @@ -1,15 +1,15 @@ import "std"; object A { - B b + b: B } object B { - A a + a: A } object Node { - Node another, + another: Node, fun something() > Node { return this.another.somethingelse(); @@ -21,6 +21,6 @@ object Node { } test "Cyclic placeholders" { - std.print("{A}"); - std.print("{B}"); -} \ No newline at end of file + std\print("{A}"); + std\print("{B}"); +} diff --git a/tests/011-list-map-properties.buzz b/tests/011-list-map-properties.buzz index f8d7c479..8dc3c369 100644 --- a/tests/011-list-map-properties.buzz +++ b/tests/011-list-map-properties.buzz @@ -1,12 +1,12 @@ import "std"; object Hey { - [int] ages, - {int: str} names, + ages: [int], + names: {int: str}, } test "List and Map as Object properties" { - Hey hey = Hey{ + const hey = Hey{ ages = [, 1, 2, 3], names = { , @@ -14,6 +14,6 @@ test "List and Map as Object properties" { }, }; - std.assert(hey.ages[0] == 1, message: "list access"); - std.assert(hey.names[1] == "hello", message: "map access"); -} \ No newline at end of file + std\assert(hey.ages[0] == 1, message: "list access"); + std\assert(hey.names[1] == "hello", message: "map access"); +} diff --git a/tests/012-lambda.buzz b/tests/012-lambda.buzz index b7627e92..2caa6feb 100644 --- a/tests/012-lambda.buzz +++ b/tests/012-lambda.buzz @@ -1,23 +1,23 @@ import "std"; test "Lambda/Anonymous functions" { - Function(int n) > int mul = fun (int n) > int => n * 2; + const mul: fun (n: int) > int = fun (n: int) > int => n * 2; - std.assert(mul(1) == 2, message: "called a lambda function"); + std\assert(mul(1) == 2, message: "called a lambda function"); } -fun callThis(Function(int n) > int fn, int arg) > int { +fun callThis(fn: fun (n: int) > int, arg: int) > int { return fn(arg); } 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 (n: int) > int { return n * n; })(10) == 100, message: "called anonymous function"); + std\assert((fun (n: int) > int => n * n)(10) == 100, message: "called lambda function"); + std\assert(callThis(fun (n: int) > int => n * 2, arg: 2) == 4, message: "called a function from a function"); } -fun mul(int a, int b) > int => a * b; +fun mul(a: int, b: int) > int => a * b; test "Any function can be an arrow function" { - std.assert(mul(a: 2, b: 2) == 4, message: "arrow function"); -} \ No newline at end of file + std\assert(mul(a: 2, b: 2) == 4, message: "arrow function"); +} diff --git a/tests/013-import-export.buzz b/tests/013-import-export.buzz index 1ed83e3d..9bd1a643 100644 --- a/tests/013-import-export.buzz +++ b/tests/013-import-export.buzz @@ -1,10 +1,10 @@ import "tests/utils/testing" as testing; -int mine = 42; +const mine = 42; test "Using a function coming from an import" { - testing.PrefixMe me = testing.PrefixMe{}; - testing.assert(me.name == "Joe", message: "prefixed global works as type"); - testing.assert(testing.hey("world") == mine, message: "unexported symbol is reachable"); - testing.assert(true, message: "yeah!"); -} \ No newline at end of file + const me = testing\PrefixMe{}; + testing\assert(me.name == "Joe", message: "prefixed global works as type"); + testing\assert(testing\hey("world") == mine, message: "unexported symbol is reachable"); + testing\assert(true, message: "yeah!"); +} diff --git a/tests/014-import-lib.buzz b/tests/014-import-lib.buzz index fe87c4b0..d171655a 100644 --- a/tests/014-import-lib.buzz +++ b/tests/014-import-lib.buzz @@ -1,6 +1,6 @@ import print, assert from "std"; test "Using a function coming from a library" { - std.assert(true, message: "yeah!"); - std.print("wat"); + std\assert(true, message: "yeah!"); + std\print("wat"); } \ No newline at end of file diff --git a/tests/015-interpolation.buzz b/tests/015-interpolation.buzz index 412ce3b8..0c0e8e68 100644 --- a/tests/015-interpolation.buzz +++ b/tests/015-interpolation.buzz @@ -1,26 +1,26 @@ import "std"; test "Escape sequences" { - std.print("\{escaped interpolation}, \nhello\tworld, backslash \\ \"hey\""); + std\print("\{escaped interpolation}, \nhello\tworld, backslash \\ \"hey\""); } test "String interpolation" { - str name = "joe"; - int age = 12; + const name = "joe"; + const age = 12; - std.assert( + std\assert( "{"$"} hello {name} i'm {age} years old {3+4}" == "$ hello joe i'm 12 years old 7", message: "interpolation" ); - std.assert("not starting with a {name} {age} yeah!" + std\assert("not starting with a {name} {age} yeah!" == "not starting with a joe 12 yeah!", message: "interpolation order"); - std.assert("\60\61\62" == "<=>", message: "raw char"); + std\assert("\60\61\62" == "<=>", message: "raw char"); } test "Printing empty string" { - std.print(""); -} \ No newline at end of file + std\print(""); +} diff --git a/tests/016-optionals.buzz b/tests/016-optionals.buzz index 27d287a1..e4bd0911 100644 --- a/tests/016-optionals.buzz +++ b/tests/016-optionals.buzz @@ -1,67 +1,67 @@ import "std"; test "Optional force unwrapping with `!`" { - | Note: trying to force unwrap a null value raises an uncatchable error - | Dart allows to catch an null unwrap but swift doesn't - | I think it's saner for it to not be catchable but to provides safe way to unwrap it - str? hello = "hello world"; + // Note: trying to force unwrap a null value raises an uncatchable error + // Dart allows to catch an null unwrap but swift doesn't + // I think it's saner for it to not be catchable but to provides safe way to unwrap it + const hello: str? = "hello world"; - std.assert(hello! == "hello world", message: "Could force unwrap an optional"); + std\assert(hello! == "hello world", message: "Could force unwrap an optional"); } test "Optional graceful unwrapping with `?`" { - [int]? optList = [1, 2, 3]; + const optList: [int]? = [1, 2, 3]; - std.assert(optList?.len() == 3, message: "could unwrap optList"); + std\assert(optList?.len() == 3, message: "could unwrap optList"); } object Me { - [int]? list + list: [int]? } test "Optional chaining" { - Me? me = Me{ + const me: Me? = Me{ list = [1, 2, 3], }; - std.assert(me?.list?.len() == 3, message: "chaining optionals work"); + std\assert(me?.list?.len() == 3, message: "chaining optionals work"); - Me? you = null; + const you: Me? = null; - std.assert(you?.list?.len() == null, message: "chaining optionals work"); + std\assert(you?.list?.len() == null, message: "chaining optionals work"); } test "Null coalescing operator" { - str? hello = null; + const hello: str? = null; - std.assert(hello ?? "world" == "world", message: "null coalescing"); + std\assert(hello ?? "world" == "world", message: "null coalescing"); } test "Unwrap map subscript" { - {str: str} map = { + const map = { "yo": "lo", "mo": "jo", }; - std.assert(map["yo"]?.len() == 2, message: "could unwrap map subscript"); + std\assert(map["yo"]?.len() == 2, message: "could unwrap map subscript"); } object You { - str name = "joe" + name: str = "joe" } test "Field access on map subscript" { - {str: You} map = { + const map = { "yo": You{} }; - std.assert(map["yo"]?.name == "joe", message: "could field access map subscript"); + std\assert(map["yo"]?.name == "joe", message: "could field access map subscript"); } object A { - static A? instance = null; + static instance: A? = null; - str msg, + msg: str, fun hello() > str { return this.msg; @@ -72,4 +72,4 @@ test "Check ahead" { A.instance = A{ msg = "hello" }; _ = A.instance?.hello(); -} \ No newline at end of file +} diff --git a/tests/017-for.buzz b/tests/017-for.buzz index ba299e82..e0b95f66 100644 --- a/tests/017-for.buzz +++ b/tests/017-for.buzz @@ -1,19 +1,19 @@ import "std"; test "for loop" { - int sum = 0; - for (int i = 0; i < 10; i = i + 1) { + var sum = 0; + for (i: int = 0; i < 10; i = i + 1) { sum = sum + i; } - std.assert(sum == 45, message: "for loop"); + std\assert(sum == 45, message: "for loop"); } test "multiple variable and expressions in for loop" { - int sum = 0; - for (int i = 0, int j = 9; i < 10 and j >= 0; i = i + 1, j = j - 1) { + var sum = 0; + for (i: int = 0, j: int = 9; i < 10 and j >= 0; i = i + 1, j = j - 1) { sum = sum + i + j; } - std.assert(sum == 90, message: "multiple var loop"); + std\assert(sum == 90, message: "multiple var loop"); } diff --git a/tests/018-foreach.buzz b/tests/018-foreach.buzz index 4e1716c0..c33b2445 100644 --- a/tests/018-foreach.buzz +++ b/tests/018-foreach.buzz @@ -1,36 +1,36 @@ import "std"; test "foreach on list" { - [int] list = [1, 2, 3]; + const list = [1, 2, 3]; - int sum = 0; - foreach (int item in list) { + var sum = 0; + foreach (item in list) { sum = sum + item; } - std.assert(sum == 6, message: "foreach on list"); + std\assert(sum == 6, message: "foreach on list"); } test "list.next" { - [int] list = [1, 2, 3]; + const list = [1, 2, 3]; - std.assert(list.next(null) == 0, message: "calling next native"); - std.assert(list.next(0) == 1, message: "calling next native"); + std\assert(list.next(null) == 0, message: "calling next native"); + std\assert(list.next(0) == 1, message: "calling next native"); } test "foreach on map" { - {str: int} map = { + const map = { "one": 1, "two": 2, "three": 3 }; - int sum = 0; - foreach (int value in map) { + var sum = 0; + foreach (value in map) { sum = sum + value; } - std.assert(sum == 6, message: "foreach on map"); + std\assert(sum == 6, message: "foreach on map"); } enum Hey { @@ -40,39 +40,39 @@ enum Hey { } test "foreach on enum" { - int sum = 0; - foreach (Hey case in Hey) { + var sum = 0; + foreach (case in Hey) { sum = sum + case.value; } - std.assert(sum == 3, message: "foreach on enum"); + std\assert(sum == 3, message: "foreach on enum"); } test "foreach on str" { - str hello = ""; - foreach (str char in "hello world") { + var hello = ""; + foreach (char in "hello world") { hello = "{hello}{char}"; } - std.assert(hello == "hello world", message: "foreach on str"); + std\assert(hello == "hello world", message: "foreach on str"); } test "Omit key in foreach" { - int sum = 0; - foreach (int n in [1, 2, 3]) { + var sum = 0; + foreach (n in [1, 2, 3]) { sum = sum + n; } - std.assert(sum == 6, message: "Could omit list key"); + std\assert(sum == 6, message: "Could omit list key"); - str hello = ""; - foreach (str char in "hello") { + var hello = ""; + foreach (char in "hello") { hello = "{hello}{char}"; } - std.assert(hello == "hello", message: "Could omit string key"); + std\assert(hello == "hello", message: "Could omit string key"); sum = 0; - foreach (int n in {"hello": 1, "world": 2}) { + foreach (n in {"hello": 1, "world": 2}) { sum = sum + n; } - std.assert(sum == 3, message: "Could omit map key"); -} \ No newline at end of file + std\assert(sum == 3, message: "Could omit map key"); +} diff --git a/tests/019-is.buzz b/tests/019-is.buzz index 64534f5d..862e62eb 100644 --- a/tests/019-is.buzz +++ b/tests/019-is.buzz @@ -1,7 +1,7 @@ import "std"; object MyObj { - int id = 1, + id: int = 1, fun bound() > bool { return true; @@ -14,21 +14,21 @@ enum MyEnum { three, } -fun myFun(int id) > int { +fun myFun(id: int) > int { return id * 2; } test "`is` operator" { - std.assert(12 is int, message: "`is` on int"); - std.assert(true is bool, message: "`is` on bool"); - std.assert("yo" is str, message: "`is` on str"); + std\assert(12 is int, message: "`is` on int"); + std\assert(true is bool, message: "`is` on bool"); + std\assert("yo" is str, message: "`is` on str"); - std.assert(MyObj{} is MyObj, message: "`is` for an object instance"); - std.assert(MyEnum.one is MyEnum, message: "`is` for an enum instance"); - std.assert(myFun is Function(int id) > int, message: "`is` for a function"); + std\assert(MyObj{} is MyObj, message: "`is` for an object instance"); + std\assert(MyEnum.one is MyEnum, message: "`is` for an enum instance"); + std\assert(myFun is fun (id: int) > int, message: "`is` for a function"); - std.assert([, 1,2,3] is [int], message: "`is` on a list"); - std.assert({, "one": 1} is {str: int}, message: "`is` on a map"); - | TODO: should be `Function(MyObj) > bool` - std.assert(MyObj{}.bound is Function() > bool, message: "`is` on bound method"); -} \ No newline at end of file + std\assert([, 1,2,3] is [int], message: "`is` on a list"); + std\assert({, "one": 1} is {str: int}, message: "`is` on a map"); + // TODO: should be `fun (MyObj) > bool` + std\assert(MyObj{}.bound is fun () > bool, message: "`is` on bound method"); +} diff --git a/tests/021-upvalues.buzz b/tests/021-upvalues.buzz index a7345214..3f031cc0 100644 --- a/tests/021-upvalues.buzz +++ b/tests/021-upvalues.buzz @@ -1,12 +1,12 @@ import "std"; -fun upvals() > Function() { - int upvalue = 12; - str up = "up"; +fun upvals() > fun () { + const upvalue = 12; + const up = "up"; - return fun () > void => std.print("{upvalue} {up}"); + return fun () > void => std\print("{upvalue} {up}"); } test "Upvalues" { upvals()(); -} \ No newline at end of file +} diff --git a/tests/022-io.buzz b/tests/022-io.buzz index 1e0a7ca4..e607b408 100644 --- a/tests/022-io.buzz +++ b/tests/022-io.buzz @@ -3,40 +3,40 @@ import "io"; import "fs"; test "Write & read a file" { - var file = io.File.open("./hello.txt", mode: io.FileMode.write); + var file = io\File.open("./hello.txt", mode: io\FileMode.write); file.write("Hello World"); file.close(); - | Now read it - var fileB = io.File.open("./hello.txt", mode: io.FileMode.read); + // Now read it + var fileB = io\File.open("./hello.txt", mode: io\FileMode.read); - std.assert(file.readAll() == "Hello World", message: "Could write and read a file"); + std\assert(file.readAll() == "Hello World", message: "Could write and read a file"); fileB.close(); - fs.delete("./hello.txt"); + fs\delete("./hello.txt"); } test "Write on stdout" { - io.stdout.write("Hello World !\n"); + io\stdout.write("Hello World !\n"); } test "Read by lines" { - var file = io.File.open("./README.md", mode: io.FileMode.read); + var file = io\File.open("./README.md", mode: io\FileMode.read); - for (int lines = 0, str? line = ""; line != null; line = file.readLine(), lines = lines + 1) { - std.print("{lines}: {line}"); + for (lines: int = 0, line: str? = ""; line != null; line = file.readLine(), lines = lines + 1) { + std\print("{lines}: {line}"); } file.close(); } test "Read" { - var file = io.File.open("./README.md", mode: io.FileMode.read); + var file = io\File.open("./README.md", mode: io\FileMode.read); - std.assert(file.read(18) == "

", message: "Can read n bytes"); + std\assert(file.read(18) == "

", message: "Can read n bytes"); file.close(); -} \ No newline at end of file +} diff --git a/tests/023-std.buzz b/tests/023-std.buzz index 546f142f..cd30421d 100644 --- a/tests/023-std.buzz +++ b/tests/023-std.buzz @@ -1,23 +1,23 @@ import "std"; -test "std.parseInt/Float" { - std.assert(std.parseInt("12") == 12, message: "Could parse int"); - std.assert(std.parseFloat("12.42") == 12.42, message: "Could parse float"); - std.assert(std.parseInt("not a number") == null, message: "Doesn't parse stupid shit"); +test "std\parseInt/Float" { + std\assert(std\parseInt("12") == 12, message: "Could parse int"); + std\assert(std\parseFloat("12.42") == 12.42, message: "Could parse float"); + std\assert(std\parseInt("not a number") == null, message: "Doesn't parse stupid shit"); - std.assert(std.toInt(23.34) == 23, message: "Could cast float to int"); - std.assert(std.toFloat(23) == 23.0, message: "Could cast int to float"); - std.assert(std.toUd(23) is ud, message: "Could cast int to ud"); - std.assert(std.toUd(23.0) is ud, message: "Could cast float to ud"); + std\assert(std\toInt(23.34) == 23, message: "Could cast float to int"); + std\assert(std\toFloat(23) == 23.0, message: "Could cast int to float"); + std\assert(std\toUd(23) is ud, message: "Could cast int to ud"); + std\assert(std\toUd(23.0) is ud, message: "Could cast float to ud"); - std.assert(std.parseUd("42") == std.toUd(42), message: "Could parse ud"); + std\assert(std\parseUd("42") == std\toUd(42), message: "Could parse ud"); } test "char" { - std.assert(std.char(65) == "A", message: "char"); + std\assert(std\char(65) == "A", message: "char"); } test "random" { - std.assert(std.random(min: 5, max: 10) >= 5, message: "random range"); - std.assert(std.random(max: 10) <= 10, message: "random range"); + std\assert(std\random(min: 5, max: 10) >= 5, message: "random range"); + std\assert(std\random(max: 10) <= 10, message: "random range"); } \ No newline at end of file diff --git a/tests/024-os.buzz b/tests/024-os.buzz index 0f64cabb..9c5433a9 100644 --- a/tests/024-os.buzz +++ b/tests/024-os.buzz @@ -1,27 +1,27 @@ import "std"; import "os" as os; -test "os.env" { - std.assert(os.env("HOME") != null, message: "could get env variable"); +test "os\env" { + std\assert(os\env("HOME") != null, message: "could get env variable"); } -test "os.time" { - std.assert(os.time() > 0, message: "Got time"); +test "os\time" { + std\assert(os\time() > 0, message: "Got time"); } -test "os.tmpDir" { - | TODO: replace by .len check - std.assert(os.tmpDir() != "", message: "Got system tmp dir"); +test "os\tmpDir" { + // TODO: replace by .len check + std\assert(os\tmpDir() != "", message: "Got system tmp dir"); } -test "os.tmpFilename" { - std.assert(os.tmpFilename("buzz_test") != "", message: "Got tmp file name"); +test "os\tmpFilename" { + std\assert(os\tmpFilename("buzz_test") != "", message: "Got tmp file name"); } -test "os.execute" { - std.assert(os.execute(["./zig-out/bin/buzz", "--version"]) == 0, message: "Could execute a command"); +test "os\execute" { + std\assert(os\execute(["./zig-out/bin/buzz", "--version"]) == 0, message: "Could execute a command"); } -test "os.sleep" { - os.sleep(500.0); +test "os\sleep" { + os\sleep(500.0); } \ No newline at end of file diff --git a/tests/025-fs.buzz b/tests/025-fs.buzz index 7802f932..3af8da63 100644 --- a/tests/025-fs.buzz +++ b/tests/025-fs.buzz @@ -1,51 +1,51 @@ import "std"; import "fs" as fs; -test "fs.cwd" { - std.assert(fs.currentDirectory() != "", message: "Could get cwd"); +test "fs\cwd" { + std\assert(fs\currentDirectory() != "", message: "Could get cwd"); } test "mkDir/rm" { - fs.makeDirectory("yo"); - fs.makeDirectory("{fs.currentDirectory()}/yo2"); + fs\makeDirectory("yo"); + fs\makeDirectory("{fs\currentDirectory()}/yo2"); - fs.delete("yo"); - fs.delete("{fs.currentDirectory()}/yo2"); + fs\delete("yo"); + fs\delete("{fs\currentDirectory()}/yo2"); } test "ls" { - bool containsREADME = false; - foreach (str el in fs.list(fs.currentDirectory())) { - str _ = "hello there!"; + var containsREADME = false; + foreach (el in fs\list(fs\currentDirectory())) { + _ = "hello there!"; if (el == "README.md") { containsREADME = true; break; } } - str anotherRandomLocal = "bye there!"; + const anotherRandomLocal = "bye there!"; - std.assert(anotherRandomLocal == "bye there!", message: "foreach break is wrong"); + std\assert(anotherRandomLocal == "bye there!", message: "foreach break is wrong"); - std.assert(containsREADME, message: "Could list element in current directory"); + std\assert(containsREADME, message: "Could list element in current directory"); - foreach (str el in fs.list("/doesnotexist") catch ["wentwrong"]) { - std.assert(el == "wentwrong", message: "Trying to list a non existent directory raised an error"); + foreach (el in fs\list("/doesnotexist") catch ["wentwrong"]) { + std\assert(el == "wentwrong", message: "Trying to list a non existent directory raised an error"); } } test "move" { - fs.move(source: "README.md", destination: "src/README.md"); + fs\move(source: "README.md", destination: "src/README.md"); - std.assert( - fs.list("src").indexOf("README.md") != null, + std\assert( + fs\list("src").indexOf("README.md") != null, message: "Moved file to expected location" ); - fs.move(source: "src/README.md", destination: "README.md"); + fs\move(source: "src/README.md", destination: "README.md"); - std.assert( - fs.list(".").indexOf("README.md") != null, + std\assert( + fs\list(".").indexOf("README.md") != null, message: "Moved file to expected location" ); -} \ No newline at end of file +} diff --git a/tests/026-break-continue.buzz b/tests/026-break-continue.buzz index 61b8ffae..aa29131a 100644 --- a/tests/026-break-continue.buzz +++ b/tests/026-break-continue.buzz @@ -1,7 +1,7 @@ import "std"; test "break statement" { - int i = 0; + var i = 0; while (i < 10) { i = i + 1; @@ -10,11 +10,11 @@ test "break statement" { } } - std.assert(i == 3, message: "break"); + std\assert(i == 3, message: "break"); } test "continue statement" { - int i = 0; + var i = 0; while (i < 10) { i = i + 1; @@ -25,5 +25,5 @@ test "continue statement" { i = i + 1; } - std.assert(i == 11, message: "break"); -} \ No newline at end of file + std\assert(i == 11, message: "break"); +} diff --git a/tests/027-run-file.buzz b/tests/027-run-file.buzz index a8326e22..6fc28779 100644 --- a/tests/027-run-file.buzz +++ b/tests/027-run-file.buzz @@ -2,18 +2,18 @@ import "std"; import "io"; test "runFile" { - io.runFile("tests/utils/testing.buzz"); + io\runFile("tests/utils/testing.buzz"); - std.assert(true, message: "Could run a buzz file"); + std\assert(true, message: "Could run a buzz file"); } test "run non existent file" { - bool errorRaised = false; + var errorRaised = false; try { - io.runFile("tests/utils/testingsldkfj.buzz"); + io\runFile("tests/utils/testingsldkfj.buzz"); } catch { errorRaised = true; } - std.assert(errorRaised, message: "Non existent file raised an error"); -} \ No newline at end of file + std\assert(errorRaised, message: "Non existent file raised an error"); +} diff --git a/tests/028-math.buzz b/tests/028-math.buzz index 7cc0bb75..d9c77bc6 100644 --- a/tests/028-math.buzz +++ b/tests/028-math.buzz @@ -2,21 +2,21 @@ import "std"; import "math" as math; test "math" { - std.assert(math.abs(-12.234) == 12.234, message: "math.abs"); - std.assert(math.acos(0.1) == 1.4706289056333368, message: "math.acos"); - std.assert(math.asin(0.1) == 0.1001674211615598, message: "math.asin"); - std.assert(math.atan(0.1) == 0.09966865249116204, message: "math.atan"); - std.assert(math.ceil(12.234) == 13, message: "math.ceil"); - std.assert(math.cos(12.234) == 0.9452715049027691, message: "math.cos"); - std.assert(math.exp(12.234) == 205664.19575705, message: "math.exp"); - std.assert(math.floor(12.234) == 12, message: "math.floor"); - std.assert(math.sin(12.234) == -0.3262848173281347, message: "math.sin"); - std.assert(math.sqrt(12.234) == 3.4977135388707863, message: "math.sqrt"); - std.assert(math.tan(12.234) == -0.34517576763481983, message: "math.tan"); + std\assert(math\abs(-12.234) == 12.234, message: "math\\abs"); + std\assert(math\acos(0.1) == 1.4706289056333368, message: "math\\acos"); + std\assert(math\asin(0.1) == 0.1001674211615598, message: "math\\asin"); + std\assert(math\atan(0.1) == 0.09966865249116204, message: "math\\atan"); + std\assert(math\ceil(12.234) == 13, message: "math\\ceil"); + std\assert(math\cos(12.234) == 0.9452715049027691, message: "math\\cos"); + std\assert(math\exp(12.234) == 205664.19575705, message: "math\\exp"); + std\assert(math\floor(12.234) == 12, message: "math\\floor"); + std\assert(math\sin(12.234) == -0.3262848173281347, message: "math\\sin"); + std\assert(math\sqrt(12.234) == 3.4977135388707863, message: "math\\sqrt"); + std\assert(math\tan(12.234) == -0.34517576763481983, message: "math\\tan"); - std.assert(math.minInt(a: 12, b: 124) == 12, message: "math.min"); - std.assert(math.maxInt(a: 12, b: 124) == 124, message: "math.max"); + std\assert(math\minInt(a: 12, b: 124) == 12, message: "math\\min"); + std\assert(math\maxInt(a: 12, b: 124) == 124, message: "math\\max"); - std.assert(math.deg(2.0) == 114.59155902616439, message: "math.deg"); - std.assert(math.rad(math.deg(2.0)) == 2, message: "math.rad"); -} \ No newline at end of file + std\assert(math\deg(2.0) == 114.59155902616439, message: "math\\deg"); + std\assert(math\rad(math\deg(2.0)) == 2, message: "math\\rad"); +} diff --git a/tests/029-default-arguments.buzz b/tests/029-default-arguments.buzz index ccbc6284..edbfcaec 100644 --- a/tests/029-default-arguments.buzz +++ b/tests/029-default-arguments.buzz @@ -1,12 +1,12 @@ import "std"; -fun hey(str name = "Joe", int age = 12, str? father, int fourth = 1) > str +fun hey(name: str = "Joe", age: int = 12, father: str?, fourth: int = 1) > str => "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"); - std.assert(hey(age: 25) == "Hello Joe you're 25 null 1", message: "Could reorder or omit argument"); - std.assert(hey(father: "Doe") == "Hello Joe you're 12 Doe 1", message: "Could reorder or omit argument"); - std.assert(hey(fourth: 42) == "Hello Joe you're 12 null 42", message: "Could reorder or omit argument"); - std.assert(hey(fourth: 12, age: 44) == "Hello Joe you're 44 null 12", message: "Could reorder or omit argument"); -} \ No newline at end of file + std\assert(hey("John") == "Hello John you're 12 null 1", message: "Could reorder or omit argument"); + std\assert(hey(age: 25) == "Hello Joe you're 25 null 1", message: "Could reorder or omit argument"); + std\assert(hey(father: "Doe") == "Hello Joe you're 12 Doe 1", message: "Could reorder or omit argument"); + std\assert(hey(fourth: 42) == "Hello Joe you're 12 null 42", message: "Could reorder or omit argument"); + std\assert(hey(fourth: 12, age: 44) == "Hello Joe you're 44 null 12", message: "Could reorder or omit argument"); +} diff --git a/tests/030-str.buzz b/tests/030-str.buzz index e0febd38..25ca7f2f 100644 --- a/tests/030-str.buzz +++ b/tests/030-str.buzz @@ -1,47 +1,47 @@ import "std"; test "str subscript" { - std.assert("hello world"[1] == "e", message: "str subscript"); + std\assert("hello world"[1] == "e", message: "str subscript"); } test "str.len" { - std.assert("hello world".len() == 11, message: "str.len"); + std\assert("hello world".len() == 11, message: "str.len"); } test "str.byte" { - std.assert("hello world".byte(1) == 101, message: "str.byte"); + std\assert("hello world".byte(1) == 101, message: "str.byte"); } test "str.indexOf" { - std.assert("hello world".indexOf("world") == 6, message: "str.indexOf"); - std.assert("hello world".indexOf("moon") == null, message: "str.indexOf"); + std\assert("hello world".indexOf("world") == 6, message: "str.indexOf"); + std\assert("hello world".indexOf("moon") == null, message: "str.indexOf"); } test "str.split" { - [str] splits = "one,two,three".split(","); + const splits = "one,two,three".split(","); - std.assert(splits[0] == "one" and splits[1] == "two" and splits[2] == "three", message: "str.split"); + std\assert(splits[0] == "one" and splits[1] == "two" and splits[2] == "three", message: "str.split"); } test "str.sub" { - std.assert("hello world".sub(6) == "world", message: "str.sub"); - std.assert("hello world".sub(0, len: 5) == "hello", message: "str.sub"); + std\assert("hello world".sub(6) == "world", message: "str.sub"); + std\assert("hello world".sub(0, len: 5) == "hello", message: "str.sub"); } test "base64" { - std.assert("hello world".encodeBase64() == "aGVsbG8gd29ybGQ=", message: "could encode in b64"); - std.assert("aGVsbG8gd29ybGQ=".decodeBase64() == "hello world", message: "could encode in b64"); + std\assert("hello world".encodeBase64() == "aGVsbG8gd29ybGQ=", message: "could encode in b64"); + std\assert("aGVsbG8gd29ybGQ=".decodeBase64() == "hello world", message: "could encode in b64"); } test "upper/lower" { - std.assert("hello world!".upper() == "HELLO WORLD!", message: "upper"); - std.assert("HellO WorlD!".lower() == "hello world!", message: "lower"); + std\assert("hello world!".upper() == "HELLO WORLD!", message: "upper"); + std\assert("HellO WorlD!".lower() == "hello world!", message: "lower"); } test "hex/bin" { - std.assert("c3fcd3d76192e4007dfb496cca67e13b".bin().hex() == "c3fcd3d76192e4007dfb496cca67e13b", message: "hex/bin"); + std\assert("c3fcd3d76192e4007dfb496cca67e13b".bin().hex() == "c3fcd3d76192e4007dfb496cca67e13b", message: "hex/bin"); } test "trim" { - std.assert(" hello world \t\n".trim() == "hello world", message: "could trim str"); -} \ No newline at end of file + std\assert(" hello world \t\n".trim() == "hello world", message: "could trim str"); +} diff --git a/tests/031-json.buzz b/tests/031-json.buzz index 935c06fe..1cc420fc 100644 --- a/tests/031-json.buzz +++ b/tests/031-json.buzz @@ -2,26 +2,26 @@ import "std"; import "serialize"; test "Json.encode" { - {str: any} data = { + const data = { "hello": "world", "bye": 42, }; - std.assert( - serialize.jsonEncode(serialize.Boxed.init(data)) == `\{"hello":"world","bye":42}`, + std\assert( + serialize\jsonEncode(serialize\Boxed.init(data)) == `\{"hello":"world","bye":42}`, message: "valid encode" ); } test "Json.decode" { - std.assert( - serialize.jsonDecode(`[ -12, true, "hello" ]`).listValue()[2].string() == "hello", + std\assert( + serialize\jsonDecode(`[ -12, true, "hello" ]`).listValue()[2].string() == "hello", message: "could decode simple JSON" ); } test "Boxed.q" { - {str: any} data = { + const data = { "submap": { , "subsubmap": { @@ -32,7 +32,7 @@ test "Boxed.q" { } }; - var boxed = serialize.Boxed.init(data); + var boxed = serialize\Boxed.init(data); - std.assert(boxed.q(["submap", "subsubmap", "one"]).integer() == 1, message: "Boxed.q"); -} \ No newline at end of file + std\assert(boxed.q(["submap", "subsubmap", "one"]).integer() == 1, message: "Boxed.q"); +} diff --git a/tests/032-debug.buzz b/tests/032-debug.buzz index ab47a6c0..603691a0 100644 --- a/tests/032-debug.buzz +++ b/tests/032-debug.buzz @@ -1,18 +1,18 @@ import "debug"; -| import "serialize"; +// import "serialize"; -| TODO: put back one debug.ast is reactivated -| test "Get AST" { -| str source = debug.ast(` -| import \"std\"; -| -| fun main([str] _) > void => std.print(\"hello world\"); -| `, scriptName: "test"); -| -| Boxed jsonAST = jsonDecode(source); -| -| std.print(jsonEncode(jsonAST)); -| } +// TODO: put back one debug\ast is reactivated +// test "Get AST" { +// str source = debug\ast(` +// import \"std\"; +// +// fun main([str] _) > void => std\print(\"hello world\"); +// `, scriptName: "test"); +// +// Boxed jsonAST = jsonDecode(source); +// +// std\print(jsonEncode(jsonAST)); +// } enum MyEnum { One, @@ -27,15 +27,15 @@ enum(str) MyStringEnum { } object Data { - [int] data, + data: [int], } object MyObject { - str name, - int age = 12, - Data data, + name: str, + age: int = 12, + data: Data, - static fun init(str name, int age) > MyObject { + static fun init(name: str, age: int) > MyObject { return MyObject{ name = name, age = age, @@ -45,14 +45,14 @@ object MyObject { } test "dump" { - [int] list = [1, 2, 3, 4]; - {str: int} map = { + const list = [1, 2, 3, 4]; + const map = { "one": 1, "two": 2, "three": 3, }; - MyObject instance = MyObject{ + const instance = MyObject{ name = "joe", age = 35, data = Data{ @@ -60,11 +60,11 @@ test "dump" { }, }; - debug.dump(list); - debug.dump(map); - debug.dump(instance); - debug.dump(MyStringEnum.One); - debug.dump(MyEnum.One); - debug.dump("hello world"); - debug.dump($"hello .*"); -} \ No newline at end of file + debug\dump(list); + debug\dump(map); + debug\dump(instance); + debug\dump(MyStringEnum.One); + debug\dump(MyEnum.One); + debug\dump("hello world"); + debug\dump($"hello .*"); +} diff --git a/tests/033-invoke.buzz b/tests/033-invoke.buzz index ce891638..74eee434 100644 --- a/tests/033-invoke.buzz +++ b/tests/033-invoke.buzz @@ -1,16 +1,16 @@ import "std"; object A { - [A] list, + list: [A], fun hello() > A { - std.print("hello"); + std\print("hello"); return this; } } test "Chained invoke" { - A a = A{ + const a = A{ list = [ A{ list = [ A{ list = [] } ] @@ -22,4 +22,4 @@ test "Chained invoke" { }; _ = a.list[0].hello().list[0].hello(); -} \ No newline at end of file +} diff --git a/tests/034-scope.buzz b/tests/034-scope.buzz index daa69b63..dd9c85f8 100644 --- a/tests/034-scope.buzz +++ b/tests/034-scope.buzz @@ -1,30 +1,30 @@ import "std"; test "locals inside a foreach" { - str hello = ""; + const hello = ""; - foreach (str _ in "hello world") { - str new = "yo"; - str old = "lo"; + foreach (_ in "hello world") { + const new = "yo"; + const old = "lo"; - foreach (str _ in "goodbye world") { - str newnew = "yoyo"; - str oldold = "lolo"; + foreach (_ in "goodbye world") { + const newnew = "yoyo"; + const oldold = "lolo"; - std.assert(new == "yo", message: "locals are ok"); - std.assert(old == "lo", message: "locals are ok"); - std.assert(newnew == "yoyo", message: "locals are ok"); - std.assert(oldold == "lolo", message: "locals are ok"); + std\assert(new == "yo", message: "locals are ok"); + std\assert(old == "lo", message: "locals are ok"); + std\assert(newnew == "yoyo", message: "locals are ok"); + std\assert(oldold == "lolo", message: "locals are ok"); } - std.assert(hello == ""); + std\assert(hello == ""); } - for (int i = 0; i < 3; i = i + 1) { - str new = "yo"; - str old = "lo"; + for (i: int = 0; i < 3; i = i + 1) { + const new = "yo"; + const old = "lo"; - std.assert(new == "yo", message: "locals are ok"); - std.assert(old == "lo", message: "locals are ok"); + std\assert(new == "yo", message: "locals are ok"); + std\assert(old == "lo", message: "locals are ok"); } -} \ No newline at end of file +} diff --git a/tests/035-const-expr.buzz b/tests/035-const-expr.buzz index 559f98d4..5d2d78b5 100644 --- a/tests/035-const-expr.buzz +++ b/tests/035-const-expr.buzz @@ -1,37 +1,37 @@ import "std"; -fun hello([str] name = ["John", "Doe"], {str: str} address = { "street": "somewhere street", "town": "New York" }) > void { - std.assert(name.len() == 2, message: "default arg is clone of the default value"); - std.assert(address.size() == 2, message: "default arg is clone of the default value"); +fun hello(name: [str] = ["John", "Doe"], address: {str: str} = { "street": "somewhere street", "town": "New York" }) > void { + std\assert(name.len() == 2, message: "default arg is clone of the default value"); + std\assert(address.size() == 2, message: "default arg is clone of the default value"); - std.print("Hello I'm {name[0]} {name[1]} I live at {address["street"]} in {address["town"]}"); + std\print("Hello I'm {name[0]} {name[1]} I live at {address["street"]} in {address["town"]}"); name.append("Yolo"); address["country"] = "US"; } object A { - [int] list = [1, 2, 3], - {str: int} map = { "yo": 1 }, + list: [int] = [1, 2, 3], + map: {str: int} = { "yo": 1 }, } test "Constant expression" { hello(); hello(); - A a = A{}; - A b = A{}; + const a = A{}; + const b = A{}; - std.assert(a.list != b.list, message: "object default value were cloned"); - std.assert(a.map != b.map, message: "object default value were cloned"); + std\assert(a.list != b.list, message: "object default value were cloned"); + std\assert(a.map != b.map, message: "object default value were cloned"); a.list.append(4); - std.assert(a.list.len() == 4, message: "object default value were cloned"); - std.assert(b.list.len() == 3, message: "object default value were cloned"); + std\assert(a.list.len() == 4, message: "object default value were cloned"); + std\assert(b.list.len() == 3, message: "object default value were cloned"); a.map["lo"] = 4; - std.assert(a.map.size() == 2, message: "object default value were cloned"); - std.assert(b.map.size() == 1, message: "object default value were cloned"); -} \ No newline at end of file + std\assert(a.map.size() == 2, message: "object default value were cloned"); + std\assert(b.map.size() == 1, message: "object default value were cloned"); +} diff --git a/tests/036-pattern.buzz b/tests/036-pattern.buzz index e06b44cd..9484c193 100644 --- a/tests/036-pattern.buzz +++ b/tests/036-pattern.buzz @@ -1,39 +1,39 @@ import "std"; test "pattern.match" { - pat pattern = $"hello ([a-z]+)"; + const pattern = $"hello ([a-z]+)"; - [str]? results = pattern.match("All i want to say is hello joe! hello mundo!"); + const results = pattern.match("All i want to say is hello joe! hello mundo!"); - std.assert(results?.len() == 2, message: "1 match and 1 capture"); - std.assert(results![0] == "hello joe", message: "first is match"); - std.assert(results![1] == "joe", message: "second is capture"); + std\assert(results?.len() == 2, message: "1 match and 1 capture"); + std\assert(results![0] == "hello joe", message: "first is match"); + std\assert(results![1] == "joe", message: "second is capture"); } test "pattern.matchAll" { - pat pattern = $"hello ([a-z]+)"; + const pattern = $"hello ([a-z]+)"; - [[str]]? results = pattern.matchAll("All i want to say is hello joe!\nhello mundo!\nAnd hello neighbor..."); + const results = pattern.matchAll("All i want to say is hello joe!\nhello mundo!\nAnd hello neighbor..."); - std.assert(results?.len() == 3, message: "found 3 matches"); - std.assert(results![2].len() == 2, message: "1 match and 1 capture"); - std.assert(results![2][1] == "neighbor", message: "capture is correct"); + std\assert(results?.len() == 3, message: "found 3 matches"); + std\assert(results![2].len() == 2, message: "1 match and 1 capture"); + std\assert(results![2][1] == "neighbor", message: "capture is correct"); } test "Escaped pattern delimiter" { - pat pattern = $"hello \" world"; + const pattern = $"hello \" world"; - std.assert("{pattern}" == "hello \" world", message: "delimiter was properly escaped"); + std\assert("{pattern}" == "hello \" world", message: "delimiter was properly escaped"); } test "replace" { - std.assert( + std\assert( $"world".replace("All i want to say is hello world!", with: "mundo") == "All i want to say is hello mundo!", message: "replace" ); - std.assert( + std\assert( $"alright".replaceAll("he says: alright, alright, alright!", with: "check") == "he says: check, check, check!", message: "replaceAll" ); -} \ No newline at end of file +} diff --git a/tests/037-dead-branches.buzz b/tests/037-dead-branches.buzz index 29765229..665132cc 100644 --- a/tests/037-dead-branches.buzz +++ b/tests/037-dead-branches.buzz @@ -2,26 +2,26 @@ import "std"; test "if" { if (true) { - std.assert(true, message: "only this branch should be generated"); + std\assert(true, message: "only this branch should be generated"); } else { - std.assert(false, message: "unreachable"); + std\assert(false, message: "unreachable"); } } test "foreach" { - foreach (str _ in {}) { - std.assert(false, message: "unreachable"); + foreach (_ in {}) { + std\assert(false, message: "unreachable"); } } test "while" { while (false) { - std.assert(false, message: "unreachable"); + std\assert(false, message: "unreachable"); } } test "for" { - for (int i = 0; false; i = i + 1) { - std.assert(false, message: "unreachable"); + for (i: int = 0; false; i = i + 1) { + std\assert(false, message: "unreachable"); } -} \ No newline at end of file +} diff --git a/tests/038-fibers.buzz b/tests/038-fibers.buzz index ac107d7c..3550dd2f 100644 --- a/tests/038-fibers.buzz +++ b/tests/038-fibers.buzz @@ -1,34 +1,34 @@ import "std"; test "fiber" { - | Async call, creates a new fiber, yield type must be nullable because resume will return null when nothing yielded - fib counter = &count(10); + // Async call, creates a new fiber, yield type must be nullable because resume will return null when nothing yielded + const counter = &count(10); - | A fiber is over when a OP_RETURN as been executed - int sum = 0; + // A fiber is over when a OP_RETURN as been executed + var sum = 0; while (!counter.over()) { - | resume returns null if nothing was yielded and/or fiber is over + // resume returns null if nothing was yielded and/or fiber is over sum = sum + resume counter ?? 0; } - std.assert(counter.over(), message: "Fiber should be over now"); + std\assert(counter.over(), message: "Fiber should be over now"); - | resolve runs fiber until it's over and dismiss any yielded value along the way - std.assert(resolve counter == "Counting is done!", message: "Fiber is over we get its return value"); - std.assert(sum == 45, message: "Sum is good"); + // resolve runs fiber until it's over and dismiss any yielded value along the way + std\assert(resolve counter == "Counting is done!", message: "Fiber is over we get its return value"); + std\assert(sum == 45, message: "Sum is good"); - std.assert(resolve &count(10) == "Counting is done!", message: "Resolve without any resume"); + std\assert(resolve &count(10) == "Counting is done!", message: "Resolve without any resume"); - std.assert(std.currentFiber().isMain(), message: "We recognize main fiber"); + std\assert(std\currentFiber().isMain(), message: "We recognize main fiber"); } -| returns str, yields int -fun count(int n) > str *> int? { - std.assert(std.currentFiber() is fib, message: "Can get current fiber"); - std.assert(!std.currentFiber().isMain(), message: "Can know if fiber is main one"); +// returns str, yields int +fun count(n: int) > str *> int? { + std\assert(std\currentFiber() is fib, message: "Can get current fiber"); + std\assert(!std\currentFiber().isMain(), message: "Can know if fiber is main one"); - for (int i = 0; i < n; i = i + 1) { - | error or yield is ignored if not called with a async call? + for (i: int = 0; i < n; i = i + 1) { + // error or yield is ignored if not called with a async call? _ = yield i; } @@ -42,37 +42,37 @@ fun fail() > bool !> str { } fun caughFiberFail() > bool !> str { - fib fiber = &fail(); + const fiber = &fail(); return resolve fiber; } test "Throw inside a fiber" { - std.assert(caughFiberFail() catch true, message: "Caught an error from a fiber"); + std\assert(caughFiberFail() catch true, message: "Caught an error from a fiber"); } -fun closedUpvalue() > Function() > str { - str upvalue = "joe"; +fun closedUpvalue() > fun () > str { + const upvalue = "joe"; return fun () > str => "hello {upvalue}"; } test "Opened upvalue in fiber" { - str upvalue = "world"; + const upvalue = "world"; - Function() > str fiberFn = fun () > str => "hello {upvalue}"; + const fiberFn = fun () > str => "hello {upvalue}"; - std.assert(resolve &fiberFn() == "hello world", message: "Fiber could use an opened upvalue"); + std\assert(resolve &fiberFn() == "hello world", message: "Fiber could use an opened upvalue"); } test "Closed upvalue in fiber" { - std.assert(resolve &closedUpvalue()() == "hello joe", message: "Fiber could use a closed upvalue"); + std\assert(resolve &closedUpvalue()() == "hello joe", message: "Fiber could use a closed upvalue"); } test "Wrapping call inside complex expressions" { - {str: Function() > str} map = { + const map = { "hello": fun () > str => "hello world", }; - std.assert(resolve &map["hello"]?() == "hello world", message:"Could warp function call in a complex expression"); + std\assert(resolve &map["hello"]?() == "hello world", message:"Could warp function call in a complex expression"); } diff --git a/tests/039-buffer.buzz b/tests/039-buffer.buzz index 9567017d..875a9221 100644 --- a/tests/039-buffer.buzz +++ b/tests/039-buffer.buzz @@ -9,26 +9,26 @@ test "Reading and writing in a buffer" { buffer.writeFloat(1238.324); buffer.writeBoolean(true); - [int] expected = [ - 11, 0, 0, 0, | "hello world".len() - 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, | "hello world" - 158, 239, 167, 198, 75, 89, 147, 64, | 1238.324 - 1, | true + const expected = [ + 11, 0, 0, 0, // "hello world".len() + 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, // "hello world" + 158, 239, 167, 198, 75, 89, 147, 64, // 1238.324 + 1, // true ]; - foreach (int i, str char in buffer.toString()) { - std.assert(expected[i] == char.byte(0), message: "Buffer has expected content"); + foreach (i, char in buffer.toString()) { + std\assert(expected[i] == char.byte(0), message: "Buffer has expected content"); } - std.assert(buffer.len() == expected.len(), message: "wrote expected number of bytes"); + std\assert(buffer.len() == expected.len(), message: "wrote expected number of bytes"); - const int len = buffer.readInt() ?? -1; - std.assert(len == 11, message: "could read number"); + const len = buffer.readInt() ?? -1; + std\assert(len == 11, message: "could read number"); - std.assert(buffer.read(len) == "hello world", message: "could read n bytes"); - std.assert(buffer.readFloat() == 1238.324, message: "could read float"); - std.assert(buffer.readBoolean() == true, message: "could read boolean"); + std\assert(buffer.read(len) == "hello world", message: "could read n bytes"); + std\assert(buffer.readFloat() == 1238.324, message: "could read float"); + std\assert(buffer.readBoolean() == true, message: "could read boolean"); buffer.empty(); - std.assert(buffer.len() == 0, message: "could empty buffer"); -} \ No newline at end of file + std\assert(buffer.len() == 0, message: "could empty buffer"); +} diff --git a/tests/040-bitwise.buzz b/tests/040-bitwise.buzz index a4f754d8..67a18a75 100644 --- a/tests/040-bitwise.buzz +++ b/tests/040-bitwise.buzz @@ -1,10 +1,10 @@ import "std"; test "Bitwise" { - std.assert(15 << 3 == 120, message: "<<"); - std.assert(15 >> 3 == 1, message: ">>"); - std.assert(15 ^ 3 == 12, message: "^"); - std.assert(15 \ 3 == 15, message: "\\"); - std.assert(~15 == -16, message: "~"); - std.assert(12 & 23 == 4, message: "&"); + std\assert(15 << 3 == 120, message: "<<"); + std\assert(15 >> 3 == 1, message: ">>"); + std\assert(15 ^ 3 == 12, message: "^"); + std\assert(15 | 3 == 15, message: "\\"); + std\assert(~15 == -16, message: "~"); + std\assert(12 & 23 == 4, message: "&"); } \ No newline at end of file diff --git a/tests/041-iterator.buzz b/tests/041-iterator.buzz index c9501d90..ea20072d 100644 --- a/tests/041-iterator.buzz +++ b/tests/041-iterator.buzz @@ -1,11 +1,11 @@ import "std"; -fun fibonacci(int n) > void *> int? { - int n1 = 0; - int n2 = 1; - int? next = null; +fun fibonacci(n: int) > void *> int? { + var n1 = 0; + var n2 = 1; + var next: int? = null; - for (int i = 0; i < n; i = i + 1) { + for (i: int = 0; i < n; i = i + 1) { _ = yield n1; next = n1 + n2; n1 = n2; @@ -14,10 +14,10 @@ fun fibonacci(int n) > void *> int? { } test "finobacci generator" { - [int] suite = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; - int i = 0; - foreach (int n in &fibonacci(10)) { - std.assert(suite[i] == n, message: "could iterate over fiber"); + const suite = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + var i = 0; + foreach (n in &fibonacci(10)) { + std\assert(suite[i] == n, message: "could iterate over fiber"); i = i + 1; } @@ -26,7 +26,7 @@ test "finobacci generator" { object Hello { fun getRange() > [int] *> int? { var list = []; - foreach (int i in 0..10) { + foreach (i in 0..10) { _ = yield i; list.append(i); @@ -39,7 +39,7 @@ object Hello { test "dot async call" { var hello = Hello{}; - foreach (int i in &hello.getRange()) { - std.print("i {i}"); + foreach (i in &hello.getRange()) { + std\print("i {i}"); } } diff --git a/tests/042-anonymous-objects.buzz b/tests/042-anonymous-objects.buzz index f573d417..68be5524 100644 --- a/tests/042-anonymous-objects.buzz +++ b/tests/042-anonymous-objects.buzz @@ -1,6 +1,6 @@ import "std"; -fun getInfo() > obj{ str name, int age } { +fun getInfo() > obj{ name: str, age: int } { return .{ name = "Joe", age = 36, @@ -8,12 +8,12 @@ fun getInfo() > obj{ str name, int age } { } test "Anonymous objects" { - obj{ str name, int age } info = getInfo(); - | Two anonymous type matches - obj{ str name, int age } _ = info; + const info = getInfo(); + // Two anonymous type matches + _: obj{ name: str, age: int } = info; - std.assert(info.name == "Joe" and info.age == 36, message: "Could declare, instanciate and acces anonymous objects"); - std.assert(info is obj{ str name, int age }, message: "Type safety works with anonymous object"); + std\assert(info.name == "Joe" and info.age == 36, message: "Could declare, instanciate and acces anonymous objects"); + std\assert(info is obj{ name: str, age: int }, message: "Type safety works with anonymous object"); } test "Named variable init" { @@ -22,17 +22,17 @@ test "Named variable init" { const person = .{ name, age }; - std.assert(person.name == "Joe" and person.age == 42); + std\assert(person.name == "Joe" and person.age == 42); } -fun getPayload::(T data) > obj{ T data } { +fun getPayload::(data: T) > obj{ data: T } { return .{ data = data }; } test "Anonymous object with generics" { - obj{ int data } payload = getPayload::(42); + const payload = getPayload::(42); - std.assert(payload.data == 42, message: "Could use anonymous object with generic"); + std\assert(payload.data == 42, message: "Could use anonymous object with generic"); } diff --git a/tests/044-break-continue.buzz b/tests/044-break-continue.buzz index a060bf49..dd18d329 100644 --- a/tests/044-break-continue.buzz +++ b/tests/044-break-continue.buzz @@ -1,9 +1,8 @@ import "std"; test "continue properly jumps and closes scope" { - [int] list = [1, 2, 3, 4, 5]; - foreach (int value in list) { - str _ = "hello there!"; + foreach (value in 1..5) { + _ = "hello there!"; if (value == 3) { if (true) { continue; @@ -11,24 +10,23 @@ test "continue properly jumps and closes scope" { } } - str anotherRandomLocal = "bye there"; + const anotherRandomLocal = "bye there"; - std.assert(anotherRandomLocal == "bye there", message: "continue properly closed revelant scopes"); + std\assert(anotherRandomLocal == "bye there", message: "continue properly closed revelant scopes"); } test "break properly jumps and closes scope" { - [int] list = [1, 2, 3, 4, 5]; - foreach (int value in list) { - str _ = "hello there!"; + foreach (value in 1..5) { + _ = "hello there!"; if (value == 3) { if (true) { break; } } - str _ = "after break"; + _ = "after break"; } - str anotherRandomLocal = "bye there"; + const anotherRandomLocal = "bye there"; - std.assert(anotherRandomLocal == "bye there", message: "break properly closed revelant scopes"); -} \ No newline at end of file + std\assert(anotherRandomLocal == "bye there", message: "break properly closed revelant scopes"); +} diff --git a/tests/045-mutual-import.buzz b/tests/045-mutual-import.buzz index 83b647b0..fc069d41 100644 --- a/tests/045-mutual-import.buzz +++ b/tests/045-mutual-import.buzz @@ -3,8 +3,8 @@ import "tests/utils/import-b"; import "tests/utils/import-a"; test "Mutual import" { - std.print("t: {a.Hello}"); - b.printClass(); - std.print("{b.hello}"); - std.assert(b.hello is a.Hello, message: "multiple import of the same script produce the same globals"); -} \ No newline at end of file + std\print("t: {a\Hello}"); + b\printClass(); + std\print("{b\hello}"); + std\assert(b\hello is a\Hello, message: "multiple import of the same script produce the same globals"); +} diff --git a/tests/046-try-catch.buzz b/tests/046-try-catch.buzz index 7facfef9..d85683c1 100644 --- a/tests/046-try-catch.buzz +++ b/tests/046-try-catch.buzz @@ -9,8 +9,8 @@ fun partialCatch() > void !> str { willFail(); throw 12; - } catch (int _) { - std.assert(false, message: "unreachable"); + } catch (_: int) { + std\assert(false, message: "unreachable"); } } @@ -19,7 +19,7 @@ fun returnFromCatch() > int { willFail(); return 12; - } catch (str _) { + } catch (_: str) { return 21; } @@ -27,10 +27,10 @@ fun returnFromCatch() > int { } test "Try catch" { - str setme = ""; + var setme = ""; try { - str _ = "i'm local to this try block"; + _ = "i'm local to this try block"; setme = "yes"; @@ -38,34 +38,34 @@ test "Try catch" { partialCatch(); - std.assert(false, message: "unreachable"); - } catch (str error) { - str _ = "a local in catch clause"; + std\assert(false, message: "unreachable"); + } catch (error: str) { + _ = "a local in catch clause"; - std.assert(error == "Yolo", message: "caught error"); - } catch (int _) { - std.assert(false, message: "unreachable"); + std\assert(error == "Yolo", message: "caught error"); + } catch (_: int) { + std\assert(false, message: "unreachable"); } catch { - std.assert(false, message: "unreachable"); + std\assert(false, message: "unreachable"); } - str afterLocal = "bye"; + const afterLocal = "bye"; - std.assert(setme == "yes", message: "error was handled and code continues"); + std\assert(setme == "yes", message: "error was handled and code continues"); - std.assert(returnFromCatch() == 21, message: "return from catch clause works"); + std\assert(returnFromCatch() == 21, message: "return from catch clause works"); - std.assert(afterLocal == "bye", message: "catch closed its scope"); + std\assert(afterLocal == "bye", message: "catch closed its scope"); } test "catch any catches everything" { var caught = false; try { willFail(); - } catch (any error) { + } catch (error: any) { caught = true; - std.assert(error is str, message: "Could cath any error"); + std\assert(error is str, message: "Could cath any error"); } - std.assert(caught, message: "Could catch any error"); -} \ No newline at end of file + std\assert(caught, message: "Could catch any error"); +} diff --git a/tests/047-if-arrow.buzz b/tests/047-if-arrow.buzz index 42977559..1169b84f 100644 --- a/tests/047-if-arrow.buzz +++ b/tests/047-if-arrow.buzz @@ -1,14 +1,14 @@ import "std"; test "If arrow" { - int? opt = null; - str? optS = "hello"; + const opt: int? = null; + const optS: str? = "hello"; if (opt -> _) { - std.assert(false, message: "unreachable"); + std\assert(false, message: "unreachable"); } if (optS -> unwrapped) { - std.assert(unwrapped == "hello", message: "Could if-arrow unwrap"); + std\assert(unwrapped == "hello", message: "Could if-arrow unwrap"); } -} \ No newline at end of file +} diff --git a/tests/048-generics.buzz b/tests/048-generics.buzz index 181c1eea..aeb28f9f 100644 --- a/tests/048-generics.buzz +++ b/tests/048-generics.buzz @@ -1,105 +1,105 @@ import "std"; -fun count::([T] list) > int { +fun count::(list: [T]) > int { return list.len(); } test "Simple generic" { - std.assert(count::([1, 2, 3]) == 3, message: "could use generics"); + std\assert(count::([1, 2, 3]) == 3, message: "could use generics"); } -fun extractList::(obj{ [T] list } data) > [T] { +fun extractList::(data: obj{ list: [T] }) > [T] { return data.list; } test "Generic within anonymous object" { - [int] list = [1, 2, 3]; + const list = [1, 2, 3]; - std.assert(extractList::(.{ list = list }) == list, message: "could use generic within anonymous object"); + std\assert(extractList::(.{ list = list }) == list, message: "could use generic within anonymous object"); } -fun countMap::({K: V} map) > int { +fun countMap::(map: {K: V}) > int { return map.size(); } test "Multiple generic types" { - {str: int} map = { + const map = { "one": 1, "two": 2, "three": 3, }; - std.assert(countMap::(map) == 3, message: "could use multiple generic types"); + std\assert(countMap::(map) == 3, message: "could use multiple generic types"); } -fun extractMap::(obj{ {K: V} map } data) > {K: V} { +fun extractMap::(data: obj{ map: {K: V} }) > {K: V} { return data.map; } test "Generic within anonymous object and map" { - {str: int} map = { + const map = { "one": 1, "two": 2, "three": 3, }; - std.assert(extractMap::(.{ map = map }) == map, message: "could use generic within anonymous object"); + std\assert(extractMap::(.{ map = map }) == map, message: "could use generic within anonymous object"); } -fun countShuffleGenerics::() > Function([A] a, [B] b) > int { - return fun ([A] a, [B] b) > int => a.len() + b.len(); +fun countShuffleGenerics::() > fun (a: [A], b: [B]) > int { + return fun (a: [A], b: [B]) > int => a.len() + b.len(); } test "Generic in lambda function definition" { - [str] a = ["one", "two", "three"]; - [int] b = [1, 2, 3]; + const a = ["one", "two", "three"]; + const b = [1, 2, 3]; - std.assert(countShuffleGenerics::()(a, b: b) == 6, message: "could use generic in lambda function definition"); + std\assert(countShuffleGenerics::()(a, b: b) == 6, message: "could use generic in lambda function definition"); } -fun genericReturn::(T value) > T { +fun genericReturn::(value: T) > T { return value; } test "generic return" { - std.assert(genericReturn::(12) == 12, message: "could use return of generic type"); + std\assert(genericReturn::(12) == 12, message: "could use return of generic type"); } -fun fiber::([T] data) > void *> T? { - foreach (T element in data) { +fun fiber::(data: [T]) > void *> T? { + foreach (element in data) { _ = yield element; } } test "Generic with fibers" { - fib f = &fiber::([1, 2, 3]); + const f = &fiber::([1, 2, 3]); - int sum = 0; + var sum = 0; while (!f.over()) { sum = sum + resume f ?? 0; } - std.assert(sum == 6, message: "could user generic in fiber definition"); + std\assert(sum == 6, message: "could use generic in fiber definition"); } test "Generics in placeholders" { - std.assert( + std\assert( countAgain::([1, 2, 3]) == 3, message: "Could use generics with placeholders" ); } -fun countAgain::([T] list) > int { +fun countAgain::(list: [T]) > int { return list.len(); } -fun doubleGeneric::(Function::() > int lambda) > int { +fun doubleGeneric::(lambda: fun::() > int) > int { return lambda::(); } test "Generic with generic lambda parameter" { - std.assert( + std\assert( doubleGeneric::( fun::() > int => 12 ) == 12, diff --git a/tests/049-multiline-strings.buzz b/tests/049-multiline-strings.buzz index 6752d0aa..355355f5 100644 --- a/tests/049-multiline-strings.buzz +++ b/tests/049-multiline-strings.buzz @@ -2,7 +2,7 @@ import "std"; import "serialize"; test "Multiline strings" { - str multi = `\{ + const multi = `\{ "some": "json", "yes": {3 + 12}, {` @@ -10,8 +10,8 @@ test "Multiline strings" { `} }`; - var json = serialize.jsonDecode(multi); + const json = serialize\jsonDecode(multi); - std.assert(json.q(["yes"]).integer() == 15, message: "multiline string is valid"); - std.assert(json.q(["another"]).string() == "one", message: "multiline string is valid"); -} \ No newline at end of file + std\assert(json.q(["yes"]).integer() == 15, message: "multiline string is valid"); + std\assert(json.q(["another"]).string() == "one", message: "multiline string is valid"); +} diff --git a/tests/050-protocols.buzz b/tests/050-protocols.buzz index bf7a0770..d5304f2b 100644 --- a/tests/050-protocols.buzz +++ b/tests/050-protocols.buzz @@ -1,78 +1,78 @@ import "std"; protocol Comparable { - fun greater(Comparable than) > bool; + fun greater(than: Comparable) > bool; } protocol Nameable { - fun rename(str name) > void; + fun rename(name: str) > void; } object(Comparable, Nameable) Person { - str name, - int age, + name: str, + age: int, - fun greater(Comparable than) > bool !> str { - if (than as Person other) { + fun greater(than: Comparable) > bool !> str { + if (than as other: Person) { return this.age > other.age; } throw "Can't compare to {than}"; } - fun rename(str name) > void { + fun rename(name: str) > void { this.name = name; } } object(Nameable) Pet { - str name, + name: str, - fun rename(str name) > void { + fun rename(name: str) > void { this.name = name; } } test "Protocols" { - Person joe = Person{ + const joe = Person{ name = "Joe", age = 25, }; - Person bob = Person{ + const bob = Person{ name = "Bob", age = 56, }; - Pet bandit = Pet{ + const bandit = Pet{ name = "bandit", }; - std.assert(bob.greater(joe), message: "could implement protocol"); + std\assert(bob.greater(joe), message: "could implement protocol"); - Nameable nameable = bandit; + var nameable: Nameable = bandit; nameable = joe; - [Nameable] nameables = [bandit, joe]; - [str] newNames = ["Chili", "Nick"]; - foreach (int i, Nameable item in nameables) { + const nameables: [Nameable] = [bandit, joe]; + const newNames = ["Chili", "Nick"]; + foreach (i, item in nameables) { item.rename(newNames[i]); } - std.assert(bandit.name == "Chili", message: "could call protocol method"); - std.assert(joe.name == "Nick", message: "could call protocol method"); + std\assert(bandit.name == "Chili", message: "could call protocol method"); + std\assert(joe.name == "Nick", message: "could call protocol method"); - {Nameable: bool} map = { + const map: {Nameable: bool} = { bandit: true, joe: false, }; - std.assert(map[joe] == false, message: "could hold protocol as map key"); + std\assert(map[joe] == false, message: "could hold protocol as map key"); - {str: Nameable} mapValue = { + const mapValue: {str: Nameable} = { "bandit": bandit, "joe": joe, }; - std.assert(mapValue["joe"] == joe, message: "could hold protocol as map value"); -} \ No newline at end of file + std\assert(mapValue["joe"] == joe, message: "could hold protocol as map value"); +} diff --git a/tests/051-functional.buzz b/tests/051-functional.buzz index 05710807..6105bc01 100644 --- a/tests/051-functional.buzz +++ b/tests/051-functional.buzz @@ -1,120 +1,119 @@ import "std"; test "list.forEach" { - [int] data = [1, 2, 3, 4]; + const data = [1, 2, 3, 4]; - int sum = 0; - data.forEach(fun (int _, int element) > void { + var sum = 0; + data.forEach(fun (_: int, element: int) > void { sum = sum + element; }); - std.assert(sum == 10, message: "could use list.forEach"); + std\assert(sum == 10, message: "could use list.forEach"); } test "list.map" { - [int] data = [1, 2, 3, 4]; + const data = [1, 2, 3, 4]; - [str] mapped = data.map::(fun (int _, int element) => "{element}"); + const mapped = data.map::(fun (_: int, element: int) => "{element}"); - std.assert(mapped.join(", ") == "1, 2, 3, 4", message: "could use map"); + std\assert(mapped.join(", ") == "1, 2, 3, 4", message: "could use map"); } test "list.filter" { - [int] data = [1, 2, 3, 4]; + const data = [1, 2, 3, 4]; - [int] odd = data.filter(fun (int _, int element) => element % 2 != 0); + const odd = data.filter(fun (_: int, element: int) => element % 2 != 0); - std.assert(odd.join(", ") == "1, 3", message: "could use filter"); + std\assert(odd.join(", ") == "1, 3", message: "could use filter"); } test "list.reduce" { - [int] data = [1, 2, 3, 4]; + const data = [1, 2, 3, 4]; - int sum = data.reduce::( - fun (int _, int element, int accumulator) => accumulator + element, + var sum = data.reduce::( + fun (_: int, element: int, accumulator: int) => accumulator + element, initial: 0 ); - std.assert(sum == 10, message: "could use reduce"); + std\assert(sum == 10, message: "could use reduce"); } test "list.sort" { - [int] data = [10, 3, 12, 0, 1, -3]; + const data = [10, 3, 12, 0, 1, -3]; - _ = data.sort(fun (int left, int right) => left < right); + _ = data.sort(fun (left: int, right: int) => left < right); - foreach (int i, int value in [-3, 0, 1, 3, 10, 12]) { - std.assert(data[i] == value, message: "list is not ordered"); + foreach (i, value in [-3, 0, 1, 3, 10, 12]) { + std\assert(data[i] == value, message: "list is not ordered"); } } test "map.forEach" { - {str: int} map = { + const map = { "five": 5, "two": 2, "one": 1, "three": 3, }; - int sum = 0; + var sum = 0; map.forEach( - fun (str _, int value) > void => sum = sum + value + fun (_: str, value: int) > void => sum = sum + value ); - std.assert(sum == 11, message: "could use map.forEach"); + std\assert(sum == 11, message: "could use map.forEach"); } test "map.map" { - {str: int} map = { + const map = { "five": 5, "two": 2, "one": 1, "three": 3, }; - | 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 }, + const inverted = map.map::( + fun (key: str, value: int) => .{ key = value, value = key }, ); - foreach (str key, int value in map) { - std.assert(inverted[value] == key, message: "Could use map.map"); + foreach (key, value in map) { + std\assert(inverted[value] == key, message: "Could use map.map"); } } test "map.filter" { - {str: int} map = { + const map = { "five": 5, "two": 2, "one": 1, "three": 3, }; - {str: int} filtered = map.filter( - fun (str _, int value) => value % 2 != 0 + const filtered = map.filter( + fun (_: str, value: int) => value % 2 != 0 ); - std.assert(filtered["two"] == null, message: "Could use map.filter"); + std\assert(filtered["two"] == null, message: "Could use map.filter"); } test "map.reduce" { - {str: int} map = { + const map = { "five": 5, "two": 2, "one": 1, "three": 3, }; - int sum = map.reduce::( - fun (str _, int value, int accumulator) => accumulator + value, + var sum = map.reduce::( + fun (_: str, value: int, accumulator: int) => accumulator + value, initial: 0 ); - std.assert(sum == 11, message: "could use reduce"); + std\assert(sum == 11, message: "could use reduce"); } test "map.sort" { - {str: int} map = { + const map = { "five": 5, "two": 2, "one": 1, @@ -123,14 +122,14 @@ test "map.sort" { _ = map.sort( - fun (str lhs, str rhs) => map[lhs]! < map[rhs]! + fun (lhs: str, rhs: str) => map[lhs]! < map[rhs]! ); - [str] ordered = [ "one", "two", "three", "five" ]; - int i = 0; - foreach (str key in map.keys()) { - std.assert(ordered[i] == key, message: "Could sort map"); + const ordered = [ "one", "two", "three", "five" ]; + var i = 0; + foreach (key in map.keys()) { + std\assert(ordered[i] == key, message: "Could sort map"); i = i + 1; } -} \ No newline at end of file +} diff --git a/tests/052-inline-if.buzz b/tests/052-inline-if.buzz index 298d5b59..98f30dbe 100644 --- a/tests/052-inline-if.buzz +++ b/tests/052-inline-if.buzz @@ -1,17 +1,17 @@ import "std"; test "ternary" { - int value = if (true) 12 else 0; + var value = if (true) 12 else 0; - std.assert(value == 12, message: "could use constant inline if"); + std\assert(value == 12, message: "could use constant inline if"); value = if ("hello".len() == 2) 0 else 12; - std.assert(value == 12, message: "could use inline if"); + std\assert(value == 12, message: "could use inline if"); } test "multiple branches" { - int value = 12; + const value = 12; const expr = if (value == 14) "hello" @@ -20,13 +20,13 @@ test "multiple branches" { else null; - std.assert(expr == "yolo", message: "Could use multiple branches with inline if"); + std\assert(expr == "yolo", message: "Could use multiple branches with inline if"); } test "inline if in expression" { - int value = 12; + const value = 12; - std.assert( + std\assert( (if (value == 14) "hello" else if (value == 12) @@ -35,4 +35,4 @@ test "inline if in expression" { null) == "yolo", message: "Could use multiple branches inline if in expression" ); -} \ No newline at end of file +} diff --git a/tests/053-range.buzz b/tests/053-range.buzz index 5439718f..10211b1e 100644 --- a/tests/053-range.buzz +++ b/tests/053-range.buzz @@ -1,41 +1,41 @@ import "std"; test "Range" { - int limit = 10; - rg range = 0..limit; + const limit = 10; + const range = 0..limit; - std.assert(range == 0..10, message: "Could compare ranges"); - std.assert(range.low() == 0, message: "Could get low limit of range"); - std.assert(range.high() == 10, message: "Could get high limit of range"); + std\assert(range == 0..10, message: "Could compare ranges"); + std\assert(range.low() == 0, message: "Could get low limit of range"); + std\assert(range.high() == 10, message: "Could get high limit of range"); - [int] list = range.toList(); - std.assert(list.len() == 10, message: "Could create list from range"); + const list = range.toList(); + std\assert(list.len() == 10, message: "Could create list from range"); - int sum = 0; - foreach (int n in 0..10) { + var sum = 0; + foreach (n in 0..10) { sum = sum + n; } - std.assert(sum == 45, message: "Could iterate over range"); + std\assert(sum == 45, message: "Could iterate over range"); - std.assert(range.len() == 10, message: "Could get range length"); + std\assert(range.len() == 10, message: "Could get range length"); } test "Inverted range" { - int limit = 0; - rg range = 10..limit; + const limit = 0; + const range = 10..limit; - std.assert((0..10).invert() == range, message: "Could invert range"); - std.assert(range.low() == 10, message: "Could get low limit of range"); - std.assert(range.high() == 0, message: "Could get high limit of range"); + std\assert((0..10).invert() == range, message: "Could invert range"); + std\assert(range.low() == 10, message: "Could get low limit of range"); + std\assert(range.high() == 0, message: "Could get high limit of range"); - [int] list = range.toList(); - std.assert(list.len() == 10, message: "Could create list from inverted range"); + const list = range.toList(); + std\assert(list.len() == 10, message: "Could create list from inverted range"); - int sum = 0; - foreach (int n in 10..0) { + var sum = 0; + foreach (n in 10..0) { sum = sum + n; } - std.assert(sum == 55, message: "Could iterate over inverted range"); + std\assert(sum == 55, message: "Could iterate over inverted range"); - std.assert(range.len() == 10, message: "Could get range length"); + std\assert(range.len() == 10, message: "Could get range length"); } diff --git a/tests/056-crypto.buzz b/tests/056-crypto.buzz index 77a2d73b..01d7d66f 100644 --- a/tests/056-crypto.buzz +++ b/tests/056-crypto.buzz @@ -2,22 +2,22 @@ import "std"; import "crypto" as _; test "hash" { - std.assert( + std\assert( "c3fcd3d76192e4007dfb496cca67e13b" == hash(HashAlgorithm.Md5, data: "abcdefghijklmnopqrstuvwxyz").hex(), message: "md5" ); - std.assert( + std\assert( "a9993e364706816aba3e25717850c26c9cd0d89d" == hash(HashAlgorithm.Sha1, data: "abc").hex(), message: "sha1" ); - std.assert( + std\assert( "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == hash(HashAlgorithm.Sha256, data: "abc").hex(), message: "sha256" ); - std.assert( + std\assert( "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" == hash(HashAlgorithm.Sha3256, data: "abc").hex(), message: "sha3-256" ); diff --git a/tests/057-any.buzz b/tests/057-any.buzz index f0219597..9ba32683 100644 --- a/tests/057-any.buzz +++ b/tests/057-any.buzz @@ -1,66 +1,66 @@ import "std"; test "any" { - any anything = "hello"; + const anything: any = "hello"; - std.assert(anything is str, message: "can manipulate any typed value"); + std\assert(anything is str, message: "can manipulate any typed value"); - if (anything as str astring) { - std.assert(astring.len() == "hello".len(), message: "could cast any"); + if (anything as astring: str) { + std\assert(astring.len() == "hello".len(), message: "could cast any"); } } test "any placeholder" { - std.assert(placeholder is str, message: "can manipulate placeholder with any typed value"); + std\assert(placeholder is str, message: "can manipulate placeholder with any typed value"); - if (placeholder as str astring) { - std.assert(astring.len() == "hello".len(), message: "could cast placeholder any"); + if (placeholder as astring: str) { + std\assert(astring.len() == "hello".len(), message: "could cast placeholder any"); } } -any placeholder = "hello"; +const placeholder: any = "hello"; test "as?" { - any anything = 12; + const anything: any = 12; - std.assert((anything as? int) == 12, message: "as?"); + std\assert((anything as? int) == 12, message: "as?"); - std.assert((anything as? str) == null, message: "as?"); + std\assert((anything as? str) == null, message: "as?"); } test "list of any" { - [any] list = [ 1, true, 12.4, "hello" ]; + const list = [ 1, true, 12.4, "hello" ]; - foreach (any element in list) { - std.print("{element}"); + foreach (element in list) { + std\print("{element}"); } } test "map of any" { - {str: any} map = { + const map: {str: any} = { "hello": true, "world": "one", }; - foreach (str key, any element in map) { - std.print("{key}: {element}"); + foreach (key, element in map) { + std\print("{key}: {element}"); } - {any: str} map2 = { + const map2: {any: str} = { "hello": "true", true: "one", }; - foreach (any key, str element in map2) { - std.print("{key}: {element}"); + foreach (key, element in map2) { + std\print("{key}: {element}"); } - {any: any} map3 = { + const map3: {any: any} = { "hello": 1, true: "one", }; - foreach (any key, any element in map3) { - std.print("{key}: {element}"); + foreach (key, element in map3) { + std\print("{key}: {element}"); } } diff --git a/tests/058-ffi.buzz b/tests/058-ffi.buzz index 3787f2fe..dcf5949a 100644 --- a/tests/058-ffi.buzz +++ b/tests/058-ffi.buzz @@ -9,11 +9,11 @@ zdef("tests/utils/libforeign", ` `); test "scalar type" { - std.assert(acos(0.12) == 1.4505064444001086, message: "Could call FFI function with scalar arguments"); + std\assert(acos(0.12) == 1.4505064444001086, message: "Could call FFI function with scalar arguments"); } test "cstring" { - fprint(ffi.cstr("hello world")); + fprint(ffi\cstr("hello world")); } test "pointer with Buffer" { @@ -23,35 +23,35 @@ test "pointer with Buffer" { buffer.writeZ::("i32", values: [1, 2, 3]); try { - | Arguably, the zig type parameter could a constant and be built at compile time - | But: that would require a new type - | Since we cache the result of the type parsing this is roughly equivalent + // Arguably, the zig type parameter could a constant and be built at compile time + // But: that would require a new type + // Since we cache the result of the type parsing this is roughly equivalent buffer.writeZ::("u64", values: [1]); - std.assert(false, message: "Using bad buzz type triggers error"); - } catch (ffi.FFITypeMismatchError _) { - std.assert(true, message: "Using bad buzz type triggers error"); + std\assert(false, message: "Using bad buzz type triggers error"); + } catch (_: ffi\FFITypeMismatchError) { + std\assert(true, message: "Using bad buzz type triggers error"); } - int i32align = ffi.alignOf("i32"); - int len = buffer.len(align: i32align); - std.assert(len == buffer.len() / 4, message: "Len align"); - int total = sum(buffer.ptr(), len: len); + const i32align = ffi\alignOf("i32"); + const len = buffer.len(align: i32align); + std\assert(len == buffer.len() / 4, message: "Len align"); + const total = sum(buffer.ptr(), len: len); - std.assert(total == 12, message: "Could call FFI function with pointer argument"); + std\assert(total == 12, message: "Could call FFI function with pointer argument"); - int readTotal = 0; - foreach (int i in 0..buffer.len(align: i32align)) { + var readTotal = 0; + foreach (i in 0..buffer.len(align: i32align)) { readTotal = readTotal + buffer.readZAt::( at: i, zigType: "i32" ); } - std.assert(readTotal == total, message: "Could read from pointer"); + std\assert(readTotal == total, message: "Could read from pointer"); - int subTotal = sum(buffer.ptr(1, align: i32align), len: len - 1); + const subTotal = sum(buffer.ptr(1, align: i32align), len: len - 1); - std.assert(subTotal == 11, message: "Could get ptr at offset"); + std\assert(subTotal == 11, message: "Could get ptr at offset"); } zdef("tests/utils/libforeign", ` @@ -66,29 +66,29 @@ zdef("tests/utils/libforeign", ` `); test "struct" { - Data data = Data{ - msg = ffi.cstr("bye world"), + const data = Data{ + msg = ffi\cstr("bye world"), id = 123, value = 42.0, }; - std.assert(data.msg == "bye world\0", message: "Could instanciate Zig struct"); - std.assert(data.id == 123, message: "Could instanciate Zig struct"); + std\assert(data.msg == "bye world\0", message: "Could instanciate Zig struct"); + std\assert(data.id == 123, message: "Could instanciate Zig struct"); data.id = 42; - std.assert(data.id == 42, message: "Could set Zig struct field"); + std\assert(data.id == 42, message: "Could set Zig struct field"); - std.assert(get_data_msg(data) == "bye world\0", message: "Could use foreign function with struct ptr param"); + std\assert(get_data_msg(data) == "bye world\0", message: "Could use foreign function with struct ptr param"); set_data_id(data); - std.assert(data.id == 84, message: "Could use foreign function with struct ptr param that modifies the struct"); + std\assert(data.id == 84, message: "Could use foreign function with struct ptr param that modifies the struct"); } test "write/read struct in buffer" { - Data data = Data{ - msg = ffi.cstr("bye world"), + const data = Data{ + msg = ffi\cstr("bye world"), id = 123, value = 42.0, }; @@ -97,11 +97,11 @@ test "write/read struct in buffer" { buffer.writeStruct::(Data, values: [data]); - std.assert(buffer.toString().len() == ffi.sizeOfStruct(Data), message: "Could write struct to buffer"); + std\assert(buffer.toString().len() == ffi\sizeOfStruct(Data), message: "Could write struct to buffer"); - Data read = buffer.readStruct::(Data); + const read = buffer.readStruct::(Data); - std.assert( + std\assert( read.msg == data.msg and read.id == data.id, message: "Could read struct from buffer" ); @@ -125,26 +125,26 @@ zdef("tests/utils/libforeign", ` `); test "union" { - Misc misc = Misc{ + const misc = Misc{ data = Data{ id = 123, - msg = ffi.cstr("hello world"), + msg = ffi\cstr("hello world"), value = 42.0, } }; - std.assert(get_misc_msg(misc) == ffi.cstr("hello world"), message: "Could read union field"); + std\assert(get_misc_msg(misc) == ffi\cstr("hello world"), message: "Could read union field"); misc.flag = Flag{ id = 123, value = true, }; - std.assert(get_misc_flag(misc), message: "Could read union field"); + std\assert(get_misc_flag(misc), message: "Could read union field"); misc.id = 321; - std.assert(misc.id == 321, message: "Got expected memory layout of a C union"); - std.assert(misc.data.id == 321, message: "Got expected memory layout of a C union"); - std.assert(misc.flag.id == 321, message: "Got expected memory layout of a C union"); + std\assert(misc.id == 321, message: "Got expected memory layout of a C union"); + std\assert(misc.data.id == 321, message: "Got expected memory layout of a C union"); + std\assert(misc.flag.id == 321, message: "Got expected memory layout of a C union"); } diff --git a/tests/059-types-as-value.buzz b/tests/059-types-as-value.buzz index e06f2b73..1036a728 100644 --- a/tests/059-types-as-value.buzz +++ b/tests/059-types-as-value.buzz @@ -6,30 +6,30 @@ enum B { case, } -fun dumpType(type myType) > void { - std.print("{myType}"); +fun dumpType(myType: type) > void { + std\print("{myType}"); } protocol C {} test "Types as value" { - type _ = ; - type another = ; - type again = ; + const _ = ; + const another = ; + const again = ; - std.assert(another == again, message: "Can compare type values"); + std\assert(another == again, message: "Can compare type values"); } test "typeof" { - std.assert(typeof A{} == , message: "typeof operator instance"); - std.assert(typeof B.case == , message: "typeof operator case"); - std.assert(typeof "hello" == , message: "typeof operator str"); - std.assert(typeof true == , message: "typeof operator bool"); - std.assert(typeof null == , message: "typeof operator null"); - std.assert(typeof 1 == , message: "typeof operator int"); - std.assert(typeof 3.14 == , message: "typeof operator float"); - std.assert(typeof $"hello" == , message: "typeof operator pattern"); - std.assert(typeof dumpType == void *> void>, message: "typeof operator"); + std\assert(typeof A{} == , message: "typeof operator instance"); + std\assert(typeof B.case == , message: "typeof operator case"); + std\assert(typeof "hello" == , message: "typeof operator str"); + std\assert(typeof true == , message: "typeof operator bool"); + std\assert(typeof null == , message: "typeof operator null"); + std\assert(typeof 1 == , message: "typeof operator int"); + std\assert(typeof 3.14 == , message: "typeof operator float"); + std\assert(typeof $"hello" == , message: "typeof operator pattern"); + std\assert(typeof dumpType == void *> void>, message: "typeof operator"); } test "type argument" { @@ -44,22 +44,22 @@ zdef("tests/utils/libforeign", ` `); test "necessary weirdness" { - std.assert(() == typeof A{}, message: "typeof Object == typeof Object instance"); + std\assert(() == typeof A{}, message: "typeof Object == typeof Object instance"); - std.assert(typeof C == , message: "protocol is a type at runtime"); - std.assert(typeof Data == , message: "fstruct is a type at runtime"); + std\assert(typeof C == , message: "protocol is a type at runtime"); + std\assert(typeof Data == , message: "fstruct is a type at runtime"); } -fun generic::(T value) > T { +fun generic::(value: T) > T { return value; } -fun typeArg(type T, str value) > str { - debug.dump(T); +fun typeArg(T: type, value: str) > str { + debug\dump(T); return value; } test "generic type expression ambiguity" { - debug.dump(generic::("hello")); - debug.dump(typeArg(, value: "hello")); -} \ No newline at end of file + debug\dump(generic::("hello")); + debug\dump(typeArg(, value: "hello")); +} diff --git a/tests/060-free-identifiers.buzz b/tests/060-free-identifiers.buzz index 55ac1f25..339e0142 100644 --- a/tests/060-free-identifiers.buzz +++ b/tests/060-free-identifiers.buzz @@ -1,19 +1,19 @@ import "std"; test "Free identifiers" { - str @"non-standard-identifier" = "hello world"; + const @"non-standard-identifier" = "hello world"; - std.assert(@"non-standard-identifier" == "hello world", message: "Could use non-standard identifiers"); + std\assert(@"non-standard-identifier" == "hello world", message: "Could use non-standard identifiers"); } object A { - str @"type", + @"type": str, } test "Free identifier as object field" { - const A a = A{ + const a = A{ @"type" = "Hello", }; - std.assert(a.@"type" == "Hello", message: "Could use non-standard identifiers as object field"); -} \ No newline at end of file + std\assert(a.@"type" == "Hello", message: "Could use non-standard identifiers as object field"); +} diff --git a/tests/061-utf8.buzz b/tests/061-utf8.buzz index b314568f..485596f6 100644 --- a/tests/061-utf8.buzz +++ b/tests/061-utf8.buzz @@ -1,15 +1,15 @@ import "std"; test "utf8" { - str msg = "hello 🔥 buzz !"; + const msg = "hello 🔥 buzz !"; - std.assert(msg.utf8Len() == 14, message: "Could get length of utf8 string"); - std.assert(msg.utf8Valid(), message: "Could validate utf8 string"); + std\assert(msg.utf8Len() == 14, message: "Could get length of utf8 string"); + std\assert(msg.utf8Valid(), message: "Could validate utf8 string"); - str invalid = "hello \232 world!"; + const invalid = "hello \232 world!"; - std.assert(!invalid.utf8Valid(), message: "Could not validate invalid utf8 string"); + std\assert(!invalid.utf8Valid(), message: "Could not validate invalid utf8 string"); - [str] codepoints = "I'm 🦇-man so 🔥 !".utf8Codepoints(); - std.assert(codepoints[4] == "🦇", message: "Could get utf8 string codepoints"); -} \ No newline at end of file + const codepoints = "I'm 🦇-man so 🔥 !".utf8Codepoints(); + std\assert(codepoints[4] == "🦇", message: "Could get utf8 string codepoints"); +} diff --git a/tests/062-discarded-value.buzz b/tests/062-discarded-value.buzz index 0cb89f25..426e15f8 100644 --- a/tests/062-discarded-value.buzz +++ b/tests/062-discarded-value.buzz @@ -1,5 +1,3 @@ -import "std"; - _ = "unused"; test "discarding value" { diff --git a/tests/063-nullable-default.buzz b/tests/063-nullable-default.buzz index 5bcfe781..d53051d0 100644 --- a/tests/063-nullable-default.buzz +++ b/tests/063-nullable-default.buzz @@ -1,20 +1,20 @@ import "std"; object Person { - str name, - int? age, + name: str, + age: int?, } test "Nullable object field has a default value at null" { - Person person = Person{ + const person = Person{ name = "Joe" }; - std.assert(person.age == null, message: "Nullable object field has a default value at null"); + std\assert(person.age == null, message: "Nullable object field has a default value at null"); } test "Nullable variable has a default value at null" { - str? hello; + var hello: int?; - std.assert(hello == null, message: "Nullable variable has default value at null"); -} \ No newline at end of file + std\assert(hello == null, message: "Nullable variable has default value at null"); +} diff --git a/tests/064-throw-inside-try.buzz b/tests/064-throw-inside-try.buzz index 2139acfe..4fe54731 100644 --- a/tests/064-throw-inside-try.buzz +++ b/tests/064-throw-inside-try.buzz @@ -13,13 +13,13 @@ fun run() > void { willFail(); throw SomeError{}; - } catch (str _) { - std.assert(false, message: "Could throw inside try/catch"); - } catch (SomeError _) { - std.assert(true, message: "Could throw inside try/catch"); + } catch (_: str) { + std\assert(false, message: "Could throw inside try/catch"); + } catch (_: SomeError) { + std\assert(true, message: "Could throw inside try/catch"); } } test "Throw inside try/catch" { run(); -} \ No newline at end of file +} diff --git a/tests/065-inferred-var-type.buzz b/tests/065-inferred-var-type.buzz index ad712f1b..27b4fd17 100644 --- a/tests/065-inferred-var-type.buzz +++ b/tests/065-inferred-var-type.buzz @@ -1,21 +1,21 @@ import "std"; object Person { - str name = "Joe", + name: str = "Joe", } var integer = 42; const floating = 42.42; test "Inferring variable declaration type" { - std.assert(integer is int, message: "Could infer global variable declaration type"); - std.assert(floating is float, message: "Could infer global constant declaration type"); + std\assert(integer is int, message: "Could infer global variable declaration type"); + std\assert(floating is float, message: "Could infer global constant declaration type"); var string = "hello"; - std.assert(string is str, message: "Could infer variable declaration type"); + std\assert(string is str, message: "Could infer variable declaration type"); const person = Person{}; - std.assert(person is Person, message: "Could infer constant declaration type"); -} \ No newline at end of file + std\assert(person is Person, message: "Could infer constant declaration type"); +} diff --git a/tests/066-object-generics.buzz b/tests/066-object-generics.buzz index 72743e9d..d74d0535 100644 --- a/tests/066-object-generics.buzz +++ b/tests/066-object-generics.buzz @@ -1,7 +1,7 @@ import "std"; object Payload:: { - {K: V} data, + data: {K: V}, } test "Objects generics" { @@ -13,6 +13,6 @@ test "Objects generics" { payload.data["two"] = 2; - std.assert(payload is Payload::, message: "Could use objects generics"); - std.assert(payload.data["two"] == 2, message: "Could use objects generics"); -} \ No newline at end of file + std\assert(payload is Payload::, message: "Could use objects generics"); + std\assert(payload.data["two"] == 2, message: "Could use objects generics"); +} diff --git a/tests/068-testing.buzz b/tests/068-testing.buzz index e77feda2..f8e5d166 100644 --- a/tests/068-testing.buzz +++ b/tests/068-testing.buzz @@ -1,17 +1,17 @@ import "testing" as _; test "Test std lib" { - Tester t = Tester.init( - beforeAll: fun (Tester t) { + const t = Tester.init( + beforeAll: fun (t: Tester) { t.assert(true); }, - afterAll: fun (Tester t) { + afterAll: fun (t: Tester) { t.assert(true); }, - beforeEach: fun (Tester t) { + beforeEach: fun (t: Tester) { t.assert(true); }, - afterEach: fun (Tester t) { + afterEach: fun (t: Tester) { t.assert(true); } ); @@ -64,4 +64,4 @@ test "Test std lib" { ); t.summary(); -} \ No newline at end of file +} diff --git a/tests/069-named-expr.buzz b/tests/069-named-expr.buzz index 0266077c..b71104ab 100644 --- a/tests/069-named-expr.buzz +++ b/tests/069-named-expr.buzz @@ -1,9 +1,9 @@ import "std"; object Person { - str name, - int age, - bool sex, + name: str, + age: int, + sex: bool, } test "Named expr object properties" { @@ -16,7 +16,7 @@ test "Named expr object properties" { sex = true, }; - std.assert( + std\assert( person.name == "joe" and person.age == 24 and person.sex, @@ -24,7 +24,7 @@ test "Named expr object properties" { ); } -fun hello(str name, int age, bool sex) > Person { +fun hello(name: str, age: int, sex: bool) > Person { return Person{ name, age, @@ -38,10 +38,10 @@ test "Name expr function argument" { var person = hello(name, age, sex: true); - std.assert( + std\assert( person.name == "joe" and person.age == 24 and person.sex, message: "Could use named variable as function arguments" ); -} \ No newline at end of file +} diff --git a/tests/070-block-expression.buzz b/tests/070-block-expression.buzz index c76554e5..68f138b5 100644 --- a/tests/070-block-expression.buzz +++ b/tests/070-block-expression.buzz @@ -2,11 +2,11 @@ import "std"; test "block expression" { var value = from { - std.print("doing stuff in my block..."); + std\print("doing stuff in my block..."); out "my value"; }; - std.assert(value == "my value", message: "Could use block expression"); - std.assert(value is str, message: "Could infer block expression type properly"); + std\assert(value == "my value", message: "Could use block expression"); + std\assert(value is str, message: "Could infer block expression type properly"); } \ No newline at end of file diff --git a/tests/071-tail-call.buzz b/tests/071-tail-call.buzz index 3de83867..3a652aba 100644 --- a/tests/071-tail-call.buzz +++ b/tests/071-tail-call.buzz @@ -1,18 +1,18 @@ import "std"; -fun mul(int a, int b) > int { +fun mul(a: int, b: int) > int { return a * b; } -fun tail(int a, int b) > int { +fun tail(a: int, b: int) > int { return mul(a, b); } test "simple tail call" { - std.assert(tail(a: 5, b: 2) == 10); + std\assert(tail(a: 5, b: 2) == 10); } -fun recursive(int limit, int current) > int { +fun recursive(limit: int, current: int) > int { if (current > limit) { return current; } @@ -21,18 +21,18 @@ fun recursive(int limit, int current) > int { } test "recursive tail call" { - std.assert(recursive(limit: 5, current: 0) == 6); + std\assert(recursive(limit: 5, current: 0) == 6); } object Tail { - int a, - int b, + a: int, + b: int, - fun mul(int c) > int { + fun mul(c: int) > int { return (this.a + this.b) * c; } - fun tail(int c) > int { + fun tail(c: int) > int { return this.mul(c); } } @@ -43,5 +43,5 @@ test "dot tail call" { b = 2, }.tail(3); - std.print("{result}"); -} \ No newline at end of file + std\print("{result}"); +} diff --git a/tests/072-labels.buzz b/tests/072-labels.buzz index 79cfbcce..c831f1bb 100644 --- a/tests/072-labels.buzz +++ b/tests/072-labels.buzz @@ -10,12 +10,12 @@ test "labeled break" { } } - std.assert(i == 10); + std\assert(i == 10); } test "labeled break in nested loop" { var i = 0; - foreach (int _ in 0..100) :here { + foreach (_ in 0..100) :here { var _ = "hello"; while (i < 100) { @@ -27,12 +27,12 @@ test "labeled break in nested loop" { } } - std.assert(i == 10); + std\assert(i == 10); } test "labeled break in deeply nested loop" { var i = 0; - foreach (int j in 0..100) :here { + foreach (j in 0..100) :here { var _ = "hello"; while (j < 100) { @@ -48,12 +48,12 @@ test "labeled break in deeply nested loop" { } } - std.assert(i == 10); + std\assert(i == 10); } test "labeled continue" { var i = 0; - foreach (int j in 0..10) :here { + foreach (j in 0..10) :here { if (j == 3) { continue here; } @@ -61,6 +61,6 @@ test "labeled continue" { i = i + j; } - std.assert(i == 42); + std\assert(i == 42); } diff --git a/tests/073-tuples.buzz b/tests/073-tuples.buzz index d5432833..b943ddf7 100644 --- a/tests/073-tuples.buzz +++ b/tests/073-tuples.buzz @@ -1,6 +1,6 @@ import "std"; -fun pack([str] names) > obj{ str, str, str } { +fun pack(names: [str]) > obj{ :str, :str, :str } { return .{ names[0], names[1], @@ -11,17 +11,17 @@ fun pack([str] names) > obj{ str, str, str } { test "Tuples" { const tuple = .{ "joe", "doe" }; - std.assert(tuple.@"0" == "joe" and tuple.@"1" == "doe"); + std\assert(tuple.@"0" == "joe" and tuple.@"1" == "doe"); const name = "Joe"; const age = 42; - | Forced tuple + // Forced tuple const another = .{ (name), (age) }; - std.assert(another.@"0" == "Joe" and another.@"1" == 42); + std\assert(another.@"0" == "Joe" and another.@"1" == 42); const names = pack(["Joe", "John", "James"]); - std.assert(names.@"0" == "Joe" and names.@"1" == "John"); + std\assert(names.@"0" == "Joe" and names.@"1" == "John"); } diff --git a/tests/074-checked-subscript.buzz b/tests/074-checked-subscript.buzz index 0aeb2765..045e8ed4 100644 --- a/tests/074-checked-subscript.buzz +++ b/tests/074-checked-subscript.buzz @@ -2,13 +2,13 @@ import "std"; test "List checked subscript" { var list = [1, 2, 3]; - std.assert(list[?10] is int?); - std.assert(list[?10] == null); - std.assert(list[?0] == 1); + std\assert(list[?10] is int?); + std\assert(list[?10] == null); + std\assert(list[?0] == 1); } test "String checked subscript" { - std.assert("hello"[?10] is str?); - std.assert("hello"[?10] == null); - std.assert("hello"[?0] == "h"); + std\assert("hello"[?10] is str?); + std\assert("hello"[?10] == null); + std\assert("hello"[?0] == "h"); } diff --git a/tests/bench/001-btree.buzz b/tests/bench/001-btree.buzz index 3b50a080..502973d0 100644 --- a/tests/bench/001-btree.buzz +++ b/tests/bench/001-btree.buzz @@ -36,24 +36,24 @@ fun btree(int N) > void { int stretchdepth = maxdepth + 1; Node stretchtree = bottomUpTree(stretchdepth); - std.print("stretch tree of depth {stretchdepth},\t check: {itemCheck(stretchtree)}"); + std\print("stretch tree of depth {stretchdepth},\t check: {itemCheck(stretchtree)}"); Node longlivedtree = bottomUpTree(maxdepth); for (int depth = mindepth; depth < maxdepth; depth = depth + 2) { - int iterations = std.toInt(math.pow(x: 2.0, y: std.toFloat(maxdepth - depth + mindepth)) catch 0.0); + int iterations = std\toInt(math\pow(x: 2.0, y: std\toFloat(maxdepth - depth + mindepth)) catch 0.0); int check = 0; for (int i = 0; i < iterations; i = i + 1) { check = check + itemCheck(bottomUpTree(depth)); } - std.print("{iterations}\t trees of depth {depth}\t check: {check}"); + std\print("{iterations}\t trees of depth {depth}\t check: {check}"); } - std.print("long lived tree of depth {maxdepth}\t check: {itemCheck(longlivedtree)}"); + std\print("long lived tree of depth {maxdepth}\t check: {itemCheck(longlivedtree)}"); } fun main([str] args) > void !> any { - int N = if (args.len() > 0) std.parseInt(args[0]) ?? 3 else 3; + int N = if (args.len() > 0) std\parseInt(args[0]) ?? 3 else 3; btree(N); } diff --git a/tests/bench/002-merkle.buzz b/tests/bench/002-merkle.buzz index 16836fe6..17842885 100644 --- a/tests/bench/002-merkle.buzz +++ b/tests/bench/002-merkle.buzz @@ -50,7 +50,7 @@ fun calHash(Node tree) > void { fun main([str] args) > void !> any { int N = 6; if (args.len() > 0) { - N = std.parseInt(args[0]) ?? 6; + N = std\parseInt(args[0]) ?? 6; } int mindepth = 4; @@ -63,11 +63,11 @@ fun main([str] args) > void !> any { Node stretchtree = makeTree(stretchdepth); calHash(stretchtree); - std.print("stretch tree of depth {stretchdepth}\t root hash: {stretchtree.hash ?? 0} check: {check(stretchtree)}"); + std\print("stretch tree of depth {stretchdepth}\t root hash: {stretchtree.hash ?? 0} check: {check(stretchtree)}"); Node longlivedtree = makeTree(maxdepth); for (int depth = mindepth; depth < maxdepth; depth = depth + 2) { - int iterations = std.toInt(math.pow(x: 2.0, y: std.toFloat(maxdepth - depth + mindepth))); + int iterations = std\toInt(math\pow(x: 2.0, y: std\toFloat(maxdepth - depth + mindepth))); int sum = 0; for (int i = 0; i < iterations; i = i + 1) { Node t = makeTree(depth); @@ -75,9 +75,9 @@ fun main([str] args) > void !> any { sum = sum + t.hash ?? 0; } - std.print("{iterations}\t trees of depth {depth}\t root hash sum: {sum}"); + std\print("{iterations}\t trees of depth {depth}\t root hash sum: {sum}"); } calHash(longlivedtree); - std.print("long lived tree of depth {maxdepth}\t root hash: {longlivedtree.hash ?? 0} check: {check(longlivedtree)}"); + std\print("long lived tree of depth {maxdepth}\t root hash: {longlivedtree.hash ?? 0} check: {check(longlivedtree)}"); } \ No newline at end of file diff --git a/tests/bench/003-nbody.buzz b/tests/bench/003-nbody.buzz index be968d6f..194acc9d 100644 --- a/tests/bench/003-nbody.buzz +++ b/tests/bench/003-nbody.buzz @@ -32,7 +32,7 @@ fun advance([Body] bodies, int nbody, float dt) > void { float dy = biy - bj.y; float dz = biz - bj.z; float dist2 = dx * dx + dy * dy + dz * dz; - float mag = math.sqrt(dist2); + float mag = math\sqrt(dist2); mag = dt / (mag * dist2); float bm = bj.mass * mag; @@ -68,7 +68,7 @@ fun energy([Body] bodies, int nbody) > float { float dx = bi.x - bj.x; float dy = bi.y - bj.y; float dz = bi.z - bj.z; - float distance = math.sqrt(dx * dx + dy * dy + dz * dz); + float distance = math\sqrt(dx * dx + dy * dy + dz * dz); e = e - ((bim * bj.mass) / distance); } } @@ -150,16 +150,16 @@ fun main([str] args) > void { int N = 1000; if (args.len() > 0) { - N = std.parseInt(args[0]) ?? 1000; + N = std\parseInt(args[0]) ?? 1000; } int nbody = bodies.len(); offsetMomentum(bodies, nbody: nbody); - std.print("{energy(bodies, nbody: nbody)}"); + std\print("{energy(bodies, nbody: nbody)}"); for (int i = 0; i < N; i = i + 1) { advance(bodies, nbody: nbody, dt: 0.01); } - std.print("{energy(bodies, nbody: nbody)}"); + std\print("{energy(bodies, nbody: nbody)}"); } \ No newline at end of file diff --git a/tests/bench/004-spectral.buzz b/tests/bench/004-spectral.buzz index 07694b77..091c0cbc 100644 --- a/tests/bench/004-spectral.buzz +++ b/tests/bench/004-spectral.buzz @@ -10,9 +10,9 @@ fun Av([float] x, [float] y, int N) > void { for (float i = 0.0; i < N; i = i + 1.0) { float a = 0.0; for (float j = 0.0; j < N; j = j + 1.0) { - a = a + x[std.toInt(j)] * A(i: i, j: j); + a = a + x[std\toInt(j)] * A(i: i, j: j); } - y[std.toInt(i)] = a; + y[std\toInt(i)] = a; } } @@ -20,9 +20,9 @@ fun Atv([float] x, [float] y, int N) > void { for (float i = 0.0; i < N; i = i + 1.0) { float a = 0.0; for (float j = 0.0; j < N; j = j + 1.0) { - a = a + x[std.toInt(j)] * A(i: j, j: i); + a = a + x[std\toInt(j)] * A(i: j, j: i); } - y[std.toInt(i)] = a; + y[std\toInt(i)] = a; } } @@ -34,7 +34,7 @@ fun AtAv([float] x, [float] y, [float] t, int N) > void { fun main([str] args) > void { int N = 100; if (args.len() > 0) { - N = std.parseInt(args[0]) ?? 100; + N = std\parseInt(args[0]) ?? 100; } [float] u = []; @@ -60,5 +60,5 @@ fun main([str] args) > void { vv = vv + vi * vi; } - std.print("{math.sqrt(vBv / vv)}"); + std\print("{math\sqrt(vBv / vv)}"); } \ No newline at end of file diff --git a/tests/bench/005-k-nucleoide.buzz b/tests/bench/005-k-nucleoide.buzz index 842465fe..624b6e9d 100644 --- a/tests/bench/005-k-nucleoide.buzz +++ b/tests/bench/005-k-nucleoide.buzz @@ -2,10 +2,10 @@ import "std"; import "io"; import "errors"; -fun readSequence() > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { +fun readSequence() > str !> errors\ReadWriteError, errors\FileSystemError, errors\UnexpectedError { bool skippedIgnoredSequences = false; [str] lines = []; - for (str? line = ""; line != null; line = io.stdin.readLine()) { | catch null doesn't work + for (str? line = ""; line != null; line = io\stdin.readLine()) { // catch null doesn't work if (!skippedIgnoredSequences) { if (line?.startsWith(">THREE") ?? true) { skippedIgnoredSequences = true; @@ -36,7 +36,7 @@ fun count(str sequence, str fragment) > void { for (int frame = 0; frame < k; frame = frame + 1) { kfrequency(sequence, frequency: frequency, k: k, frame: frame); } - std.print("{frequency[fragment] ?? 0}\t{fragment}"); + std\print("{frequency[fragment] ?? 0}\t{fragment}"); } fun frequency(str sequence, int k) > void { @@ -47,12 +47,12 @@ fun frequency(str sequence, int k) > void { int sum = sequence.len() - k + 1; foreach (str c, int f in frequency) { - std.print("{c} {(f * 100) / sum}"); + std\print("{c} {(f * 100) / sum}"); } - std.print(""); + std\print(""); } -| buzz tests/bench/005-k-nucleoide.buzz < tests/bench/reference/knucleotide-input.txt +// buzz tests/bench/005-k-nucleoide.buzz < tests/bench/reference/knucleotide-input.txt fun main([str] _) > void { str sequence = readSequence() catch ""; frequency(sequence, k: 1); diff --git a/tests/bench/006-fasta.buzz b/tests/bench/006-fasta.buzz index 2b0990ce..72729e07 100644 --- a/tests/bench/006-fasta.buzz +++ b/tests/bench/006-fasta.buzz @@ -9,12 +9,12 @@ const int lineLength = 60; const int bufferSize = (lineLength + 1) * 1024; fun makeRepeatFasta(str id, str desc, str s, int nchars) > void { - std.print(">{id} {desc}"); + std\print(">{id} {desc}"); int p = 0; int sn = s.len(); str s2 = s + s; for (int i = lineLength; i < nchars; i = i + lineLength) { - std.print(s2.sub(p, len: lineLength - 1)); + std\print(s2.sub(p, len: lineLength - 1)); p = p + lineLength; if (p > sn) { p = p - sn; @@ -22,7 +22,7 @@ fun makeRepeatFasta(str id, str desc, str s, int nchars) > void { } int tail = nchars % lineLength; if (tail > 0) { - std.print(s2.sub(p, len: tail - 1)); + std\print(s2.sub(p, len: tail - 1)); } } @@ -65,7 +65,7 @@ object Frequency { bool skip = false; for (int i = 0; i < len; i = i + 1) { if (r < this.probs[i]) { - buffer.setAt(bufferIndex, value: this.chars.at(i)); + buffer\setAt(bufferIndex, value: this.chars.at(i)); bufferIndex = bufferIndex + 1; skip = true; break; @@ -73,7 +73,7 @@ object Frequency { } if (!skip) { - buffer.setAt(bufferIndex, value: this.chars.at(len - 1)); + buffer\setAt(bufferIndex, value: this.chars.at(len - 1)); bufferIndex = bufferIndex + 1; } } @@ -83,28 +83,28 @@ object Frequency { } fun makeRandomFasta(str id, str desc, Frequency fpf, int initialNchars) > void !> OutOfBoundError, WriteWhileReadingError { - std.print(">{id} {desc}"); + std\print(">{id} {desc}"); var nchars = initialNchars; Buffer buffer = Buffer.init(bufferSize); int bufferIndex = 0; while (nchars > 0) { - int chunkSize = std.toInt(math.minFloat(a: std.toFloat(lineLength), b: std.toFloat(nchars))); + int chunkSize = std\toInt(math\minFloat(a: std\toFloat(lineLength), b: std\toFloat(nchars))); if (bufferIndex == bufferSize) { - std.print(buffer.toString().sub(0, len: bufferIndex)); + std\print(buffer\toString().sub(0, len: bufferIndex)); buffer = Buffer.init(bufferSize); bufferIndex = 0; } bufferIndex = fpf.selectRandomIntoBuffer(buffer, initialBufferIndex: bufferIndex, nRandom: chunkSize); - buffer.setAt(bufferIndex, value: 10); + buffer\setAt(bufferIndex, value: 10); bufferIndex = bufferIndex + 1; nchars = nchars - chunkSize; } - std.print(buffer.toString().sub(0, len: bufferIndex)); + std\print(buffer\toString().sub(0, len: bufferIndex)); } const str alu = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" @@ -118,7 +118,7 @@ const str alu = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" fun main([str] args) > void !> any { int N = 1000; if (args.len() > 0) { - N = std.parseInt(args[0]) ?? 1000; + N = std\parseInt(args[0]) ?? 1000; } makeRepeatFasta("ONE", desc: "Homo sapiens alu", s: alu, nchars: N * 2); diff --git a/tests/bench/007-fib.buzz b/tests/bench/007-fib.buzz index ef18f333..90f8ff95 100644 --- a/tests/bench/007-fib.buzz +++ b/tests/bench/007-fib.buzz @@ -9,5 +9,5 @@ fun fibonnacci(int n) > int { } fun main([str] _) > void { - std.print("{fibonnacci(30)}"); + std\print("{fibonnacci(30)}"); } \ No newline at end of file diff --git a/tests/bench/008-for.buzz b/tests/bench/008-for.buzz index 950196f5..a373ecac 100644 --- a/tests/bench/008-for.buzz +++ b/tests/bench/008-for.buzz @@ -12,5 +12,5 @@ fun main([str] _) > void { sum = sum + v; } - std.print("{sum}"); + std\print("{sum}"); } \ No newline at end of file diff --git a/tests/bench/009-grid.buzz b/tests/bench/009-grid.buzz index 7a624f66..3ffa2ada 100644 --- a/tests/bench/009-grid.buzz +++ b/tests/bench/009-grid.buzz @@ -1,13 +1,13 @@ import "std"; fun main([str] args) > void { - const int width = (if (args.len() > 0) std.parseInt(args[0]) else 80) ?? 80; - const int height = (if (args.len() > 1) std.parseInt(args[1]) else 60) ?? 60; + const int width = (if (args.len() > 0) std\parseInt(args[0]) else 80) ?? 80; + const int height = (if (args.len() > 1) std\parseInt(args[1]) else 60) ?? 60; var cells = []; for (int i = 0; i < width * height; i = i + 1) { - cells.append(std.random(max: 5) == 1); + cells.append(std\random(max: 5) == 1); } for (int y = 0; y < height; y = y + 1) { diff --git a/tests/bench/010-ackermann.buzz b/tests/bench/010-ackermann.buzz index dce54d10..99bc3c7e 100644 --- a/tests/bench/010-ackermann.buzz +++ b/tests/bench/010-ackermann.buzz @@ -1,10 +1,10 @@ import "std"; fun main([str] args) > void { - const m = (if (args.len() > 0) std.parseInt(args[0]) else null) ?? 3; - const n = (if (args.len() > 1) std.parseInt(args[1]) else null) ?? 8; + const m = (if (args.len() > 0) std\parseInt(args[0]) else null) ?? 3; + const n = (if (args.len() > 1) std\parseInt(args[1]) else null) ?? 8; - std.print("result: {ack(m, n)}"); + std\print("result: {ack(m, n)}"); } fun ack(int m, int n) > int { diff --git a/tests/bench/011-bubble-sort.buzz b/tests/bench/011-bubble-sort.buzz index f2dd146a..e9283e42 100644 --- a/tests/bench/011-bubble-sort.buzz +++ b/tests/bench/011-bubble-sort.buzz @@ -1,14 +1,14 @@ import "std"; fun main([str] args) > void { - const max = (if (args.len() > 0) std.parseInt(args[0]) else null) ?? 750; + const max = (if (args.len() > 0) std\parseInt(args[0]) else null) ?? 750; var list = init(max); bubblesort(list); foreach (int e in list) { - std.print("{e}"); + std\print("{e}"); } } diff --git a/tests/compile_errors/001-const.buzz b/tests/compile_errors/001-const.buzz index 78169e9e..c75d45bd 100644 --- a/tests/compile_errors/001-const.buzz +++ b/tests/compile_errors/001-const.buzz @@ -1,14 +1,14 @@ -| Invalid assignment target. +// Can't assign to constant variable import "std"; test "`const` variable" { - const str yo = "yo"; + const yo = "yo"; yo = "no way"; } -| function arguments are `const` -fun illegal(str yo) > void { +// function arguments are `const` +fun illegal(yo: str) > void { yo = "no way"; } @@ -19,4 +19,4 @@ enum Hey { test "assigning to enum field" { Hey.lo = 1; -} \ No newline at end of file +} diff --git a/tests/compile_errors/002-break.buzz b/tests/compile_errors/002-break.buzz index e74a9e19..6c62b665 100644 --- a/tests/compile_errors/002-break.buzz +++ b/tests/compile_errors/002-break.buzz @@ -1,4 +1,4 @@ -| break is not allowed here. +// break is not allowed here. test "break outside of loop" { while (true) { break; diff --git a/tests/compile_errors/004-not-callable.buzz b/tests/compile_errors/004-not-callable.buzz index aae07851..4112cbad 100644 --- a/tests/compile_errors/004-not-callable.buzz +++ b/tests/compile_errors/004-not-callable.buzz @@ -1,5 +1,5 @@ -| Can't be called +// Can't be called test "Can't be called" { - int yo = 12; + const yo = 12; yo("mo"); -} \ No newline at end of file +} diff --git a/tests/compile_errors/005-bad-named-variable-value.buzz b/tests/compile_errors/005-bad-named-variable-value.buzz index 7e096e25..3bd36aef 100644 --- a/tests/compile_errors/005-bad-named-variable-value.buzz +++ b/tests/compile_errors/005-bad-named-variable-value.buzz @@ -1,10 +1,10 @@ -| Bad value type: got type `int`, expected `tests.compile_errors.005-bad-named-variable-value.buzz.Yo` +// Bad value type: got type `int`, expected `tests\compile_errors\005-bad-named-variable-value.buzz.Yo` object Yo { - str name, + name: str, } test "Wrong named variable value" { - Yo yo = Yo{ name = "yolo" }; + var yo = Yo{ name = "yolo" }; yo = 12; -} \ No newline at end of file +} diff --git a/tests/compile_errors/006-deep-yield.buzz b/tests/compile_errors/006-deep-yield.buzz index a0960101..25e24db7 100644 --- a/tests/compile_errors/006-deep-yield.buzz +++ b/tests/compile_errors/006-deep-yield.buzz @@ -1,8 +1,8 @@ -| Bad function yield type +// Type mismatch: got type `str`, expected `void` import "std"; fun one() > void *> str? { - yield "hello"; + _ = yield "hello"; } fun two() > void { @@ -10,6 +10,6 @@ fun two() > void { } test "Deep yield" { - fib fiber = &two(); - std.print(resume fiber ?? "nope"); -} \ No newline at end of file + const fiber = &two(); + std\print(resume fiber ?? "nope"); +} diff --git a/tests/compile_errors/007-yield-location.buzz b/tests/compile_errors/007-yield-location.buzz index 16cc72ae..6b1d0334 100644 --- a/tests/compile_errors/007-yield-location.buzz +++ b/tests/compile_errors/007-yield-location.buzz @@ -1,4 +1,4 @@ -| Can't yield here +// Can't yield here test "Bad yield" { - yield "yolo"; -} \ No newline at end of file + _ = yield "yolo"; +} diff --git a/tests/compile_errors/008-error-message.buzz b/tests/compile_errors/008-error-message.buzz index c7a8589a..a7517ea1 100644 --- a/tests/compile_errors/008-error-message.buzz +++ b/tests/compile_errors/008-error-message.buzz @@ -1,12 +1,12 @@ -| Hello world -fun fail() > void !> obj{ str message } { +// Hello world +fun fail() > void !> obj{ message: str } { throw .{ message = "Hello world" }; } -fun depth() > void !> obj{ str message } { +fun depth() > void !> obj{ message: str } { fail(); } test "Throwing an object instance with a message field" { depth(); -} \ No newline at end of file +} diff --git a/tests/compile_errors/009-bad-named-variable-value.buzz b/tests/compile_errors/009-bad-named-variable-value.buzz index f6c4db1a..10b1990a 100644 --- a/tests/compile_errors/009-bad-named-variable-value.buzz +++ b/tests/compile_errors/009-bad-named-variable-value.buzz @@ -1,11 +1,11 @@ -| Bad value type: got type `int`, expected `str` +// Bad value type: got type `int`, expected `str` test "bad named variable value" { - str hello = "hello"; + var hello = "hello"; hello = 12; - [int] list = [ + _: [int] = [ true, 12, ]; -} \ No newline at end of file +} diff --git a/tests/compile_errors/010-multiple-location.buzz b/tests/compile_errors/010-multiple-location.buzz index a6d439a8..3368fde3 100644 --- a/tests/compile_errors/010-multiple-location.buzz +++ b/tests/compile_errors/010-multiple-location.buzz @@ -1,12 +1,12 @@ -| Property `name` does not exists +// Property `name` does not exists import "errors"; object Some { - str msg, + msg: str, } test "Badly initializing an object declared in another file" { - var _ = errors.CompileError{ + var _ = errors\CompileError{ name = "wtf", }; -} \ No newline at end of file +} diff --git a/tests/compile_errors/011-protocol.buzz b/tests/compile_errors/011-protocol.buzz index 3d94765e..49e81612 100644 --- a/tests/compile_errors/011-protocol.buzz +++ b/tests/compile_errors/011-protocol.buzz @@ -1,14 +1,14 @@ -| Object declared as conforming to protocol `Living` but doesn't implement method `live` +// Object declared as conforming to protocol `Living` but doesn't implement method `live` protocol Living { fun live() > void; } object(Living) Ant { - str name, + name: str, } test "Unimplemented protocol method" { - Ant a = Ant{ + _ = Ant{ name = "joe" }; -} \ No newline at end of file +} diff --git a/tests/compile_errors/012-collect-signature.buzz b/tests/compile_errors/012-collect-signature.buzz index 6eb26351..0c77d896 100644 --- a/tests/compile_errors/012-collect-signature.buzz +++ b/tests/compile_errors/012-collect-signature.buzz @@ -1,4 +1,4 @@ -| Expected `collect` method to be `fun collect() > void` got fun collect(str arg) > void +// Expected `collect` method to be `fun collect() > void` got fun collect(_: str) > void object Collectable { - fun collect(str arg) > void {} -} \ No newline at end of file + fun collect(_: str) > void {} +} diff --git a/tests/compile_errors/013-tostring-signature.buzz b/tests/compile_errors/013-tostring-signature.buzz index 8111a4a1..b3bfdef0 100644 --- a/tests/compile_errors/013-tostring-signature.buzz +++ b/tests/compile_errors/013-tostring-signature.buzz @@ -1,4 +1,4 @@ -| Expected `toString` method to be `fun toString() > str` got fun toString(str arg) > void +// Expected `toString` method to be `fun toString() > str` got fun toString(_: str) > void object Printable { - fun toString(str arg) > void {} -} \ No newline at end of file + fun toString(_: str) > void {} +} diff --git a/tests/compile_errors/014-main-signature.buzz b/tests/compile_errors/014-main-signature.buzz index 0ffe3adb..96b2bdc3 100644 --- a/tests/compile_errors/014-main-signature.buzz +++ b/tests/compile_errors/014-main-signature.buzz @@ -1,2 +1,2 @@ -| Expected `main` signature to be `fun main([str] args) > void|int` got fun main() > void -fun main() > void {} \ No newline at end of file +// Expected `main` signature to be `fun main([str] args) > void|int` got fun main() > void +fun main() > void {} diff --git a/tests/compile_errors/015-bad-pattern.buzz b/tests/compile_errors/015-bad-pattern.buzz index 1dcc323f..df6ed7bc 100644 --- a/tests/compile_errors/015-bad-pattern.buzz +++ b/tests/compile_errors/015-bad-pattern.buzz @@ -1,6 +1,6 @@ -| Could not compile pattern, error at 5: this version of PCRE2 does not have support for \P, \p, or \X +// Could not compile pattern, error at 5: this version of PCRE2 does not have support for \P, \p, or \X import "std"; test "bad pattern" { - pat bad = $"bad\pattern"; -} \ No newline at end of file + const bad = $"bad\pattern"; +} diff --git a/tests/compile_errors/016-unused-local.buzz b/tests/compile_errors/016-unused-local.buzz index dbc2a8d7..5a8a7bce 100644 --- a/tests/compile_errors/016-unused-local.buzz +++ b/tests/compile_errors/016-unused-local.buzz @@ -1,7 +1,7 @@ -| Unused local of type `int` +// Unused local of type `int` import "std"; -fun hey(int unused) > void { +fun hey(unused: int) > void { print("hey you missed me"); } @@ -10,5 +10,5 @@ test "discarded value" { "forgot me?"; - int unused = 42; -} \ No newline at end of file + const unused = 42; +} diff --git a/tests/compile_errors/017-invalid-int-literal.buzz b/tests/compile_errors/017-invalid-int-literal.buzz index 5ed47fa0..a6e8ab25 100644 --- a/tests/compile_errors/017-invalid-int-literal.buzz +++ b/tests/compile_errors/017-invalid-int-literal.buzz @@ -1,4 +1,4 @@ -| '_' must be between digits +// '_' must be between digits test "invalid literals" { - int a = 100_; + _ = 100_; } diff --git a/tests/compile_errors/018-invalid-float-literal.buzz b/tests/compile_errors/018-invalid-float-literal.buzz index 7779e214..016b5709 100644 --- a/tests/compile_errors/018-invalid-float-literal.buzz +++ b/tests/compile_errors/018-invalid-float-literal.buzz @@ -1,4 +1,4 @@ -| '_' must be between digits +// '_' must be between digits test "invalid literals" { - int a = 100.2_; + _ = 100.2_; } diff --git a/tests/compile_errors/019-invalid-int-hex-literal.buzz b/tests/compile_errors/019-invalid-int-hex-literal.buzz index fe213736..4ad1f7df 100644 --- a/tests/compile_errors/019-invalid-int-hex-literal.buzz +++ b/tests/compile_errors/019-invalid-int-hex-literal.buzz @@ -1,4 +1,4 @@ -| '_' must be between digits +// '_' must be between digits test "invalid hex literal" { - int a = 0x_100; + _ = 0x_100; } diff --git a/tests/compile_errors/020-invalid-int-bin-literal.buzz b/tests/compile_errors/020-invalid-int-bin-literal.buzz index e9333e97..e94db0bb 100644 --- a/tests/compile_errors/020-invalid-int-bin-literal.buzz +++ b/tests/compile_errors/020-invalid-int-bin-literal.buzz @@ -1,4 +1,4 @@ -| '_' must be between digits +// '_' must be between digits test "invalid bin literal" { - int a = 0b_100; + _ = 0b_100; } diff --git a/tests/compile_errors/021-fiber-error-location.buzz b/tests/compile_errors/021-fiber-error-location.buzz index c172c466..9f0f25e6 100644 --- a/tests/compile_errors/021-fiber-error-location.buzz +++ b/tests/compile_errors/021-fiber-error-location.buzz @@ -1,8 +1,8 @@ -| :7:13 +//:7:13 import "std"; -fun count(int n) > str *> int? { - for (int i = 0; i < n; i = i + 1) { +fun count(n: int) > str *> int? { + for (i: int = 0; i < n; i = i + 1) { if (i == 2) { throw "an error occured"; } @@ -13,16 +13,16 @@ fun count(int n) > str *> int? { } fun run() > void { - fib counter = &count(10); + const counter = &count(10); - int sum = 0; + var sum = 0; while (!counter.over()) { sum = sum + resume counter ?? 0; } - std.print(resolve counter); + std\print(resolve counter); } test "fiber error location" { run(); -} \ No newline at end of file +} diff --git a/tests/compile_errors/022-var-decl-without-value.buzz b/tests/compile_errors/022-var-decl-without-value.buzz index b48b88d7..8377db78 100644 --- a/tests/compile_errors/022-var-decl-without-value.buzz +++ b/tests/compile_errors/022-var-decl-without-value.buzz @@ -1,4 +1,4 @@ -| Expected variable initial value +// Expected variable initial value test "Var decl without a value" { - str canidothis; -} \ No newline at end of file + const canidothis: str; +} diff --git a/tests/compile_errors/023-empty-import.buzz b/tests/compile_errors/023-empty-import.buzz index ffc430ab..2c2847c8 100644 --- a/tests/compile_errors/023-empty-import.buzz +++ b/tests/compile_errors/023-empty-import.buzz @@ -1,4 +1,4 @@ -| Import path can't be empty +// Import path can't be empty import ""; test "empty import" {} \ No newline at end of file diff --git a/tests/compile_errors/024-misplaced-out.buzz b/tests/compile_errors/024-misplaced-out.buzz index 7fc7abf8..5f89717d 100644 --- a/tests/compile_errors/024-misplaced-out.buzz +++ b/tests/compile_errors/024-misplaced-out.buzz @@ -1,4 +1,4 @@ -| `out` statement is only allowed inside a block expression +// `out` statement is only allowed inside a block expression test "misplaced out statement" { out "not allowed"; } \ No newline at end of file diff --git a/tests/compile_errors/025-multiple-out.buzz b/tests/compile_errors/025-multiple-out.buzz index bdb04b22..e7f7bbe2 100644 --- a/tests/compile_errors/025-multiple-out.buzz +++ b/tests/compile_errors/025-multiple-out.buzz @@ -1,4 +1,4 @@ -| Only one `out` statement is allowed in block expression +// Only one `out` statement is allowed in block expression test "multiple out statements" { from { out "one"; diff --git a/tests/compile_errors/026-out-last-statement.buzz b/tests/compile_errors/026-out-last-statement.buzz index fe8ff625..4311c76e 100644 --- a/tests/compile_errors/026-out-last-statement.buzz +++ b/tests/compile_errors/026-out-last-statement.buzz @@ -1,4 +1,4 @@ -| Last block expression statement must be `out` +// Last block expression statement must be `out` test "out must be last statement" { from { out "i should be last"; diff --git a/tests/compile_errors/027-early-return.buzz b/tests/compile_errors/027-early-return.buzz index 86c48f1a..9b1502d5 100644 --- a/tests/compile_errors/027-early-return.buzz +++ b/tests/compile_errors/027-early-return.buzz @@ -1,10 +1,10 @@ -| Code after return statement will never be reached +// Code after return statement will never be reached import "std"; test "Early return" { - std.print("I sure hope i'm not interrupted..."); + std\print("I sure hope i'm not interrupted..."); return; - std.print("Guess I was"); + std\print("Guess I was"); } \ No newline at end of file diff --git a/tests/compile_errors/028-unused-import.buzz b/tests/compile_errors/028-unused-import.buzz index d040807f..6570239d 100644 --- a/tests/compile_errors/028-unused-import.buzz +++ b/tests/compile_errors/028-unused-import.buzz @@ -1,7 +1,7 @@ -| Unused import +// Unused import import "math"; import "std"; test "Doing nothing with the math import" { - std.print("hello"); + std\print("hello"); } \ No newline at end of file diff --git a/tests/compile_errors/029-label-not-found.buzz b/tests/compile_errors/029-label-not-found.buzz index 05ca3b5a..726beef1 100644 --- a/tests/compile_errors/029-label-not-found.buzz +++ b/tests/compile_errors/029-label-not-found.buzz @@ -1,4 +1,4 @@ -| Label `somewhere` does not exists. +// Label `somewhere` does not exists. test "using a label that does not exists" { while (true) { break somewhere; diff --git a/tests/compile_errors/030-const-objects.buzz b/tests/compile_errors/030-const-objects.buzz index 8212e181..6105ef77 100644 --- a/tests/compile_errors/030-const-objects.buzz +++ b/tests/compile_errors/030-const-objects.buzz @@ -1,16 +1,16 @@ -| `age` is constant +// `age` is constant object Constant { - const str name, - const int age, + const name: str, + const age: int, } object PartiallyConstant { - const str name, - int age, + const name: str, + age: int, } test "Constant object" { - var constant = Constant{ + const constant = Constant{ name = "Joe", age = 35, }; diff --git a/tests/compile_errors/031-long-tuple.buzz b/tests/compile_errors/031-long-tuple.buzz index 255e576d..b1115e40 100644 --- a/tests/compile_errors/031-long-tuple.buzz +++ b/tests/compile_errors/031-long-tuple.buzz @@ -1,4 +1,4 @@ -| Tuples can't have more than 4 elements +// Tuples can't have more than 4 elements test "Long tuple" { .{ 1, 2, 3, 4, 5 }; } diff --git a/tests/compile_errors/032-tuple-mix.buzz b/tests/compile_errors/032-tuple-mix.buzz index c4c53d39..f74696fb 100644 --- a/tests/compile_errors/032-tuple-mix.buzz +++ b/tests/compile_errors/032-tuple-mix.buzz @@ -1,4 +1,4 @@ -| Can't mix tuple notation and regular properties in anonymous object initialization +// Can't mix tuple notation and regular properties in anonymous object initialization test "Mixing tuple notation and regular anonymous object" { .{ name = "Joe", 42 }; } diff --git a/tests/manual/001-cli-args.buzz b/tests/manual/001-cli-args.buzz index 669ef2a9..d9353990 100644 --- a/tests/manual/001-cli-args.buzz +++ b/tests/manual/001-cli-args.buzz @@ -2,6 +2,6 @@ import "std"; fun main([str] args) > void { foreach (int index, str arg in args) { - std.print("{index}: {arg}"); + std\print("{index}: {arg}"); } } \ No newline at end of file diff --git a/tests/manual/003-io.buzz b/tests/manual/003-io.buzz index b60102bf..d79d5d3d 100644 --- a/tests/manual/003-io.buzz +++ b/tests/manual/003-io.buzz @@ -2,8 +2,8 @@ import "std"; import "io"; test "Read stdin" { - for (str? line = ""; line != null; line = io.stdin.readLine()) { - std.print("= {line}"); - io.stdout.write("> "); + for (str? line = ""; line != null; line = io\stdin.readLine()) { + std\print("= {line}"); + io\stdout.write("> "); } } \ No newline at end of file diff --git a/tests/manual/004-os.buzz b/tests/manual/004-os.buzz index 252ca148..89d7ec6f 100644 --- a/tests/manual/004-os.buzz +++ b/tests/manual/004-os.buzz @@ -1,5 +1,5 @@ import "os"; -test "os.exit" { - os.exit(12); +test "os\exit" { + os\exit(12); } \ No newline at end of file diff --git a/tests/manual/005-tcp-client.buzz b/tests/manual/005-tcp-client.buzz index e456e09f..cdaeb073 100644 --- a/tests/manual/005-tcp-client.buzz +++ b/tests/manual/005-tcp-client.buzz @@ -2,13 +2,13 @@ import "std"; import "os"; test "Opening a socket" { - var socket = os.Socket.connect( + var socket = os\Socket.connect( address: "127.0.0.1", port: 8080, - netProtocol: os.SocketProtocol.tcp + netProtocol: os\SocketProtocol.tcp ); - std.print("socket fd: {socket.fd}"); + std\print("socket fd: {socket.fd}"); socket.send("hello world"); diff --git a/tests/manual/006-http-client.buzz b/tests/manual/006-http-client.buzz index b0663cb4..5e0ce868 100644 --- a/tests/manual/006-http-client.buzz +++ b/tests/manual/006-http-client.buzz @@ -4,10 +4,10 @@ import "errors"; import "serialize"; fun main([str] _) > void !> any { - const client = http.Client.init(); + const client = http\Client.init(); - const request = http.Request{ - method = http.Method.GET, + const request = http\Request{ + method = http\Method.GET, headers = { "accept": "*/*", "user-agent": "buzz", @@ -16,7 +16,7 @@ fun main([str] _) > void !> any { }; const response = client.send(request); - const fact = serialize.jsonDecode(response.body ?? "null").q(["fact"]).stringValue(); + const fact = serialize\jsonDecode(response.body ?? "null").q(["fact"]).stringValue(); - debug.dump(fact); + debug\dump(fact); } \ No newline at end of file diff --git a/tests/utils/import-a.buzz b/tests/utils/import-a.buzz index ad92b2ee..52bae629 100644 --- a/tests/utils/import-a.buzz +++ b/tests/utils/import-a.buzz @@ -1,7 +1,7 @@ namespace a; object Hello { - str message, + message: str, } -export Hello; \ No newline at end of file +export Hello; diff --git a/tests/utils/import-b.buzz b/tests/utils/import-b.buzz index 4bb7f966..52385223 100644 --- a/tests/utils/import-b.buzz +++ b/tests/utils/import-b.buzz @@ -3,11 +3,11 @@ namespace b; import "tests/utils/import-a"; import "std"; -var hello = a.Hello{ message = "hello world" }; +var hello = a\Hello{ message = "hello world" }; fun printClass() > void { - std.print("b: {a.Hello}"); + std\print("b: {a\Hello}"); } export hello; -export printClass; \ No newline at end of file +export printClass; diff --git a/tests/utils/testing.buzz b/tests/utils/testing.buzz index ffa7d89e..ec5c5adc 100644 --- a/tests/utils/testing.buzz +++ b/tests/utils/testing.buzz @@ -2,20 +2,20 @@ namespace testing; import "std" as std; -int unexported = 42; +const unexported = 42; -fun hey(str message) > int { - std.print(message); +fun hey(message: str) > int { + std\print(message); return unexported; } -str ignore = "ignore me!"; +const ignore = "ignore me!"; object PrefixMe { - str name = "Joe", + name: str = "Joe", } -export std.assert as assert; +export std\assert as assert; export hey; export ignore; -export PrefixMe; \ No newline at end of file +export PrefixMe;