-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathseq.lua
162 lines (138 loc) · 2.83 KB
/
seq.lua
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
local mt = {}
mt.__index = mt
mt.length = function(self)
return #self.data
end
mt.current = function(self, str)
if str then self.data[self.cursor] = str end
return self.data[self.cursor]
end
mt.peek = function(self, offset)
return self.data[self.cursor + offset]
end
mt.next = function(self, offset)
offset = offset or 1
self.cursor = self.cursor + offset
return self.data[self.cursor], self.cursor
end
mt.prev = function(self, offset)
offset = offset or 1
self.cursor = self.cursor - offset
return self.data[self.cursor]
end
mt.unget = mt.prev
mt.seek = function(self, offset)
self.cursor = offset
end
mt.reset = function(self)
mt.seek(self, 1)
end
mt.skip_to = function(self, pred)
local pred_ = pred
if type(pred) == 'string' then
pred_ = function(item)
return item:find(pred)
end
end
for item in self:iter() do
if pred_(item) then break end
end
end
mt.skip_over = function(self, pred)
self:skip_to(pred)
self:next()
end
mt.iter = function(self)
self:prev()
return function()
return self:next()
end
end
mt.append = function(self, t)
if type(t) == 'table' then
for _, v in ipairs(t) do
table.insert(self.data, v)
end
else
table.insert(self.data, t)
end
self.count = self.count + #t
end
mt.concat = function(self, delim)
return table.concat(self.data, delim)
end
local function array_to_sequence(t)
local inst = {}
setmetatable(inst, mt)
inst.data = t or {}
inst.count = #inst.data
inst.cursor = 1
return inst
end
local util = {
explode = function(src, sep, no_regex) -- ref. http://lua-users.org/wiki/SplitJoin
local result = {}
local cur = 0
if (#src == 1) then return {src} end
while true do
local i, j = string.find(src, sep, cur, no_regex)
if i then
table.insert(result, src:sub(cur, i-1))
cur = j + 1
else
table.insert(result, src:sub(cur))
break
end
end
return result
end
, load_lines = function(filename)
local t = {}
local f, err
if filename == '--stdin' or filename == '-' then
f = io.stdin
else
f, err = io.open(filename)
end
if f then
for line in f:lines() do
table.insert(t, line)
end
f:close()
return t
else
return nil, err
end
end
, load_text = function(filename)
return io.open(filename):read'*a'
end
, trim = function(s)
-- from PiL2 20.4
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
}
local function new_from_string(str)
return array_to_sequence(
util.explode(str, "\n")
)
end
local function new_from_file(filename)
local lines, err = util.load_lines(filename)
if err then return nil, err end
return array_to_sequence(lines)
end
local function new(t)
if type(t) == 'string' then
return new_from_string(t)
end
t = t or {}
return array_to_sequence(t)
end
----------------------------------------
return {
new = new
, new_from_file = new_from_file
, new_from_string = new_from_string
, util = util
}