Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c56b390
Add tessellation
btipling Oct 16, 2024
f410fc6
Adding a compiler
btipling Oct 16, 2024
0743afd
starting on compiler
btipling Oct 16, 2024
1190d9d
progress on arg parser
btipling Oct 17, 2024
3131d8d
Making progress on reading files
btipling Oct 17, 2024
3b653f8
progress on finding includes
btipling Oct 17, 2024
3126e4b
update docs
btipling Oct 17, 2024
ac6876f
Add parser tests
btipling Oct 18, 2024
77bac13
Add an includer
btipling Oct 18, 2024
56e241c
Compiler works
btipling Oct 18, 2024
fa47c62
works
btipling Oct 18, 2024
0842e59
easy file with embed creation
btipling Oct 18, 2024
9bee21d
It works
btipling Oct 19, 2024
30e6f68
runs
btipling Oct 19, 2024
7dee50c
we are now totally free
btipling Oct 19, 2024
41c77fa
builds
btipling Oct 19, 2024
34f5ab0
it works
btipling Oct 19, 2024
65ea435
back to the tesselation
btipling Oct 19, 2024
451d272
get ready for a new way
btipling Oct 19, 2024
bb18cbd
pretty cool
btipling Oct 19, 2024
8cfeba2
about to add some tessellation
btipling Oct 19, 2024
78cffdb
well it renders
btipling Oct 19, 2024
dd6e074
no errors
btipling Oct 19, 2024
cbe8926
hey some tessellation
btipling Oct 19, 2024
918885b
remove point
btipling Oct 19, 2024
d135066
add a surface scaffolding code
btipling Oct 19, 2024
021c2b0
give surface its own shaders
btipling Oct 19, 2024
acea843
ok bezier surface works
btipling Oct 19, 2024
08dad31
ezpz
btipling Oct 19, 2024
99980b1
Starting on terrain tessellation
btipling Oct 20, 2024
d2cbe36
tesselated terrain low res
btipling Oct 20, 2024
38619be
Hey more terrain
btipling Oct 20, 2024
668ce80
progress on terrain map with lighting
btipling Oct 20, 2024
580b8ae
progress on lights
btipling Oct 20, 2024
2709568
progress
btipling Oct 20, 2024
8466702
yup
btipling Oct 20, 2024
f721441
this is not correct
btipling Oct 20, 2024
53afedc
tessallation works
btipling Oct 20, 2024
421cdb9
fix normal
btipling Oct 20, 2024
3e8b533
Add better limits to attenuation controls
btipling Oct 20, 2024
e166802
use light direction not surface normal for can cast shadow
btipling Oct 20, 2024
a498694
back to tessellation
btipling Oct 20, 2024
8cd4af5
fix tesselator typo
btipling Oct 20, 2024
ff0ebf4
remove stuff
btipling Oct 21, 2024
8f760e8
starting on lod tessellator
btipling Oct 21, 2024
2da6b04
lod works
btipling Oct 21, 2024
42afd21
fix missing y
btipling Oct 21, 2024
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
20 changes: 20 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,24 @@ pub fn build(b: *std.Build) void {
});
const run_tests = b.addRunArtifact(tests);
test_step.dependOn(&run_tests.step);

// fssc - the foundation simple shader compiler
const compiler_exe = b.addExecutable(.{
.name = "fssc",
.root_source_file = b.path("src/compiler.zig"),
.target = target,
.optimize = optimize,
});

b.installArtifact(compiler_exe);

const fssc_cmd = b.addRunArtifact(compiler_exe);

fssc_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
fssc_cmd.addArgs(args);
}

const fssc_step = b.step("fssc", "Compile a shder");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in step description

There's a typo in the description of the "fssc" step. "shder" should be "shader".

Apply this diff to fix the typo:

-    const fssc_step = b.step("fssc", "Compile a shder");
+    const fssc_step = b.step("fssc", "Compile a shader");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fssc_step = b.step("fssc", "Compile a shder");
const fssc_step = b.step("fssc", "Compile a shader");

fssc_step.dependOn(&fssc_cmd.step);
Comment on lines +114 to +131
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add Required C Libraries to "fssc" Executable

The "fssc" executable does not link any system libraries, which may cause issues due to its usage of C functions (c.deinit() and c.run()). Please add the necessary linkSystemLibrary calls in build.zig for "fssc" similar to the "foundations" executable.

  • File: build.zig
  • Executable: fssc
  • Suggestion: Link required C libraries, for example:
    fssc.linkSystemLibrary("c");
🔗 Analysis chain

Verify dependencies for the new "fssc" executable

The new "fssc" executable doesn't have any specific dependencies or libraries linked, unlike the "foundations" executable. If this is intentional, it's fine. However, if "fssc" requires any of the same libraries or has its own dependencies, make sure to add them.

To verify the dependencies, you can check the src/compiler.zig file:

Please review the output of this script to ensure all necessary dependencies are properly linked in the build configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check imports and potential dependencies in src/compiler.zig

# Test: Look for import statements
echo "Checking imports in src/compiler.zig:"
rg -n "^const .* = @import\(" src/compiler.zig

# Test: Look for external function calls that might indicate needed libraries
echo "Checking for potential external dependencies:"
rg -n "std\.c\." src/compiler.zig
rg -n "c\." src/compiler.zig

Length of output: 430


Script:

#!/bin/bash
# Description: Check linker settings for the "fssc" executable in build.zig

# Test: Extract linker flags or library links for "fssc"
echo "Extracting linker settings for fssc in build.zig:"
rg -A5 'b\.addExecutable\(\.\{\s*\.name\s*=\s*"fssc",' build.zig

# Compare with "foundations" executable
echo "Extracting linker settings for foundations in build.zig:"
rg -A5 'b\.addExecutable\(\.\{\s*\.name\s*=\s*"foundations",' build.zig

Length of output: 372


Script:

#!/bin/bash
# Description: Extract all executable definitions and their dependencies in build.zig

# Extract all addExecutable calls with their configurations
echo "Extracting all executable definitions in build.zig:"
rg -C5 'b\.addExecutable\(\.\{' build.zig

# Extract all library linkings
echo "Extracting library linkings in build.zig:"
rg -n '\.linkSystemLibrary\(".*"\)' build.zig

Length of output: 1149

}
16 changes: 16 additions & 0 deletions src/compiler.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pub fn main() !void {
std.debug.print("Starting compiler.\n", .{});

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

const c: *Compiler = try Compiler.init(gpa.allocator());
defer c.deinit();

try c.run();

std.debug.print("Compiler finished.\n", .{});
}

const std = @import("std");
const Compiler = @import("compiler/Compiler.zig");
89 changes: 89 additions & 0 deletions src/compiler/Args.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
parsed: struct {
source_file: ?[]const u8 = null,
output_path: ?[]const u8 = null,
file_name: ?[]const u8 = null,
arg_ctx: arg_context = .none,
} = .{},
source_file: []const u8 = undefined,
output_path: []const u8 = undefined,
file_name: []const u8 = undefined,
process_args: std.process.ArgIterator = undefined,

const Args = @This();

const ValidationErrorSourceInvalid: []const u8 = "invalid --source file path";
const ValidationErrorOutputInvalid: []const u8 = "invalid --output path";
const ValidationErrorNameInvalid: []const u8 = "invalid out file --name";

pub const ArgsError = error{
ValidationErrorSourceInvalid,
ValidationErrorOutputInvalid,
ValidationErrorNameInvalid,
};
Comment on lines +14 to +22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Define error identifiers instead of string constants in 'ArgsError'.

Currently, ArgsError is defined as an error set containing string constants. In Zig, it's more idiomatic to define error identifiers and handle mapping to error messages separately. This improves type safety and makes it easier to handle errors programmatically.

Consider defining ArgsError like this:

-pub const ArgsError = error{
-    ValidationErrorSourceInvalid,
-    ValidationErrorOutputInvalid,
-    ValidationErrorNameInvalid,
-};
+pub const ArgsError = error{
+    SourceInvalid,
+    OutputInvalid,
+    NameInvalid,
+};

Then, define the error messages separately:

const errorMessages = struct {
    pub fn getMessage(err: ArgsError) []const u8 {
        switch (err) {
            .SourceInvalid => return "invalid --source file path",
            .OutputInvalid => return "invalid --output path",
            .NameInvalid => return "invalid out file --name",
        }
    }
};

This way, you can retrieve the error message when needed.


const arg_context = enum {
none,
source_file,
output_path,
file_name,
};

pub fn init(allocator: std.mem.Allocator) !*Args {
var process_args: std.process.ArgIterator = try std.process.argsWithAllocator(allocator);
errdefer process_args.deinit();
const args: *Args = try allocator.create(Args);
args.* = .{
.process_args = process_args,
};
return args;
}

pub fn deinit(self: *Args, allocator: std.mem.Allocator) void {
self.process_args.deinit();
allocator.destroy(self);
}

pub fn parse(self: *Args, _: std.mem.Allocator) !void {
while (self.process_args.next()) |pa| self.handle_arg(pa);
}
Comment on lines +46 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused parameter 'allocator' from 'parse' function.

The parse function takes an allocator parameter which is not used in the function body. Consider removing the unused parameter to simplify the function signature.

Apply this diff to remove the unused parameter:

-pub fn parse(self: *Args, _: std.mem.Allocator) !void {
+pub fn parse(self: *Args) !void {

And update any calls to parse accordingly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn parse(self: *Args, _: std.mem.Allocator) !void {
while (self.process_args.next()) |pa| self.handle_arg(pa);
}
pub fn parse(self: *Args) !void {
while (self.process_args.next()) |pa| self.handle_arg(pa);
}


pub fn validate(self: *Args) ArgsError!void {
self.source_file = self.parsed.source_file orelse return ArgsError.ValidationErrorSourceInvalid;
self.output_path = self.parsed.output_path orelse return ArgsError.ValidationErrorOutputInvalid;
self.file_name = self.parsed.file_name orelse return ArgsError.ValidationErrorSourceInvalid;
}
Comment on lines +51 to +54
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the returned error when validating 'file_name'.

In line 53, when validating self.file_name, the error returned on failure is ArgsError.ValidationErrorSourceInvalid, which is incorrect. It should be ArgsError.ValidationErrorNameInvalid to match the field being validated.

Apply this diff to fix the error:

-    self.file_name = self.parsed.file_name orelse return ArgsError.ValidationErrorSourceInvalid;
+    self.file_name = self.parsed.file_name orelse return ArgsError.ValidationErrorNameInvalid;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.source_file = self.parsed.source_file orelse return ArgsError.ValidationErrorSourceInvalid;
self.output_path = self.parsed.output_path orelse return ArgsError.ValidationErrorOutputInvalid;
self.file_name = self.parsed.file_name orelse return ArgsError.ValidationErrorSourceInvalid;
}
self.source_file = self.parsed.source_file orelse return ArgsError.ValidationErrorSourceInvalid;
self.output_path = self.parsed.output_path orelse return ArgsError.ValidationErrorOutputInvalid;
self.file_name = self.parsed.file_name orelse return ArgsError.ValidationErrorNameInvalid;
}


pub fn debug(self: *Args) void {
std.debug.print("args: \n", .{});
std.debug.print("\t--source {s}\n", .{self.source_file});
std.debug.print("\t--output {s}\n", .{self.output_path});
std.debug.print("\t--name: {s}\n", .{self.file_name});
}

fn handle_arg(self: *Args, pa: [:0]const u8) void {
switch (self.parsed.arg_ctx) {
.none => {
if (std.mem.eql(u8, "--source", pa)) {
self.parsed.arg_ctx = .source_file;
} else if (std.mem.eql(u8, "--output", pa)) {
self.parsed.arg_ctx = .output_path;
} else if (std.mem.eql(u8, "--name", pa)) {
self.parsed.arg_ctx = .file_name;
}
},
Comment on lines +63 to +73
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add handling for unrecognized command-line arguments.

In the handle_arg function, if an unknown argument is passed, it is silently ignored. This could lead to user confusion if they pass an incorrect argument by mistake. Consider adding error handling or a warning message for unrecognized arguments to improve user feedback.

Apply this diff to handle unrecognized arguments:

            } else {
+               std.debug.print("Unrecognized argument: {s}\n", .{pa});
+               // Optionally, set an error state or return an error
            }

Alternatively, you could return an error or set a flag indicating invalid arguments.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn handle_arg(self: *Args, pa: [:0]const u8) void {
switch (self.parsed.arg_ctx) {
.none => {
if (std.mem.eql(u8, "--source", pa)) {
self.parsed.arg_ctx = .source_file;
} else if (std.mem.eql(u8, "--output", pa)) {
self.parsed.arg_ctx = .output_path;
} else if (std.mem.eql(u8, "--name", pa)) {
self.parsed.arg_ctx = .file_name;
}
},
fn handle_arg(self: *Args, pa: [:0]const u8) void {
switch (self.parsed.arg_ctx) {
.none => {
if (std.mem.eql(u8, "--source", pa)) {
self.parsed.arg_ctx = .source_file;
} else if (std.mem.eql(u8, "--output", pa)) {
self.parsed.arg_ctx = .output_path;
} else if (std.mem.eql(u8, "--name", pa)) {
self.parsed.arg_ctx = .file_name;
} else {
std.debug.print("Unrecognized argument: {s}\n", .{pa});
// Optionally, set an error state or return an error
}
},

.source_file => {
self.parsed.source_file = pa;
self.parsed.arg_ctx = .none;
},
.output_path => {
self.parsed.output_path = pa;
self.parsed.arg_ctx = .none;
},
.file_name => {
self.parsed.file_name = pa;
self.parsed.arg_ctx = .none;
},
}
}

const std = @import("std");
97 changes: 97 additions & 0 deletions src/compiler/Compiler.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
allocator: std.mem.Allocator,
ctx: Ctx,

const Compiler = @This();

const CompilerError = error{
NoOutputError,
};

var cwd_buf: [1000]u8 = undefined;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Avoid using global mutable state (cwd_buf).

Using a global mutable buffer cwd_buf can lead to concurrency issues and reduces code modularity. It's better to allocate the buffer locally within the functions that use it.

Apply this diff to allocate the buffer locally:

@@ -10,1 +10,0 @@
-var cwd_buf: [1000]u8 = undefined;
@@ -21,0 +21,1 @@
+        var cwd_buf: [1000]u8 = undefined;
@@ -21 +22 @@
-        const cwd = try std.fs.cwd().realpath(".", &cwd_buf);
+        const cwd = try std.fs.cwd().realpath(".", &cwd_buf);
@@ -68,0 +69,1 @@
+        var cwd_buf: [1000]u8 = undefined;
@@ -68 +70 @@
-            .cwd = std.fs.cwd().realpath(".", &cwd_buf) catch @panic("no cwd"),
+            .cwd = try std.fs.cwd().realpath(".", &cwd_buf),

Also applies to: 21-21, 68-68


pub const Ctx = struct {
cwd: []const u8,
args: *Args,
};

pub fn init(allocator: std.mem.Allocator) !*Compiler {
const c: *Compiler = try allocator.create(Compiler);
errdefer allocator.destroy(c);

const cwd = try std.fs.cwd().realpath(".", &cwd_buf);
c.* = .{
.allocator = allocator,
.ctx = .{
.cwd = cwd,
.args = Args.init(allocator) catch |err| std.debug.panic("{any}\n", .{err}),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Use proper error propagation instead of terminating with panic.

Using std.debug.panic and @panic for error handling abruptly terminates the program and is not suitable for production code. Consider propagating errors to allow callers to handle them gracefully.

Apply this diff to propagate errors:

@@ -26 +26 @@
-                .args = Args.init(allocator) catch |err| std.debug.panic("{any}\n", .{err}),
+                .args = try Args.init(allocator),
@@ -33 +33 @@
-        self.ctx.args.parse(self.allocator) catch |err| std.debug.panic("{any}\n", .{err});
+        try self.ctx.args.parse(self.allocator);
@@ -34 +34 @@
-        self.ctx.args.validate() catch |err| std.debug.panic("{any}\n", .{err});
+        try self.ctx.args.validate();
@@ -68 +70 @@
-            .cwd = std.fs.cwd().realpath(".", &cwd_buf) catch @panic("no cwd"),
+            .cwd = try std.fs.cwd().realpath(".", &cwd_buf),

Also applies to: 33-34, 68-68

},
};
return c;
}

pub fn run(self: *Compiler) !void {
self.ctx.args.parse(self.allocator) catch |err| std.debug.panic("{any}\n", .{err});
self.ctx.args.validate() catch |err| std.debug.panic("{any}\n", .{err});
self.ctx.args.debug();

const source_file: *File = try File.init(self.allocator, self.ctx, self.ctx.args.source_file);
defer source_file.deinit(self.allocator);
try source_file.read(self.allocator);
if (source_file.bytes) |bytes| std.debug.print("numbytes: {d}\n", .{bytes.len});

var parser: *Parser = try Parser.init(self.allocator, source_file);
defer parser.deinit(self.allocator);

try parser.parse(self.allocator);

parser.debug();

var inc = try Includer.init(self.allocator, source_file, self.ctx, parser);
defer inc.deinit(self.allocator);

try inc.fetch(self.allocator, self.ctx);
try inc.include(self.allocator);
try inc.output_file.write(self.allocator);
}

// Caller owns returned bytes.
pub fn runWithBytes(
allocator: std.mem.Allocator,
in: []const u8,
) ![]u8 {
var args: Compiler.Args = .{
.source_file = "sourc.glsl",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the typo in the source file name.

The source file name "sourc.glsl" seems to be a typo. It should likely be "source.glsl".

Apply this diff to fix the typo:

@@ -63 +63 @@
-            .source_file = "sourc.glsl",
+            .source_file = "source.glsl",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.source_file = "sourc.glsl",
.source_file = "source.glsl",

.output_path = "out",
.file_name = "shader.out.glsl",
};
const ctx: Compiler.Ctx = .{
.cwd = std.fs.cwd().realpath(".", &cwd_buf) catch @panic("no cwd"),
.args = &args,
};
const source_file: *File = try File.initWithEmbed(allocator, in);
defer source_file.deinit(allocator);

var parser: *Parser = try Parser.init(allocator, source_file);
defer parser.deinit(allocator);

try parser.parse(allocator);

var inc = try Includer.init(allocator, source_file, ctx, parser);
defer inc.deinit(allocator);

try inc.fetch(allocator, ctx);
try inc.include(allocator);
const bytes = inc.output_file.bytes orelse return CompilerError.NoOutputError;
return try allocator.dupe(u8, bytes);
}

pub fn deinit(self: *Compiler) void {
self.ctx.args.deinit(self.allocator);
self.allocator.destroy(self);
}

const std = @import("std");
pub const Args = @import("Args.zig");
const File = @import("File.zig");
const Parser = @import("Parser.zig");
const Includer = @import("Includer.zig");
61 changes: 61 additions & 0 deletions src/compiler/File.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
path: []const u8 = undefined,
absolute_path: ?[]const u8 = null,
bytes: ?[]const u8 = null,
owned: bool = true,
ctx: Compiler.Ctx = undefined,

const File = @This();

const FileError = error{
NoBytesToWriteError,
NoPathError,
};

const max_bytes = 4096 << 12;

pub fn init(allocator: std.mem.Allocator, ctx: Compiler.Ctx, path: []const u8) !*File {
const f: *File = try allocator.create(File);
errdefer allocator.destroy(f);

const full_source_path = try std.fs.path.join(allocator, &[_][]const u8{ ctx.cwd, path });

f.* = .{
.path = path,
.absolute_path = full_source_path,
.ctx = ctx,
};
return f;
}

pub fn initWithEmbed(allocator: std.mem.Allocator, bytes: []const u8) !*File {
const f: *File = try allocator.create(File);
errdefer allocator.destroy(f);

f.* = .{
.bytes = bytes,
.owned = false,
};
return f;
}

pub fn read(self: *File, allocator: std.mem.Allocator) !void {
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
const fs = try std.fs.openFileAbsolute(absolute_path, .{});
self.bytes = try fs.readToEndAlloc(allocator, max_bytes);
}
Comment on lines +42 to +45
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure file handles are properly closed after file operations

In the read function, the file handle fs opened with std.fs.openFileAbsolute is not being closed, which could lead to resource leaks. Please close the file handle after reading.

Apply the following diff to close the file handle:

 pub fn read(self: *File, allocator: std.mem.Allocator) !void {
     const absolute_path = self.absolute_path orelse return FileError.NoPathError;
-    const fs = try std.fs.openFileAbsolute(absolute_path, .{});
+    var fs = try std.fs.openFileAbsolute(absolute_path, .{});
+    defer fs.close();
     self.bytes = try fs.readToEndAlloc(allocator, max_bytes);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
const fs = try std.fs.openFileAbsolute(absolute_path, .{});
self.bytes = try fs.readToEndAlloc(allocator, max_bytes);
}
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
var fs = try std.fs.openFileAbsolute(absolute_path, .{});
defer fs.close();
self.bytes = try fs.readToEndAlloc(allocator, max_bytes);
}


pub fn write(self: *File, _: std.mem.Allocator) !void {
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
const bytes = self.bytes orelse return FileError.NoBytesToWriteError;
const fs = try std.fs.createFileAbsolute(absolute_path, .{});
try fs.writeAll(bytes);
}
Comment on lines +48 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure file handles are properly closed after file operations

In the write function, the file handle fs created with std.fs.createFileAbsolute is not being closed, which could lead to resource leaks. Please close the file handle after writing.

Apply the following diff to close the file handle:

 pub fn write(self: *File, _: std.mem.Allocator) !void {
     const absolute_path = self.absolute_path orelse return FileError.NoPathError;
     const bytes = self.bytes orelse return FileError.NoBytesToWriteError;
-    const fs = try std.fs.createFileAbsolute(absolute_path, .{});
+    var fs = try std.fs.createFileAbsolute(absolute_path, .{});
+    defer fs.close();
     try fs.writeAll(bytes);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
const bytes = self.bytes orelse return FileError.NoBytesToWriteError;
const fs = try std.fs.createFileAbsolute(absolute_path, .{});
try fs.writeAll(bytes);
}
const absolute_path = self.absolute_path orelse return FileError.NoPathError;
const bytes = self.bytes orelse return FileError.NoBytesToWriteError;
var fs = try std.fs.createFileAbsolute(absolute_path, .{});
defer fs.close();
try fs.writeAll(bytes);
}


pub fn deinit(self: *File, allocator: std.mem.Allocator) void {
if (self.absolute_path) |absolute_path| allocator.free(absolute_path);
if (self.owned) if (self.bytes) |b| allocator.free(b);
allocator.destroy(self);
}

const std = @import("std");
const Compiler = @import("Compiler.zig");
Loading