FLD3LMMKYONE4I6TMVNQOT3QT2QGGQNXPGXLX6RYDUOCLP7JTCBAC
const std = @import("std");
const Scanner = @import("./Scanner.zig");
pub fn main() !void {
var gen_alloc = std.heap.GeneralPurposeAllocator(.{
.stack_trace_frames = 128,
}){};
defer std.debug.assert(!gen_alloc.deinit());
const gpa = gen_alloc.allocator();
const args = try std.process.argsAlloc(gpa);
defer std.process.argsFree(gpa, args);
switch (args.len) {
1 => {
try runPrompt(gpa);
},
2 => {
try runFile(gpa, args[1]);
},
else => {
std.debug.print("Usage: jlox [script]\n", .{});
},
}
}
// No Mutex shenanigans, as there is no async yet.
// var stdout_mutex: std.event.Lock = .{};
pub fn print(comptime fmt: []const u8, args: anytype) !void {
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
const stdout = bw.writer();
stdout.print(fmt, args) catch return;
try bw.flush();
}
pub fn readLine(allocator: std.mem.Allocator) !?[]u8 {
var br = std.io.bufferedReader(std.io.getStdIn().reader());
const stdin = br.reader();
return stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(u8));
}
fn runPrompt(allocator: std.mem.Allocator) !void {
while (true) {
try print("> ", .{});
// Quit on errors
const line = try readLine(allocator);
// Handle EOF gracefully, and dealloc each line when done.
// TODO Maybe store lines if they don't form a full statement, until they do.
if (line) |uline| {
defer allocator.free(uline);
if (uline.len == 0) {
break;
}
try run(allocator, uline);
} else {
break;
}
}
}
fn runFile(allocator: std.mem.Allocator, file_name: [:0]u8) !void {
std.debug.print("Running file {s}\n", .{file_name});
const cwd = std.fs.cwd();
const file = try cwd.openFileZ(file_name, .{ .mode = .read_only });
const contents = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
// defer allocator.free(contents);
try run(allocator, contents);
}
fn run(allocator: std.mem.Allocator, source: []u8) !void {
std.debug.print("{s}\n", .{source});
var scanner = try Scanner.init(allocator);
defer scanner.deinit();
for (try scanner.scanTokens()) |token| {
std.debug.print("{d}:{d} \'{?s}\' : {any}\n", .{
token.source_start,
token.source_end(),
token.data,
token.token_type,
});
}
}
// test "simple test" {
// var list = std.ArrayList(i32).init(std.testing.allocator);
// defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
// try list.append(42);
// try std.testing.expectEqual(@as(i32, 42), list.pop());
// }
//! Because these are u32, the max size for source is limited to 4GiB
//! Which means that for reading source, the maximum bytes read should be
//! std.math.maxInt(u32)
const Self = @This();
/// Token type
const Type = enum {
identifier,
};
token_type: Type,
data: ?[]const u8,
source_start: u32, // Source end should be automatically calculated
pub fn source_end(self: *const Self) u32 {
return self.source_start + @truncate(u32, (self.data orelse &[_]u8{}).len);
}
const std = @import("std");
const Token = @import("./Token.zig");
const Self = @This();
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) !Self {
return .{ .allocator = allocator };
}
pub fn deinit(self: *Self) void {
_ = self;
}
pub fn scanTokens(self: *Self) ![]const Token {
_ = self;
return &[_]Token{.{
.token_type = .identifier,
.data = "deez",
.source_start = 0,
}};
}
const std = @import("std");
const ErrorType = error{};
pub fn err(line: u32, comptime fmt: []const u8, args: anytype) !void {
report(line, "unspecified", fmt, args);
}
pub fn report(line: u32, where: []const u8, comptime fmt: []const u8, args: anytype) !void {
const bw = std.io.bufferedWriter(std.io.getStdErr().writer());
const stderr = bw.writer();
stderr.print("[line {d}] Error ({s}): ", .{ line, where });
stderr.print(fmt, args);
try stderr.flush();
}
.{
.name = "jloxz",
.version = "0.1.0",
.dependencies = .{
.ziglyph = .{
.url = "https://github.com/jecolon/ziglyph/archive/a737cf1808f35f7cb5eb54a9b0bc47d839bae506.tar.gz",
.hash = "1220c892b709f43fac99c3ea7876fd0333274c8bec5fee62f7a341b523687e85d722",
}
}
}
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "jloxz",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// Add deps
const ziglyph = b.dependency("ziglyph", .{
.target = target,
.optimize = optimize,
});
exe.addModule("ziglyph", ziglyph.module("ziglyph"));
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
exe.install();
// This *creates* a RunStep in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = exe.run();
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Creates a step for unit testing.
const exe_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step);
}
zig-cache/
zig-out/
zig-cache/
zig-out/