Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CRUSH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
CRUSH.md

Build, lint, test
- Build: zig build
- Run REPL: zig build run
- Run file: zig build run -- path/to/file.buzz
- Install (user): zig build -Doptimize=ReleaseSafe install -p ~/.local
- Install (system): sudo zig build -Doptimize=ReleaseSafe install -p /usr/local
- Clean: rm -rf .zig-cache zig-out
- Typecheck/lsp: zls (use your editor’s Zig LSP); no separate typecheck script
- Format Zig: zig fmt .
- Web WASM tooling: npm install; node src/wasm.ts (uses esbuild+ts)
- Run single test: zig build run -- tests/068-testing.buzz --name "<test_name>" (tests are Buzz scripts; prefer targeted script runs)
- Example single test: zig build run -- tests/023-std.buzz

Project conventions
- Language: Zig 0.15.x; entry in src/main.zig; build via build.zig; vendor deps under vendors/
- Buzz tests: each .buzz file in tests/ acts as an executable scenario; keep them self-contained
- Imports: Zig uses relative imports (const x = @import("file.zig")); keep import blocks at top, grouped std, vendors, local
- Formatting: run zig fmt before commits; keep line width conventional (~100) and avoid trailing spaces
- Types: prefer explicit types in public APIs; use var/const deliberately; avoid anyopaque unless necessary
- Naming: snake_case for Zig functions/vars, TitleCase for types, SCREAMING_SNAKE for compile-time consts
- Errors: use Zig error sets; return !T and propagate with try/errdefer; avoid panic except unrecoverable
- Memory: use provided allocators; pair alloc/free; errdefer for cleanup; avoid leaks in hot paths
- Concurrency: fibers exist at Buzz level; in Zig keep APIs non-blocking where possible
- Logging/Reporting: use Reporter.zig utilities; avoid printing in libraries
- Performance: prefer slices over arrays; minimize copies; use inline and comptime judiciously

Notes
- No .cursor or Copilot rules found
- VS Code: install Buzz extension and Zig LSP for best experience
- Security: never commit secrets; do not log keys or tokens
Empty file added out.txt
Empty file.
14 changes: 7 additions & 7 deletions src/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,11 @@ pub const Slice = struct {
const left_map = if (left.isObj()) obj.ObjMap.cast(left.obj()) else null;

if (right_string) |rs| {
var new_string = std.array_list.Managed(u8).init(gc.allocator);
try new_string.appendSlice(left_string.?.string);
try new_string.appendSlice(rs.string);
var new_string = std.ArrayList(u8).empty;
try new_string.appendSlice(gc.allocator, left_string.?.string);
try new_string.appendSlice(gc.allocator, rs.string);

return (try gc.copyString(try new_string.toOwnedSlice())).toValue();
return (try gc.copyString(try new_string.toOwnedSlice(gc.allocator))).toValue();
} else if (right_float) |rf| {
return Value.fromDouble(rf + left_float.?);
} else if (right_integer) |ri| {
Expand Down Expand Up @@ -819,13 +819,13 @@ pub const Slice = struct {
.String => string: {
const elements = self.nodes.items(.components)[node].String;

var string = std.array_list.Managed(u8).init(gc.allocator);
const writer = &string.writer();
var string = std.ArrayList(u8).empty;
const writer = &string.writer(gc.allocator);
for (elements) |element| {
try (try self.toValue(element, gc)).toString(writer);
}

break :string (try gc.copyString(try string.toOwnedSlice())).toValue();
break :string (try gc.copyString(try string.toOwnedSlice(gc.allocator))).toValue();
},
.Subscript => subscript: {
const components = self.nodes.items(.components)[node].Subscript;
Expand Down
60 changes: 36 additions & 24 deletions src/Codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1142,10 +1142,14 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
const arg_keys = args.keys();
const arg_count = arg_keys.len;

var missing_arguments = std.StringArrayHashMap(usize).init(self.gc.allocator);
defer missing_arguments.deinit();
var missing_arguments = std.StringArrayHashMapUnmanaged(usize).empty;
defer missing_arguments.deinit(self.gc.allocator);
for (arg_keys, 0..) |arg_name, pindex| {
try missing_arguments.put(arg_name.string, pindex);
try missing_arguments.put(
self.gc.allocator,
arg_name.string,
pindex,
);
}

if (components.arguments.len > args.count()) {
Expand Down Expand Up @@ -1211,10 +1215,11 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
}

// Argument order reference
var arguments_order_ref = std.array_list.Managed([]const u8).init(self.gc.allocator);
defer arguments_order_ref.deinit();
var arguments_order_ref = std.ArrayList([]const u8).empty;
defer arguments_order_ref.deinit(self.gc.allocator);
for (components.arguments) |arg| {
try arguments_order_ref.append(
self.gc.allocator,
if (arg.name) |name|
lexemes[name]
else
Expand All @@ -1224,25 +1229,25 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj

// Push default arguments
if (missing_arguments.count() > 0) {
var tmp_missing_arguments = try missing_arguments.clone();
defer tmp_missing_arguments.deinit();
var tmp_missing_arguments = try missing_arguments.clone(self.gc.allocator);
defer tmp_missing_arguments.deinit(self.gc.allocator);
const missing_keys = tmp_missing_arguments.keys();
for (missing_keys) |missing_key| {
if (defaults.get(try self.gc.copyString(missing_key))) |default| {
// TODO: like ObjTypeDef, avoid generating constants multiple time for the same value
try self.emitConstant(locations[node], default);
try self.OP_CLONE(locations[node]);

try arguments_order_ref.append(missing_key);
try arguments_order_ref.append(self.gc.allocator, missing_key);
_ = missing_arguments.orderedRemove(missing_key);
needs_reorder = true;
}
}
}

if (missing_arguments.count() > 0) {
var missing = std.array_list.Managed(u8).init(self.gc.allocator);
const missing_writer = missing.writer();
var missing = std.ArrayList(u8).empty;
const missing_writer = missing.writer(self.gc.allocator);
for (missing_arguments.keys(), 0..) |key, i| {
try missing_writer.print(
"{s}{s}",
Expand All @@ -1255,7 +1260,7 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
},
);
}
defer missing.deinit();
defer missing.deinit(self.gc.allocator);
self.reporter.reportErrorFmt(
.call_arguments,
self.ast.tokens.get(locations[node]),
Expand Down Expand Up @@ -1342,8 +1347,8 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
} else if (error_types) |errors| {
if (self.current.?.enclosing != null and self.current.?.function.?.type_def.resolved_type.?.Function.function_type != .Test) {
var handles_any = false;
var not_handled = std.array_list.Managed(*obj.ObjTypeDef).init(self.gc.allocator);
defer not_handled.deinit();
var not_handled = std.ArrayList(*obj.ObjTypeDef).empty;
defer not_handled.deinit(self.gc.allocator);
for (errors) |error_type| {
if (error_type.def_type == .Void) {
continue;
Expand Down Expand Up @@ -1373,12 +1378,12 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
locations[components.callee],
);
} else {
try not_handled.append(error_type);
try not_handled.append(self.gc.allocator, error_type);
}
}

if (handles_any) {
not_handled.clearAndFree();
not_handled.clearAndFree(self.gc.allocator);
break;
}
}
Expand Down Expand Up @@ -3621,10 +3626,11 @@ fn generateObjectInit(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error

var fields = if (node_type_def.def_type == .ObjectInstance) inst: {
const fields = node_type_def.resolved_type.?.ObjectInstance.of.resolved_type.?.Object.fields;
var fields_type_defs = std.StringArrayHashMap(*obj.ObjTypeDef).init(self.gc.allocator);
var fields_type_defs = std.StringArrayHashMapUnmanaged(*obj.ObjTypeDef).empty;
var it = fields.iterator();
while (it.next()) |kv| {
try fields_type_defs.put(
self.gc.allocator,
kv.value_ptr.*.name,
kv.value_ptr.*.type_def,
);
Expand All @@ -3633,7 +3639,7 @@ fn generateObjectInit(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error
} else node_type_def.resolved_type.?.ForeignContainer.buzz_type;

defer if (node_type_def.def_type == .ObjectInstance) {
fields.deinit();
fields.deinit(self.gc.allocator);
};

const object_location = if (node_type_def.def_type == .ObjectInstance)
Expand All @@ -3642,8 +3648,8 @@ fn generateObjectInit(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error
node_type_def.resolved_type.?.ForeignContainer.location;

// Keep track of what's been initialized or not by this statement
var init_properties = std.StringHashMap(void).init(self.gc.allocator);
defer init_properties.deinit();
var init_properties = std.StringHashMapUnmanaged(void).empty;
defer init_properties.deinit(self.gc.allocator);

for (components.properties) |property| {
const property_name = lexemes[property.name];
Expand Down Expand Up @@ -3701,7 +3707,7 @@ fn generateObjectInit(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error

_ = try self.generateNode(property.value, breaks);

try init_properties.put(property_name, {});
try init_properties.put(self.gc.allocator, property_name, {});

try self.emitCodeArg(
location,
Expand Down Expand Up @@ -4185,8 +4191,8 @@ fn generateTry(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj.
// Jump reached if no error was raised
const no_error_jump = try self.OP_JUMP(self.ast.nodes.items(.end_location)[components.body]);

var exit_jumps = std.array_list.Managed(usize).init(self.gc.allocator);
defer exit_jumps.deinit();
var exit_jumps = std.ArrayList(usize).empty;
defer exit_jumps.deinit(self.gc.allocator);

self.patchTryOrJit(try_jump);
var has_unconditional = components.unconditional_clause != null;
Expand Down Expand Up @@ -4214,7 +4220,10 @@ fn generateTry(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj.
self.current.?.try_should_handle = previous;

// After handling the error, jump over next clauses
try exit_jumps.append(try self.emitJump(location, .OP_JUMP));
try exit_jumps.append(
self.gc.allocator,
try self.emitJump(location, .OP_JUMP),
);

self.patchJump(next_clause_jump);
// Pop `is` result
Expand All @@ -4230,7 +4239,10 @@ fn generateTry(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj.
_ = try self.generateNode(unconditional_clause, breaks);
self.current.?.try_should_handle = previous;

try exit_jumps.append(try self.emitJump(location, .OP_JUMP));
try exit_jumps.append(
self.gc.allocator,
try self.emitJump(location, .OP_JUMP),
);
}

// Tell runtime we're not in a try block anymore
Expand Down
Loading
Loading