Skip to content
  •  
  •  
  •  
31 changes: 16 additions & 15 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Guidance for coding agents working in this repository.

## Project

Buzz is a small/lightweight statically typed scripting language written in Zig.
buzz is a small/lightweight statically typed scripting language written in Zig.

Main Buzz implementation subsystems:
Main buzz implementation subsystems:

- Scanner: `src/Scanner.zig`
- Parser and AST: `src/Parser.zig`, `src/Ast.zig`
Expand Down Expand Up @@ -75,21 +75,21 @@ Run formatter tests:
zig build test
```

`zig build test` currently tests the Buzz formatter. `zig build test-behavior` is the most important test suite for language behavior.
`zig build test` currently tests the buzz formatter. `zig build test-behavior` is the most important test suite for language behavior.

Run a single Buzz file containing `test` blocks:
Run a single buzz file containing `test` blocks:

```sh
zig build run -- -t tests/behavior/descriptive-name.buzz
zig build run -- test tests/behavior/descriptive-name.buzz
```

Run a regular Buzz script with a `main` function:
Run a regular buzz script with a `main` function:

```sh
zig build run -- path/to/file.buzz
zig build run -- run path/to/file.buzz
```

Prefer `zig build run` because it builds Buzz and then runs the script. Do not bother setting `BUZZ_PATH` manually.
Prefer `zig build run` because it builds buzz and then runs the script. Do not bother setting `BUZZ_PATH` manually.

Check Zig formatting:

Expand All @@ -104,7 +104,7 @@ Only Zig files need formatting checks for now.
- If Zig code was touched, run `zig build` before finishing.
- For language behavior changes, run `zig build test-behavior`.
- For formatter changes, run `zig build test`.
- For focused behavior work, first run the relevant file with `zig build run -- -t <testfile.buzz>`, then run the broader suite when appropriate.
- For focused behavior work, first run the relevant file with `zig build run -- test <testfile.buzz>`, then run the broader suite when appropriate.
- Tests are not expected to be flaky or platform-specific.
- Supported platforms are macOS and Linux. Do not spend effort on Windows compatibility unless explicitly asked.
- Do not test WASM unless the task is specifically WASM-related.
Expand All @@ -116,11 +116,12 @@ Only Zig files need formatting checks for now.
- Every language feature or bug fix should include a behavior test unless there is a clear reason not to.
- Parser, typechecker, compiler, and crash fixes should include a reduced regression test when possible.
- Do not add fuzzed crashes yourself.
- Tests that intentionally trigger a Buzz compile error belong in `tests/compile_errors/`.
- Compile-error tests must have a first-line comment containing the expected Buzz error message.
- Tests that intentionally trigger a buzz compile error belong in `tests/compile_errors/`.
- Compile-error tests must have a first-line comment containing the expected buzz error message.

## Style

- Always write uncapitalized buzz and not Buzz
- Keep patches minimal and localized.
- Preserve existing naming and conventions, even if they look inconsistent, unless the task is specifically cleanup.
- Do not break logic into small functions unless those small functions are used more than once.
Expand All @@ -129,15 +130,15 @@ Only Zig files need formatting checks for now.
- Comments are encouraged for compiler/runtime logic, but keep them concise and useful.
- Any non-trivial code added must be properly commented in the code. Comments should explain intent, invariants, or tricky control flow, not restate obvious assignments.
- Any new Zig file under `src/` must start with a file docblock (`//! ...`) describing the general role of the file.
- Any new functions, structs, objects, properties, and enums introduced in Zig or Buzz code must have a docblock.
- When modifying of creating a buzz file, always reformat it with `buzz -f`
- Any new functions, structs, objects, properties, and enums introduced in Zig or buzz code must have a docblock.
- When modifying of creating a buzz file, always reformat it with `buzz format`

## Runtime And GC Rules

- Strings and types are interned.
- Strings generally come from `gc.copyString`.
- Types generally come from `gc.type_registry.getTypeDef`.
- When doing work while the VM is running, temporary Buzz objects must be pushed on the stack so they are not collected by the GC.
- When doing work while the VM is running, temporary buzz objects must be pushed on the stack so they are not collected by the GC.

## JIT And Debug Flags

Expand Down Expand Up @@ -174,5 +175,5 @@ The matrix writes timings and output-hash comparisons under `zig-cache/jit-bench
- For parser/typechecker/codegen issues, prefer the smallest `.buzz` regression test that reproduces the behavior.
- For VM or GC issues, check object lifetime and stack rooting before changing collection behavior.
- For JIT issues, compare behavior with JIT enabled and disabled before changing JIT code.
- For FFI issues, be careful with pointer lifetimes and ownership across the Zig/Buzz boundary.
- For FFI issues, be careful with pointer lifetimes and ownership across the Zig/buzz boundary.
- If a change may affect performance, mention that in the final response when relevant, but do not run benchmarks unless explicitly asked.
23 changes: 20 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ This release brings a lot of useful tools to write buzz code: LSP, formatter and
- Windows support (https://github.com/buzz-language/buzz/issues/74)
- First working version of a LSP thanks to [lsp-kit](https://github.com/zigtools/lsp-kit) (https://github.com/buzz-language/buzz/issues/16)
- First working version of the debugger that implements the [Debugger Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/) thanks to [buzz-language/dap-kit](https://github.com/buzz-language/dap-kit) (https://github.com/buzz-language/buzz/issues/88)
- Code formatter (`buzz --fmt`) (https://github.com/buzz-language/buzz/issues/96)
- Code formatter (`buzz format`) (https://github.com/buzz-language/buzz/issues/96)
- Package manager (https://github.com/buzz-language/buzz/issues/85)
- Package manifests with `manifest.buzz` and the new `buzz:manifest` std lib definitions
- Package scaffolding with `buzz init`
- Dependency fetching with `buzz fetch`, supporting git repositories, archives and local directories
- `manifest.lock.buzz` lock files with resolved refs and dependency content hashes
- `match` statement/expression for value matching with type-specific condition semantics (https://github.com/buzz-language/buzz/issues/80)
- Enum name can be omitted if it can be inferred (`final list: [Locale] = [ .fr, .it, .en ]`) (https://github.com/buzz-language/buzz/issues/360)
- Object initialization name can be omitted if it can be inferred (`final payload: Payload = .{ data "..." };`) (https://github.com/buzz-language/buzz/issues/373)
Expand All @@ -25,15 +30,27 @@ This release brings a lot of useful tools to write buzz code: LSP, formatter and

## Changed

- buzz binary now uses subcommands rather than options
- `buzz <script.buzz>` becomes `buzz run-script <script.buzz>`
- `buzz -t <script.buzz>` becomes `buzz test <script.buzz>`
- `buzz -f <script.buzz>` becomes `buzz format <script.buzz>`
- `buzz run` runs `src/main.buzz` from the current package
- `buzz init` and `buzz fetch` manage package scaffolding and dependencies
- `buzz` will start the REPL
- Extern libraries now must expose only one function which will be called by the compiler to lookup the functions of the library
- `int` are now `i48` instead of `i32` (https://github.com/buzz-language/buzz/issues/306). If you're wondering why, it's because all buzz values live in a NaN boxed f64 and the maximum bits available for an integer in there is 48. However, C ABI does not understand `i48` so we're still stuck with `i32` in FFI for now.
- `main` signature can omit `args` argument
- Maximum number of enum cases is now 16 777 215 instead of 255
- `pattern.matchAgainst` returns now a list of `obj{ start: int, end: int, capture: str }` and `matchAllAgainst` a list of those lists
- Selective import erases the imported namespace: `import print from "std"; ... print("hello world");`
- Common part of imported namespace gets erased: il imported file as namesapce `a\b\c` and importing script has namespace `a\b`, only `c\` remains
- Tuples no longer require free form identifier to access their properties: `tuple.@"0"` can now be `tuple.0`

### Imports
- Import do rely on searchers any more, instead the import path provides a deterministic way of finding the imported script
- `buzz:<name>` will look for a buzz's standard library `<name>`
- `pkg:<name>/path/to/<script.buzz>` will look for the script under `vendors/<name>/src/path/to/<script.buzz>`
- Selective import erases the imported namespace: `import print from "buzz:std"; ... print("hello world");`
- Common part of imported namespace gets erased: il imported file as namesapce `a\b\c` and importing script has namespace `a\b`, only `c\` remains

## Internal

- JIT compiler works in a separate thread
Expand Down
4 changes: 0 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -674,10 +674,6 @@ fn buildTestLibraries(
foreign_lib.getEmittedBin(),
b.pathJoin(&.{ "tests", "utils", foreign_lib.out_filename }),
);
copy_test_libs.addCopyFileToSource(
hello_lib.getEmittedBin(),
hello_lib.out_filename,
);
copy_test_libs.addCopyFileToSource(
hello_lib.getEmittedBin(),
b.pathJoin(&.{ "tests", "utils", hello_lib.out_filename }),
Expand Down
8 changes: 4 additions & 4 deletions examples/2048.buzz
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
// trying a move that doesn't change the board.
// - Win condition.
// - Lose condition.
import "std";
import "io";
import "errors";
import "os";
import "buzz:std";
import "buzz:io";
import "buzz:errors";
import "buzz:os";

object Pair {
srcX: int,
Expand Down
2 changes: 1 addition & 1 deletion examples/fibonacci.buzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "std";
import "buzz:std";

fun fibonacci(n: int) > void *> int? {
var n1 = 0;
Expand Down
2 changes: 1 addition & 1 deletion examples/fizzbuzz.buzz
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace examples\fizzbuzz;

import "std";
import "buzz:std";

fun fizzBuzz(n: int) > str {
final fizz = n % 3 == 0;
Expand Down
6 changes: 3 additions & 3 deletions examples/game-of-life.buzz
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "std";
import "io";
import "examples/sdl-wrapped" as _;
import "buzz:std";
import "buzz:io";
import "sdl-wrapped" as _;

/// buzz -L/path/to/SDL2.dylib/so/dll examples/game-of-life.buzz
object World {
Expand Down
4 changes: 2 additions & 2 deletions examples/sdl-wrapped.buzz
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace sdl;

import "std";
import "ffi";
import "buzz:std";
import "buzz:ffi";

zdef("SDL2", `
const SDL_Window = opaque{};
Expand Down
2 changes: 1 addition & 1 deletion examples/sdl.buzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "examples/sdl-wrapped" as _;
import "sdl-wrapped" as _;

/// buzz -L/path/to/SDL2.dylib/so/dll examples/sdl.buzz
fun main() > int !> SDLError {
Expand Down
10 changes: 5 additions & 5 deletions examples/sqlite.buzz
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace sqlite;

import "ffi";
import "std";
import "buffer";
import "serialize" as _;
import "errors";
import "buzz:ffi";
import "buzz:std";
import "buzz:buffer";
import "buzz:serialize" as _;
import "buzz:errors";

zdef(
"sqlite3",
Expand Down
6 changes: 3 additions & 3 deletions examples/voronoi-diagram.buzz
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "std";
import "examples/sdl-wrapped" as _;
import "math";
import "buzz:std";
import "sdl-wrapped" as _;
import "buzz:math";

fun hypot(x: int, y: int) > int {
return std\toInt(
Expand Down
1 change: 1 addition & 0 deletions src/Debugger.zig
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ pub fn launch(self: *Debugger, arguments: Arguments(.launch)) Error!Response(.la

// While debugger is active, the program won't start right away
_ = self.session.?.runner.runFile(
null,
program,
&.{}, // TODO
) catch return error.LaunchFailed;
Expand Down
Loading
Loading