| 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 |  | 
|---|