]>
git.saurik.com Git - cycript.git/blob - Complete.cpp
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
;