模組:沙盒/a2569875/Script

local p = {}
local sollib = require("Module:Complex_Number/Solver")
local calclib = require("Module:Complex_Number/Calculate")
local noop_func = function()end
--mw.log(require("Module:Complex_Number/Calculate").calc("call(object(mw,logObject),string(abc))",p.script.init(),p.script.init().constructor,true,true,function(msg)mw.log("錯誤! "..msg)end))
p.script={
	new = function(obj)
		if type(obj) == type({}) and obj.isObject then return mw.clone(obj) end
		local value = obj
		local newObj = {
			isObject = true,
			value = value
		}
		newObj.numberType = "object"
		setmetatable(newObj,p.script.ObjectMeta)
		return newObj
	end,['new/doc'] = {name="新物件",title="",othername={},
		example="new(string(text))",description="", count = 1},
	
	['string'] = function(str,...)
		local result = ''..tostring(str)
		local str_list = {...}
		for i = 1,#str_list do
			result = result .. tostring(str_list[i])
		end
		return p.script.new(result)
	end,['string/doc'] = {name="字串物件",title="",othername={},
		example="string(text)",description="", count = 1},

	number = function(num)
		return p.script.new(tonumber(tostring(num)))
	end,['number/doc'] = {name="數字物件",title="",othername={},
		example="number(10)",description="", count = 1},
	
	array = function(...)
		return p.script.toObject({...})
	end,['array/doc'] = {name="陣列物件",title="",othername={},
		example="array(1,2,3)",description="", count = "不定"},
	
	newScope = function()
		return p.script.toObject({})
	end,['newScope/doc'] = {name="新的變數儲存域",title="",othername={},
		example="newScope(nil)",description="", count = 1},
	
	object = function(obj,...)
		local input_obj = obj
		if type(obj) == type({}) and obj.isObject then 
			input_obj = obj.value
		else
			if type(obj) == type("string") then input_obj = _G[obj] end
		end
		if type(input_obj) == type(0) then return p.script.toObject(obj) end
		if type(input_obj) == type(noop_func) then return p.script.toObject(obj) end
		if input_obj == nil then return p.script.toObject(nil) end 
		local members = {...}
		if #members > 0 then
			local it_obj = input_obj
			for i = 1,#members do
				if type(it_obj) ~= type({}) then return nil end
				it_obj = (it_obj or {})[p.script.toObject(members[i]).value]
				if it_obj == nil then return nil end
			end
			return p.script.toObject(it_obj)
		end
		return p.script.toObject(input_obj)
	end,['object/doc'] = {name="物件",title="",othername={},
		example="object(mw,site,namespaces,0,displayName)",description="", count = "不定"},
	
	assignMember = function(obj, member, value)
		local input_obj = p.script.toObject(obj).value
		if type(input_obj) == type("string") then input_obj = _G[input_obj] end
		if type(input_obj) == type(0) then error("無法傳值給數字", 2) end
		if type(input_obj) == type(noop_func) then error("無法傳值給函數", 2) end
		if input_obj == nil then error("無法傳值給空值", 2) end 
		input_obj[p.script.toObject(member).value] = value
		return value
	end,['assignMember/doc'] = {name="賦值",title="",othername={},
		example="",description="", count = "3"},
	
	call = function(obj, ...)
	 	local func = p.script.toObject(obj).value
		if type(func) == type(noop_func) then return func(...)end
		return func
	end,['call/doc'] = {},
	
	typeof=function(input_obj)
		local obj = input_obj
		if type(obj) == type({}) and obj.isObject then obj = obj.value end
		if type(obj) == type({}) then
			if obj.numberType then return p.script.toObject(type(0)) end
			local is_array = true
			for index, data in pairs(obj) do
				if not tonumber(index) and index ~= 'metatable' then
					is_array = false
					break
				end
			end
			if is_array then return p.script.toObject('array') end
		end
		return p.script.toObject(type(obj))
	end,['typeof/doc'] = {},
	
	equals = function(op1, op2)
		local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
		return (obj1 == obj2) and 1 or 0
	end,['equals/doc'] = {},
	
	isTrue = function(op)
		local obj = p.script.toObject(op)
		local val_check = tonumber(tostring(obj.value))
		if val_check then
			return (math.abs(val_check) > 1e-14) and 1 or 0
		end
		return obj.value and 1 or 0
	end,['isTrue/doc'] = {},
	
	isFalse = function(op)
		local obj = p.script.toObject(op)
		local val_check = tonumber(tostring(obj.value))
		if val_check then
			return (math.abs(val_check) > 1e-14) and 0 or 1
		end
		return obj.value and 0 or 1
	end,['isFalse/doc'] = {},
	
	abs = function(op)
		local obj = p.script.toObject(op)
		if type(obj.value) == type(0) then
			return math.abs(tonumber(tostring(obj.value)))
		end
		return obj.value and 1 or 0
	end,
	floor=function(op)
		local obj = p.script.toObject(op)
		return math.floor(obj.value)
	end,
	ceil=function(op)
		local obj = p.script.toObject(op)
		return math.ceil(obj.value)
	end,
	round=function(op1,op2,op3)
		local number = p.script.toObject(op1).value
		local digs = p.script.toObject(op2).value
		local base = p.script.toObject(op3).value
		local round_rad = math.pow(base,digs)
		local check_number = number * round_rad
		check_number = check_number + 0.5
		return math.floor( check_number ) / round_rad
	end,
	div=function(op1,op2)
		local obj1 = p.script.toObject(op1)
		local obj2 = p.script.toObject(op2)
		return obj1.value / obj2.value
	end,
	re=function(z) return tonumber(tostring(z)) or z end,
	im=function(z) return 0 end,
	nonRealPart=function(z) return 0 end,
	conjugate=function(z) return z end,
	inverse=function(op)
		local obj = p.script.toObject(op)
		return 1 / obj.value
	end,
	tovector=function(z)
		return {z}
	end,
	trunc=function(op, digs)
		local obj = p.script.toObject(op)
		local n = tonumber(tostring(digs))
		return sollib._trunc(obj.value, n)
	end,
	digits=function(op)
		local obj = p.script.toObject(op)
		if type(obj.value) == type("string") then return mw.ustring.len(obj.value) end
		local value = math.floor(math.abs(obj.value))
		return tostring(value):len()
	end,
	sqrt=function(op)
		local obj = p.script.toObject(op)
		return math.sqrt(obj.value)
	end,
	sin=function(op)
		local obj = p.script.toObject(op)
		return math.sin(obj.value)
	end,
	cos=function(op)
		local obj = p.script.toObject(op)
		return math.cos(obj.value)
	end,
	tan=function(op)
		local obj = p.script.toObject(op)
		return math.tan(obj.value)
	end,
	cot=function(op)
		local obj = p.script.toObject(op)
		return 1 / math.tan(obj.value)
	end,
	asin=function(op)
		local obj = p.script.toObject(op)
		return math.asin(obj.value)
	end,
	acos=function(op)
		local obj = p.script.toObject(op)
		return math.acos(obj.value)
	end,
	atan=function(op)
		local obj = p.script.toObject(op)
		return math.atan(obj.value)
	end,
	atan2=function(op1,op2)
		local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
		return math.atan2(obj1.value, obj2.value)
	end,
	acot=function(op)
		local obj = p.script.toObject(op)
		return math.atan(1/obj.value)
	end,
	sinh=function(op)
		local obj = p.script.toObject(op)
		return math.sinh(obj.value)
	end,
	cosh=function(op)
		local obj = p.script.toObject(op)
		return math.cosh(obj.value)
	end,
	tanh=function(op)
		local obj = p.script.toObject(op)
		return math.tanh(obj.value)
	end,
	coth=function(op)
		local obj = p.script.toObject(op)
		return math.cosh(obj.value) / math.sinh(obj.value)
	end,
	asinh=function(op)
		local obj = p.script.toObject(op)
		return math.log( obj.value + math.sqrt( obj.value * obj.value + 1 ) )
	end,
	acosh=function(op)
		local obj = p.script.toObject(op)
		return math.log( obj.value + math.sqrt( obj.value * obj.value - 1 ) )
	end,
	atanh=function(op)
		local obj = p.script.toObject(op)
		return 0.5 * math.log((1+obj.value)/(1-obj.value))
	end,
	atanh2=function(op1,op2)
		local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
		return p.script.atanh(obj1.value / obj2.value)
	end,
	acoth=function(op)
		local obj = p.script.toObject(op)
		return 0.5 * math.log((obj.value+1)/(obj.value-1))
	end,
	exp=function(op)
		local obj = p.script.toObject(op)
		return math.exp(obj.value)
	end,
	elog=function(op)
		local obj = p.script.toObject(op)
		return math.log(obj.value)
	end,
	log=function(op,basez)
		local obj = p.script.toObject(op)
		if basez~=nil then return p.script.elog(basez) * p.script.inverse(p.script.elog(op)) end
		return math.log(obj.value)
	end,
	pow=function(op1,op2)
		local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
		return math.pow(obj1.value, obj2.value)
	end,
	random=function(op1,op2)
		local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
		if obj1.value ==nil and obj2.value == nil then return math.random() end
		if obj1.value ==nil then return math.random(obj2.value) end
		if obj2.value == nil then return math.random(obj1.value) end
		return math.random(obj1.value, obj2.value)
	end,
	isReal=function(z) return not not tonumber(tostring(z)) end,
	toObject = function(obj)
		if type(obj) == type({}) and obj.isObject then return obj end
		return p.script.new(obj)
	end,
	loadObject = function(obj)
		if type(obj) == type({}) and obj.isObject then return obj end
		return tonumber(obj)
	end,
	ObjectMeta = {
		__add = function (op1, op2) 
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			if type(obj1.value) == type("string") or type(obj2.value) == type("string") then
				return p.script.new(tostring(op1.value) .. tostring(obj2.value))
			elseif type(obj1.value) == type(0) and type(obj2.value) == type(0) then
				return p.script.new(obj1.value + obj2.value)
			elseif type(obj1.value) == type({}) and type(obj2.value) == type({}) then
				local result = {}
				for k,v in pairs(obj1.value) do result[k] = v end
				for k,v in pairs(obj2.value) do result[k] = result[k] or v end
				return p.script.new(result)
			end
			return p.script.new(obj1.value + obj2.value)
		end,
		__sub = function (op1, op2) 
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			if type(obj1.value) == type("string") or type(obj2.value) == type("string") then
				local str1, str2 = tostring(obj1.value), tostring(obj2.value)
				if obj1.value == obj2.value then return 0 end
				local keys = {str1, str2}
				table.sort(keys)
				return (keys[1] == str1) and -1 or 1
			elseif type(obj1.value) == type(true) or type(obj2.value) == type(true) then
				local bool1, bool2 = (not obj1.value) and 0 or 1, (not obj2.value) and 0 or 1
				return math.max(bool1 - bool2, 0)
			elseif type(obj1.value) == type(nil) or type(obj2.value) == type(nil) then
				if obj1.value == obj2.value then return 0 end
				return (obj1.value == nil) and -1 or 1
			end
			if obj1.value == obj2.value then return 0 end
			return p.script.new(obj1.value - obj2.value)
		end,
		__mul = function (op1, op2) 
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return p.script.new(obj1.value * obj2.value)
		end,
		__div = function (op1, op2) 
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return p.script.new(obj1.value / obj2.value)
		end,
		__mod = function (op1, op2) 
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return p.script.new(obj1.value % obj2.value)
		end,
		__tostring = function (obj) 
			local this = p.script.toObject(obj)
			local typeof = p.script.typeof(this)
			if typeof == 'array' then
				local result = ''
				for i=1,#(this.value) do
					if result ~= '' then result = result .. ', ' end
					result = result .. tostring(this.value[i] or 'nil')
				end
				return '{' .. result .. '}'
			end
			return tostring(this.value or 'nil')
		end,
		__unm = function (obj)
			local this = p.script.new(obj)
			this.value = -this.value
			return this
		end,
		__eq = function (op1, op2)
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return obj1.value == obj2.value
		end,
		__lt = function (op1, op2)
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return obj1.value < obj2.value
		end,
		__le = function (op1, op2)
			local obj1, obj2 = p.script.toObject(op1), p.script.toObject(op2)
			return obj1.value <= obj2.value
		end,
	},
	init = function()
		p.script['true'] = 1;p.script['true/doc']={}
		p.script['false'] = 0;p.script['false/doc']={}
		p.script['nil'] = p.script.toObject()
		p.script.emptyString = p.script.new("");p.script['emptyString/doc']={}
		p.script.numberType = sollib._numberType
		p.script.constructor = p.script.loadObject
		return p.script
	end
}

function p.run(script)
	local code = script
	if type(script) == type({}) then code = (script.args or script)[1] 
	elseif type(script) ~= type("string") then tostring(code) end
	local scriptlib = p.script.init()
	return calclib.calc(code, scriptlib, scriptlib.constructor)
end

function p.runScope(script)
	local code = script
	if type(script) == type({}) then code = (script.args or script)[1] 
	elseif type(script) ~= type("string") then tostring(code) end
	local scriptlib = p.script.init()
	return calclib.calc("scope←newScope(nil);mainFunction:scope↦"..((mw.text.trim(code)=='') and 'nil' or code)..";(scope)", scriptlib, scriptlib.constructor)
end

return p