]> git.saurik.com Git - cycript.git/blob - website/index.html
Objective-C++ does not have a normal -Wall macro.
[cycript.git] / website / index.html
1 <html><head><title>Cycript</title>
2 </head><body>
3
4 <h1>Cycript: Objective-JavaScript</h1>
5
6 <h3>What is Cycript?</h3>
7
8 <p>A programming language designed to blend the barrier between Objective-C and JavaScript. This project has similar goals to JSCocoa, but a very different set of starting technologies and a different guiding philosophy. In particular, Cycript has started life with a full-blown JavaScript parser/serializer, allowing it to have interesting hybrid syntax without constraints (such as those imposed on JSCocoa by JSLint).</p>
9
10 <h3>Is it done?</h3>
11
12 <p>Well, it works ;P. It is still "in flux": core language features are changing every few hours. However, it has already changed the workflow of the "elite" iPhone developers that write most of the extensions you see in Cydia: having a language that changes doesn't matter when you are mostly using it at the immediate console. I'm hoping, however, that I manage tolock it into something that feels "correct" in the very near future.</p>
13
14 <h3>How do you pronounce "Cycript"?</h3>
15
16 <p>I pronounce it "sscript" (with a geminate, aka long, 's'). I doubt anyone else will pronounce it like this, but I have my hopes.</p>
17
18 <h3>Where do I get it?</h3>
19
20 <p>Right now you can find releases of it at: <a href="http://www.cycript.org/debs/">http://www.cycript.org/debs/</a>. This package depends on MobileSubstrate and libffi (both of which are in Cydia). Note that Cycript is an open source project, with its source code available at: <a href="http://svn.saurik.com/repos/cycript/trunk/">http://svn.saurik.com/repos/cycript/trunk/</a>. There is an IRC channel at irc.saurik.com, #cycript.</p>
21
22 <h3>So, how do I use it?!</h3>
23
24 <p>Although you can write full applications in Cycript, the fastest way to get playing with it is via the immediate console: just type "cycript".<p>
25
26 <xmp>iPhone:~$ cycript
27 cy# </xmp>
28
29 <p>Code typed at this prompt will be executed as it is able to be parsed: the immediate console is trying to eagerly parse lines of code as they come in (and thereby is not subject to automatic-semicolon insertion, for those JavaScript experts). Parse errors will be noted to the output in a hopefully useful fashion.</p>
30
31 <xmp>cy# function a() {
32 cy> a + q r
33 | .........^
34 | syntax error, unexpected Identifier, expecting ; or "\n"
35 cy# </xmp>
36
37 <p>It should be noted that it is possible that you will manage to break my JavaScript serializer. In these cases, parse errors may be thrown by the underlying JavaScript engine rather than Cycript. To debug these issues you can use the special console command ?debug.</p>
38
39 <xmp>cy# ?debug
40 debug == true
41 cy# var a = ((0 + (1)) * (2 * 3)) + m['a']('\'')
42 var a=(0+1)*(2*3)+m.a("'");
43 ...</xmp>
44
45 <p>Because Cycript is implemented as a Cycript->JavaScript compiler, it is able to add functionality that may be lacking in the underlying JavaScript implementation. Right now, Cycript supports array comprehensions and for each loops.</p>
46
47 <xmp>cy# function range(b, e) { var q = []; for (var i = b; i != e; ++i) q.push(i); return q; }
48 cy# ?debug
49 debug == true
50 cy# e = []; for each (var i in range(1, 4)) e.push(i); e
51 e=[];with({$cys:0,$cyt:0}){$cys=range(1,4);for($cyt in $cys){i=$cys[$cyt];e.push(i);}}e;
52 [1,2,3]
53 cy# evens = [i for each (i in range(0, 21)) if (i % 2 == 0)]
54 evens=(function($cyv,i){$cyv=[];(function($cys){$cys=range(0,21);for(i in $cys){i=$cys[i];if(i%2==0)$cyv.push(i);}}());return $cyv;}());
55 [0,2,4,6,8,10,12,14,16,18,20]</xmp>
56
57 <p>In addition to standard JavaScript, you an also access anything in the Objective-C runtime. Attempts have been made, sparingly, to bridge syntax when possible between the two environments. In particular, you may notice interesting properties of arrays, dictonaries, strings, and numbers. Care has been taken to minimize the damage to the object model.</p>
58
59 <xmp>cy# var a = [NSMutableArray arrayWithCapacity:4]
60 cy# a instanceof Array
61 true
62 cy# [a class]
63 "NSCFArray"
64 cy# [a addObject:"hello"]; a
65 ["hello"]
66 cy# a[1] = 4; a.push(10); a
67 ["hello",4,10]
68 cy# a.splice(1, 1, 6, 7); a
69 ["hello",6,7,10]
70 cy# b = [1, 2]; [b replaceObjectAtIndex:0 withObject:5]; b
71 [5,2]</xmp>
72
73 <p>Memory management is mostly automatic, but instead of using the usual -[alloc] message you will need to use JavaScript's "new" operator, which returns a special "uninitialized" handle that can be used to send a single message (probably a form of init) before it "expires" and reverts to nil.</p>
74
75 <xmp>cy# var a = new NSMutableDictionary
76 cy# a
77 "*** -[NSCFDictionary count]: method sent to an uninitialized mutable dictionary object"
78 cy# var b = [a init]; b
79 {}
80 cy# a
81 nil
82 cy# var q = [new NSString init]; q
83 ""</xmp>
84
85 <p>One note in particular is made about selectors. Not only do they act as in Objective-C, including being typed using @selector notation, but they also have Function.prototype in their prototype-chain, allowing you to use them in interesting functional ways ala JavaScript. You can also generate one from a string using new Selector().</p>
86
87 <xmp>cy# var sel = @selector(initWithFrame:)
88 cy# sel
89 @selector(initWithFrame:)
90 cy# sel.call(new UIView, [UIHardware fullScreenApplicationContentRect])
91 "<UIView: 0x22dae0; frame = (0 20; 320 460); layer = <CALayer: 0x209990>>"
92 cy# new Selector("initWithFrame:")
93 @selector(initWithFrame:)</xmp>
94
95 <p>As one would expect from JavaScript, objects have a property called constructor that references their class. You can also add methods along the prototype chain to instances. Eventually, all objects go through Instance, where you can put functions that should be available for all Objective-C classes.</p>
96
97 <xmp>cy# Instance.prototype.getMethod = function (sel) { return class_getInstanceMethod(this, sel); }
98 {}
99 cy# NSObject.getMethod(@selector(init))
100 0x801354
101 cy# NSObject.prototype.getMethod = function (sel) { return "ark"; }
102 {}
103 cy# NSObject.getMethod(@selector(init))
104 "ark"</xmp>
105
106 <p>Given that sending messages is actually a different namespace than function resolution, it is important to separate out the analog of a "prototype" in the world of Objective-C from that in JavaScript. Therefore, a field called "messages" (may change) is also added to Class objects. These messages can even be traded around and reassigned, with the results fully mapping back to the Objective-C runtime.</p>
107
108 <xmp>cy# var view = [new UIView init]
109 cy# view.constructor
110 "UIView"
111 cy# view.constructor.messages['description']
112 0x309d84f5
113 cy# [view description]
114 "<UIView: 0x229bc0; frame = (0 0; 0 0); layer = <CALayer: 0x229d60>>"
115 cy# view.constructor.messages['description'] = function () { return "not!"; }
116 {}
117 cy# [view description]
118 "not!"</xmp>
119
120 <p>Structures are also supported (although unions are currently on the todo list and bitfields are still DOA): they are bridged back/forth as much as possible. You can specify them using either array syntax or in the form of dictionaries.</p>
121
122 <xmp>cy# var rect = [UIHardware fullScreenApplicationContentRect]
123 cy# rect
124 {origin:{x:0,y:20},size:{width:320,height:460}}
125 cy# rect.origin = [2, 3]
126 [2,3]
127 cy# rect.size = {width: 0, height: 1}
128 {width:0,height:1}
129 cy# rect
130 {origin:{x:2,y:3},size:{width:0,height:1}}</xmp>
131
132 <p>Access, allocation, and casting of pointers is possible through the usage of the Pointer and Type classes. Pointers can be indirected using the * and -> operators, as in C.</p>
133
134 <xmp>cy# var count = new new Type("I")
135 cy# var methods = class_copyMethodList(UIApplication, count)
136 cy# *count
137 305
138 cy# *new Pointer(count, "d")
139 7.304555902977629e-304
140 cy# free(count)
141 cy# methods
142 0x843800
143 cy# methods[304]
144 0x825248
145 cy# method_getName(methods[304])
146 @selector(init)</xmp>
147
148 <p>Objective-C @properties (some of which are auto-detected, as Apple doesn't always compile them into the resulting binaries) can be accessed using . notation. Currently, auto-detected @properties are usable, but aren't enumerable. This namespace is strictly separated from that of instance variables, which you can access by indirecting the object using * or ->.</p>
149
150 <xmp>cy# var view = [new UIView init]
151 cy# ps = []; for (var p in view) ps.push(p); ps
152 ["skipsSubviewEnumeration","gestureRecognizers","gesturesEnabled","capturesDescendantTouches","deliversTouchesForGesturesToSuperview","userInteractionEnabled","layer","tag"]
153 cy# vs = []; for (var v in *view) vs.push(v); vs
154 ["isa","_layer","_tapInfo","_gestureInfo","_gestureRecognizers","_charge","_tag","_viewFlags"]
155 cy# view.layer
156 "<CALayer: 0x228f60>"
157 cy# view->_layer
158 "<CALayer: 0x228f60>"
159 cy# (*view)._layer
160 "<CALayer: 0x228f60>"</xmp>
161
162 <p>Fully-fledged Objective-C classes can also be declared using @implementation, which also takes on functionality of Objective-C's @interface. Right now, declaring instance variables are not supported, but will be in a future version: for now you must provide an empty variable block.</p>
163
164 <xmp>cy# @implementation TestClass : NSObject {
165 cy> }
166 cy> - description {
167 cy> return "test";
168 cy> }
169 cy> @end
170 cy# [new TestClass init]
171 "test"</xmp>
172
173 <p>The @implementation syntax can also be used to extend existing classes in the form of an Objective-C category. Note that type signatures, however, are not yet supported, so you end up heavily restricted in what you can add via this mechanism. In this case, one can also use a parenthesized expression as the class name.</p>
174
175 <xmp>cy# @implementation NSObject (MyStuff)
176 cy> - description { return "replaced"; }
177 cy> @end
178 cy# var o = [new NSObject init]
179 cy# o
180 "replaced"
181 cy# @implementation ([o class]) (MyStuff) - description { return "again"; } @end
182 cy# o
183 "again"</xmp>
184
185 <p>Cycript is also capable of accessing normal C functions and variables. Knowledge of the type signatures of various functions are provided in the bridge definition file, which is currently a plist stored at /usr/lib/libcycript.plist.</p>
186
187 <xmp>cy# malloc
188 0x31d48389
189 cy# var p = malloc(4)
190 cy# p
191 0x22e0a0
192 cy# free(p)
193 cy# </xmp>
194
195 <p>Cycript attempts to do its best to serialize information to the console about objects. In particular, CoreFoundaton objects bridged to Objective-C are detected and printed using CFCopyDescription.</p>
196
197 <xmp>cy# UIGetScreenImage()
198 "<CGImage 0x22f540>"
199 cy# ABAddressBookCreate()
200 "<ABCAddressBook 0x229cf0 [0x38208484]>"</xmp>
201
202 <h3>How do I write an application with it?</h3>
203
204 <p>This isn't quite "ready for primetime", but you can download the example HelloCycript.app from <a href="http://www.cycript.org/examples/">http://www.cycript.org/examples/</a> and put it in /Applicatons.</p>
205
206 <h3>What else can it do?</h3>
207
208 <p>Probably the awesomest thing you can do with Cycript is to hook into an existing process using the -p argument to the console interpreter. As an example, let's hook our way into SpringBoard and start spelunking.</p>
209
210 <xmp>iPhone:~$ ps ax | grep Spring
211 18110 ?? Us 0:03.03 /System/Library/CoreServices/SpringBoard.app/SpringBoard
212 18115 s006 S+ 0:00.02 grep --color=auto --exclude=.svn Spring
213 iPhone:~$ cycript -p 18110
214 cy# UIApp
215 "<SpringBoard: 0x266f00>"
216 cy# UIApp->_uiController.window
217 "<SBAppWindow: 0x27ac10; baseClass = UIWindow; frame = (0 0; 320 480); layer = <CALayer: 0x27aba0>>"
218 cy# UIApp->_uiController.window.subviews
219 ["<UIView: 0x4a6efa0; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x4a62d70>>","<SBAppContextHostView: 0x49a68f0; frame = (0 0; 320 480); clipsToBounds = YES; hidden = YES; layer = <CALayer: 0x2b4d10>> enabled: yes, context array: (\n)","<SBAppContextHostView: 0x4b5ccf0; frame = (0 0; 320 480); clipsToBounds = YES; hidden = YES; layer = <CALayer: 0x4b7f180>> enabled: yes, context array: (\n)"]
220 cy# UIApp->_uiController.window.subviews[0].subviews
221 ["<UIImageView: 0x4b3cea0; frame = (0 0; 320 480); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4a75550>>","<UIView: 0x4b4ba80; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x4b4bbf0>>"]
222 cy# UIApp->_uiController.window.subviews[0].subviews[0].image.size
223 {width:320,height:480}
224 cy# UIApp->_uiController.window.subviews[0].subviews[1].subviews
225 ["<SBIconContentView: 0x4b4bc20; frame = (0 40; 320 349); autoresize = H; layer = <CALayer: 0x4a613c0>>","<UIView: 0x4a25250; frame = (0 389; 320 91); layer = <CALayer: 0x4a38630>>"]
226 cy# UIApp->_uiController.window.subviews[0].subviews[1].subviews[0].subviews
227 ["<SBIconListPageControl: 0x27aab0; baseClass = UIPageControl; frame = (0 330; 320 19); autoresize = TM; layer = <CALayer: 0x4b3c370>>","<SBIconScrollView: 0x4a62360; baseClass = UIScrollView; frame = (0 0; 320 330); autoresize = H; layer = <CALayer: 0x4a624e0>>"]
228 cy# var pages = UIApp->_uiController.window.subviews[0].subviews[1].subviews[0].subviews[0]
229 cy# pages.currentPage
230 1
231 cy# pages.numberOfPages
232 15</xmp>
233
234 </body></html>