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
|
-- lib/supple/request.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Contextual object storage and identification. Wrapping and unwrapping.
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
local capi = require 'supple.capi'
local my_objects_by_obj = {}
local my_objects_by_tag = {}
local my_name = "UNSET"
local my_counter = 0
local their_objects_by_tag = setmetatable({}, { __mode="v" })
local their_objects_by_obj = setmetatable({}, { __mode="k" })
local proc_call = nil
local type = capi.rawtype
local function set_name(newname)
my_name = newname
end
local function set_proc_call(pc)
proc_call = pc
end
local integral = {
["nil"] = true,
boolean = true,
string = true,
number = true,
}
local function give(obj)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- If the passed object is one of their objects then "unwrap" it by
-- returning their tag.
local tag = their_objects_by_obj[obj];
if tag then
return { tag = tag }
end
-- If it's one of our objects which has already been wrapped, return our
-- tag
local tag = my_objects_by_obj[obj]
if tag then
return { tag = tag }
end
-- otherwise wrap it freshly for us and return that.
local tag = ("%s:%d"):format(my_name, my_counter)
local expn = capi.explain(obj, tag)
my_objects_by_obj[obj] = tag
my_objects_by_tag[tag] = obj
return expn
end
local function receive(obj)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- It's not integral, so it must be a tagged object
assert(type(obj) == "table")
assert(type(obj.tag) == "string")
local tag = obj.tag
-- First up, is it one of our objects?
local ret = my_objects_by_tag[tag]
if ret then
return ret
end
-- Now is it a known one of their objects?
ret = their_objects_by_tag[tag]
if ret then
return ret
end
-- Okay, prepare a proxy?
assert(type(obj.type) == "string")
local proxy, mt = capi.new_proxy(obj.type)
their_objects_by_tag[tag] = proxy
their_objects_by_obj[proxy] = tag
-- Fill out the metatable
obj.methods = obj.methods or {}
obj.methods[#obj.methods+1] = "__gc"
if obj.type == "function" then
obj.methods[#obj.methods+1] = "__call"
end
if obj.type == "table" then
obj.methods[#obj.methods+1] = "__index"
obj.methods[#obj.methods+1] = "__newindex"
end
for _, name in ipairs(obj.methods or {}) do
local function meta_func(...)
return proc_call(tag, name, ...)
end
mt[name] = meta_func
end
-- And return the proxy object
return proxy
end
return {
set_name = set_name,
set_proc_call = set_proc_call,
give = give,
receive = receive,
}
|