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