lbp_completion.cpp

Go 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