1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-11 00:52:44 +03:00

zig: simplify the reader, fix a memory leak

This commit is contained in:
Nicolas Boulenguez 2024-09-19 14:00:11 +02:00 committed by Joel Martin
parent 8c7d495eea
commit 0a24696ae1
13 changed files with 59 additions and 176 deletions

View File

@ -294,18 +294,14 @@ fn empty(args: []*MalType) !*MalType {
}
fn prn(args: []*MalType) MalError!*MalType {
const s = try printer.print_mal_to_string(args, true, true);
defer Allocator.free(s);
try stdout_file.writeAll(s);
try printer.n_stdout(args, true, true);
try stdout_file.writeAll("\n");
const mal = &MalType.NIL;
return mal;
}
fn println(args: []*MalType) !*MalType {
const s = try printer.print_mal_to_string(args, false, true);
defer Allocator.free(s);
try stdout_file.writeAll(s);
try printer.n_stdout(args, false, true);
try stdout_file.writeAll("\n");
const mal = &MalType.NIL;
return mal;
@ -313,11 +309,13 @@ fn println(args: []*MalType) !*MalType {
fn str(args: []*MalType) !*MalType {
const items = try printer.print_mal_to_string(args, false, false);
errdefer Allocator.free(items);
return MalType.new_string(items, false);
}
fn pr_str(args: []*MalType) !*MalType {
const s = try printer.print_mal_to_string(args, true, true);
errdefer Allocator.free(s);
return MalType.new_string(s, false);
}

View File

@ -1,208 +1,114 @@
const io = @import("std").io;
const fmt = @import("std").fmt;
const std = @import("std");
const stdout_writer = std.io.getStdOut().writer();
const Allocator = @import("std").heap.c_allocator;
const MalType = @import("types.zig").MalType;
const MalLinkedList = @import("linked_list.zig").MalLinkedList;
const MalError = @import("error.zig").MalError;
const ResizeBuffer = struct {
buffer: ?[]u8,
pos: usize,
len: usize,
};
// TODO fix emacs highlighting, remove this
const backslash =
\\\
;
fn appendToBuffer(resize_buffer: *ResizeBuffer, buffer: []const u8) !void {
const n: usize = buffer.len;
if(n + resize_buffer.pos > resize_buffer.len or resize_buffer.buffer == null) {
var new_len: usize = 10;
const new_len2 = 2*resize_buffer.len;
if(new_len < new_len2)
new_len = new_len2;
const new_len3 = n+resize_buffer.pos;
if(new_len < new_len3)
new_len = new_len3;
var bigger_buffer: [] u8 = try Allocator.alloc(u8, new_len);
if(resize_buffer.buffer) |old_buffer| {
for(0..resize_buffer.len) |i|
bigger_buffer[i] = old_buffer[i];
Allocator.free(old_buffer);
}
resize_buffer.buffer = bigger_buffer;
resize_buffer.len = new_len;
}
if(resize_buffer.buffer) |n_buffer|
for(0..n) |i| {
n_buffer[resize_buffer.pos] = buffer[i];
resize_buffer.pos += 1;
};
pub fn one_stdout(mal: MalType) !void {
try print_to_buffer(mal, stdout_writer, true);
}
// TODO: Writer and ResizeBuffer should probably me merged.
fn writeFn(context: *ResizeBuffer, bytes: []const u8) !usize {
try appendToBuffer(context, bytes);
return bytes.len;
}
pub const Writer = io.Writer(*ResizeBuffer, MalError, writeFn);
pub fn writer(rb: *ResizeBuffer) Writer {
return .{ .context = rb };
pub fn n_stdout(args: []const *MalType, readably: bool, sep: bool) !void {
try n_writer(stdout_writer, args, readably, sep);
}
pub fn print_str(mal: MalType) ![]const u8 {
// const stdout_file = io.getStdOut();
var rb = ResizeBuffer{
.buffer = null,
.pos = 0,
.len = 0,
};
try print_to_buffer(mal, &rb, true);
if(rb.buffer) |buffer| {
//stdout_file.write(buffer[0..rb.pos]);
//stdout_file.write("\n");
var return_string: [] u8 = try Allocator.alloc(u8, rb.pos);
// TODO: replace with memcpy (and elsewhere)
for (0..rb.pos) |i| {
return_string[i] = buffer[i];
}
Allocator.free(buffer);
return return_string;
}
return MalError.SystemError;
}
pub fn print_mal_to_string(args: []const *MalType, readable: bool, sep: bool) ![] u8 {
// TODO: handle empty string
var rb = ResizeBuffer{
.buffer = null,
.pos = 0,
.len = 0,
};
fn n_writer(rb: anytype, args: []const *MalType, readable: bool, sep: bool) !void {
for (args, 0..) |node, idx| {
if(0 < idx and sep) {
try appendToBuffer(&rb, " ");
try rb.writeAll(" ");
}
try print_to_buffer(node.*, &rb, readable);
try print_to_buffer(node.*, rb, readable);
}
// TODO: is this the right exception?
if(rb.buffer) |buffer| {
const len = rb.pos;
var return_string: [] u8 = try Allocator.alloc(u8, len);
for (0..len) |i| {
return_string[i] = buffer[i];
}
Allocator.free(buffer);
return return_string;
}
const s: []u8 = "";
return s;
}
fn print_to_buffer(mal: MalType, rb: *ResizeBuffer, readable: bool) !void {
pub fn print_mal_to_string(args: []const *MalType, readable: bool, sep: bool) ![]u8 {
var rb = std.ArrayListUnmanaged(u8) { };
errdefer rb.deinit(Allocator);
const writer = rb.writer(Allocator);
try n_writer(writer, args, readable, sep);
return rb.toOwnedSlice(Allocator);
}
fn print_to_buffer(mal: MalType, rb: anytype, readable: bool) MalError!void {
switch(mal) {
.String => |string| {
if(readable) {
try appendToBuffer(rb, "\"");
try rb.writeAll("\"");
// TODO: optimize this
for(string.data, 0..) |this_char, i| {
if(this_char == '"' or this_char==92) {
try appendToBuffer(rb, backslash);
try rb.writeAll(backslash);
}
if(this_char == '\n') {
try appendToBuffer(rb, "\\n");
try rb.writeAll("\\n");
}
else {
try appendToBuffer(rb, string.data[i..i+1]);
try rb.writeAll(string.data[i..i+1]);
}
}
try appendToBuffer(rb, "\"");
try rb.writeAll("\"");
}
else {
try appendToBuffer(rb, string.data);
try rb.writeAll(string.data);
}
},
.Keyword => |kwd| {
try appendToBuffer(rb, ":");
try appendToBuffer(rb, kwd.data);
try rb.writeAll(":");
try rb.writeAll(kwd.data);
},
.Int => |val| {
try fmt.format(writer(rb), "{0}", .{val.data});
try rb.print("{0}", .{val.data});
},
.Nil => {
try appendToBuffer(rb, "nil");
try rb.writeAll("nil");
},
.True => {
try appendToBuffer(rb, "true");
try rb.writeAll("true");
},
.False => {
try appendToBuffer(rb, "false");
try rb.writeAll("false");
},
.List => |l| {
try appendToBuffer(rb, "(");
for (l.data.items, 0..) |next_mal, i| {
if(0<i) {
try appendToBuffer(rb, " ");
}
try print_to_buffer(next_mal.*, rb, readable);
}
try appendToBuffer(rb, ")");
try rb.writeAll("(");
try n_writer(rb, l.data.items, readable, true);
try rb.writeAll(")");
},
.Vector => |v| {
try appendToBuffer(rb, "[");
for (v.data.items, 0..) |next_mal, i| {
if(0<i) {
try appendToBuffer(rb, " ");
}
try print_to_buffer(next_mal.*, rb, readable);
}
try appendToBuffer(rb, "]");
try rb.writeAll("[");
try n_writer(rb, v.data.items, readable, true);
try rb.writeAll("]");
},
.Atom => |atom_value| {
try appendToBuffer(rb, "(atom ");
try rb.writeAll("(atom ");
try print_to_buffer(atom_value.data.*, rb, readable);
try appendToBuffer(rb, ")");
try rb.writeAll(")");
},
.Func, .FnCore => {
try appendToBuffer(rb, "#<function>");
try rb.writeAll("#<function>");
},
.Symbol => |value| {
try appendToBuffer(rb, value.data);
try rb.writeAll(value.data);
},
.HashMap => |h| {
try appendToBuffer(rb, "{");
try rb.writeAll("{");
var iterator = h.data.iterator();
var first = true;
while(iterator.next()) |pair| {
if(!first) {
try appendToBuffer(rb, " ");
}
switch (pair.key_ptr.*.*) {
.Keyword => |k| {
try appendToBuffer(rb, ":");
try appendToBuffer(rb, k.data);
},
.String => |s| {
try appendToBuffer(rb, "\"");
try appendToBuffer(rb, s.data);
try appendToBuffer(rb, "\"");
},
else => unreachable,
try rb.writeAll(" ");
}
try appendToBuffer(rb, " ");
try print_to_buffer(pair.key_ptr.*.*, rb, true);
try rb.writeAll(" ");
try print_to_buffer(pair.value_ptr.*.*, rb, readable);
first = false;
}
try appendToBuffer(rb, "}");
try rb.writeAll("}");
},
}
}

View File

@ -7,7 +7,6 @@ const pcre = @cImport({
const MalType = @import("types.zig").MalType;
const MalError = @import("error.zig").MalError;
const MalLinkedList = @import("linked_list.zig").MalLinkedList;
const printer = @import("printer.zig");
const Allocator = @import("std").heap.c_allocator;
const string_eql = @import("std").hash_map.eqlString;

View File

@ -19,9 +19,7 @@ fn EVAL(a: *MalType) *MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -65,9 +65,7 @@ fn EVAL(mal: *MalType, env: hash_map.MalHashMap) MalError!*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -118,9 +118,7 @@ fn EVAL_let(args: []*MalType, env: *Env) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -176,9 +176,7 @@ fn EVAL_fn(args: []*MalType, env: *Env) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -207,9 +207,7 @@ fn EVAL_fn(args: []*MalType, env: *Env) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -213,9 +213,7 @@ fn EVAL_fn(args: []*MalType, env: *Env) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -301,9 +301,7 @@ fn qq_loop(items: []*MalType) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -333,9 +333,7 @@ fn qq_loop(items: []*MalType) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -370,9 +370,7 @@ fn qq_loop(items: []*MalType) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}

View File

@ -370,9 +370,7 @@ fn qq_loop(items: []*MalType) !*MalType {
}
fn PRINT(mal: MalType) !void {
const output = try printer.print_str(mal);
defer Allocator.free(output);
try stdout_file.writeAll(output);
try printer.one_stdout(mal);
try stdout_file.writeAll("\n");
}