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