1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
const std = @import("std");
const gc = @import("gc.zig");
const value = @import("value.zig");
const Value = value.Value;
const State = struct {
alloc: std.mem.Allocator,
input: []const u8,
pos: usize = 0,
next: enum {
start,
list,
list_end,
err,
done,
} = .start,
retval: Value = value.eof.eof,
parent: ?*State = null,
};
pub fn read(input: []const u8) Value {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
var top = State{ .alloc = gpa.allocator(), .input = input };
var s = ⊤
while (s.pos <= s.input.len) : (s.pos += 1) {
s = switch (s.next) {
.start => start(s),
.list => list(s),
.list_end => list(s),
.err => err(s),
.done => ret: {
if (s.parent) |parent| {
s.alloc.destroy(s);
break :ret parent;
} else {
return s.retval;
}
},
};
}
unreachable;
}
fn start(s: *State) *State {
switch (s.input[s.pos]) {
0...8 => s.next = .err,
'\t', '\n' => {},
11...31 => s.next = .err,
' ' => {},
'!' => s.next = .err,
'"' => quotedString(s),
else => s.next = .err,
}
return s;
}
fn quotedString(s: *State) void {
var buf: [6]u8 = .{0} ** 6;
const len = readString(&buf, s);
s.retval = value.pair.cons(
value.sstr.pack("quote"),
value.pair.cons(
value.sstr.pack(buf[0..len]),
value.nil.nil,
),
);
s.next = .done;
}
fn readString(buf: []u8, s: *State) usize {
s.pos += 1; // skip opening quote
for (s.input[s.pos..], 0..) |c, i| {
if (c == '"') {
s.pos += i;
return i;
}
buf[i] = c;
}
unreachable;
}
fn list(s: *State) *State {
return s;
}
fn err(s: *State) *State {
return s;
}
|