]> git.saurik.com Git - cycript.git/blob - Output.cpp
Implemented ivar access, added some general runtime reflection hierarchy, changed...
[cycript.git] / Output.cpp
1 #include "Parser.hpp"
2
3 #include <iostream>
4 #include <iomanip>
5
6 #include <objc/runtime.h>
7 #include <sstream>
8
9 _finline CYFlags operator ~(CYFlags rhs) {
10 return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
11 }
12
13 _finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
14 return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
15 }
16
17 _finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
18 return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
19 }
20
21 _finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
22 return lhs = lhs | rhs;
23 }
24
25 _finline CYFlags CYLeft(CYFlags flags) {
26 return flags & ~CYNoTrailer;
27 }
28
29 _finline CYFlags CYCenter(CYFlags flags) {
30 return flags & CYNoIn;
31 }
32
33 _finline CYFlags CYRight(CYFlags flags) {
34 return flags & (CYNoIn | CYNoTrailer);
35 }
36
37 bool CYFalse::Value() const {
38 return false;
39 }
40
41 bool CYTrue::Value() const {
42 return true;
43 }
44
45 #define CYPA 16
46
47 void CYAddressOf::Output(std::ostream &out, CYFlags flags) const {
48 rhs_->Output(out, 1, CYLeft(flags));
49 out << ".addressOf()";
50 }
51
52 void CYArgument::Output(std::ostream &out) const {
53 if (name_ != NULL) {
54 out << *name_;
55 if (value_ != NULL)
56 out << ":";
57 }
58 if (value_ != NULL)
59 value_->Output(out, CYPA, CYNoFlags);
60 if (next_ != NULL) {
61 if (next_->name_ == NULL)
62 out << ',';
63 else
64 out << ' ';
65 next_->Output(out);
66 }
67 }
68
69 void CYArray::Output(std::ostream &out, CYFlags flags) const {
70 out << '[';
71 if (elements_ != NULL)
72 elements_->Output(out);
73 out << ']';
74 }
75
76 void CYAssignment::Output(std::ostream &out, CYFlags flags) const {
77 lhs_->Output(out, Precedence() - 1, CYLeft(flags));
78 out << Operator();
79 rhs_->Output(out, Precedence(), CYRight(flags));
80 }
81
82 void CYBoolean::Output(std::ostream &out, CYFlags flags) const {
83 if ((flags & CYNoLeader) != 0)
84 out << ' ';
85 out << (Value() ? "true" : "false");
86 if ((flags & CYNoTrailer) != 0)
87 out << ' ';
88 }
89
90 void CYBreak::Output(std::ostream &out) const {
91 out << "break";
92 if (label_ != NULL)
93 out << ' ' << *label_;
94 out << ';';
95 }
96
97 void CYCall::Output(std::ostream &out, CYFlags flags) const {
98 function_->Output(out, Precedence(), CYLeft(flags));
99 out << '(';
100 if (arguments_ != NULL)
101 arguments_->Output(out);
102 out << ')';
103 }
104
105 void CYCatch::Output(std::ostream &out) const {
106 out << "catch(" << *name_ << ')';
107 code_->Output(out, true);
108 }
109
110 void CYCategory::Output(std::ostream &out) const {
111 out << "(function($cys,$cyp,$cyc,$cyn,$cyt){";
112 out << "$cyp=object_getClass($cys);";
113 out << "$cyc=$cys;";
114 if (messages_ != NULL)
115 messages_->Output(out, true);
116 out << "})(";
117 name_->ClassName(out);
118 out << ");";
119 }
120
121 void CYClass::Output(std::ostream &out) const {
122 out << "(function($cys,$cyp,$cyc,$cyn,$cyt,$cym){";
123 out << "$cyp=object_getClass($cys);";
124 out << "$cyc=objc_allocateClassPair($cys,\"" << *name_ << "\",0);";
125 out << "$cym=object_getClass($cyc);";
126 if (fields_ != NULL)
127 fields_->Output(out);
128 if (messages_ != NULL)
129 messages_->Output(out, false);
130 out << "objc_registerClassPair($cyc);";
131 out << "})(";
132 if (super_ != NULL)
133 super_->Output(out, CYPA, CYNoFlags);
134 else
135 out << "null";
136 out << ");";
137 }
138
139 void CYCompound::Output(std::ostream &out, CYFlags flags) const {
140 if (CYExpression *expression = expressions_)
141 if (CYExpression *next = expression->next_) {
142 expression->Output(out, CYLeft(flags));
143 CYFlags center(CYCenter(flags));
144 while (next != NULL) {
145 expression = next;
146 out << ',';
147 next = expression->next_;
148 CYFlags right(next != NULL ? center : CYRight(flags));
149 expression->Output(out, right);
150 }
151 } else
152 expression->Output(out, flags);
153 }
154
155 void CYCondition::Output(std::ostream &out, CYFlags flags) const {
156 test_->Output(out, Precedence() - 1, CYLeft(flags));
157 out << '?';
158 if (true_ != NULL)
159 true_->Output(out, CYPA, CYNoFlags);
160 out << ':';
161 false_->Output(out, CYPA, CYRight(flags));
162 }
163
164 void CYContinue::Output(std::ostream &out) const {
165 out << "continue";
166 if (label_ != NULL)
167 out << ' ' << *label_;
168 out << ';';
169 }
170
171 void CYClause::Output(std::ostream &out) const {
172 if (case_ != NULL) {
173 out << "case";
174 case_->Output(out, CYNoFlags);
175 } else
176 out << "default";
177 out << ':';
178 if (code_ != NULL)
179 code_->Output(out, false);
180 out << *next_;
181 }
182
183 // XXX: deal with NoIn
184 void CYDeclaration::Part(std::ostream &out) const {
185 out << "var ";
186 Output(out);
187 }
188
189 void CYDeclaration::Output(std::ostream &out) const {
190 out << *identifier_;
191 if (initialiser_ != NULL) {
192 out << '=';
193 initialiser_->Output(out, CYPA, CYNoFlags);
194 }
195 }
196
197 // XXX: deal with NoIn
198 void CYDeclarations::Part(std::ostream &out) const {
199 out << "var ";
200
201 const CYDeclarations *declaration(this);
202 output:
203 out << *declaration->declaration_;
204 declaration = declaration->next_;
205
206 if (declaration != NULL) {
207 out << ',';
208 goto output;
209 }
210 }
211
212 void CYDeclarations::Output(std::ostream &out) const {
213 Part(out);
214 out << ';';
215 }
216
217 void CYDoWhile::Output(std::ostream &out) const {
218 // XXX: extra space character!
219 out << "do ";
220 code_->Output(out, false);
221 out << "while(";
222 test_->Output(out, CYNoFlags);
223 out << ')';
224 }
225
226 void CYElement::Output(std::ostream &out) const {
227 if (value_ != NULL)
228 value_->Output(out, CYPA, CYNoFlags);
229 if (next_ != NULL || value_ == NULL)
230 out << ',';
231 if (next_ != NULL)
232 next_->Output(out);
233 }
234
235 void CYEmpty::Output(std::ostream &out) const {
236 out << ';';
237 }
238
239 void CYEmpty::Output(std::ostream &out, bool block) const {
240 if (next_ != NULL)
241 CYSource::Output(out, block);
242 else
243 out << "{}";
244 }
245
246 void CYExpress::Output(std::ostream &out) const {
247 expression_->Output(out, CYNoFunction | CYNoBrace);
248 out << ';';
249 }
250
251 void CYExpression::ClassName(std::ostream &out) const {
252 Output(out, CYPA, CYNoFlags);
253 }
254
255 void CYExpression::Part(std::ostream &out) const {
256 // XXX: this should handle LeftHandSideExpression
257 Output(out, CYNoIn);
258 }
259
260 void CYExpression::Output(std::ostream &out, unsigned precedence, CYFlags flags) const {
261 if (precedence < Precedence()) {
262 out << '(';
263 Output(out, CYNoFlags);
264 out << ')';
265 } else
266 Output(out, flags);
267 }
268
269 void CYField::Output(std::ostream &out) const {
270 // XXX: implement!
271 }
272
273 void CYFor::Output(std::ostream &out) const {
274 out << "for(";
275 if (initialiser_ != NULL)
276 initialiser_->Part(out);
277 out << ';';
278 if (test_ != NULL)
279 test_->Output(out, CYNoFlags);
280 out << ';';
281 if (increment_ != NULL)
282 increment_->Output(out, CYNoFlags);
283 out << ')';
284 code_->Output(out, false);
285 }
286
287 void CYForIn::Output(std::ostream &out) const {
288 out << "for(";
289 initialiser_->Part(out);
290 // XXX: deal with this space character!
291 out << ' ';
292 out << "in";
293 set_->Output(out, CYNoLeader);
294 out << ')';
295 code_->Output(out, false);
296 }
297
298 void CYFunction::Output(std::ostream &out) const {
299 CYLambda::Output(out, CYNoFlags);
300 }
301
302 void CYFunctionParameter::Output(std::ostream &out) const {
303 out << *name_;
304 if (next_ != NULL) {
305 out << ',';
306 out << *next_;
307 }
308 }
309
310 void CYIf::Output(std::ostream &out) const {
311 out << "if(";
312 test_->Output(out, CYNoFlags);
313 out << ')';
314 true_->Output(out, true);
315 if (false_ != NULL) {
316 out << "else ";
317 false_->Output(out, false);
318 }
319 }
320
321 void CYIndirect::Output(std::ostream &out, CYFlags flags) const {
322 rhs_->Output(out, 1, CYLeft(flags));
323 out << "[0]";
324 }
325
326 void CYInfix::Output(std::ostream &out, CYFlags flags) const {
327 const char *name(Operator());
328 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in"));
329 if (protect)
330 out << '(';
331 bool alphabetic(Alphabetic());
332 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
333 if (alphabetic)
334 left |= CYNoTrailer;
335 lhs_->Output(out, Precedence(), left);
336 out << name;
337 CYFlags right(protect ? CYNoFlags : CYRight(flags));
338 if (alphabetic)
339 right |= CYNoLeader;
340 rhs_->Output(out, Precedence() - 1, right);
341 if (protect)
342 out << ')';
343 }
344
345 void CYLambda::Output(std::ostream &out, CYFlags flags) const {
346 bool protect((flags & CYNoFunction) != 0);
347 if (protect)
348 out << '(';
349 out << "function";
350 if (name_ != NULL)
351 out << ' ' << *name_;
352 out << '(';
353 if (parameters_ != NULL)
354 out << *parameters_;
355 out << "){";
356 if (body_ != NULL)
357 body_->Show(out);
358 out << '}';
359 if (protect)
360 out << ')';
361 }
362
363 void CYMember::Output(std::ostream &out, CYFlags flags) const {
364 object_->Output(out, Precedence(), CYLeft(flags));
365 if (const char *word = property_->Word())
366 out << '.' << word;
367 else {
368 out << '[';
369 property_->Output(out, CYNoFlags);
370 out << ']';
371 }
372 }
373
374 void CYMessage::Output(std::ostream &out, bool replace) const {
375 if (next_ != NULL)
376 next_->Output(out, replace);
377 out << "$cyn=new Selector(\"";
378 for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
379 if (parameter->tag_ != NULL) {
380 out << *parameter->tag_;
381 if (parameter->name_ != NULL)
382 out << ':';
383 }
384 out << "\");";
385 out << "$cyt=$cyn.type($cy" << (instance_ ? 's' : 'p') << ");";
386 out << "class_" << (replace ? "replace" : "add") << "Method($cy" << (instance_ ? 'c' : 'm') << ",$cyn,";
387 out << "new Functor(function(self,_cmd";
388 for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
389 if (parameter->name_ != NULL)
390 out << ',' << *parameter->name_;
391 out << "){return function(){";
392 if (body_ != NULL)
393 body_->Show(out);
394 out << "}.call(self);},$cyt),$cyt);";
395 }
396
397 void CYNew::Output(std::ostream &out, CYFlags flags) const {
398 if ((flags & CYNoLeader) != 0)
399 out << ' ';
400 out << "new";
401 constructor_->Output(out, Precedence(), CYCenter(flags) | CYNoLeader);
402 out << '(';
403 if (arguments_ != NULL)
404 arguments_->Output(out);
405 out << ')';
406 }
407
408 void CYNull::Output(std::ostream &out, CYFlags flags) const {
409 if ((flags & CYNoLeader) != 0)
410 out << ' ';
411 CYWord::Output(out);
412 if ((flags & CYNoTrailer) != 0)
413 out << ' ';
414 }
415
416 void CYNumber::Output(std::ostream &out, CYFlags flags) const {
417 if ((flags & CYNoLeader) != 0)
418 out << ' ';
419 // XXX: decide on correct precision
420 out << std::setprecision(9) << Value();
421 if ((flags & CYNoTrailer) != 0)
422 out << ' ';
423 }
424
425 void CYNumber::PropertyName(std::ostream &out) const {
426 Output(out);
427 }
428
429 void CYObject::Output(std::ostream &out, CYFlags flags) const {
430 bool protect((flags & CYNoBrace) != 0);
431 if (protect)
432 out << '(';
433 out << '{';
434 if (property_ != NULL)
435 property_->Output(out);
436 out << '}';
437 if (protect)
438 out << ')';
439 }
440
441 void CYPostfix::Output(std::ostream &out, CYFlags flags) const {
442 lhs_->Output(out, Precedence(), CYLeft(flags));
443 out << Operator();
444 }
445
446 void CYPrefix::Output(std::ostream &out, CYFlags flags) const {
447 bool alphabetic(Alphabetic());
448 out << Operator();
449 CYFlags right(CYRight(flags));
450 if (alphabetic)
451 right |= CYNoLeader;
452 rhs_->Output(out, Precedence(), right);
453 }
454
455 void CYProperty::Output(std::ostream &out) const {
456 name_->PropertyName(out);
457 out << ':';
458 value_->Output(out, CYPA, CYNoFlags);
459 if (next_ != NULL) {
460 out << ',';
461 next_->Output(out);
462 }
463 }
464
465 void CYReturn::Output(std::ostream &out) const {
466 out << "return";
467 if (value_ != NULL)
468 value_->Output(out, CYNoLeader);
469 out << ';';
470 }
471
472 void CYSelector::Output(std::ostream &out, CYFlags flags) const {
473 if ((flags & CYNoLeader) != 0)
474 out << ' ';
475 out << "new Selector(\"";
476 if (name_ != NULL)
477 name_->Output(out);
478 out << "\")";
479 }
480
481 void CYSelectorPart::Output(std::ostream &out) const {
482 if (name_ != NULL)
483 out << *name_;
484 if (value_)
485 out << ':';
486 if (next_ != NULL)
487 next_->Output(out);
488 }
489
490 void CYSend::Output(std::ostream &out, CYFlags flags) const {
491 if ((flags & CYNoLeader) != 0)
492 out << ' ';
493 out << "objc_msgSend(";
494 self_->Output(out, CYPA, CYNoFlags);
495 out << ",";
496 std::ostringstream name;
497 for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
498 if (argument->name_ != NULL) {
499 name << *argument->name_;
500 if (argument->value_ != NULL)
501 name << ':';
502 }
503 out << reinterpret_cast<void *>(sel_registerName(name.str().c_str()));
504 for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
505 if (argument->value_ != NULL) {
506 out << ",";
507 argument->value_->Output(out, CYPA, CYNoFlags);
508 }
509 out << ')';
510 }
511
512 void CYSource::Show(std::ostream &out) const {
513 for (const CYSource *next(this); next != NULL; next = next->next_)
514 next->Output(out);
515 }
516
517 void CYSource::Output(std::ostream &out, bool block) const {
518 if (!block && next_ == NULL)
519 Output(out);
520 else {
521 out << '{';
522 Show(out);
523 out << '}';
524 }
525 }
526
527 void CYString::Output(std::ostream &out, CYFlags flags) const {
528 unsigned quot(0), apos(0);
529 for (const char *value(value_), *end(value_ + size_); value != end; ++value)
530 if (*value == '"')
531 ++quot;
532 else if (*value == '\'')
533 ++apos;
534
535 bool single(quot > apos);
536
537 out << (single ? '\'' : '"');
538 for (const char *value(value_), *end(value_ + size_); value != end; ++value)
539 switch (*value) {
540 case '\\': out << "\\\\"; break;
541 case '\b': out << "\\b"; break;
542 case '\f': out << "\\f"; break;
543 case '\n': out << "\\n"; break;
544 case '\r': out << "\\r"; break;
545 case '\t': out << "\\t"; break;
546 case '\v': out << "\\v"; break;
547
548 case '"':
549 if (!single)
550 out << "\\\"";
551 else goto simple;
552 break;
553
554 case '\'':
555 if (single)
556 out << "\\'";
557 else goto simple;
558 break;
559
560 default:
561 if (*value < 0x20 || *value >= 0x7f)
562 out << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value);
563 else simple:
564 out << *value;
565 }
566 out << (single ? '\'' : '"');
567 }
568
569 void CYString::PropertyName(std::ostream &out) const {
570 if (const char *word = Word())
571 out << word;
572 else
573 Output(out);
574 }
575
576 void CYSwitch::Output(std::ostream &out) const {
577 out << "switch(";
578 value_->Output(out, CYNoFlags);
579 out << "){";
580 if (clauses_ != NULL)
581 out << *clauses_;
582 out << '}';
583 }
584
585 void CYThis::Output(std::ostream &out, CYFlags flags) const {
586 if ((flags & CYNoLeader) != 0)
587 out << ' ';
588 CYWord::Output(out);
589 if ((flags & CYNoTrailer) != 0)
590 out << ' ';
591 }
592
593 void CYThrow::Output(std::ostream &out) const {
594 out << "throw";
595 if (value_ != NULL)
596 value_->Output(out, CYNoLeader);
597 out << ';';
598 }
599
600 void CYTry::Output(std::ostream &out) const {
601 out << "try";
602 try_->Output(out, true);
603 if (catch_ != NULL)
604 out << catch_;
605 if (finally_ != NULL) {
606 out << "finally";
607 finally_->Output(out, true);
608 }
609 }
610
611 void CYVariable::Output(std::ostream &out, CYFlags flags) const {
612 if ((flags & CYNoLeader) != 0)
613 out << ' ';
614 out << *name_;
615 if ((flags & CYNoTrailer) != 0)
616 out << ' ';
617 }
618
619 void CYWhile::Output(std::ostream &out) const {
620 out << "while(";
621 test_->Output(out, CYNoFlags);
622 out << ')';
623 code_->Output(out, false);
624 }
625
626 void CYWith::Output(std::ostream &out) const {
627 out << "with(";
628 scope_->Output(out, CYNoFlags);
629 out << ')';
630 code_->Output(out, false);
631 }
632
633 void CYWord::ClassName(std::ostream &out) const {
634 out << "objc_getClass(\"" << Value() << "\")";
635 }
636
637 void CYWord::Output(std::ostream &out) const {
638 out << Value();
639 }
640
641 void CYWord::PropertyName(std::ostream &out) const {
642 Output(out);
643 }