File size: 3,323 Bytes
			
			| b6a38d7 | 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 | --- An object which can resolve a key to a value.
-- Context objects can be nested to create a complex value resolution structure.
-- The global function ResolveValue allows resolving a tuple to a value in an arbitrary context.
DefineClass.Context = {
	__parents = {},
	__hierarchy_cache = true,	
}
function Context:new(obj)
	return setmetatable(obj or {}, self)
end
function Context:ResolveValue(key)
	local value = rawget(self, key)
	if value ~= nil then return value end
	for _, sub_context in ipairs(self) do
		value = ResolveValue(sub_context, key)
		if value ~= nil then return value end
	end
end
-- change __index method to allow full member resolution without warning
function OnMsg.ClassesBuilt()
	local context_class = g_Classes.Context
	context_class.__index = function (self, key)
		if type(key) == "string" then
			return rawget(context_class, key) or context_class.ResolveValue(self, key)
		end
	end
end
function Context:IsKindOf(class)
	if IsKindOf(self, class) then return true end
	for _, sub_context in ipairs(self) do
		if IsKindOf(sub_context, "Context") and sub_context:IsKindOf(class) or IsKindOf(sub_context, class) then
			return true
		end
	end
end
function Context:IsKindOfClasses(...)
	if IsKindOfClasses(self, ...) then return true end
	for _, sub_context in ipairs(self) do
		if IsKindOf(sub_context, "Context") and sub_context:IsKindOfClasses(...) or IsKindOfClasses(sub_context, ...) then
			return true
		end
	end
end
function ForEachObjInContext(context, f, ...)
	if not context then return end
	if IsKindOf(context, "Context") then
		for _, sub_context in ipairs(context) do
			ForEachObjInContext(sub_context, f, ...)
		end
	else
		f(context, ...)
	end
end
function SubContext(context, t)
	assert(not IsKindOf(t, "PropertyObject"))
	t = t or {}
	if IsKindOf(context, "PropertyObject") or type(context) ~= "table" then
		t[#t + 1] = context
	elseif type(context) == "table" then
		for _, obj in ipairs(context) do
			t[#t + 1] = obj
		end
		for k, v in pairs(context) do
			if rawget(t, k) == nil then
				t[k] = v
			end
		end
	end
	return Context:new(t)
end
function ResolveValue(context, key, ...)
	if key == nil then return context end
	if type(context) == "table" then
		if IsKindOfClasses(context, "Context", "PropertyObject") then
			return ResolveValue(context:ResolveValue(key), ...)
		end
		return ResolveValue(rawget(context, key), ...)
	end
end
function ResolveFunc(context, key)
	if key == nil then return end
	if type(context) == "table" then
		if IsKindOf(context, "Context") then
			local f = rawget(context, key)
			if type(f) == "function" then
				return f
			end
			for _, sub_context in ipairs(context) do
				local f, obj = ResolveFunc(sub_context, key)
				if f ~= nil then return f, obj end
			end
			return
		end
		if IsKindOf(context, "PropertyObject") and context:HasMember(key) then
			local f = context[key]
			if type(f) == "function" then return f, context end
		else
			local f = rawget(context, key)
			if f == false or type(f) == "function" then return f end
		end
	end
end
function ResolvePropObj(context)
	if IsKindOf(context, "PropertyObject") then
		return context
	end
	if IsKindOf(context, "Context") then
		for _, sub_context in ipairs(context) do
			local obj = ResolvePropObj(sub_context)
			if obj then return obj end
		end
	end
end
 | 
