Method.pm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package Logos::Generator::internal::Method;
  2. use strict;
  3. use parent qw(Logos::Generator::Base::Method);
  4. sub superFunctionName {
  5. my $self = shift;
  6. my $method = shift;
  7. return Logos::sigil(($method->scope eq "+" ? "meta_" : "")."super").$method->groupIdentifier."\$".$method->class->name."\$".$method->_new_selector;
  8. }
  9. sub originalCallParams {
  10. my $self = shift;
  11. my $method = shift;
  12. my $customargs = shift;
  13. return "" if $method->isNew;
  14. my $build = "(self, _cmd";
  15. if(defined $customargs && $customargs ne "") {
  16. $build .= ", ".$customargs;
  17. } elsif($method->numArgs > 0) {
  18. $build .= ", ".join(", ",@{$method->argnames});
  19. }
  20. $build .= ")";
  21. return $build;
  22. }
  23. sub definition {
  24. my $self = shift;
  25. my $method = shift;
  26. my $build = "";
  27. my $selftype = $self->selfTypeForMethod($method);
  28. my $classref = "";
  29. my $cgen = Logos::Generator::for($method->class);
  30. if($method->scope eq "+") {
  31. $classref = $cgen->superMetaVariable;
  32. } else {
  33. $classref = $cgen->superVariable;
  34. }
  35. my $arglist = "";
  36. map $arglist .= ", ".Logos::Method::declarationForTypeWithName($method->argtypes->[$_], $method->argnames->[$_]), (0..$method->numArgs - 1);
  37. my $parameters = "(".$selftype." self, SEL _cmd".$arglist.")";
  38. my $return = $self->returnTypeForMethod($method);
  39. my $functionAttributes = $self->functionAttributesForMethod($method);
  40. if(!$method->isNew) {
  41. my $argtypelist = join(", ", @{$method->argtypes});
  42. $build .= "static ".Logos::Method::declarationForTypeWithName($return, $self->superFunctionName($method).$parameters).$functionAttributes." {";
  43. my $pointerType = "(*)(".$selftype.", SEL";
  44. $pointerType .= ", ".$argtypelist if $argtypelist;
  45. $pointerType .= ")";
  46. $build .= "return ((".$functionAttributes." ".Logos::Method::declarationForTypeWithName($return, $pointerType).")class_getMethodImplementation(".$classref.",".$self->selectorRef($method->selector)."))";
  47. $build .= $self->originalCallParams($method).";";
  48. $build .= "}";
  49. }
  50. $build .= "static ".Logos::Method::declarationForTypeWithName($return, $self->newFunctionName($method).$parameters).$functionAttributes;
  51. return $build;
  52. }
  53. sub originalCall {
  54. my $self = shift;
  55. my $method = shift;
  56. my $customargs = shift;
  57. return $self->originalFunctionName($method).$self->originalCallParams($method, $customargs);
  58. }
  59. sub declarations {
  60. my $self = shift;
  61. my $method = shift;
  62. my $build = "";
  63. if(!$method->isNew) {
  64. my $selftype = $self->selfTypeForMethod($method);
  65. my $functionAttributes = $self->functionAttributesForMethod($method);
  66. $build .= "static ";
  67. my $name = "";
  68. $name .= $functionAttributes."(*".$self->originalFunctionName($method).")(".$selftype.", SEL";
  69. my $argtypelist = join(", ", @{$method->argtypes});
  70. $name .= ", ".$argtypelist if $argtypelist;
  71. $name .= ")";
  72. $build .= Logos::Method::declarationForTypeWithName($self->returnTypeForMethod($method), $name);
  73. $build .= ";";
  74. }
  75. return $build;
  76. }
  77. sub initializers {
  78. my $self = shift;
  79. my $method = shift;
  80. my $cgen = Logos::Generator::for($method->class);
  81. my $classvar = ($method->scope eq "+" ? $cgen->metaVariable : $cgen->variable);
  82. my $r = "{ ";
  83. if(!$method->isNew) {
  84. my $classargtype = "";
  85. if($method->scope eq "+") {
  86. $classargtype = "Class";
  87. } else {
  88. $classargtype = $method->class->type;
  89. }
  90. $r .= "Class _class = ".$classvar.";";
  91. $r .= "Method _method = class_getInstanceMethod(_class, ".$self->selectorRef($method->selector)."));";
  92. $r .= "if (_class) {";
  93. $r .= "if (_method) {";
  94. $r .= $self->originalFunctionName($method)." = ".$self->superFunctionName($method).";";
  95. $r .= "if (!class_addMethod(_class, ".$self->selectorRef($method->selector)."), (IMP)&".$self->newFunctionName($method).", method_getTypeEncoding(_method))) {";
  96. $r .= $self->originalFunctionName($method)." = (".$pointertype.")method_getImplementation(_method);";
  97. $r .= $self->originalFunctionName($method)." = (".$pointertype.")method_setImplementation(_method, (IMP)&".$self->newFunctionName($method).");";
  98. $r .= "}";
  99. $r .= "} else {";
  100. $r .= "HBLogError(@\"logos: message not found [%s %s]\", \"".$method->class->name."\", \"".$method->selector."\");";
  101. $r .= "}";
  102. $r .= "} else {";
  103. $r .= "HBLogError(@\"logos: nil class %s\", \"".$method->class->name."\");";
  104. $r .= "}";
  105. } else {
  106. if(!$method->type) {
  107. $r .= "char _typeEncoding[1024]; unsigned int i = 0; ";
  108. for ($method->return, "id", "SEL", @{$method->argtypes}) {
  109. my $typeEncoding = Logos::Method::typeEncodingForArgType($_);
  110. if(defined $typeEncoding) {
  111. my @typeEncodingBits = split(//, $typeEncoding);
  112. my $i = 0;
  113. for my $char (@typeEncodingBits) {
  114. $r .= "_typeEncoding[i".($i > 0 ? " + $i" : "")."] = '$char'; ";
  115. $i++;
  116. }
  117. $r .= "i += ".(scalar @typeEncodingBits)."; ";
  118. } else {
  119. $r .= "memcpy(_typeEncoding + i, \@encode($_), strlen(\@encode($_))); i += strlen(\@encode($_)); ";
  120. }
  121. }
  122. $r .= "_typeEncoding[i] = '\\0'; ";
  123. } else {
  124. $r .= "const char *_typeEncoding = \"".$method->type."\"; ";
  125. }
  126. $r .= "class_addMethod(".$classvar.", ".$self->selectorRef($method->selector).", (IMP)&".$self->newFunctionName($method).", _typeEncoding); ";
  127. }
  128. $r .= "}";
  129. return $r;
  130. }
  131. 1;