Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local Class = {}
- local ClassObject = {}
- local ClassProxy = {}
- local Object = {}
- local ObjectProxy = {}
- local ClassFunction = {}
- local ObjectFunction = {}
- local ClassValue = {}
- local ObjectValue = {}
- local ValueReference = {}
- local ClassParser = {}
- local Annotation = {}
- local AccessRequest = {}
- setmetatable(Annotation,{__call=function(_,AnnotationType) return Annotation.new(AnnotationType) end})
- local currentClass = {}
- local Utils = {}
- local ClassTree = {}
- setmetatable(getfenv(),{__index=ClassTree})
- local pModifiers = {
- ["public"] = true;
- ["private"] = true;
- ["static"] = true;
- ["abstract"] = true;
- ["final"] = true;
- }
- local pTypes = {
- ["number"] = true;
- ["table"] = true;
- ["thread"] = true;
- ["function"] = true;
- ["string"] = true;
- ["boolean"] = true;
- ["nil"] = true;
- }
- local function instanceof(Obj)
- if type(Obj) == "table" then
- if Obj.isInstance then
- return Obj.getClass().getName()
- end
- end
- end
- local function annotationInstance(Annotation)
- if type(Annotation) ~= "table" then
- return false
- end
- if Annotation.__type then
- return Annotation.__type == "Annotation"
- end
- end
- local function typeof(Value)
- if type(Value) == "table" then
- if Value.__obj and Value.__obj.className then
- return "class"
- end
- end
- return type(Value)
- end
- function Utils.getClassByName(ClassName)
- if not ClassTree[ClassName] then
- error("Can't find class "..ClassName..". Has it been created ?")
- end
- return ClassTree[ClassName]
- end
- function Utils.makeGlobal(ClassObj) -- make the new class globally usable
- currentClass = ClassObj
- _G[ClassObj:getName()] = ClassObj
- ClassTree[ClassObj:getName()] = ClassObj
- end
- function Utils.parseClassPath(Location)
- local isPath = string.find(Location,"%.") ~= nil
- local currentLocation = ClassTree
- if isPath then
- local className = ""
- Location = string.gsub(Location,"%.(%a+)$",function(name) className = name return "" end)
- if #className == 0 then
- error("Malformed classpath")
- end
- string.gsub(Location,"(%a+)%.*",function(current)
- if currentLocation[current] then
- if currentLocation[current].__obj then
- error("Classpath overwrites existing class "..currentLocation[current]:getName())
- end
- currentLocation = currentLocation[current]
- else
- currentLocation[current] = {}
- currentLocation = currentLocation[current]
- end
- end)
- return currentLocation,className
- else
- return false
- end
- end
- function Utils.hasFieldAnnotation(FieldTable)
- return annotationInstance(FieldTable)
- end
- function Utils.getFieldAnnotation(FieldTable)
- return {
- annotations = FieldTable.annotationList;
- fieldValue = FieldTable.fieldValue;
- }
- end
- function Utils.isClassEntry(ClassTable,Field)
- local field = ClassTable[Field]
- if type(field) == "table" then
- if field.visibility and field.modifiers and field.value then
- return true
- end
- end
- return false
- end
- function Utils.getEqualPublicMethods(Sender,Object)
- local indexMap = {}
- local equalPublicMethods = {}
- for k,v in pairs(Object.raw) do
- if v:getAccessLevel() == 0 and type(v.value) == "function" then
- indexMap[k] = v
- end
- end
- local cSender = nil
- for i = #Sender,1, -1 do
- cSender = Sender[i]
- for k,v in pairs(cSender.raw) do
- if v:getAccessLevel() == 0 and type(v.value) == "function" and indexMap[k] and indexMap[k].type == v.type and (k~="getClass" and k~="instanceof") then
- equalPublicMethods[k] = v
- end
- end
- end
- return equalPublicMethods
- end
- function Utils.checkType(FType,VType)
- return ((FType == nil and true) or (FType == VType))
- end
- local function parseAnnotations(Left,Right)
- if annotationInstance(Left) and annotationInstance(Right) then
- for _,annotation in pairs(Left.annotationList) do
- table.insert(Right.annotationList,annotation)
- end
- return Right
- elseif typeof(Left) == "class" or typeof(Right) == "class" then
- local className = (typeof(Left) == "class" and Left:getName()) or Right:getName()
- if typeof(Left) == "class" then
- if not annotationInstance(Right) then
- local annotation = Annotation()
- annotation.fieldValue = Right
- for _,anno in pairs(rawget(Left,"annotationList")) do
- table.insert(annotation.annotationList,anno)
- end
- return annotation
- end
- for _,annotation in pairs(rawget(Left,"annotationList")) do
- table.insert(Right.annotationList,annotation)
- end
- return Right
- else
- for _,annotation in pairs(Left.annotationList) do
- table.insert(rawget(Right,"annotationList"),annotation)
- end
- return Right
- end
- elseif annotationInstance(Left) and (not (annotationInstance(Right) or typeof(Right) == "class")) then
- local annotation = Annotation()
- annotation.fieldValue = Right
- for _,anno in pairs(Left.annotationList) do
- table.insert(annotation.annotationList,anno)
- end
- return annotation
- end
- end
- function Annotation.new(AnnotationType)
- local object = {
- __type = "Annotation";
- annotationList = {[1] = AnnotationType;};
- fieldValue = {};
- }
- return setmetatable(object,{
- __index = Annotation,
- __sub = parseAnnotations;
- })
- end
- public = Annotation("public")
- private = Annotation("private")
- final = Annotation("final")
- static = Annotation("static")
- Number = Annotation("number")
- Table = Annotation("table")
- Thread = Annotation("thread")
- Function = Annotation("function")
- String = Annotation("string")
- Boolean = Annotation("boolean")
- void = Annotation("nil")
- -- _G.property = Annotation("property") WIP
- abstract = Annotation("abstract")
- function using(ClassPath)
- local cName = ""
- ClassPath = string.gsub(ClassPath,"%.([%a%*]*)$",function(name) cName = name return "" end)
- local isSingleImport = (cName ~= "*")
- local currentLocation = ClassTree
- if isSingleImport then
- string.gsub(ClassPath,"(%a+)%.*",function(current)
- if currentLocation[current] then
- if currentLocation[current].instanceof then
- error("Malformed path to loaded class")
- end
- currentLocation = currentLocation[current]
- else
- currentLocation[current] = {}
- currentLocation = currentLocation[current]
- end
- end)
- if currentLocation[cName] then
- _G[cName] = currentLocation[cName]
- ClassTree[cName] = currentLocation[cName]
- else
- error("Can't find class at specified classpath. Has it been loaded ?")
- end
- else
- string.gsub(ClassPath,"(%a+)%.*",function(current)
- if currentLocation[current] then
- if currentLocation[current].instanceof then
- error("Malformed path to loaded class")
- end
- currentLocation = currentLocation[current]
- else
- currentLocation[current] = {}
- currentLocation = currentLocation[current]
- end
- end)
- for className, c in pairs(currentLocation) do
- _G[className] = c
- ClassTree[className] = c
- end
- end
- end
- setmetatable(ClassParser,{
- __index = function(_,ClassName)
- return function(_,ClassBody)
- currentClass:setSuperByName(ClassName)
- currentClass:buildClass(ClassBody,ClassBody)
- end
- end;
- __call = function(_,ClassBody)
- currentClass:buildClass(ClassBody,ClassBody)
- end;
- })
- function Class.new(ClassName)
- local location, className = Utils.parseClassPath(ClassName)
- if location then
- if not location[className] then
- location[className] = ClassObject(ClassName)
- currentClass = location[className]
- else
- error("Can't overwrite existing class at given classpath")
- end
- else
- Utils.makeGlobal(ClassObject(ClassName))
- end
- return ClassParser
- end
- function ClassObject.new(ClassName)
- local object = {
- type = "class";
- className = ClassName;
- inherits = false;
- super = nil;
- raw = setmetatable({},{__index = ClassObject});
- properties = {};
- interfaces = {};
- annotationList = {[1] = ClassName};
- constructed = false;
- }
- local proxy = {__obj = object}
- setmetatable (proxy,{
- __index = function(_,k)
- if Utils.isClassEntry(object.raw,k) then
- return object.raw[k]:get()
- elseif object.raw[k] then
- return object.raw[k]
- elseif object.super then
- return object.super[k]
- end
- return nil
- end;
- __newindex = function(t,k,v)
- if type(v) == "table" and v.value and v.visibility then
- object.raw[k] = v
- else
- object.raw[k] = (type(v) == "function" and ClassFunction(v,{})) or ClassValue(v,{})
- end
- end;
- __call = function(_,...) return proxy:createInstance(...) end -- TODO / WIP
- })
- return proxy
- end
- function ClassObject:createInstance(...)
- local abstracts = {}
- if self.__obj.super then
- abstracts = self.__obj.super:getAbstractMethods()
- end
- for k,v in pairs(abstracts) do
- if self.__obj.raw[k] == nil then
- error("Class "..self.__obj.className.." does not override abstract method "..k)
- elseif not (self.__obj.raw[k] and type(self.__obj.raw[k].value) == "function" and self.__obj.raw[k].type == abstracts[k].type and self.__obj.raw[k]:getAccessLevel() == 0) then
- error("Class "..self.__obj.className.." does not override abstract method "..k)
- end
- end
- local nObject = Object(self)
- local proxy = ObjectProxy(nObject)
- if nObject:getField(self:getName()) ~= nil then
- nObject:getField(self:getName())(...)
- end
- return proxy
- end
- function ClassObject:setSuperByName(ClassName)
- local super = Utils.getClassByName(ClassName)
- self.__obj.super = super
- self.__obj.inherits = true
- end
- function ClassObject:buildClass(ClassBody)
- for fieldName, value in pairs(ClassBody) do
- if type(value) ~= "function" then
- self:addValue(fieldName,value)
- else
- self:addFunction(fieldName,value)
- end
- end
- self.__obj.constructed = true;
- end
- function ClassObject:getName()
- return self.__obj.className
- end
- function ClassObject:hasSuper()
- if self.__obj.super ~= nil then
- return true
- end
- return false
- end
- function ClassObject:getSuper()
- return self.__obj.super
- end
- function ClassObject:addValue(FieldName,Value)
- if Utils.hasFieldAnnotation(Value) then
- local annotations = Utils.getFieldAnnotation(Value)
- local fieldValue = annotations.fieldValue
- if type(fieldValue) == "function" then
- self:addFunction(FieldName,fieldValue,annotations)
- return
- end
- self[FieldName] = ClassValue(fieldValue,annotations)
- else
- self[FieldName] = ClassValue(Value,{})
- end
- end
- function ClassObject:addFunction(FieldName,Value,Annotations)
- self[FieldName] = ClassFunction(Value,Annotations or {})
- end
- function ClassObject:getAbstractMethods()
- local m = {}
- for k,v in pairs(self.__obj.raw) do
- if type(v.value) == "function" and v.modifiers.abstract then
- m[k] = v
- end
- end
- return m
- end
- function ClassValue.new(Value,Annotations)
- local object = setmetatable({
- value = Value;
- visibility = {};
- modifiers = {};
- type = nil;
- },{
- __index = ClassValue;
- })
- object:getVisibility(Annotations)
- object:getModifiers(Annotations)
- return object
- end
- function ClassValue:get()
- return self.value
- end
- function ClassValue:getVisibility(Annotations)
- for k,v in pairs(Annotations.annotations or {}) do
- if v == "private" then
- self.visibility = 1
- elseif v == "public" then
- self.visibility = 0
- end
- end
- if type(self.visibility) == "table" then
- self.visibility = 0
- end
- end
- function ClassValue:getModifiers(Annotations)
- for k,v in pairs(Annotations.annotations or {}) do
- if v ~= "private" and v ~= "public" then
- if pModifiers[v] then
- self.modifiers[v] = true
- elseif pTypes[v] then
- self.type = v
- end
- end
- end
- end
- function ClassValue:getAccessLevel()
- return self.visibility
- end
- function ClassFunction.new(Value,Annotations)
- local object = {
- value = Value;
- visibility = 0;
- modifiers = {};
- }
- setmetatable (object,{
- __index = ClassFunction;
- __call = function() error("Attempt to call class function") end;
- })
- object:getVisibility(Annotations)
- object:getModifiers(Annotations)
- return object
- end
- function ClassFunction:get()
- return self
- end
- function ClassFunction:getVisibility(Annotations)
- for k,v in pairs(Annotations.annotations or {}) do
- if v == "private" then
- self.visibility = 1
- elseif v == "public" then
- self.visibility = 0
- end
- end
- end
- function ClassFunction:getModifiers(Annotations)
- for k,v in pairs(Annotations.annotations or {}) do
- if v ~= "private" and v ~= "public" then
- if pModifiers[v] then
- self.modifiers[v] = true
- elseif pTypes[v] then
- self.type = v
- end
- end
- end
- end
- function ClassFunction:getAccessLevel()
- return self.visibility
- end
- function Object.new(Class)
- local object = {
- type = "Object";
- raw = {};
- super = nil;
- class = Class;
- }
- if Class:hasSuper() then
- object.super = Class.__obj.super:createInstance()
- end
- setmetatable(object,{
- __index = Object;
- })
- object:parseClassbody(Class)
- return object
- end
- function Object:parseClassbody(Class)
- local proxy = ObjectProxy(self,true)
- for fieldName,classValue in pairs(Class.__obj.raw) do
- self.raw[fieldName] = (type(classValue.value) == "function" and ObjectFunction(classValue,proxy)) or ObjectValue(classValue)
- end
- self.raw.super = ObjectValue({
- value = self.super;
- visibility = 0;
- modifiers = {final = true};
- type = nil;
- proxy = {};
- })
- self:addHelperFunctions(proxy)
- end
- function Object:addHelperFunctions(Proxy)
- local struct = {
- value = nil;
- visibility = 0;
- modifiers = {};
- type = nil;
- proxy = {};
- }
- local _name = self.class:getName()
- local _class = self.class
- local instanceof = function(_,ClassName)
- if _name == ClassName then
- return true
- elseif self.super then
- return self.super : instanceof(ClassName)
- end
- return false
- end
- local getClass = function() return _class end
- struct.value = instanceof
- self.raw.instanceof = ObjectFunction(struct,Proxy)
- struct.value = getClass
- self.raw.getClass = ObjectFunction(struct,Proxy)
- end
- function Object:getField(Field)
- return self.raw[Field]
- end
- function Object:requestGet(Request)
- local field = Request.field
- local access = Request.access
- local sender = Request.sender
- local selfLookup = (sender[1] == self) or (sender == nil)
- if self.raw[field] and self.raw[field]:getAccessLevel() == 0 then
- Request.result = self.raw[field]:get(sender,selfLookup)
- return true
- elseif self.raw[field] and self.raw[field]:getAccessLevel() == 1 then
- if self.raw[field]:getAccessLevel() > access then
- Request.result = self.raw[field]:get(sender,selfLookup)
- return true
- end
- end
- Request.access = Request.access + 1
- return false
- end
- function Object:requestSet(Request)
- local field = Request.field
- local access = Request.access
- local value = Request.value
- if self.raw[field] and self.raw[field]:getAccessLevel() == 0 then
- self.raw[field]:set(value)
- return true
- elseif self.raw[field] and self.raw[field]:getAccessLevel() == 1 then
- if self.raw[field]:getAccessLevel() > access then
- self.raw[field]:set(value)
- return true
- end
- end
- Request.access = Request.access + 1
- return false
- end
- function Object:hasSuper()
- return self.super ~= nil
- end
- function Object:getSuper()
- if self:hasSuper() then
- return self.super
- end
- end
- function ObjectProxy.new(Object,isInner,RemapsToSender)
- local object = {
- __cObj = Object
- }
- setmetatable(object,{
- __index = function(_,k)
- if RemapsToSender and RemapsToSender[k] then
- return RemapsToSender[k]:get()
- end
- local req = nil
- if type(k) == "table" then
- req = k
- table.insert(req.sender,Object)
- else
- req = AccessRequest((isInner and 0) or 1,k,nil,Object)
- end
- if object.__cObj:requestGet(req) then
- return req.result
- elseif Object:hasSuper() then
- return Object:getSuper()[req]
- end
- return nil
- end;
- __newindex = function(_,k,v)
- local req = nil
- if type(k) == "table" then
- req = k
- else
- req = AccessRequest(1,k,v)
- end
- if object.__cObj:requestSet(req) ~= true then
- if object.__cObj:hasSuper() and object.__cObj:getSuper()[req] then
- object.__cObj:getSuper()[req] = v
- end
- end
- end
- })
- return object
- end
- function ObjectValue.new(ClassValue)
- local object = setmetatable({
- value = ClassValue.value;
- visibility = ClassValue.visibility;
- modifiers = ClassValue.modifiers;
- type = ClassValue.type;
- __static = ClassValue
- },{
- __index = ObjectValue;
- })
- return object
- end
- function ObjectValue:get(Sender,IsSelf)
- if self.modifiers.static then
- return self.__static.value
- end
- return self.value
- end
- function ObjectValue:set(NewValue)
- if self.modifiers.final then
- error("Members flagged as final can't be modified")
- end
- if self.modifiers.static then
- if type(NewValue) == self.__static.type or self.__static.type == nil or type(NewValue) == "nil" then
- self.__static.value = NewValue
- else
- error("Type of :"..type(NewValue).." - "..self.__static.type)
- end
- else
- if type(NewValue) == self.type or self.type == nil or type(NewValue) == "nil" then
- self.value = NewValue
- else
- error("Incompatible types : "..type(NewValue).." - "..self.type)
- end
- end
- end
- function ObjectValue:getAccessLevel()
- return self.visibility
- end
- function ObjectFunction.new(ClassFunction,ObjectProxy)
- local object = {
- value = ClassFunction.value;
- visibility = ClassFunction.visibility;
- modifiers = ClassFunction.modifiers;
- type = ClassFunction.type;
- proxy = ObjectProxy;
- useSenderInstance = false;
- senderInstance = nil;
- }
- setmetatable(object,{
- __index = ObjectFunction;
- __call = function(_,...)
- if object.modifiers.abstract then
- error("Attempt to call abstract method in "..object.proxy.__cObj.class:getName().."@"..tostring(object.proxy):sub(8))
- end
- local args = {...}
- local _self = args[1]
- if type(_self) == "table" and _self.__cObj and _self.__cObj.class:getName() == object.proxy.__cObj.class:getName() then
- table.remove(args,1)
- end
- return object.value((object.useSenderInstance and object.senderInstance) or object.proxy,unpack(args))
- end;
- })
- return object
- end
- function ObjectFunction:getAccessLevel()
- return self.visibility
- end
- function ObjectFunction:get(Sender,IsSelf)
- if IsSelf == false then
- self.useSenderInstance = true
- self.senderInstance = ObjectProxy(self.proxy.__cObj,true,Utils.getEqualPublicMethods(Sender,self.proxy.__cObj))
- else
- self.useSenderInstance = false
- end
- return self
- end
- function AccessRequest.new(Level,Field,Value,Sender)
- local object = {
- access = Level;
- field = Field;
- value = Value;
- result = nil;
- sender = {[1] = Sender};
- }
- setmetatable(object,{
- __index = AccessRequest;
- })
- return object
- end
- setmetatable(Class,{__call=function(_,ClassName) return Class.new(ClassName) end})
- setmetatable(ClassObject,{__call=function(_,ClassName) return ClassObject.new(ClassName) end})
- setmetatable(ClassProxy,{__call=function() return ClassProxy.new() end})
- setmetatable(Object,{__call=function(_,Class) return Object.new(Class) end})
- setmetatable(ObjectProxy,{__call=function(_,OfObject,IsInner,RemapToSender) return ObjectProxy.new(OfObject,IsInner,RemapToSender) end})
- setmetatable(ClassFunction,{__call=function(_,Value,Annotations) return ClassFunction.new(Value,Annotations) end})
- setmetatable(ObjectFunction,{__call=function(_,Value,Annotations) return ObjectFunction.new(Value,Annotations) end})
- setmetatable(ClassValue,{__call=function(_,Value,Annotations) return ClassValue.new(Value,Annotations) end})
- setmetatable(ObjectValue,{__call=function(_,Value,Annotations) return ObjectValue.new(Value,Annotations) end})
- setmetatable(ValueReference,{__call=function() return ValueReference.new() end})
- setmetatable(AccessRequest,{__call=function(_,Level,Field,Value,Sender) return AccessRequest.new(Level,Field,Value,Sender) end})
- _G.class = Class
Advertisement
Add Comment
Please, Sign In to add comment