]>
git.saurik.com Git - cycript.git/blob - Complete.cpp
75b80c0c542d007f1435078364c8c1c72ffbb921
   1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2015  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   7  * This program is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU Affero General Public License as published by 
   9  * the Free Software Foundation, either version 3 of the License, or 
  10  * (at your option) any later version. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  17  * You should have received a copy of the GNU Affero General Public License 
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  22 #include "cycript.hpp" 
  25 #include "Cycript.tab.hh" 
  26 #include "Replace.hpp" 
  29 static CYExpression 
*ParseExpression(CYPool 
&pool
, CYUTF8String code
) { 
  30     std::stringstream stream
; 
  31     stream 
<< '(' << code 
<< ')'; 
  32     CYDriver 
driver(pool
, stream
); 
  34     cy::parser 
parser(driver
); 
  35     if (parser
.parse() != 0 || !driver
.errors_
.empty()) 
  39     CYContext 
context(options
); 
  41     CYStatement 
*statement(driver
.program_
->code_
); 
  42     _assert(statement 
!= NULL
); 
  43     _assert(statement
->next_ 
== NULL
); 
  45     CYExpress 
*express(dynamic_cast<CYExpress 
*>(driver
.program_
->code_
)); 
  46     _assert(express 
!= NULL
); 
  48     CYParenthetical 
*parenthetical(dynamic_cast<CYParenthetical 
*>(express
->expression_
)); 
  49     _assert(parenthetical 
!= NULL
); 
  51     return parenthetical
->expression_
; 
  54 _visible 
char **CYComplete(const char *word
, const std::string 
&line
, CYUTF8String (*run
)(CYPool 
&pool
, const std::string 
&)) { 
  57     std::istringstream 
stream(line
); 
  58     CYDriver 
driver(pool
, stream
); 
  62     cy::parser 
parser(driver
); 
  63     if (parser
.parse() != 0 || !driver
.errors_
.empty()) 
  66     if (driver
.mode_ 
== CYDriver::AutoNone
) 
  69     CYExpression 
*expression
; 
  72     CYContext 
context(options
); 
  74     std::ostringstream prefix
; 
  76     switch (driver
.mode_
) { 
  77         case CYDriver::AutoPrimary
: 
  78             expression 
= $ 
CYThis(); 
  81         case CYDriver::AutoDirect
: 
  82             expression 
= driver
.context_
; 
  85         case CYDriver::AutoIndirect
: 
  86             expression 
= $ 
CYIndirect(driver
.context_
); 
  89         case CYDriver::AutoMessage
: { 
  90             CYDriver::Context 
&thing(driver
.contexts_
.back()); 
  91             expression 
= $
M($
C1($
V("object_getClass"), thing
.context_
), $
S("messages")); 
  92             for (CYDriver::Context::Words::const_iterator 
part(thing
.words_
.begin()); part 
!= thing
.words_
.end(); ++part
) 
  93                 prefix 
<< (*part
)->word_ 
<< ':'; 
 100     std::string 
begin(prefix
.str()); 
 102     driver
.program_ 
= $ 
CYProgram($ 
CYExpress($
C3(ParseExpression(pool
, 
 103     "   function(object, prefix, word) {\n" 
 105     "       var before = prefix.length;\n" 
 107     "       var entire = prefix.length;\n" 
 108     "       for (var name in object)\n" 
 109     "           if (name.substring(0, entire) == prefix)\n" 
 110     "               names.push(name.substr(before));\n" 
 113     ), expression
, $
S(begin
.c_str()), $
S(word
)))); 
 115     driver
.program_
->Replace(context
); 
 118     CYOutput 
out(str
, options
); 
 119     out 
<< *driver
.program_
; 
 121     std::string 
code(str
.str()); 
 122     CYUTF8String 
json(run(pool
, code
)); 
 123     // XXX: if this fails we should not try to parse it 
 125     CYExpression 
*result(ParseExpression(pool
, json
)); 
 129     CYArray 
*array(dynamic_cast<CYArray 
*>(result
->Primitive(context
))); 
 133     // XXX: use an std::set? 
 134     typedef std::vector
<std::string
> Completions
; 
 135     Completions completions
; 
 140     CYForEach (element
, array
->elements_
) { 
 141         CYString 
*string(dynamic_cast<CYString 
*>(element
->value_
)); 
 142         _assert(string 
!= NULL
); 
 144         std::string completion
; 
 145         if (string
->size_ 
!= 0) 
 146             completion
.assign(string
->value_
, string
->size_
); 
 147         else if (driver
.mode_ 
== CYDriver::AutoMessage
) 
 152         completions
.push_back(completion
); 
 158             size_t limit(completion
.size()), size(common
.size()); 
 160                 common 
= common
.substr(0, limit
); 
 163             for (limit 
= 0; limit 
!= size
; ++limit
) 
 164                 if (common
[limit
] != completion
[limit
]) 
 167                 common 
= common
.substr(0, limit
); 
 171     size_t count(completions
.size()); 
 175     size_t colon(common
.find(':')); 
 176     if (colon 
!= std::string::npos
) 
 177         common 
= common
.substr(0, colon 
+ 1); 
 178     if (completions
.size() == 1) 
 181     char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count 
+ 2)))); 
 183     results
[0] = strdup(common
.c_str()); 
 185     for (Completions::const_iterator 
i(completions
.begin()); i 
!= completions
.end(); ++i
) 
 186         results
[++index
] = strdup(i
->c_str()); 
 187     results
[count 
+ 1] = NULL
;