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