do MRDefaultSetting = MRDefaultSetting or {Type=vtAutoAssembler;Script=table.concat({'[ENABLE]','[DISABLE]'},"\n")} local function trim(self,dir) if dir==true then return self:match('^%s*(.-)$') elseif dir==false then return self:match('^(.-)%s*$') elseif dir==nil then return self:match('^%s*(.-)%s*$') else return self end end local function sep(self,SEP,extra) local r,s,i,a,b = {},{},1,1,-1 if type(SEP)=='number' then for i=1,self:len(),SEP do r[1+#r]=self:sub(i,i+SEP-1) end if extra == true then for i=1,#r do r[i]={string.byte(r[i],1,-1)}end end return r end SEP = type(SEP)=='string' and SEP or ',' a,b = self:find(SEP,i) while a~=nil do r[1+#r]= trim(self:sub(i,a-1)) s[1+#s]= self:sub(a,b) i = b + 1 a,b = self:find(SEP,i) end r[1+#r] = self:sub(i) if extra== true then return r end return r,s end function ceupd(o,p,...)-- handy function to update ce userdata/guiclass if type(p)~='table' then return o end for k,v in pairs(p) do if type(v)=='table' then local peek = o[k] -- o[k]=type(peek)=='table' and ceupd(peek,v) or type(peek)=='userdata' and ceupd(peek,v) or v o[k]=ceupd(peek,v) -- type(peek)=='userdata' and ceupd(peek,v) or v else o[k]=v end end if select('#',...)==0 then return o end return ceupd(o,...) end function isMR(o) return type(o)=='userdata' and o.ClassName=='TMemoryRecord'end function isAL(o) return type(o)=='userdata' and o.ClassName=='TAddresslist'end function setMR(mr,...) local args ={n=select('#',...),...} if isMR(mr) and args.n>0 then local detail = {} for i=1,args.n do local part = args[i] if type(part)=='table' then for k,v in pairs(part) do detail[k]=v end end end local d = detail.Description if type(d)=='string' and d:len()>0 and mr.Description:match(d) then -- Description already match, don't change detail.Description=nil end if detail.Type~=nil then -- set type 1st, else some property cannot set properly if type(detail.Type)=='string' then -- if Type is string, assume it is name of vtType, convert to number detail.Type = loadstring('return _G["'..detail.Type..'"]')() end if type(detail.Type)=='number' then ceupd(mr,{Type=detail.Type}) end end ceupd(mr,detail) return true end return false end function newMR(root,detail,...) local al = getAddressList() local newmr = al.createMemoryRecord() setMR(newmr,detail,...) if isMR(root) then newmr.appendToEntry(root)end return newmr end function getMR(mr,root,detail,...) -- print(tostring(mr),tostring(root)) local al = getAddressList() if isMR(mr) then return mr elseif type(mr)=='number' then return al.getMemoryRecordByID(mr) elseif type(mr)=='string' then -- find mr by matching Description with re pattern (not exact equality) if mr:len()==0 then return end -- empty re pattern string always match, assume typo error root = getMR(root) root = root==nil and al or root if isMR(root) or isAL(root) then for i=1,root.Count do local r = root[i-1] if r.Description:match(mr) then return r end end -- not found, test if create new mr with detail setting ??? if type(detail)=='table' then return newMR(root,{Description=mr},detail,...) end end end end function getMRByPath(descpath,detail,...) detail = type(detail)=='table' and detail or descpath:match('/$') and MRDefaultSetting or nil local parts = sep(descpath:gsub('//+','/'),'/') while #parts>0 and parts[#parts]:len()==0 do table.remove(parts) end while #parts>0 and parts[1]:len()==0 do table.remove(parts,1) end local lastexistidx,lastexist,cur=0,getAddressList() if #parts>0 then cur = getMR(parts[1]) for i=2,#parts do if cur==nil then break else lastexistidx=i-1 lastexist=cur end cur = getMR(parts[i],lastexist) end if cur~=nil and lastexistidx==#parts-1 then return cur end -- not found, test if create new mr with detail setting ??? if type(detail)=='table' then for i=lastexistidx+1,#parts-1 do lastexist = getMR(parts[i],lastexist,MRDefaultSetting) -- newMR lastexist.Description = parts[i] end lastexist = getMR(parts[#parts],lastexist,detail) -- newMR lastexist.Description = parts[#parts] return lastexist end end end function regAA(cmd,cmdf) if autoAssemble(cmd.."()") or autoAssemble(cmd.."(TEST)") then unregisterAutoAssemblerCommand(cmd) end if cmdf~=nil then registerAutoAssemblerCommand(cmd,cmdf) end end function makeNestedKV(t,k,v) if type(t)=='table' then local ks = sep(k:gsub('%.[%.]+','.'),'%.') while #ks>0 and ks[#ks]:len()==0 do table.remove(ks) end while #ks>0 and ks[1]:len()==0 do table.remove(ks,1) end if #ks>0 then local cur = t for i=1,#ks-1 do if type(cur[ks[i]])~='table' then cur[ks[i]]={} end cur = cur[ks[i]] end cur[ks[#ks]]=v end end end function dumpTbl(t,seen,lv,textmode) seen = type(seen)~='table' and {} or seen if type(t)~='table' or seen[t]~=nil then return {} end lv = type(lv)~='number' and 0 or lv local pr = {} seen[t]=true local tab = string.rep(' ',lv) for k,v in pairs(t) do local n,d = k,tostring(v) if type(k)~='string' or not k:match('^[_%a][_%w]*$') then n = '['..tostring(k)..']' end if type(v)=='table' then local ret = dumpTbl(v,seen,lv+1,textmode) if #ret>0 then pr[1+#pr]=tab..n..' = {\n'..tab..ret..'\n'..tab..'}' else pr[1+#pr]=tab..n..' = {}' end else if type(v)=='string' and textmode~=true then d = '"'..d..'"' end pr[1+#pr]=tab..n..' = '..d..' ~'..type(v) end end return table.concat(pr,',\n') end function aaSetMR(mr,...) local args,detail ={...},{} if isMR(mr) then for i=1,#args do local k,v = args[i]:match('^([^=]+)=(.*)$') -- print(k," = ",tostring(v)) if v~=nil then makeNestedKV(detail,k,v) end end end if AADebug==true then print(dumpTbl(detail,nil,nil,true)) end return setMR(mr,detail) end function aa_MemoryRecord(s,sc) if s=='' or s=='TEST' or sc==true then return '// test' end local part = sep(s) if #part>=1 then local path,mtype = part[1],part[2] while path:match('^"[^"]*"$') do path=path:sub(2,-2) end local mr= getMRByPath(path..'/') -- newmr if not exist, use defauult type (script) if isMR(mr) then if mtype~=nil then if mtype:sub(1,1)=='*' then -- loop mode print('yet to implemented') else -- individual mode aaSetMR(mr,unpack(part,2)) end end end end return '// no parse error unless by external exception!' end regAA('mr',aa_MemoryRecord) regAA('memoryrecord',aa_MemoryRecord) end