File: declare.lua

package info (click to toggle)
instead 3.5.2%2Bdfsg-0.3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,316 kB
  • sloc: ansic: 28,336; sh: 452; makefile: 236
file content (254 lines) | stat: -rw-r--r-- 4,992 bytes parent folder | download | duplicates (4)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
-- luacheck: globals const global declare

local declarations = {}
local variables = {}
local std = stead

local type = std.type
local rawget = std.rawget
local rawset = std.rawset
local pairs = std.pairs
local table = std.table
local next = std.next

local function __declare_one(k, v, t)
	local link

	if type(k) ~= 'string' then -- k:find("^[a-zA-Z_][a-zA-Z0-9_]*$") then
		std.err ("Wrong declaration name: "..k, 3)
	end
	if declarations[k] then
		std.err ("Duplicate declaration: "..k, 3)
	end

	link = rawget(_G, k)

	declarations[k] = { value = v, type = t, link = link }

	if link and v ~= link then
		std.err("Overwite global declaration: "..std.tostr(k), 3)
	end

	if t == 'global' then
		if type(v) == 'function' and not std.functions[v] then
			std.err("Use declare to declare function: "..k, 3)
		end
		rawset(_G, k, v)
		variables[k] = true
	end
	if type(v) == 'function' and not std.functions[v] then
		std.functions[v] = k
	end
	if std.__in_init and std.is_obj(v, 'list') then
		table.insert(v.__in_init, v)
	end
end

local function __declare(n, t)
	if stead.game then
		std.err ("Use "..t.." only in global context", 2)
	end
	if type(n) == 'string' then
		return function(v)
			if v == nil then
				v = false
--				std.err("Wrong declaration: "..std.tostr(t), 2)
			end
			__declare_one(n, v, t)
		end
	end
	if type(n) ~= 'table' then
		std.err ("Wrong parameter to "..n, 2)
	end
	for k, v in std.pairs(n) do
		__declare_one(k, v, t)
	end
	return n
end

function std.const(n)
	return __declare(n, 'const')
end

function std.global(n)
	return __declare(n, 'global')

end

function std.declare(n)
	return __declare(n, 'declare')
end

local function do_depends(t, tables, deps)
	if type(t) ~= 'table' then return end
	if tables[t] then
		deps[t] = tables[t]
	end
	for _, v in pairs(t) do
		if type(v) == 'table' and not std.getmt(v) then
			do_depends(v, tables, deps)
		end
	end
end

local function makedeps(nam, depends, deps)
	local ndeps = {}
	local rc = false

	local t = rawget(_G, nam)
	if type(t) ~= 'table' then
		return
	end
	if type(depends[nam]) ~= 'table' then
		return
	end
	local d = depends[nam]
	for k, v in pairs(d) do
		local dd = depends[v]
		if dd and k ~= t then
			ndeps[k] = v
			rc = rc or makedeps(v, depends, deps)
		end
	end
	if not next(ndeps) then
		depends[nam] = nil
		table.insert(deps, t)
		rc = true
	else
		depends[nam] = ndeps
	end
	return rc
end

local function mod_save(fp)
	-- save global variables
	std.tables = {}
	local tables = {}
	local deps = {}
	for k, v in pairs(declarations) do -- name all table variables
		local o = rawget(_G, k) or v.value
		if type(o) == 'table' then
			if not tables[o] then
				tables[o] = k
			end
		end
	end

	for k, _ in pairs(variables) do
		local d = {}
		local o = rawget(_G, k)
		do_depends(o, tables, d)
		if k == tables[o] then -- self depend
			d[o] = nil
		end
		if next(d) then
			deps[k] = d
		end
	end

	std.tables = tables -- save all depends

	for k, _ in pairs(variables) do -- write w/o deps
		local o = rawget(_G, k)
		if not deps[k] then
			std.save_var(o, fp, k)
		end
	end
	for k, _ in pairs(variables) do
		local d = {}
		while makedeps(k, deps, d) do
			for i=1, #d do
				std.save_var(d[i], fp, k)
			end
			d = {}
		end
	end
end

local function mod_init()
	std.setmt(_G, {
	__index = function(_, n)
		local d = declarations[n]
		if d then --
			if std.game and (d.type ~= 'const') then
				rawset(_, n, d.value)
			end
			return d.value
		end
		local f = std.getinfo(2, "S").source
		std.err ("Uninitialized global variable: "..n.." in "..f, 2)
	end;
	__newindex = function(t, k, v)
		if not std.game and std.is_obj(v) then -- autodeclare objects
			__declare_one(k, v, 'declare')
		end
		local d = declarations[k]
		if d then
			if v == d.value then
				return --nothing todo
			end
			if not std.game then
				d.value = v
				return
			end
			if d.type == 'const' then
				std.err ("Modify read-only constant: "..k, 2)
			else
				d.value = v
				rawset(t, k, v)
			end
			return
		end
		if std.game or type(v) ~= 'function' then
			local f = std.getinfo(2, "S").source
			if f ~= '=[C]' then
				std.err ("Set uninitialized variable: "..k.." in "..f, 2)
			end
		end
		rawset(t, k, v)
	end
	})
end

std.obj {
	nam = '@declare';
	ini = function(_, ...)
-- init all list objs
		for _, v in pairs(declarations) do
			if std.is_obj(v.value, 'list') then
				v.value:__ini(...)
			end
		end
	end;
	declarations = function()
		return declarations;
	end;
	variables = function()
		return variables
	end;
}

local function mod_done()
	std.setmt(_G, {})
	local decl = {}
	for k, v in pairs(declarations) do
		local o = std.rawget(_G, k) or v.value
		if std.is_system(o) then -- save system declarations
			decl[k] = v
		elseif not v.link then
			rawset(_G, k, nil)
		end
	end
	std.tables = {}
	std.functions = {}
	declarations = decl
	variables = {}
end

std.mod_init(mod_init)
std.mod_done(mod_done)
std.mod_save(mod_save)

const = std.const
global = std.global
declare = std.declare