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