Files
2025-12-02 20:37:18 +07:00

1153 lines
34 KiB
Lua

local error = logger.error
local pairs = pairs
local ipairs = ipairs
local select = select
local concat = table.concat
local format = string.format
local getinfo = debug.getinfo
local setmetatable = setmetatable
local warn = warn or print
local assert = assert
local HyperLua = require("HyperLua")
local Log = HyperLua.Log
local IsObject = HyperLua.IsObject
local IsObjectType = HyperLua.IsObjectType
local IsDerivedFrom = HyperLua.IsDerivedFrom
local IsInstance = HyperLua.IsInstance
local NewObjectType = HyperLua.NewObjectType
local RenewObjectType = HyperLua.RenewObjectType
local ReloadObjectType = HyperLua.ReloadObjectType
local IsReloadingType = HyperLua.IsReloadingType
local CommitObjectType = HyperLua.CommitObjectType
local IsCommitedType = HyperLua.IsCommitedType
local HasField = HyperLua.HasField
local AddField = HyperLua.AddField
local AddMethod = HyperLua.AddMethod
local ReplaceMethod = HyperLua.ReplaceMethod
local HotAddMethod = HyperLua.HotAddMethod
local HotReplaceMethod = HyperLua.HotReplaceMethod
local SetObjectAsConst = HyperLua.SetObjectAsConst
local IsConstObject = HyperLua.IsConstObject
local GetObjectID = HyperLua.GetObjectID
local GetObjectSize = HyperLua.GetObjectSize
local GetObjectCount = HyperLua.GetObjectCount
local GetMethodInfo = HyperLua.GetMethodInfo
local GetConstructor = HyperLua.GetConstructor
local GetTypeName = HyperLua.GetTypeName
local GetBaseTypeName = HyperLua.GetBaseTypeName
local TryGet = HyperLua.TryGet
local TrySet = HyperLua.TrySet
local LuaType = HyperLua.LuaType
local LuaPairs = HyperLua.Pairs
local LuaObjects = HyperLua.Objects
local LuaToString = HyperLua.ToString
local DumpEnv = HyperLua.DumpEnv
local AddExternalTypeSys = HyperLua.AddExternalTypeSystem
local IsExternalType = HyperLua.IsExternalType
local IsExternalInstance = HyperLua.IsExternalInstance
local LogLevel_Info = 0
local LogLevel_Warn = 1
local LogLevel_Error = 2
local ProfilerWrapper = _G.g_ProfilerWrapper
local ASSETS_PATH = _G.g_AssetsPath or "."
local IS_BUILD_SHIPPING = _G.g_IsBuildShipping
local PLACEHOLDER = "placeholder"
local OPTIONAL = "optional"
local EMPTY_TABLE = {}
local HL = {}
HL.Boolean = "boolean"
HL.Number = "number"
HL.Int = "int"
HL.String = "string"
HL.Table = "table"
HL.Userdata = "userdata"
HL.Pointer = "pointer"
HL.Function = "function"
HL.Varlist = "varlist"
HL.Thread = "thread"
HL.Any = "any"
HL.Opt = function(...)
return OPTIONAL, ...
end
local HyperLuaObject
local HyperLuaReloading = true
local HyperLuaClasses = {}
local HyperLuaFwdClasses = {}
local HyperLuaStrCache = {}
local AnonymousTypeID = 1
local MT_CTOR = 1
local MT_STATIC = 2
local MT_INSTANCE = 3
local MT_VIRTUAL = 4
local MT_OVERRIDE = 5
local MT_FINAL = 6
local HyperLuaBuiltinTypes = {
["boolean"] = true,
["number"] = true,
["int"] = true,
["pointer"] = true,
["string"] = true,
["table"] = true,
["userdata"] = true,
["function"] = true,
["thread"] = true,
["any"] = true,
}
local HyperLuaInitValueTypes = {
["boolean"] = {
["boolean"] = true,
},
["number"] = {
["number"] = true,
},
["int"] = {
["number"] = true,
},
["pointer"] = {
["nil"] = true,
["pointer"] = true,
},
["string"] = {
["string"] = true,
},
["table"] = {
["nil"] = true,
["function"] = true,
},
["userdata"] = {
["nil"] = true,
["function"] = true,
},
["function"] = {
["nil"] = true,
["function"] = true,
},
["thread"] = {
["nil"] = true,
["function"] = true,
},
}
local HyperLuaParamValueTypes = {
["boolean"] = {
["boolean"] = true,
},
["number"] = {
["number"] = true,
},
["int"] = {
["number"] = true,
},
["pointer"] = {
["nil"] = true,
["pointer"] = true,
},
["string"] = {
["string"] = true,
},
["table"] = {
["nil"] = true,
["table"] = true,
},
["userdata"] = {
["nil"] = true,
["userdata"] = true,
},
["function"] = {
["nil"] = true,
["function"] = true,
},
["thread"] = {
["nil"] = true,
["thread"] = true,
},
}
local function SaveOption(name, value)
value = tostring(value)
local path = string.format("%s/%s.flag", ASSETS_PATH, name)
local file = io.open(path, "wb")
if file then
file:write(value)
file:close()
end
return value
end
local function LoadOption(name, default)
local path = string.format("%s/%s.flag", ASSETS_PATH, name)
local file = io.open(path, "rb")
if file then
local ret = file:read("*a")
file:close()
return ret
end
return default
end
local RuntimeTypeCheckLevel_None = 0
local RuntimeTypeCheckLevel_Log = 1
local RuntimeTypeCheckLevel_Error = 2
local RuntimeTypeCheckLevel = RuntimeTypeCheckLevel_Error
local RuntimeTypeCheck = true
HL.RuntimeTypeCheckLevel_None = RuntimeTypeCheckLevel_None
HL.RuntimeTypeCheckLevel_Log = RuntimeTypeCheckLevel_Log
HL.RuntimeTypeCheckLevel_Error = RuntimeTypeCheckLevel_Error
do
function HL.SetRuntimeTypeCheckLevel(level)
assert(level >= RuntimeTypeCheckLevel_None and level <= RuntimeTypeCheckLevel_Error)
SaveOption("rttc", level)
return level
end
function HL.GetRuntimeTypeCheckLevel()
return RuntimeTypeCheckLevel
end
local DefaultRuntimeTypeCheckLevel, RuntimeTypeCheckFlag
if IS_BUILD_SHIPPING then
DefaultRuntimeTypeCheckLevel = RuntimeTypeCheckLevel_None
RuntimeTypeCheckFlag = RuntimeTypeCheckLevel_None
else
DefaultRuntimeTypeCheckLevel = _G.g_OverrideDefaultTypeCheckFlag or RuntimeTypeCheckLevel_Error
RuntimeTypeCheckFlag = _G.g_OverrideTypeCheckFlag or LoadOption("rttc", DefaultRuntimeTypeCheckLevel)
end
RuntimeTypeCheckFlag = tonumber(RuntimeTypeCheckFlag) or DefaultRuntimeTypeCheckLevel
RuntimeTypeCheckLevel = RuntimeTypeCheckFlag
RuntimeTypeCheck = RuntimeTypeCheckLevel ~= RuntimeTypeCheckLevel_None
HyperLua.SetRuntimeTypeCheckLevel(RuntimeTypeCheckLevel)
end
local RuntimeObjectTrack = false
do
function HL.SetRuntimeObjectTrackEnabled(enabled)
if enabled == nil then enabled = not RuntimeObjectTrack end
SaveOption("rtot", enabled and "1" or "0")
return enabled
end
function HL.GetRuntimeObjectTrackEnabled()
return RuntimeObjectTrack
end
local RuntimeObjectTrackFlag = LoadOption("rtot", "0")
RuntimeObjectTrack = RuntimeObjectTrackFlag == "1"
HyperLua.SetRuntimeObjectTrack(RuntimeObjectTrack)
end
local function TypeCheckError(str, ...)
local msg = select('#', ...) > 0 and format(str, ...) or str
if RuntimeTypeCheckLevel == RuntimeTypeCheckLevel_Error then
error(msg)
else
Log(LogLevel_Error, msg)
end
end
local function Error(str, ...)
local msg = select('#', ...) > 0 and format(str, ...) or str
error(msg)
end
local function GetType(object)
local typeName = GetTypeName(object)
return typeName and HyperLuaClasses[typeName] or nil
end
local function GetBaseType(objectOrType)
local baseTypeName = GetBaseTypeName(objectOrType)
return baseTypeName and HyperLuaClasses[baseTypeName] or nil
end
local function IsBuiltinType(typeName)
return HyperLuaBuiltinTypes[typeName] ~= nil
end
local function CheckFieldType(fieldType)
if not IsBuiltinType(fieldType) and not IsObjectType(fieldType) and not IsExternalType(fieldType) then
Error("invalid field type '%s'", tostring(fieldType))
end
end
local function CheckFieldName(objectType, fieldName)
if HasField(objectType, fieldName) then
Error("member with name '%s' already exists in '%s'", fieldName, GetTypeName(objectType))
end
end
local function CheckFieldInitValue(objectType, fieldName, fieldType, storeInObject, initValue)
if fieldType == "any" then
return
end
local initValueType = LuaType(initValue)
local expectedTypes = HyperLuaInitValueTypes[fieldType]
if not expectedTypes then
if storeInObject then
if initValueType ~= "function" and initValueType ~= "nil" then
Error("%s @ %s: '%s' or '%s' expected, got '%s'", fieldName, GetTypeName(objectType), "function", "nil", initValueType)
end
else
if initValueType ~= "userdata" and initValueType ~= "function" and initValueType ~= "nil" then
Error("%s @ %s: '%s' or '%s' or '%s' expected, got '%s'", fieldName, GetTypeName(objectType), "userdata", "function", "nil", initValueType)
end
if initValueType == "userdata" then
if not IsInstance(initValue, fieldType) then
Error("%s @ %s: '%s' expected", fieldName, GetTypeName(objectType), GetTypeName(fieldType))
end
end
end
else
if not expectedTypes[initValueType] then
if storeInObject then
local types = {}
for k, _ in pairs(expectedTypes) do
types[#types + 1] = "'" .. k .. "'"
end
Error("%s @ %s: %s expected, got '%s'", fieldName, GetTypeName(objectType), concat(types, " or "), initValueType)
else
if fieldType ~= initValueType then
local types = { fieldType }
for k, _ in pairs(expectedTypes) do
types[#types + 1] = "'" .. k .. "'"
end
Error("%s @ %s: %s expected, got '%s'", fieldName, GetTypeName(objectType), concat(types, " or "), initValueType)
end
end
end
end
end
local function CheckMethodInitValue(methodBody)
local methodBodyType = LuaType(methodBody)
if methodBodyType ~= "function" then
Error("'%s' expected, got '%s'", "function", methodBodyType)
end
end
local function CheckMethodParamTypes(paramTypes, baseParamTypes, isReturn)
local name = isReturn and "return value" or "param"
if paramTypes and baseParamTypes then
if #paramTypes ~= #baseParamTypes then
TypeCheckError("%s type count mismatch ('%d' expected, got '%d')", name, #baseParamTypes, #paramTypes)
return false
end
for ith, paramType in ipairs(paramTypes) do
local baseParamType = baseParamTypes[ith]
if paramType ~= baseParamType then
if IsBuiltinType(paramType) or IsBuiltinType(baseParamType) or not IsDerivedFrom(paramType, baseParamType) then
local paramTypeName = IsBuiltinType(paramType) and paramType or GetTypeName(paramType)
local baseParamTypeName = IsBuiltinType(baseParamType) and baseParamType or GetTypeName(baseParamType)
TypeCheckError("bad %s type #%d ('%s' expected, got '%s')", name, ith, baseParamTypeName, paramTypeName)
return false
end
end
end
elseif paramTypes then
TypeCheckError("%s type count mismatch ('%d' expected, got '%d')", name, 0, #paramTypes)
return false
elseif baseParamTypes then
TypeCheckError("%s type count mismatch ('%d' expected, got '%d')", name, #baseParamTypes, 0)
return false
end
return true
end
local function CheckOverrideMethod(objectType, baseObjectType, methodName, inParams, retParams)
local methodInfo = GetMethodInfo(baseObjectType, methodName)
if not methodInfo then
TypeCheckError("'%s' override method '%s' not exists in '%s'", GetTypeName(objectType), methodName, GetTypeName(baseObjectType))
return false
end
local baseMethodType, baseInParams, baseRetParams = methodInfo[1], methodInfo[2], methodInfo[3]
if baseMethodType == MT_VIRTUAL or baseMethodType == MT_OVERRIDE then
CheckMethodParamTypes(inParams, baseInParams)
CheckMethodParamTypes(retParams, baseRetParams)
elseif baseMethodType == MT_FINAL then
TypeCheckError("'%s' can not override final method '%s' in '%s'", GetTypeName(objectType), methodName, GetTypeName(baseObjectType))
return false
elseif baseMethodType == MT_STATIC then
TypeCheckError("'%s' can not override static method '%s' in '%s'", GetTypeName(objectType), methodName, GetTypeName(baseObjectType))
return false
else
TypeCheckError("'%s' can not override non-virtual method '%s' in '%s'", GetTypeName(objectType), methodName, GetTypeName(baseObjectType))
return false
end
return true
end
local function CreateMethodParams(isReturn, ...)
local hasVarList = false
local curParams = {}
local requireCnt = nil
for _, paramType in ipairs({ ... }) do
if hasVarList then
if isReturn then
TypeCheckError("'varlist' must be the last return value type")
else
TypeCheckError("'varlist' must be the last param type")
end
else
if paramType == "varlist" then
hasVarList = true
curParams[#curParams + 1] = paramType
elseif paramType == PLACEHOLDER then
curParams[#curParams + 1] = paramType
elseif paramType == OPTIONAL then
if requireCnt ~= nil then
TypeCheckError("'Opt' should be the last group or parameters.")
end
requireCnt = #curParams
elseif IsBuiltinType(paramType) then
curParams[#curParams + 1] = paramType
elseif IsObjectType(paramType) then
curParams[#curParams + 1] = paramType
elseif IsExternalType(paramType) then
curParams[#curParams + 1] = paramType
else
if isReturn then
TypeCheckError("invalid return value type")
else
TypeCheckError("invalid param type")
end
end
end
end
if isReturn and #curParams == 0 then
TypeCheckError("no return value type found.")
end
if requireCnt == nil then
requireCnt = #curParams
end
return #curParams > 0 and curParams or nil, requireCnt
end
local function CheckMethodParamValues(debugInfo, paramTypes, requireCnt, isReturn, ...)
if requireCnt == nil then
requireCnt = 0
end
local name = isReturn and "return value" or "argument"
for ith, paramType in ipairs(paramTypes) do
if paramType == "varlist" then
return select(1, ...)
elseif paramType ~= "any" then
local paramValue = select(ith, ...)
local gotType = LuaType(paramValue)
local expectedTypes = HyperLuaParamValueTypes[paramType]
if expectedTypes then
if not expectedTypes[gotType] then
if ith <= requireCnt or
gotType ~= "nil" then
local types = {}
for k, _ in pairs(expectedTypes) do
types[#types + 1] = "'" .. k .. "'"
end
TypeCheckError("%s: bad %s #%d (%s expected, got '%s')", debugInfo, name, ith, concat(types, ' or '), gotType)
end
end
elseif paramValue then
local ok, errParam = IsInstance(paramValue, paramType)
if not ok then
local externalTypeName = IsExternalType(paramType)
if externalTypeName then
if not IsExternalInstance(paramValue, paramType) then
TypeCheckError("%s: bad %s #%d (external '%s' expected, got '%s')", debugInfo, name, ith, externalTypeName, LuaType(paramValue))
end
else
if errParam == 1 then
TypeCheckError("%s: bad %s #%d (HL 'object' expected, got '%s')", debugInfo, name, ith, gotType)
elseif errParam == 2 then
TypeCheckError("%s: bad %s #%d (HL 'class' expected)", debugInfo, name, ith)
else
TypeCheckError("%s: bad %s #%d ('%s' expected, got '%s)", debugInfo, name, ith, GetTypeName(paramType), GetTypeName(paramValue))
end
end
end
end
end
end
local expectedMinCount = requireCnt
local expectedMaxCount = #paramTypes
local gotCount = select('#', ...)
if expectedMinCount == expectedMaxCount then
if expectedMinCount ~= gotCount then
TypeCheckError("%s: %s count mismatch (expected '%d', got '%d')", debugInfo, name, expectedMinCount, gotCount)
end
else
if gotCount < expectedMinCount then
TypeCheckError("%s: %s count mismatch (expected '%d' at least, got '%d')", debugInfo, name, expectedMinCount, gotCount)
elseif gotCount > expectedMaxCount then
TypeCheckError("%s: %s count mismatch (expected '%d' at most, got '%d')", debugInfo, name, expectedMaxCount, gotCount)
end
end
return select(1, ...)
end
local function CreateMethodWrapper(methodName, methodBody, inParams, inRequireCnt, retParams, retRequireCnt)
local info = getinfo(methodBody, "S")
local debugInfo = format("%s:%d:%s", info.source, info.linedefined, methodName)
if inParams and retParams then
return function(...)
return CheckMethodParamValues(debugInfo, retParams, retRequireCnt, true, methodBody(CheckMethodParamValues(debugInfo, inParams, inRequireCnt, false, ...)))
end
elseif inParams then
return function(...)
return methodBody(CheckMethodParamValues(debugInfo, inParams, inRequireCnt, false, ...))
end
elseif retParams then
return function(...)
return CheckMethodParamValues(debugInfo, retParams, retRequireCnt, true, methodBody(...))
end
else
return methodBody
end
end
local function CreateProxy(metatable)
return setmetatable({}, metatable)
end
local function AddStringToCache(str)
HyperLuaStrCache[str] = true
end
local function FieldInternal(objectType, fieldType, storeInObject, constant, fieldName, initValue)
if IsReloadingType(objectType) then
return
end
CheckFieldType(fieldType)
CheckFieldName(objectType, fieldName)
CheckFieldInitValue(objectType, fieldName, fieldType, storeInObject, initValue)
local internalFieldType
if IsObjectType(fieldType) then
internalFieldType = "object"
elseif IsExternalType(fieldType) then
internalFieldType = "external"
else
internalFieldType = fieldType
end
if not AddField(objectType, fieldName, internalFieldType, storeInObject, constant, initValue, fieldType) then
Error("add '%s' field to '%s' failed", fieldName, GetTypeName(objectType))
end
AddStringToCache(fieldName)
end
local function MethodInternal(objectType, methodType, inParams, inRequireCnt, retParams, retRequireCnt, methodName, methodBody)
local methodInfo
if RuntimeTypeCheck then
methodInfo = { methodType, inParams, retParams }
end
local typeName = GetTypeName(objectType)
local isOverrideOrFinal = methodType == MT_OVERRIDE or methodType == MT_FINAL
local methodWrapper = methodBody
if RuntimeTypeCheck then
local isConstructor = methodType == MT_CTOR
if isConstructor then
if retParams then
TypeCheckError("return value is not allowed in constructor '%s'", methodName)
end
end
CheckMethodInitValue(methodBody)
methodWrapper = CreateMethodWrapper(methodName, methodBody, inParams, inRequireCnt, retParams, retRequireCnt)
end
if ProfilerWrapper then
local info = getinfo(methodBody, "S")
local funcName = format("%s.%s %s:%d", typeName, methodName, info.source, info.linedefined)
methodWrapper = ProfilerWrapper(funcName, methodWrapper)
end
if IsReloadingType(objectType) then
local bHasMethodField = HasField(objectType, methodName)
local subTypes = {}
do
local insert = table.insert
for _, t in pairs(HyperLuaClasses) do
if t ~= objectType and IsDerivedFrom(t, objectType) then
local bValidInSubType = true
if RuntimeTypeCheck and false then
if (not bHasMethodField) and HasField(t, methodName) then
if not CheckOverrideMethod(objectType, GetBaseType(objectType) or HyperLuaObject, methodName, inParams, retParams) then
Log(LogLevel_Error, "hot replace method '%s' in '%s' failed, method with the same name already exists in sub-type '%s'", methodName, GetTypeName(objectType), GetTypeName(t))
bValidInSubType = false
end
end
end
if bValidInSubType then
insert(subTypes, t)
end
end
end
end
if bHasMethodField then
if isOverrideOrFinal then
if RuntimeTypeCheck then
CheckOverrideMethod(objectType, GetBaseType(objectType) or HyperLuaObject, methodName, inParams, retParams)
end
end
if not HotReplaceMethod(objectType, methodName, methodType, methodWrapper, methodInfo, subTypes) then
Error("hot replace method '%s' in '%s' failed", methodName, GetTypeName(objectType))
end
else
if not HotAddMethod(objectType, methodName, methodType, methodWrapper, methodInfo, subTypes) then
Error("hot add new method '%s' in '%s' failed", methodName, GetTypeName(objectType))
end
end
else
if isOverrideOrFinal then
if RuntimeTypeCheck then
CheckOverrideMethod(objectType, GetBaseType(objectType) or HyperLuaObject, methodName, inParams, retParams)
end
if not ReplaceMethod(objectType, methodName, methodType, methodWrapper, methodInfo) then
Error("replace method '%s' in '%s' failed", methodName, GetTypeName(objectType))
end
else
CheckFieldName(objectType, methodName)
if not AddMethod(objectType, methodName, methodType, methodWrapper, methodInfo) then
Error("add method '%s' to '%s' failed", methodName, GetTypeName(objectType))
end
end
end
AddStringToCache(methodName)
end
function HL.Class(classNameOrNil, baseObjectType)
local className = classNameOrNil
if not className then
className = format("HL.Anonymous.%d", AnonymousTypeID)
AnonymousTypeID = AnonymousTypeID + 1
end
local objectType = HyperLuaClasses[className]
local bReloading = false
if objectType then
if not HyperLuaReloading then
Error("class with name '%s' already exists", className)
end
bReloading = true
end
if baseObjectType and not IsCommitedType(baseObjectType) then
Error("base type '%s' is not commited", GetTypeName(baseObjectType))
end
baseObjectType = baseObjectType or HyperLuaObject
if bReloading then
if GetBaseType(objectType) ~= baseObjectType then
Error("bad base type, '%s' expected, got '%s'", GetTypeName(GetBaseType(objectType)), GetTypeName(baseObjectType))
end
ReloadObjectType(objectType)
return objectType
end
local fwdObjectType = HyperLuaFwdClasses[className]
if fwdObjectType then
HyperLuaFwdClasses[className] = nil
objectType = RenewObjectType(fwdObjectType, baseObjectType)
else
objectType = NewObjectType(className, baseObjectType)
end
HyperLuaClasses[className] = objectType
return objectType
end
do
local fieldStoreInObject = false
local fieldIsConstant = false
local fieldValueType
local fieldInitValue
local fieldProxy = nil
fieldProxy = CreateProxy({
__shl = function(_, defaultValue)
fieldInitValue = defaultValue
return fieldProxy
end,
})
local function MakeFieldProxy(storeInObject, isConstant)
return function(valueType, initValue)
fieldStoreInObject = storeInObject
fieldIsConstant = isConstant
fieldValueType = valueType
fieldInitValue = initValue
return fieldProxy
end
end
HL.Field = MakeFieldProxy(true, false)
HL.Const = MakeFieldProxy(false, true)
HL.StaticField = MakeFieldProxy(false, false)
local methodType
local methodInParams, methodInRequireCnt
local methodRetParams, methodRetRequireCnt
local methodBody
local methodProxy = nil
methodProxy = CreateProxy({
__shl = function(_, func)
methodBody = func
return methodProxy
end,
__index = {
Return = function(...)
if RuntimeTypeCheck then
methodRetParams, methodRetRequireCnt = CreateMethodParams(true, ...)
end
return methodProxy
end,
Assign = function(func)
methodBody = func
return methodBody
end,
},
})
local function MakeMethodProxy(inMethodType)
return function(...)
if RuntimeTypeCheck then
methodType = nil
methodInParams = nil
methodInRequireCnt = nil
methodRetParams = nil
methodRetRequireCnt = nil
methodBody = nil
end
methodType = inMethodType
if methodType ~= MT_STATIC then
if RuntimeTypeCheck then
methodInParams, methodInRequireCnt = CreateMethodParams(false, PLACEHOLDER, ...)
end
else
if RuntimeTypeCheck then
methodInParams, methodInRequireCnt = CreateMethodParams(false, ...)
end
end
return methodProxy
end
end
HL.Constructor = MakeMethodProxy(MT_CTOR)
HL.Method = MakeMethodProxy(MT_INSTANCE)
HL.Virtual = MakeMethodProxy(MT_VIRTUAL)
HL.Override = MakeMethodProxy(MT_OVERRIDE)
HL.Final = MakeMethodProxy(MT_FINAL)
HL.StaticMethod = MakeMethodProxy(MT_STATIC)
local function DeclareMemberToObjectType(objectType, memberName, memberProxy)
if memberProxy == methodProxy then
if RuntimeTypeCheck then
if methodType ~= MT_STATIC then
methodInParams[1] = objectType
end
if methodType == MT_CTOR then
assert(methodRetParams == nil)
elseif methodRetParams == nil then
methodRetParams = EMPTY_TABLE
end
end
MethodInternal(objectType, methodType, methodInParams, methodInRequireCnt, methodRetParams, methodRetRequireCnt, memberName, methodBody)
if RuntimeTypeCheck then
methodType = nil
methodInParams = nil
methodInRequireCnt = nil
methodRetParams = nil
methodRetRequireCnt = nil
methodBody = nil
end
return
end
if memberProxy == fieldProxy then
FieldInternal(objectType, fieldValueType, fieldStoreInObject, fieldIsConstant, memberName, fieldInitValue)
fieldValueType = nil
fieldStoreInObject = false
fieldIsConstant = false
fieldInitValue = nil
return
end
Error("unknown declaration '%s' with member name '%s' to object type '%s'", tostring(memberProxy), memberName, GetTypeName(objectType))
end
HyperLua.SetObjectTypeNewIndexBeforeCommit(DeclareMemberToObjectType)
end
function HL.Commit(objectType)
local isCommited = IsCommitedType(objectType)
if isCommited then
Error("repeated Commit to class '%s'", GetTypeName(objectType))
end
CommitObjectType(objectType)
return objectType
end
function HL.Forward(className)
local objectType = HyperLuaClasses[className] or HyperLuaFwdClasses[className]
if not objectType then
objectType = NewObjectType(className)
HyperLuaFwdClasses[className] = objectType
end
return objectType
end
do
local ObjectTypeFallbackAccessors = {
Super = function(objectType)
return HL.GetBaseType(objectType)
end,
SuperConstructor = function(objectType)
return HL.Super(objectType)
end,
}
local function AccessFallbackFieldOfObjectType(objectType, key)
local f = ObjectTypeFallbackAccessors[key]
return f and f(objectType, key)
end
HyperLua.SetObjectTypeIndexFallback(AccessFallbackFieldOfObjectType)
end
function HL.Super(objectType)
local baseType = GetBaseType(objectType)
return baseType and GetConstructor(baseType) or nil
end
local function DumpObject(obj, onlyHyperLua, usePrint)
if type(obj) ~= "userdata" or not HL.Is(obj, HL.Object) then
Error("bad argument #1, instance of HyperLua Object expected, got '%s'", type(obj))
end
local lines = {}
local insert = table.insert
insert(lines, format("%s = {", LuaToString(obj)))
for k, v in LuaPairs(obj) do
if IsObject(v) then
insert(lines, format(" %s = %s", k, LuaToString(v)))
else
if not onlyHyperLua then
insert(lines, format(" %s = %s", k, v))
end
end
end
insert(lines, "}")
local ret = table.concat(lines, "\n")
if usePrint == nil or usePrint == true then
print(ret)
return
end
return ret
end
local function DumpObjects(onlyHyperLua)
collectgarbage("stop")
for obj, t in LuaObjects() do
DumpObject(obj, onlyHyperLua)
end
collectgarbage("restart")
end
local function DumpObjectCount(outputFunc)
if outputFunc == nil then
outputFunc = warn
end
local nameLength = 0
local countTotal = 0
local countArray = {}
for typeName, objectType in pairs(HyperLuaClasses) do
local objectCount = GetObjectCount(objectType)
if objectCount > 0 then
countTotal = countTotal + objectCount
countArray[#countArray + 1] = { typeName, objectCount }
if #typeName > nameLength then
nameLength = #typeName
end
end
end
table.sort(countArray, function(e1, e2)
return e1[2] > e2[2]
end)
local dumpFmt = format("%%%ds: %%d", nameLength)
outputFunc(format("HL object count: %d", countTotal))
for k, v in pairs(countArray) do
outputFunc(format(dumpFmt, v[1], v[2]))
end
end
HL.DumpObject = DumpObject
HL.DumpObjects = DumpObjects
HL.DumpObjectCount = DumpObjectCount
HL.DumpUncommited = function()
warn("Uncommitted HL Classes:")
for objectType, v in pairs(HyperLuaClasses) do
if not IsCommitedType(objectType) then
warn(GetTypeName(objectType))
end
end
end
HyperLuaObject = HL.Class("HyperLua.Object")
do
HL.Commit(HyperLuaObject)
end
HL.Object = HyperLuaObject
HL.GetType = GetType
HL.GetTypeName = GetTypeName
HL.GetBaseType = GetBaseType
HL.GetBaseTypeName = GetBaseTypeName
HL.GetObjectID = GetObjectID
HL.GetObjectSize = GetObjectSize
HL.GetObjectCount = GetObjectCount
HL.SetObjectAsConst= SetObjectAsConst
HL.IsConstObject = IsConstObject
HL.As = function(object, objectType)
return IsInstance(object, objectType) and object or nil
end
HL.Is = IsInstance
HL.TryGet = TryGet
HL.TrySet = TrySet
HL.DumpEnv = function(objectType, reason)
DumpEnv(objectType, reason or "unknown")
end
HL.SetReloading = function(bReload)
HyperLuaReloading = bReload == true
end
HL.IsReloading = function()
return HyperLuaReloading
end
local HLExternalTypeSystem = HL.Class("HLExternalTypeSystem")
do
HLExternalTypeSystem.IsExternalType = HL.Virtual(HL.Any).Return(HL.Opt(HL.String)) << function(self, typeToTest)
return nil
end
HLExternalTypeSystem.IsExternalInstance = HL.Virtual(HL.Userdata, HL.Any).Return(HL.Boolean) << function(self, instanceToTest, type)
return false
end
HLExternalTypeSystem.Register = HL.Method() << function(self)
AddExternalTypeSys(self)
end
HL.Commit(HLExternalTypeSystem)
end
HL.ExternalTypeSystem = HLExternalTypeSystem
return HL