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
|
local tablex = require 'pl.tablex'
local function save()
local g = {}
for k,_ in next, _G, nil do
g[k] = rawget(_G, k)
end
return {
gmt = getmetatable(_G),
g = g,
loaded = tablex.copy(package.loaded)
}
end
local function restore(state)
setmetatable(_G, state.gmt)
for k,_ in next, _G, nil do
rawset(_G, k, state.g[k])
end
for k,_ in pairs(package.loaded) do
package.loaded[k] = state.loaded[k]
end
end
return function()
local context = {}
local data = {}
local parents = {}
local children = {}
local stack = {}
function context.ref()
local ref = {}
local ctx = data
function ref.get(key)
if not key then return ctx end
return ctx[key]
end
function ref.set(key, value)
ctx[key] = value
end
function ref.clear()
data = {}
parents = {}
children = {}
stack = {}
ctx = data
end
function ref.attach(child)
if not children[ctx] then children[ctx] = {} end
parents[child] = ctx
table.insert(children[ctx], child)
end
function ref.children(parent)
return children[parent] or {}
end
function ref.parent(child)
return parents[child]
end
function ref.push(current)
if not parents[current] then error('Detached child. Cannot push.') end
if ctx ~= current and current.descriptor == 'file' then
current.state = save()
end
table.insert(stack, ctx)
ctx = current
end
function ref.pop()
local current = ctx
ctx = table.remove(stack)
if ctx ~= current and current.state then
restore(current.state)
current.state = nil
end
if not ctx then error('Context stack empty. Cannot pop.') end
end
return ref
end
return context
end
|