lbp_completion.cppGo to the documentation of this file.00001 /* 00002 ******************************************************************** 00003 ******************************************************************** 00004 ******************************************************************** 00005 00006 Lua completer, derived from Lua advanced readline 00007 support patch, with original copyright al follows: 00008 00009 Copyright (C) 2004-2006 Mike Pall. 00010 Same license as Lua. See lua.h. 00011 00012 The below version is adapted to go with SWIG generated 00013 __index functions (as opposed to the perhaps more common 00014 __index tables). The interface was changed to a more 00015 C++ like style, to make a better match with applications 00016 like DESTool. The current implementation is preliminary 00017 and requires some clean-up. 00018 00019 This file is included by lbp_function.cpp and the functions 00020 are called by the LuaState methods for completion. 00021 00022 Thomas Moor, 2011. 00023 00024 ******************************************************************** 00025 ******************************************************************** 00026 ******************************************************************** 00027 */ 00028 00029 00030 // Lua keywords 00031 static const char *const luafaudes_rl_keywords[] = { 00032 "and", "break", "do", "else", "elseif", "end", "false", 00033 "for", "function", "if", "in", "local", "nil", "not", "or", 00034 "repeat", "return", "then", "true", "until", "while", NULL 00035 }; 00036 00037 // Test identifier 00038 static bool luafaudes_rl_valididentifier(const std::string& str) { 00039 std::string::const_iterator sit=str.begin(); 00040 if(sit==str.end()) return false; 00041 if(!(isalpha(*sit) || *sit=='_')) return false; 00042 for(++sit; sit!=str.end(); ++sit) 00043 if(!(isalnum(*sit) || *sit=='_')) return true; 00044 return true; 00045 } 00046 00047 // Append compound prefix + string + suffix to list and maintain common prefix. 00048 static void luafaudes_rl_dmadd(std::list< std::string > & mlist, const std::string& prefix, const std::string& str, const std::string& suffix) { 00049 // iterate suffxes 00050 if(suffix.size()>1) { 00051 for(unsigned int i=0;i<suffix.size();i++) 00052 luafaudes_rl_dmadd(mlist,prefix,str,std::string(1,suffix.at(i))); 00053 return; 00054 } 00055 // build compound 00056 std::string comp; 00057 comp=prefix + str + suffix; 00058 // initialize: matching prefix equals first entry 00059 if(mlist.size()==0) { 00060 mlist.push_back(comp); 00061 return; 00062 } 00063 // initialize: matching prefix equals first entry 00064 if(mlist.size()==1) { 00065 mlist.push_back(*mlist.begin()); 00066 mlist.push_back(comp); 00067 } 00068 // figure maximal matching prefix 00069 std::string& match=*mlist.begin(); 00070 std::string::iterator mit, cit; 00071 mit=match.begin(); 00072 cit=comp.begin(); 00073 while(mit!=match.end() && cit!=comp.end()) { 00074 if(*mit!=*cit) break; 00075 mit++; cit++; 00076 } 00077 // adjust matching prefix in list 00078 if(mit!=match.end()) 00079 match.erase(mit,match.end()); 00080 // append to list 00081 mlist.push_back(comp); 00082 } 00083 00084 // Get __index field of metatable of object on top of stack 00085 // -- return 1 for ok and leave __index field on stack 00086 // -- return 0 for error, nothing on stack 00087 static int luafaudes_rl_getmetaindex(lua_State *L) { 00088 // object has no metatable, error 00089 if(!lua_getmetatable(L, -1)) 00090 { lua_pop(L, 1); return 0; } // stack: 00091 lua_replace(L, -2); // stack: metatable 00092 // get the __ index field 00093 lua_pushstring(L, "__index"); 00094 lua_rawget(L, -2); // stack: metatable,__index 00095 lua_replace(L, -2); // stack: __index 00096 // invald result, error 00097 if(lua_isnil(L,-1) || lua_rawequal(L, -1, -2)) 00098 { lua_pop(L, 1); return 0; } // stack: 00099 return 1; // stack: __index 00100 } 00101 00102 // Get .fn fields of metatable of object on top of stack. 00103 // -- the SWIG __index function retrieves methods from the .fn attribute 00104 // -- allways puts a table on the stack, empty on error 00105 static void luafaudes_rl_getmetafn(lua_State *L) { 00106 // object has no metatable: return empty table 00107 if(!lua_getmetatable(L, -1)) 00108 { lua_pop(L, 1); lua_newtable(L); return; } 00109 lua_replace(L, -2); // stack: metatable 00110 // get .fn 00111 lua_pushstring(L, ".fn"); 00112 lua_rawget(L, -2); // stack: metatable,.fn 00113 lua_replace(L, -2); // stack: .fn 00114 if(!lua_istable(L, -1)) 00115 { lua_pop(L, 1); lua_newtable(L); return; } 00116 } 00117 00118 // Get .get field of metatable of object on top of stack. 00119 // -- the SWIG __index function retrieves member access from the .get attribute 00120 // -- allways puts a table on the stack, empty on error 00121 static void luafaudes_rl_getmetaget(lua_State *L) { 00122 // object has no metatable: just pop the object 00123 if(!lua_getmetatable(L, -1)) 00124 { lua_pop(L, 1); lua_newtable(L); return; } 00125 lua_replace(L, -2); // stack: metatable 00126 // get .get 00127 lua_pushstring(L, ".get"); 00128 lua_rawget(L, -2); // stack: metatable,.get 00129 lua_replace(L, -2); // stack: .get 00130 if(!lua_istable(L, -1)) 00131 { lua_pop(L, 1); lua_newtable(L); return; } 00132 } 00133 00134 // Get __index/.fn/.get field of metatable of object on top of stack. 00135 // -- allways puts a table on stack, empty of error 00136 // -- returns 1 to indicate ussage of SWIG .get table 00137 static int luafaudes_rl_getmeta(lua_State *L, bool has_colon) { 00138 // try __index first 00139 lua_pushvalue(L,-1); // stack: obj,obj 00140 if(luafaudes_rl_getmetaindex(L)) { 00141 // is it a table // stack: obj,_index 00142 if(lua_istable(L,-1)) { 00143 // is it non-empty? // stack: obj,_index 00144 lua_pushnil(L); 00145 if(lua_next(L, -2)) { 00146 lua_pop(L, 2); // stack: obj,_index 00147 lua_replace(L, -2); // stack: _index 00148 return 0; 00149 } 00150 } 00151 lua_pop(L,1); // stack: obj1 00152 } // stack: obj 00153 // colon indicates method, so we use .fn 00154 if(has_colon) { 00155 luafaudes_rl_getmetafn(L); // stack: .fn 00156 return 0; 00157 } 00158 // absence of colon indicates member, so we use .get 00159 luafaudes_rl_getmetaget(L); // stack: .get 00160 return 1; 00161 00162 } 00163 00164 00165 // Get field from object on top of stack (without calling metamethods) 00166 static int luafaudes_rl_getfield(lua_State *L, const char *s, size_t n) { 00167 int i = 20; // max loop count to limit infinite metatable loops. */ 00168 do { 00169 if(lua_istable(L, -1)) { // if obj is a table, try to get the requested field 00170 lua_pushlstring(L, s, n); 00171 lua_rawget(L, -2); // stack: obj,field 00172 if(!lua_isnil(L, -1)) // ok, got the field 00173 {lua_replace(L, -2); return 1;} 00174 lua_pop(L, 1); // stack: obj 00175 } 00176 if(!luafaudes_rl_getmetaindex(L)) break; // stack: _index 00177 } while (--i > 0); 00178 lua_pop(L, 1); 00179 return 0; 00180 } /* 1: obj -- val, 0: obj -- */ 00181 00182 00183 // actual completer 00184 static std::list< std::string > luafaudes_rl_complete(lua_State *L, const std::string& word) { 00185 00186 // C++ style interface 00187 std::list< std::string > mlist; 00188 const char* text= word.c_str(); 00189 int start=0; 00190 int end=word.size(); 00191 00192 // other locals 00193 const char *s; 00194 size_t i, n, dot, loop; 00195 int colon; 00196 int savetop; 00197 bool used_swig_get=false; 00198 00199 // bail ot on text that cannot complete to an identifier 00200 if (!(text[0] == '\0' || isalpha(text[0]) || text[0] == '_')) return mlist; 00201 00202 // recird top of stack 00203 savetop = lua_gettop(L); 00204 00205 // figure the right most complete field in "word" and 00206 // -- leave the table of globals on the stack, if there is no complete field 00207 lua_pushvalue(L, LUA_GLOBALSINDEX); 00208 for (n = (size_t)(end-start), i = dot = 0, colon=-1; i < n; i++) 00209 if (text[i] == '.' || text[i] == ':') { 00210 if (!luafaudes_rl_getfield(L, text+dot, i-dot)) 00211 { lua_settop(L, savetop); return mlist; } // error 00212 dot = i+1; // Points to first char after dot/colon. 00213 if(text[i] == ':') colon=dot; // record whether we have seen a colon 00214 } 00215 00216 // Append all matches against keywords if there is no dot/colon. 00217 if (dot == 0) 00218 for (i = 0; (s = luafaudes_rl_keywords[i]) != NULL; i++) 00219 if(!strncmp(s, text, n)) luafaudes_rl_dmadd(mlist, "", std::string(s), " "); 00220 00221 // Append all valid matches from all tables/metatables. 00222 loop = 0; // Avoid infinite metatable loops. 00223 do { 00224 if(lua_istable(L, -1) && 00225 (loop == 0 || !lua_rawequal(L, -1, LUA_GLOBALSINDEX))) 00226 for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) 00227 if (lua_type(L, -2) == LUA_TSTRING) { 00228 s = lua_tostring(L, -2); 00229 // Only match names starting with '_' if explicitly requested. 00230 if (!strncmp(s, text+dot, n-dot) && luafaudes_rl_valididentifier(s) && 00231 (*s != '_' || text[dot] == '_')) { 00232 std::string suf = " "; // Default suffix is a space. 00233 switch (lua_type(L, -1)) { 00234 case LUA_TTABLE: suf = ":."; break; 00235 case LUA_TFUNCTION: if(!used_swig_get) suf = "("; break; 00236 case LUA_TUSERDATA: 00237 if (lua_getmetatable(L, -1)) { lua_pop(L, 1); suf = ":."; } 00238 break; 00239 } 00240 luafaudes_rl_dmadd(mlist, std::string(text,dot), std::string(s), suf); 00241 } 00242 } 00243 used_swig_get = luafaudes_rl_getmeta(L,colon>0); 00244 } while (++loop < 20); 00245 00246 // Fix stack 00247 lua_settop(L, savetop); 00248 00249 // done 00250 return mlist; 00251 } 00252 libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |