Property.pm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package Logos::Generator::Base::Property;
  2. use strict;
  3. use Logos::Util;
  4. sub key {
  5. my $self = shift;
  6. my $property = shift;
  7. my $build = "_logos_property_key\$" . $property->group . "\$" . $property->class . "\$" . $property->name;
  8. return $build;
  9. }
  10. sub getter {
  11. my $self = shift;
  12. my $property = shift;
  13. my $name = shift;
  14. my $key = shift;
  15. my $type = $property->type;
  16. $type =~ s/\s+$//;
  17. if(!$name){
  18. # Use property name if no getter specified
  19. $name = $property->name;
  20. }
  21. # Build function start
  22. my $build = "static " . $type . " _logos_method\$" . $property->group . "\$" . $property->class . "\$" . $name . "\$" . "(" . $property->class . "* self, SEL _cmd){";
  23. # Build function body
  24. $build .= " return ";
  25. if ($type =~ /^(BOOL|(unsigned )?char|double|float|CGFloat|(unsigned )?int|NSInteger|unsigned|NSUInteger|(unsigned )?long (long)?|(unsigned )?short|NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
  26. $build .= "[";
  27. }
  28. $build .= "objc_getAssociatedObject(self, &" . $key . ")";
  29. if ($type eq "BOOL"){
  30. $build .= " boolValue]";
  31. } elsif ($type eq "char"){
  32. $build .= " charValue]";
  33. } elsif ($type eq "unsigned char"){
  34. $build .= " unsignedCharValue]";
  35. } elsif ($type eq "double"){
  36. $build .= " doubleValue]";
  37. } elsif ($type =~ /^(float|CGFloat)$/){
  38. $build .= " floatValue]";
  39. } elsif ($type eq "int"){
  40. $build .= " intValue]";
  41. } elsif ($type eq "NSInteger"){
  42. $build .= " integerValue]";
  43. } elsif ($type =~ /^unsigned( int)?$/){
  44. $build .= " unsignedIntValue]";
  45. } elsif ($type eq "NSUInteger"){
  46. $build .= " unsignedIntegerValue]";
  47. } elsif ($type eq "long"){
  48. $build .= " longValue]";
  49. } elsif ($type eq "unsigned long"){
  50. $build .= " unsignedLongValue]";
  51. } elsif ($type eq "long long"){
  52. $build .= " longLongValue]";
  53. } elsif ($type eq "unsigned long long"){
  54. $build .= " unsignedLongLongValue]";
  55. } elsif ($type eq "short"){
  56. $build .= " shortValue]";
  57. } elsif ($type eq "unsigned short"){
  58. $build .= " unsignedShortValue]";
  59. } elsif ($type =~ /^(NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
  60. $build .= " " . $type . "Value]";
  61. }
  62. $build .= "; }";
  63. return $build;
  64. }
  65. sub setter {
  66. my $self = shift;
  67. my $property = shift;
  68. my $name = shift;
  69. my $policy = shift;
  70. my $key = shift;
  71. my $type = $property->type;
  72. $type =~ s/\s+$//;
  73. if(!$name){
  74. # Capitalize first letter
  75. $_ = $property->name;
  76. $_ =~ s/^([a-z])/\u$1/;
  77. $name = "set" . $_;
  78. }
  79. # Remove semicolon
  80. $name =~ s/://;
  81. my $build = "static void _logos_method\$" . $property->group . "\$" . $property->class . "\$" . $name . "\$" . "(" . $property->class . "* self, SEL _cmd, " . $type . " arg){ ";
  82. $build .= "objc_setAssociatedObject(self, &" . $key . ", ";
  83. my $hasOpening = 1;
  84. if ($type eq "BOOL"){
  85. $build .= "[NSNumber numberWithBool:";
  86. } elsif ($type eq "char"){
  87. $build .= "[NSNumber numberWithChar:";
  88. } elsif ($type eq "unsigned char"){
  89. $build .= "[NSNumber numberWithUnsignedChar:";
  90. } elsif ($type eq "double"){
  91. $build .= "[NSNumber numberWithDouble:";
  92. } elsif ($type =~ /^(float|CGFloat)$/){
  93. $build .= "[NSNumber numberWithFloat:";
  94. } elsif ($type eq "int"){
  95. $build .= "[NSNumber numberWithInt:";
  96. } elsif ($type eq "NSInteger"){
  97. $build .= "[NSNumber numberWithInteger:";
  98. } elsif ($type =~ /^unsigned( int)?$/){
  99. $build .= "[NSNumber numberWithUnsignedInt:";
  100. } elsif ($type eq "NSUInteger"){
  101. $build .= "[NSNumber numberWithUnsignedInteger:";
  102. } elsif ($type eq "long"){
  103. $build .= "[NSNumber numberWithLong:";
  104. } elsif ($type eq "unsigned long"){
  105. $build .= "[NSNumber numberWithUnsignedLong:";
  106. } elsif ($type eq "long long"){
  107. $build .= "[NSNumber numberWithLongLong:";
  108. } elsif ($type eq "unsigned long long"){
  109. $build .= "[NSNumber numberWithUnsignedLongLong:";
  110. } elsif ($type eq "short"){
  111. $build .= "[NSNumber numberWithShort:";
  112. } elsif ($type eq "unsigned short"){
  113. $build .= "[NSNumber numberWithUnsignedShort:";
  114. } elsif ($type =~ /^(NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
  115. $build .= "[NSValue valueWith " . $type . ":";
  116. } else {
  117. $hasOpening = 0;
  118. }
  119. $build .= "arg";
  120. if ($hasOpening){
  121. $build .= "]";
  122. }
  123. $build .= ", ".$policy.")";
  124. $build .= "; }";
  125. return $build;
  126. }
  127. sub getters_setters {
  128. my $self = shift;
  129. my $property = shift;
  130. my ($assign, $retain, $nonatomic, $copy, $getter, $setter);
  131. for(my $i = 0; $i < $property->numattr; $i++){
  132. my $attr = $property->attributes->[$i];
  133. if($attr =~ /assign/){
  134. $assign = 1;
  135. }elsif($attr =~ /retain/){
  136. $retain = 1;
  137. }elsif($attr =~ /nonatomic/){
  138. $nonatomic = 1;
  139. }elsif($attr =~ /copy/){
  140. $copy = 1;
  141. }elsif($attr =~ /getter=(\w+)/){
  142. $getter = $1;
  143. }elsif($attr =~ /setter=(\w+:)/){
  144. $setter = $1;
  145. }
  146. }
  147. my $policy = "OBJC_ASSOCIATION_";
  148. if($retain){
  149. $policy .= "RETAIN";
  150. }elsif($copy){
  151. $policy .= "COPY";
  152. }elsif($assign){
  153. $policy .= "ASSIGN";
  154. }else{
  155. print "error: no 'assign', 'retain', or 'copy' attribu...wait, how did you manage to get here?\n";
  156. }
  157. if($nonatomic){
  158. # The 'assign' attribute appears to be nonatomic by default.
  159. if(!$assign){
  160. $policy .= "_NONATOMIC";
  161. }
  162. }
  163. $property->associationPolicy($policy);
  164. my $build;
  165. my $key = $self->key($property);
  166. my $getter_func = $self->getter($property, $getter, $key);
  167. my $setter_func = $self->setter($property, $setter, $policy, $key);
  168. $build .= $build . "static char " . $key . ";";
  169. $build .= $getter_func;
  170. $build .= $setter_func;
  171. return $build;
  172. }
  173. sub initializers {
  174. my $self = shift;
  175. my $property = shift;
  176. my ($getter, $setter);
  177. for(my $i = 0; $i < $property->numattr; $i++){ # This could be more efficient
  178. my $attr = $property->attributes->[$i];
  179. if($attr =~ /getter=(\w+)/){
  180. $getter = $1;
  181. }elsif($attr =~ /setter=(\w+:)/){
  182. $setter = $1;
  183. $setter =~ s/://;
  184. }
  185. }
  186. if(!$setter){
  187. # Capitalize first letter
  188. $_ = $property->name;
  189. $_ =~ s/^([a-z])/\u$1/;
  190. $setter = "set" . $_;
  191. }
  192. if(!$getter){
  193. # Use property name if no getter specified
  194. $getter = $property->name;
  195. }
  196. my $build = "";
  197. $build .= "{ ";
  198. # Getter
  199. $build .= "class_addMethod(";
  200. $build .= "_logos_class\$" . $property->group . "\$" . $property->class . ", ";
  201. $build .= "\@selector(" . $getter . "), " . "(IMP)&" . "_logos_method\$" . $property->group . "\$" . $property->class . "\$" . $getter . "\$, [[NSString stringWithFormat:\@\"%s\@:\", \@encode(".$property->type.")] UTF8String]);";
  202. # Setter
  203. $build .= "class_addMethod(";
  204. $build .= "_logos_class\$" . $property->group . "\$" . $property->class . ", ";
  205. $build .= "\@selector(" . $setter . ":), " . "(IMP)&" . "_logos_method\$" . $property->group . "\$" . $property->class . "\$" . $setter . "\$, [[NSString stringWithFormat:\@\"v\@:%s\", \@encode(".$property->type.")] UTF8String]);";
  206. $build .= "} ";
  207. return $build;
  208. }
  209. 1;