| 1 | -- tolua: class class | 
|---|
| 2 | -- Written by Waldemar Celes | 
|---|
| 3 | -- TeCGraf/PUC-Rio | 
|---|
| 4 | -- Jul 1998 | 
|---|
| 5 | -- $Id: $ | 
|---|
| 6 |  | 
|---|
| 7 | -- This code is free software; you can redistribute it and/or modify it. | 
|---|
| 8 | -- The software provided hereunder is on an "as is" basis, and | 
|---|
| 9 | -- the author has no obligation to provide maintenance, support, updates, | 
|---|
| 10 | -- enhancements, or modifications. | 
|---|
| 11 |  | 
|---|
| 12 |  | 
|---|
| 13 | -- Class class | 
|---|
| 14 | -- Represents a class definition. | 
|---|
| 15 | -- Stores the following fields: | 
|---|
| 16 | --    name = class name | 
|---|
| 17 | --    base = class base, if any (only single inheritance is supported) | 
|---|
| 18 | --    {i}  = list of members | 
|---|
| 19 | classClass = { | 
|---|
| 20 |     classtype = 'class', | 
|---|
| 21 |     name = '', | 
|---|
| 22 |     base = '', | 
|---|
| 23 |     type = '', | 
|---|
| 24 |     btype = '', | 
|---|
| 25 |     ctype = '', | 
|---|
| 26 | } | 
|---|
| 27 | classClass.__index = classClass | 
|---|
| 28 | setmetatable(classClass,classContainer) | 
|---|
| 29 |  | 
|---|
| 30 |  | 
|---|
| 31 | -- register class | 
|---|
| 32 | function classClass:register (pre) | 
|---|
| 33 |     if not self:check_public_access() then | 
|---|
| 34 |         return | 
|---|
| 35 |     end | 
|---|
| 36 |  | 
|---|
| 37 |     pre = pre or '' | 
|---|
| 38 |     push(self) | 
|---|
| 39 |     if _collect[self.type] then | 
|---|
| 40 |         output(pre,'#ifdef __cplusplus\n') | 
|---|
| 41 |         output(pre..'tolua_cclass(tolua_S,"'..self.lname..'","'..self.type..'","'..self.btype..'",'.._collect[self.type]..');') | 
|---|
| 42 |         output(pre,'#else\n') | 
|---|
| 43 |         output(pre..'tolua_cclass(tolua_S,"'..self.lname..'","'..self.type..'","'..self.btype..'",NULL);') | 
|---|
| 44 |         output(pre,'#endif\n') | 
|---|
| 45 |     else | 
|---|
| 46 |         output(pre..'tolua_cclass(tolua_S,"'..self.lname..'","'..self.type..'","'..self.btype..'",NULL);') | 
|---|
| 47 |     end | 
|---|
| 48 |     if self.extra_bases then | 
|---|
| 49 |         for k,base in ipairs(self.extra_bases) do | 
|---|
| 50 |             -- not now | 
|---|
| 51 |             --output(pre..' tolua_addbase(tolua_S, "'..self.type..'", "'..base..'");') | 
|---|
| 52 |         end | 
|---|
| 53 |     end | 
|---|
| 54 |     output(pre..'tolua_beginmodule(tolua_S,"'..self.lname..'");') | 
|---|
| 55 |     local i=1 | 
|---|
| 56 |     while self[i] do | 
|---|
| 57 |         self[i]:register(pre..' ') | 
|---|
| 58 |         i = i+1 | 
|---|
| 59 |     end | 
|---|
| 60 |     output(pre..'tolua_endmodule(tolua_S);') | 
|---|
| 61 |     pop() | 
|---|
| 62 | end | 
|---|
| 63 |  | 
|---|
| 64 | -- return collection requirement | 
|---|
| 65 | function classClass:requirecollection (t) | 
|---|
| 66 |     if self.flags.protected_destructor then | 
|---|
| 67 |         return false | 
|---|
| 68 |     end | 
|---|
| 69 |     push(self) | 
|---|
| 70 |     local r = false | 
|---|
| 71 |     local i=1 | 
|---|
| 72 |     while self[i] do | 
|---|
| 73 |         r = self[i]:requirecollection(t) or r | 
|---|
| 74 |         i = i+1 | 
|---|
| 75 |     end | 
|---|
| 76 |     pop() | 
|---|
| 77 |     -- only class that exports destructor can be appropriately collected | 
|---|
| 78 |     -- classes that export constructors need to have a collector (overrided by -D flag on command line) | 
|---|
| 79 |     if self._delete or ((not flags['D']) and self._new) then | 
|---|
| 80 |         --t[self.type] = "tolua_collect_" .. gsub(self.type,"::","_") | 
|---|
| 81 |         t[self.type] = "tolua_collect_" .. clean_template(self.type) | 
|---|
| 82 |         r = true | 
|---|
| 83 |     end | 
|---|
| 84 |     return r | 
|---|
| 85 | end | 
|---|
| 86 |  | 
|---|
| 87 | -- output tags | 
|---|
| 88 | function classClass:decltype () | 
|---|
| 89 |     push(self) | 
|---|
| 90 |     self.type = regtype(self.original_name or self.name) | 
|---|
| 91 |     self.btype = typevar(self.base) | 
|---|
| 92 |     self.ctype = 'const '..self.type | 
|---|
| 93 |     if self.extra_bases then | 
|---|
| 94 |         for i=1,table.getn(self.extra_bases) do | 
|---|
| 95 |             self.extra_bases[i] = typevar(self.extra_bases[i]) | 
|---|
| 96 |         end | 
|---|
| 97 |     end | 
|---|
| 98 |     local i=1 | 
|---|
| 99 |     while self[i] do | 
|---|
| 100 |         self[i]:decltype() | 
|---|
| 101 |         i = i+1 | 
|---|
| 102 |     end | 
|---|
| 103 |     pop() | 
|---|
| 104 | end | 
|---|
| 105 |  | 
|---|
| 106 |  | 
|---|
| 107 | -- Print method | 
|---|
| 108 | function classClass:print (ident,close) | 
|---|
| 109 |     print(ident.."Class{") | 
|---|
| 110 |     print(ident.." name = '"..self.name.."',") | 
|---|
| 111 |     print(ident.." base = '"..self.base.."';") | 
|---|
| 112 |     print(ident.." lname = '"..self.lname.."',") | 
|---|
| 113 |     print(ident.." type = '"..self.type.."',") | 
|---|
| 114 |     print(ident.." btype = '"..self.btype.."',") | 
|---|
| 115 |     print(ident.." ctype = '"..self.ctype.."',") | 
|---|
| 116 |     local i=1 | 
|---|
| 117 |     while self[i] do | 
|---|
| 118 |         self[i]:print(ident.." ",",") | 
|---|
| 119 |         i = i+1 | 
|---|
| 120 |     end | 
|---|
| 121 |     print(ident.."}"..close) | 
|---|
| 122 | end | 
|---|
| 123 |  | 
|---|
| 124 | function classClass:set_protected_destructor(p) | 
|---|
| 125 | self.flags.protected_destructor = self.flags.protected_destructor or p | 
|---|
| 126 | end | 
|---|
| 127 |  | 
|---|
| 128 | -- Internal constructor | 
|---|
| 129 | function _Class (t) | 
|---|
| 130 |     setmetatable(t,classClass) | 
|---|
| 131 |     t:buildnames() | 
|---|
| 132 |     append(t) | 
|---|
| 133 |     return t | 
|---|
| 134 | end | 
|---|
| 135 |  | 
|---|
| 136 | -- Constructor | 
|---|
| 137 | -- Expects the name, the base (array) and the body of the class. | 
|---|
| 138 | function Class (n,p,b) | 
|---|
| 139 |  | 
|---|
| 140 |     if table.getn(p) > 1 then | 
|---|
| 141 |         b = string.sub(b, 1, -2) | 
|---|
| 142 |         for i=2,table.getn(p),1 do | 
|---|
| 143 |             b = b.."\n tolua_inherits "..p[i].." __"..p[i].."__;\n" | 
|---|
| 144 |         end | 
|---|
| 145 |         b = b.."\n}" | 
|---|
| 146 |     end | 
|---|
| 147 |  | 
|---|
| 148 |     -- check for template | 
|---|
| 149 |     b = string.gsub(b, "^{%s*TEMPLATE_BIND", "{\nTOLUA_TEMPLATE_BIND") | 
|---|
| 150 |     local t,_,T,I = string.find(b, "^{%s*TOLUA_TEMPLATE_BIND%s*%(+%s*\"?([^\",]*)\"?%s*,%s*([^%)]*)%s*%)+") | 
|---|
| 151 |     if t then | 
|---|
| 152 |  | 
|---|
| 153 |         -- remove quotes | 
|---|
| 154 |         I = string.gsub(I, "\"", "") | 
|---|
| 155 |         T = string.gsub(T, "\"", "") | 
|---|
| 156 |         -- get type list | 
|---|
| 157 |         local types = split_c_tokens(I, ",") | 
|---|
| 158 |         -- remove TEMPLATE_BIND line | 
|---|
| 159 |         local bs = string.gsub(b, "^{%s*TOLUA_TEMPLATE_BIND[^\n]*\n", "{\n") | 
|---|
| 160 |  | 
|---|
| 161 |         -- replace | 
|---|
| 162 |         for i =1 , types.n do | 
|---|
| 163 |  | 
|---|
| 164 |             local Tl = split(T, " ") | 
|---|
| 165 |             local Il = split_c_tokens(types[i], " ") | 
|---|
| 166 |             local bI = bs | 
|---|
| 167 |             local pI = {} | 
|---|
| 168 |             for j = 1,Tl.n do | 
|---|
| 169 |                 Tl[j] = findtype(Tl[j]) or Tl[j] | 
|---|
| 170 |                 bI = string.gsub(bI, "([^_%w])"..Tl[j].."([^_%w])", "%1"..Il[j].."%2") | 
|---|
| 171 |                 if p then | 
|---|
| 172 |                     for i=1,table.getn(p) do | 
|---|
| 173 |                         pI[i] = string.gsub(p[i], "([^_%w]?)"..Tl[j].."([^_%w]?)", "%1"..Il[j].."%2") | 
|---|
| 174 |                     end | 
|---|
| 175 |                 end | 
|---|
| 176 |             end | 
|---|
| 177 |             --local append = "<"..string.gsub(types[i], "%s+", ",")..">" | 
|---|
| 178 |             local append = "<"..concat(Il, 1, table.getn(Il), ",")..">" | 
|---|
| 179 |             append = string.gsub(append, "%s*,%s*", ",") | 
|---|
| 180 |             append = string.gsub(append, ">>", "> >") | 
|---|
| 181 |             for i=1,table.getn(pI) do | 
|---|
| 182 |                 --pI[i] = string.gsub(pI[i], ">>", "> >") | 
|---|
| 183 |                 pI[i] = resolve_template_types(pI[i]) | 
|---|
| 184 |             end | 
|---|
| 185 |             bI = string.gsub(bI, ">>", "> >") | 
|---|
| 186 |             Class(n..append, pI, bI) | 
|---|
| 187 |         end | 
|---|
| 188 |         return | 
|---|
| 189 |     end | 
|---|
| 190 |  | 
|---|
| 191 |     local mbase | 
|---|
| 192 |  | 
|---|
| 193 |     if p then | 
|---|
| 194 |         mbase = table.remove(p, 1) | 
|---|
| 195 |         if not p[1] then p = nil end | 
|---|
| 196 |     end | 
|---|
| 197 |  | 
|---|
| 198 |     mbase = mbase and resolve_template_types(mbase) | 
|---|
| 199 |  | 
|---|
| 200 |     local c | 
|---|
| 201 |     local oname = string.gsub(n, "@.*$", "") | 
|---|
| 202 |     oname = getnamespace(classContainer.curr)..oname | 
|---|
| 203 |  | 
|---|
| 204 |     if _global_classes[oname] then | 
|---|
| 205 |         c = _global_classes[oname] | 
|---|
| 206 |         if mbase and ((not c.base) or c.base == "") then | 
|---|
| 207 |             c.base = mbase | 
|---|
| 208 |         end | 
|---|
| 209 |     else | 
|---|
| 210 |         c = _Class(_Container{name=n, base=mbase, extra_bases=p}) | 
|---|
| 211 |  | 
|---|
| 212 |         local ft = getnamespace(c.parent)..c.original_name | 
|---|
| 213 |         append_global_type(ft, c) | 
|---|
| 214 |     end | 
|---|
| 215 |  | 
|---|
| 216 |     push(c) | 
|---|
| 217 |     c:parse(strsub(b,2,strlen(b)-1)) -- eliminate braces | 
|---|
| 218 |     pop() | 
|---|
| 219 | end | 
|---|
| 220 |  | 
|---|