-------------------------------------------------------------------------------- ------------------------------ ##### ## ------------------------------ ------------------------------ ## ## # ## ------------------------------ ------------------------------ ## ## ## ## ------------------------------ ------------------------------ ## ## # ## ------------------------------ ------------------------------ ##### ### ###### ------------------------------ -------------------------------- -------------------------------- ----------------------- An Object Request Broker in Lua ------------------------ -------------------------------------------------------------------------------- -- Project: OiL - ORB in Lua: An Object Request Broker in Lua -- -- Release: 0.5 -- -- Title : Mapping of Lua values into CDR using dynamic generated code -- -- Authors: Renato Maia -- -------------------------------------------------------------------------------- -- codec:Facet -- encoder:object encoder() -- decoder:object decoder(stream:string) -- -- proxies:Receptacle -- proxy:object proxyto(ior:table, iface:table|string) -- -- objects:Receptacle -- proxy:object register(implementation:object, iface:table|string) -------------------------------------------------------------------------------- local ipairs = ipairs local loadstring = loadstring local select = select local unpack = unpack local string = require "string" local table = require "table" local oo = require "oil.oo" local assert = require "oil.assert" local idl = require "oil.corba.idl" local Codec = require "oil.corba.giop.Codec" --[[VERBOSE]] local verbose = require "oil.verbose" module "oil.corba.giop.CodecGen" oo.class(_M, Codec) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- CodeGenerator = oo.class{ stacksize = 0, stacktop = 0, source = table.concat, } local upvaluefmt = "_up%d_" local stackposfmt = "_%d_" function CodeGenerator:__init(...) self = oo.rawnew(self, ...) if self.upvalues == nil then self.upvalues = {n=0} end return self end function CodeGenerator:add(...) for i = 1, select("#", ...) do self[#self+1] = select(i, ...) end end function CodeGenerator:push(...) self.stacktop = self.stacktop + 1 if self.stacktop > self.stacksize then self.stacksize = self.stacktop end self:add(self:top(),' = ',...) self:add("\n") end function CodeGenerator:pop() self.stacktop = self.stacktop - 1 end function CodeGenerator:top(shift) return stackposfmt:format(self.stacktop+(shift or 0)) end function CodeGenerator:upvalue(value) local upvalues = self.upvalues if value == nil then value = upvalues end -- special value to represent 'nil' if upvalues[value] == nil then upvalues.n = upvalues.n + 1 upvalues[value] = upvaluefmt:format(upvalues.n) if value ~= upvalues then upvalues[upvalues.n] = value end end return upvalues[value] end function CodeGenerator:compile(idltype) local source = self:source() local positions = {"self"} for i = 1, self.stacksize do positions[i+1] = stackposfmt:format(i) end source = string.format([=[ local assert = require "oil.assert" --[[VERBOSE]] local verbose = require "oil.verbose" return function(%s) %s end ]=], table.concat(positions, ","), source) local upvalues = self.upvalues if upvalues.n > 0 then local names = {} for i = 1, upvalues.n do names[i] = upvaluefmt:format(i) end source = string.format("local %s = ...\n%s", table.concat(names, ","), source) end local codename = string.format("(un)marshaller for %s %s", idltype._type, idltype.repID or idltype.name or "anonymous") return assert.results(loadstring(source, codename))( unpack(upvalues, 1, upvalues.n)) end function CodeGenerator:illegal(description, sysex) self:add([[ assert.exception{ ']],(sysex or "illegal value"),[[', reason = 'value', message = 'illegal ]],description,[[', valuename = ']],description,[[' } ]]) end -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- DecoderGenerator = oo.class({}, CodeGenerator) function DecoderGenerator:__init(...) self = CodeGenerator.__init(self, ...) if #self == 0 then self[1] = "return " end return self end local code = "self.unpack('%s',self.data,nil,nil,self:alignedjump(%d))" local function numberunmarshaller(size, format) local code = code:format(format, size) return function(self) self:add(code) end end DecoderGenerator.null = function(self) self:add(" nil") end DecoderGenerator.void = DecoderGenerator.null DecoderGenerator.short = numberunmarshaller( 2, "s") DecoderGenerator.long = numberunmarshaller( 4, "l") DecoderGenerator.longlong = numberunmarshaller( 8, "g") DecoderGenerator.ushort = numberunmarshaller( 2, "S") DecoderGenerator.ulong = numberunmarshaller( 4, "L") DecoderGenerator.ulonglong = numberunmarshaller( 8, "G") DecoderGenerator.float = numberunmarshaller( 4, "f") DecoderGenerator.double = numberunmarshaller( 8, "d") DecoderGenerator.longdouble = numberunmarshaller(16, "D") function DecoderGenerator:boolean() self:add "(" self:octet() self:add "~=0)" end function DecoderGenerator:char() self:add "self.data:sub(self.cursor,self:jump(1))" end function DecoderGenerator:octet() self:add "self.unpack('B',self.data,nil,nil,self:jump(1))" end function DecoderGenerator:struct(idltype) self:add "setmetatable({\n" for _, field in ipairs(idltype.fields) do self:add(field.name,'=') self:generate(field.type) self:add(',\n') end self:add("},",self:upvalue(idltype),")\n") end function DecoderGenerator:union(idltype) local gen = DecoderGenerator{""} local default = idltype.options[idltype.default+1] gen:add([[ local switch local function default(self) return { _switch = switch, ]]) if default then gen:add([[ _field = ]],default.name,[[, _value = ]]) gen:generate(default.type) gen:add([[, ]]) end gen:add([[ } end ]]) gen:add 'return setmetatable({\n' for _, option in ipairs(idltype.options) do --[] = function() -- return { -- _switch = , -- _field = , -- _value = , -- } --end, local switch = gen:upvalue(option.label) gen:add([[ []],switch,[[] = function(self) return { _switch = ]],switch,[[, _field = ']],option.name,[[', _value = ]]) gen:generate(option.type) gen:add[[, } end, ]] end gen:add[[ },{ __index=function(_,value) switch=value return default end, }) ]] local selector = gen:compile(idltype) -- setmetatable(__selector__[](self), __idltype__) self:add("setmetatable(",self:upvalue(selector()),"[") self:generate(idltype.switch) self:add("](self),",self:upvalue(idltype),")") end function DecoderGenerator:enum(idltype) -- [unmarhsal(ulong)+1] or illegal("enumeration value") self:add(self:upvalue(idltype.enumvalues),"[") self:ulong() self:add("+1] or ") self:illegal("enumeration value", "MARSHAL") end function DecoderGenerator:string() self:add "self.data:sub(self:jump(" self:ulong() self:add "),self.cursor-2)" end function DecoderGenerator:sequence(idltype) local elementtype = idltype.elementtype while elementtype._type == "typecode" do elementtype = elementtype.type end if elementtype == idl.octet or elementtype == idl.char then self:add "self.data:sub(self:jump(" self:ulong() self:add "),self.cursor-1)" else local gen = DecoderGenerator() gen:generate(elementtype) self:add("setmetatable(self:sequenceof(",self:upvalue(gen:compile(elementtype)),",") self:ulong() self:add("),",self:upvalue(idltype),")") end end function DecoderGenerator:array(idltype) local length = idltype.length local elementtype = idltype.elementtype while elementtype._type == "typecode" do elementtype = elementtype.type end if elementtype == idl.octet or elementtype == idl.char then self:add("self.data:sub(self:jump(",length,"),self.cursor-1)") else self:add "setmetatable({\n" for i = 1, length do self:generate(elementtype) self:add ",\n" end self:add("},",self:upvalue(elementtype),")") end end function DecoderGenerator:typedef(idltype) return self:generate(idltype.type) end function DecoderGenerator:except(idltype) self:add "setmetatable({\n" for _, member in ipairs(idltype.members) do self:add(member.name,"=") self:generate(member.type) self:add(",\n") end self:add("},",self:upvalue(idltype),")") end function DecoderGenerator:generate(idltype) local generator = self[idltype._type] if generator then --[[VERBOSE]] self:add("verbose:gen_marshal(self,",self:upvalue(idltype),",") generator(self, idltype) --[[VERBOSE]] self:add(")") else self:add("self:",idltype._type,"(",self:upvalue(idltype),")") end end -------------------------------------------------------------------------------- Decoder = oo.class({}, Decoder) function Decoder:alignedjump(value) local shift = value - (self.cursor - 2) % value - 1 local pos = self.cursor + shift self:jump(shift + value) return pos end function Decoder:sequenceof(decoder, length) local sequence = { n = length } for i = 1, length do sequence[i] = decoder(self) end return sequence end function Decoder:get(idltype) local unmarshall = idltype.unmarshall if unmarshall == nil then local type = idltype._type if DecoderGenerator[type] then local gen = DecoderGenerator() gen:generate(idltype) --[[VERBOSE]] verbose:marshal("generating new unmarshaller for type ",idltype._type) unmarshall = gen:compile(idltype) idltype.unmarshall = unmarshall else --[[VERBOSE]] verbose:marshal("using dynamic unmarshaller for type ",idltype._type) unmarshall = self[type] or assert.illegal(type, "supported type", "MARSHAL") end --[[VERBOSE]] else verbose:marshal("generated unmarshaller found for type ",idltype._type) end return unmarshall(self, idltype) end -- generate string decoder because 'Decoder:string()' does not get an argument. local gen = DecoderGenerator() gen:generate(idl.string) idl.string.unmarshall = gen:compile(idl.string) Decoder.string = idl.string.unmarshall Decoder.struct = Decoder.get Decoder.union = Decoder.get Decoder.enum = Decoder.get Decoder.sequence = Decoder.get Decoder.array = Decoder.get Decoder.typedef = Decoder.get Decoder.except = Decoder.get -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- EncoderGenerator = oo.class({ stacksize = 1, stacktop = 1, }, CodeGenerator) function EncoderGenerator:__init(...) self = CodeGenerator.__init(self, ...) if #self == 0 then self[1] = [[ local format = self.format local aux ]] end return self end function EncoderGenerator:rawput(format, size, value) self:add("local index = self.index") self:add("\nformat[index],self[index] = '",format,"',",value or self:top()) self:add("\nself.index,self.cursor = index+1,self.cursor+",size,"\n") end local function numbermarshaller(size, format) return function(self) self:add('aux = ',size-1,'-(self.cursor-2)%',size,'\n') self:rawput('"', 'aux', '("\\255"):rep(aux)') self:rawput(format, size) end end EncoderGenerator.null = function() end EncoderGenerator.void = DecoderGenerator.null EncoderGenerator.short = numbermarshaller( 2, "s") EncoderGenerator.long = numbermarshaller( 4, "l") EncoderGenerator.longlong = numbermarshaller( 8, "g") EncoderGenerator.ushort = numbermarshaller( 2, "S") EncoderGenerator.ulong = numbermarshaller( 4, "L") EncoderGenerator.ulonglong = numbermarshaller( 8, "G") EncoderGenerator.float = numbermarshaller( 4, "f") EncoderGenerator.double = numbermarshaller( 8, "d") EncoderGenerator.longdouble = numbermarshaller(16, "D") function EncoderGenerator:boolean() self:add(self:top(),' = ',self:top(),' and 1 or 0\n') self:octet() end function EncoderGenerator:char() self:add('if #',self:top(),' ~= 1 then assert.illegal(',self:top(),', "character", "MARSHAL") end\n') self:rawput('"', 1) end function EncoderGenerator:octet() self:rawput("B", 1) end function EncoderGenerator:struct(idltype) for _, field in ipairs(idltype.fields) do self:push(self:top(),".",field.name) self:generate(field.type) self:pop() end end function EncoderGenerator:union(idltype) self:push(self:top(),"._switch") self:add('if ',self:top(),' == nil then\n') self:pop() -- nil self:push(self:upvalue(idltype.selector),'[',self:top(),'._field]') self:add('if ',self:top(),' == nil then\n') for index, option in ipairs(idltype.options) do self:pop() -- nil self:add('if ',self:top(),'.',option.name,' ~= nil then ') self:push(self:upvalue(option.label)) self:add('else') end self:add '\n' local default = idltype.options[idltype.default+1] if default then self:pop() -- nil self:push(self:upvalue(default)) else self:illegal("union value (no discriminator)", "MARSHAL") end self:add 'end\nend\nend\n' self:generate(idltype.switch) for index, option in ipairs(idltype.options) do self:add('if ',self:top(),' == ',self:upvalue(option.label),' then\n') self:pop() -- switch self:push(self:top(),'._value') self:add('if ',self:top(),' == nil then\n') self:pop() -- nil self:push(self:top(),".",option.name) self:add('if ',self:top(),' == nil then\n') self:illegal("union value (none contents)", "MARSHAL") self:add "end\nend\n" self:generate(option.type) if index == #idltype.options then self:add 'end\n' else self:add 'else' end end self:pop() -- switch or value end function EncoderGenerator:enum(idltype) self:push(self:upvalue(idltype.labelvalue),'[',self:top(),'] or tonumber(',self:top(),')') self:ulong() self:pop() end function EncoderGenerator:string() self:push('#',self:top(),'+1') self:ulong() self:pop() self:rawput('"', self:top(1)) self:rawput('"', 0, "'\\0'") end function EncoderGenerator:sequence(idltype) local elementtype = idltype.elementtype while elementtype._type == "typecode" do elementtype = elementtype.type end local dostring = elementtype == idl.octet or elementtype == idl.char if dostring then self:add('if type(',self:top(),') == "string" then\n') self:push('#',self:top()) self:ulong() self:pop() self:rawput('"', self:top(1)) self:add 'else\n' end self:push(self:top(),'.n or #',self:top()) self:ulong() self:pop() self:add('for i = 1, ',self:top(1),' do\n') self:push(self:top(),'[i]') self:generate(elementtype) self:pop() self:add 'end\n' if dostring then self:add 'end\n' end end function EncoderGenerator:array(idltype) local elementtype = idltype.elementtype while elementtype._type == "typecode" do elementtype = elementtype.type end local dostring = elementtype == idl.octet or elementtype == idl.char if dostring then self:add('if type(',self:top(),') == "string" then\n') self:rawput('"', idltype.length) self:add('else\n') end self:add('for i = 1,',idltype.length,' do\n') self:generate(elementtype) self:add 'end\n' if dostring then self:add 'end\n' end end function EncoderGenerator:typedef(idltype) return self:generate(idltype.type) end function EncoderGenerator:except(idltype) for _, member in ipairs(idltype.members) do self:push(self:top(),'.',member.name) self:generate(member.type) self:pop() end end function EncoderGenerator:generate(idltype) local generator = self[idltype._type] if generator then --[[VERBOSE]] self:add('verbose:marshal(true,self,',self:upvalue(idltype),',',self:top(),')\n') generator(self, idltype) --[[VERBOSE]] self:add('verbose:marshal(false)\n') else self:add('self:',idltype._type,'(',self:top(),',',self:upvalue(idltype),')\n') end end -------------------------------------------------------------------------------- Encoder = oo.class({}, Encoder) function Encoder:alignedjump(value) local pos = self.cursor - 2 self:jump(value - pos % value - 1) return self.cursor end function Encoder:put(value, idltype) local marshall = idltype.marshall if marshall == nil then local type = idltype._type if EncoderGenerator[type] then local gen = EncoderGenerator() gen:generate(idltype) --[[VERBOSE]] verbose:marshal("generating new marshaller for type ",idltype._type) marshall = gen:compile(idltype) idltype.marshall = marshall else --[[VERBOSE]] verbose:marshal("using dynamic marshaller for type ",idltype._type) marshall = self[type] or assert.illegal(type, "supported type", "MARSHAL") end --[[VERBOSE]] else verbose:marshal("generated marshaller found for type ",idltype._type) end return marshall(self, value, idltype) end -- generate string encoder because 'Decoder:string()' does not get an argument. local gen = EncoderGenerator() gen:generate(idl.string) idl.string.marshall = gen:compile(idl.string) Encoder.string = idl.string.marshall Encoder.struct = Encoder.put Encoder.union = Encoder.put Encoder.enum = Encoder.put Encoder.sequence = Encoder.put Encoder.array = Encoder.put Encoder.typedef = Encoder.put Encoder.except = Encoder.put -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --[[VERBOSE]] verbose.codecop[Encoder] = verbose.codecop[Codec.Encoder] --[[VERBOSE]] verbose.codecop[Decoder] = verbose.codecop[Codec.Decoder] --[[VERBOSE]] function verbose:gen_marshal(codec, type, value) --[[VERBOSE]] self:marshal(codec, type, value) --[[VERBOSE]] return value --[[VERBOSE]] end