summaryrefslogtreecommitdiff
path: root/src/libzisp/read.zig
blob: 9ef9891eb79f042bcbc746c221eb8e35308568b8 (plain)
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;
}