blob: 2989ae95e86f03b94ff1d3d68f2a34cd4a8584ba [file] [log] [blame]
Chris Lattner92101ac2001-08-23 17:05:04 +00001//===-- UserInput.cpp - Interpreter Input Loop support --------------------===//
2//
3// This file implements the interpreter Input I/O loop.
4//
5//===----------------------------------------------------------------------===//
6
7#include "Interpreter.h"
Chris Lattner2e42d3a2001-10-15 05:51:48 +00008#include "llvm/Bytecode/Reader.h"
Chris Lattner92101ac2001-08-23 17:05:04 +00009#include "llvm/Assembly/Writer.h"
Chris Lattnerf8f2afb2001-10-18 21:55:32 +000010#include "llvm/DerivedTypes.h"
Chris Lattnere43db882001-10-27 04:15:57 +000011#include "llvm/Transforms/Linker.h"
Chris Lattner92101ac2001-08-23 17:05:04 +000012#include <algorithm>
13
14enum CommandID {
Chris Lattner86660982001-08-27 05:16:50 +000015 Quit, Help, // Basics
16 Print, Info, List, StackTrace, Up, Down, // Inspection
17 Next, Step, Run, Finish, Call, // Control flow changes
18 Break, Watch, // Debugging
Chris Lattner92101ac2001-08-23 17:05:04 +000019 Load, Flush
20};
21
22// CommandTable - Build a lookup table for the commands available to the user...
23static struct CommandTableElement {
24 const char *Name;
25 enum CommandID CID;
26
27 inline bool operator<(const CommandTableElement &E) const {
28 return string(Name) < string(E.Name);
29 }
30 inline bool operator==(const string &S) const {
31 return string(Name) == S;
32 }
33} CommandTable[] = {
34 { "quit" , Quit }, { "q", Quit }, { "", Quit }, // Empty str = eof
35 { "help" , Help }, { "h", Help },
36
37 { "print" , Print }, { "p", Print },
38 { "list" , List },
Chris Lattner86660982001-08-27 05:16:50 +000039 { "info" , Info },
Chris Lattner92101ac2001-08-23 17:05:04 +000040 { "backtrace", StackTrace }, { "bt", StackTrace }, { "where", StackTrace },
41 { "up" , Up },
42 { "down" , Down },
43
44 { "next" , Next }, { "n", Next },
45 { "step" , Step }, { "s", Step },
46 { "run" , Run },
47 { "finish" , Finish },
48 { "call" , Call },
49
50 { "break" , Break }, { "b", Break },
51 { "watch" , Watch },
52
53 { "load" , Load },
54 { "flush" , Flush },
55};
56static CommandTableElement *CommandTableEnd =
57 CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]);
58
59
60//===----------------------------------------------------------------------===//
61// handleUserInput - Enter the input loop for the interpreter. This function
62// returns when the user quits the interpreter.
63//
64void Interpreter::handleUserInput() {
65 bool UserQuit = false;
66
67 // Sort the table...
68 sort(CommandTable, CommandTableEnd);
69
70 // Print the instruction that we are stopped at...
71 printCurrentInstruction();
72
73 do {
74 string Command;
75 cout << "lli> " << flush;
76 cin >> Command;
77
78 CommandTableElement *E = find(CommandTable, CommandTableEnd, Command);
79
80 if (E == CommandTableEnd) {
81 cout << "Error: '" << Command << "' not recognized!\n";
82 continue;
83 }
84
85 switch (E->CID) {
86 case Quit: UserQuit = true; break;
Chris Lattner2e42d3a2001-10-15 05:51:48 +000087 case Load:
88 cin >> Command;
89 loadModule(Command);
90 break;
91 case Flush: flushModule(); break;
Chris Lattner92101ac2001-08-23 17:05:04 +000092 case Print:
93 cin >> Command;
Chris Lattner2e42d3a2001-10-15 05:51:48 +000094 print(Command);
Chris Lattner92101ac2001-08-23 17:05:04 +000095 break;
Chris Lattner86660982001-08-27 05:16:50 +000096 case Info:
97 cin >> Command;
98 infoValue(Command);
99 break;
100
Chris Lattner92101ac2001-08-23 17:05:04 +0000101 case List: list(); break;
102 case StackTrace: printStackTrace(); break;
103 case Up:
104 if (CurFrame > 0) --CurFrame;
105 else cout << "Error: Already at root of stack!\n";
106 break;
107 case Down:
108 if ((unsigned)CurFrame < ECStack.size()-1) ++CurFrame;
109 else cout << "Error: Already at bottom of stack!\n";
110 break;
111 case Next: nextInstruction(); break;
112 case Step: stepInstruction(); break;
113 case Run: run(); break;
114 case Finish: finish(); break;
115 case Call:
116 cin >> Command;
117 callMethod(Command); // Enter the specified method
118 finish(); // Run until it's complete
119 break;
120
121 default:
122 cout << "Command '" << Command << "' unimplemented!\n";
123 break;
124 }
125
126 } while (!UserQuit);
127}
128
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000129//===----------------------------------------------------------------------===//
130// loadModule - Load a new module to execute...
131//
132void Interpreter::loadModule(const string &Filename) {
Chris Lattnere43db882001-10-27 04:15:57 +0000133 string ErrorMsg;
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000134 if (CurMod && !flushModule()) return; // Kill current execution
135
Chris Lattnere43db882001-10-27 04:15:57 +0000136 CurMod = ParseBytecodeFile(Filename, &ErrorMsg);
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000137 if (CurMod == 0) {
Chris Lattnere43db882001-10-27 04:15:57 +0000138 cout << "Error parsing '" << Filename << "': No module loaded: "
139 << ErrorMsg << "\n";
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000140 return;
141 }
142
Chris Lattnere43db882001-10-27 04:15:57 +0000143 string RuntimeLib = getCurrentExecutablePath() + "/RuntimeLib.bc";
144 if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) {
145 if (LinkModules(CurMod, SupportLib, &ErrorMsg))
146 cerr << "Error Linking runtime library into current module: "
147 << ErrorMsg << endl;
148 } else {
149 cerr << "Error loading runtime library '"+RuntimeLib+"': "
150 << ErrorMsg << "\n";
151 }
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000152}
153
154
155//===----------------------------------------------------------------------===//
156// flushModule - Return true if the current program has been unloaded.
157//
158bool Interpreter::flushModule() {
159 if (CurMod == 0) {
160 cout << "Error flushing: No module loaded!\n";
161 return false;
162 }
163
164 if (!ECStack.empty()) {
165 // TODO: if use is not sure, return false
166 cout << "Killing current execution!\n";
167 ECStack.clear();
168 CurFrame = -1;
169 }
170
171 delete CurMod;
172 CurMod = 0;
173 ExitCode = 0;
174 return true;
175}
Chris Lattner92101ac2001-08-23 17:05:04 +0000176
177//===----------------------------------------------------------------------===//
178// setBreakpoint - Enable a breakpoint at the specified location
179//
180void Interpreter::setBreakpoint(const string &Name) {
181 Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name));
182 // TODO: Set a breakpoint on PickedVal
183}
184
185//===----------------------------------------------------------------------===//
186// callMethod - Enter the specified method...
187//
188bool Interpreter::callMethod(const string &Name) {
189 vector<Value*> Options = LookupMatchingNames(Name);
190
191 for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches...
Chris Lattner1d87bcf2001-10-01 20:11:19 +0000192 if (!isa<Method>(Options[i])) {
Chris Lattner92101ac2001-08-23 17:05:04 +0000193 Options.erase(Options.begin()+i);
194 --i;
195 }
196 }
197
198 Value *PickedMeth = ChooseOneOption(Name, Options);
199 if (PickedMeth == 0)
200 return true;
201
Chris Lattner9636a912001-10-01 16:18:37 +0000202 Method *M = cast<Method>(PickedMeth);
Chris Lattner365a76e2001-09-10 04:49:44 +0000203
204 vector<GenericValue> Args;
205 // TODO, get args from user...
206
207 callMethod(M, Args); // Start executing it...
Chris Lattner92101ac2001-08-23 17:05:04 +0000208
209 // Reset the current frame location to the top of stack
210 CurFrame = ECStack.size()-1;
211
212 return false;
213}
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000214
215
216// callMainMethod - This is a nasty gross hack that will dissapear when
217// callMethod can parse command line options and stuff for us.
218//
219bool Interpreter::callMainMethod(const string &Name,
220 const string &InputFilename) {
221 vector<Value*> Options = LookupMatchingNames(Name);
222
223 for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches...
224 if (!isa<Method>(Options[i])) {
225 Options.erase(Options.begin()+i);
226 --i;
227 }
228 }
229
230 Value *PickedMeth = ChooseOneOption(Name, Options);
231 if (PickedMeth == 0)
232 return true;
233
234 Method *M = cast<Method>(PickedMeth);
235 const MethodType *MT = M->getMethodType();
236
237 vector<GenericValue> Args;
238 switch (MT->getParamTypes().size()) {
239 default:
240 cout << "Unknown number of arguments to synthesize for '" << Name << "'!\n";
241 return true;
242 case 2: {
243 PointerType *SPP = PointerType::get(PointerType::get(Type::SByteTy));
244 if (MT->getParamTypes()[1] != SPP) {
245 cout << "Second argument of '" << Name << "' should have type: '"
246 << SPP->getDescription() << "'!\n";
247 return true;
248 }
249 // TODO:
250 GenericValue GV; GV.PointerVal = 0;
251 Args.push_back(GV);
252 }
253 // fallthrough
254 case 1:
255 if (!MT->getParamTypes()[0]->isIntegral()) {
256 cout << "First argument of '" << Name << "' should be integral!\n";
257 return true;
258 } else {
259 GenericValue GV; GV.IntVal = 1;
260 Args.insert(Args.begin(), GV);
261 }
262 // fallthrough
263 case 0:
264 break;
265 }
266
267 callMethod(M, Args); // Start executing it...
268
269 // Reset the current frame location to the top of stack
270 CurFrame = ECStack.size()-1;
271
272 return false;
273}