-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathapi.lua
125 lines (102 loc) · 2.45 KB
/
api.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
local vstruct = require "vstruct"
local cursor = require "vstruct.cursor"
local ast = require "vstruct.ast"
local lua52 = tonumber(_VERSION:match"%d+%.%d+") >= 5.2
local loadstring = lua52 and load or loadstring
local _unpack = table.unpack or unpack
local api = {}
vstruct.registry = {}
function api.check_arg(caller, index, value, typename, check)
if not check then
check = function(v) return type(v) == typename end
end
return check(value)
or error(string.format(
"bad argument #%d to '%s' (%s expected, got %s)",
index,
caller,
typename,
type(value)))
end
local function is_fd(fd)
local e,r = pcall(function()
return fd and (fd.read or fd.write)
end)
return e and r
end
local function wrap_fd(fd)
if type(fd) == "string" then
return cursor(fd)
end
return fd
end
local function unwrap_fd(fd)
if getmetatable(fd) == cursor then
fd:flush()
return fd.str
end
return fd
end
function api.read(ast, fd, data)
fd = wrap_fd(fd)
api.check_arg("vstruct.read", 2, fd, "file or string", is_fd)
if data ~= nil then
api.check_arg("vstruct.read", 3, data, "table")
end
return ast.ast:read(fd, data or {})
end
function api.write(ast, fd, data)
if fd and not data then
data,fd = fd,nil
end
fd = wrap_fd(fd or "")
api.check_arg("vstruct.write", 2, fd, "file or string", is_fd)
api.check_arg("vstruct.write", 3, data, "table")
local result = ast.ast:write(fd, data)
return unwrap_fd(fd)
end
function api.records(ast, fd, unpacked)
fd = wrap_fd(fd or "")
api.check_arg("vstruct.records", 2, fd, "file or string", is_fd)
if unpacked ~= nil then
api.check_arg("vstruct.records", 3, unpacked, "boolean")
end
return function()
if fd:read(0) then
if unpacked then
return _unpack(ast:read(fd))
else
return ast:read(fd)
end
end
end
end
function api.sizeof(ast)
return ast.ast.size
end
local cache = {}
function api.compile(name, format)
local obj,root
if vstruct.cache ~= nil and cache[format] then
obj = cache[format]
root = obj.ast
else
root = ast.parse(format)
obj = {
source = format;
ast = root;
read = api.read;
write = api.write;
records = api.records;
sizeof = api.sizeof;
}
if vstruct.cache == true then
cache[format] = obj
end
end
if name then
vstruct.registry[name] = root
end
return obj
end
return api