]>
git.saurik.com Git - cycript.git/blob - sig/parse.cpp
20fa5a2474536ca4d0a3af83c29a8169e64e395d
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "sig/parse.hpp"
32 void Parse_(CYPool
&pool
, struct Signature
*signature
, const char **name
, char eos
, Callback callback
);
33 struct Type
*Parse_(CYPool
&pool
, const char **name
, char eos
, bool named
, Callback callback
);
36 /* XXX: I really screwed up this time */
37 void *prealloc_(CYPool
&pool
, void *odata
, size_t osize
, size_t nsize
) {
38 void *ndata(pool
.malloc
<void>(nsize
));
39 memcpy(ndata
, odata
, osize
);
43 void Parse_(CYPool
&pool
, struct Signature
*signature
, const char **name
, char eos
, Callback callback
) {
44 _assert(*name
!= NULL
);
46 // XXX: this is just a stupid check :(
47 bool named(**name
== '"');
49 signature
->elements
= NULL
;
58 signature
->elements
= (struct Element
*) prealloc_(pool
, signature
->elements
, signature
->count
* sizeof(struct Element
), (signature
->count
+ 1) * sizeof(struct Element
));
59 _assert(signature
->elements
!= NULL
);
61 struct Element
*element
= &signature
->elements
[signature
->count
++];
66 const char *quote
= strchr(++*name
, '"');
67 element
->name
= pool
.strmemdup(*name
, quote
- *name
);
71 element
->type
= Parse_(pool
, name
, eos
, named
, callback
);
73 if (**name
< '0' || **name
> '9')
74 element
->offset
= _not(size_t);
79 element
->offset
= element
->offset
* 10 + (*(*name
)++ - '0');
80 while (**name
>= '0' && **name
<= '9');
85 Type
*Parse_(CYPool
&pool
, const char **encoding
, char eos
, bool named
, Callback callback
) {
86 char next
= *(*encoding
)++;
93 case '?': type
= new(pool
) Unknown(); break;
96 case '#': type
= new(pool
) Meta(); break;
100 type
= new(pool
) Aggregate(true);
104 case '*': type
= new(pool
) String(); break;
107 case ':': type
= new(pool
) Selector(); break;
110 char next(**encoding
);
113 type
= new(pool
) Block();
120 const char *quote
= strchr(*encoding
+ 1, '"');
122 CYThrow("unterminated specific id type {%s}", *encoding
- 10);
123 else if (!named
|| quote
[1] == eos
|| quote
[1] == '"') {
124 name
= pool
.strmemdup(*encoding
+ 1, quote
- *encoding
- 1);
125 *encoding
= quote
+ 1;
131 type
= new(pool
) Object(name
);
137 case 'B': type
= new(pool
) Primitive
<bool>(); break;
138 case 'C': type
= new(pool
) Primitive
<unsigned char>(); break;
139 case 'I': type
= new(pool
) Primitive
<unsigned int>(); break;
140 case 'L': type
= new(pool
) Primitive
<unsigned long>(); break;
141 case 'Q': type
= new(pool
) Primitive
<unsigned long long>(); break;
142 case 'S': type
= new(pool
) Primitive
<unsigned short>(); break;
145 size_t size(strtoul(*encoding
, (char **) encoding
, 10));
146 type
= new(pool
) Array(*Parse_(pool
, encoding
, eos
, false, callback
), size
);
147 if (**encoding
!= ']')
148 CYThrow("']' != \"%s\"", *encoding
);
153 if (**encoding
== '"')
154 _assert(false); // XXX: why is this here?!?
156 type
= Parse_(pool
, encoding
, eos
, named
, callback
);
158 Aggregate
*aggregate(dynamic_cast<Aggregate
*>(type
));
159 if (aggregate
!= NULL
&& strcmp(aggregate
->name
, "_objc_class") == 0)
160 type
= new(pool
) Meta();
163 type
= new(pool
) Pointer(*type
);
168 type
= new(pool
) Bits(strtoul(*encoding
, (char **) encoding
, 10));
171 case 'c': type
= new(pool
) Primitive
<signed char>(); break;
172 case 'd': type
= new(pool
) Primitive
<double>(); break;
173 case 'f': type
= new(pool
) Primitive
<float>(); break;
174 case 'i': type
= new(pool
) Primitive
<signed int>(); break;
175 case 'l': type
= new(pool
) Primitive
<signed long>(); break;
176 case 'q': type
= new(pool
) Primitive
<signed long long>(); break;
177 case 's': type
= new(pool
) Primitive
<short>(); break;
178 case 'v': type
= new(pool
) Void(); break;
180 #ifdef __SIZEOF_INT128__
181 case 't': type
= new(pool
) Primitive
<signed __int128
>(); break;
182 case 'T': type
= new(pool
) Primitive
<unsigned __int128
>(); break;
186 type
= new(pool
) Aggregate(false);
191 Aggregate
*aggregate(static_cast<Aggregate
*>(type
));
194 const char *begin
= *encoding
;
195 do switch (next
= *(*encoding
)++) {
199 // XXX: this is actually a type reference
200 aggregate
->signature
.count
= _not(size_t);
201 next
= '='; // this is a "break". I'm sorry
202 } while (next
!= '=');
204 size_t length
= *encoding
- begin
- 1;
205 if (strncmp(begin
, "?", length
) != 0)
206 aggregate
->name
= (char *) pool
.strmemdup(begin
, length
);
208 if (aggregate
->signature
.count
== _not(size_t))
209 aggregate
->signature
.elements
= NULL
;
211 Parse_(pool
, &aggregate
->signature
, encoding
, end
, callback
);
213 // XXX: this is a hack to support trivial unions
214 if (aggregate
->signature
.count
<= 1)
215 aggregate
->overlap
= false;
217 if (callback
!= NULL
)
218 type
= (*callback
)(pool
, aggregate
);
221 case 'r': flags
|= JOC_TYPE_CONST
; goto next
;
223 case 'n': flags
|= JOC_TYPE_IN
; goto next
;
224 case 'N': flags
|= JOC_TYPE_INOUT
; goto next
;
225 case 'o': flags
|= JOC_TYPE_OUT
; goto next
;
226 case 'O': flags
|= JOC_TYPE_BYCOPY
; goto next
;
227 case 'R': flags
|= JOC_TYPE_BYREF
; goto next
;
228 case 'V': flags
|= JOC_TYPE_ONEWAY
; goto next
;
231 next
= *(*encoding
)++;
236 CYThrow("invalid type character: '%c' {%s}", next
, *encoding
- 10);
244 void Parse(CYPool
&pool
, struct Signature
*signature
, const char *name
, Callback callback
) {
245 const char *temp
= name
;
246 Parse_(pool
, signature
, &temp
, '\0', callback
);
247 _assert(temp
[-1] == '\0');
250 const char *Unparse(CYPool
&pool
, const struct Signature
*signature
) {
251 const char *value
= "";
254 for (offset
= 0; offset
!= signature
->count
; ++offset
) {
255 const char *type
= Unparse(pool
, signature
->elements
[offset
].type
);
256 value
= pool
.strcat(value
, type
, NULL
);
263 const char *Primitive
<bool>::Encode(CYPool
&pool
) const {
268 const char *Primitive
<char>::Encode(CYPool
&pool
) const {
273 const char *Primitive
<double>::Encode(CYPool
&pool
) const {
278 const char *Primitive
<float>::Encode(CYPool
&pool
) const {
283 const char *Primitive
<signed char>::Encode(CYPool
&pool
) const {
288 const char *Primitive
<signed int>::Encode(CYPool
&pool
) const {
292 #ifdef __SIZEOF_INT128__
294 const char *Primitive
<signed __int128
>::Encode(CYPool
&pool
) const {
300 const char *Primitive
<signed long int>::Encode(CYPool
&pool
) const {
305 const char *Primitive
<signed long long int>::Encode(CYPool
&pool
) const {
310 const char *Primitive
<signed short int>::Encode(CYPool
&pool
) const {
315 const char *Primitive
<unsigned char>::Encode(CYPool
&pool
) const {
320 const char *Primitive
<unsigned int>::Encode(CYPool
&pool
) const {
324 #ifdef __SIZEOF_INT128__
326 const char *Primitive
<unsigned __int128
>::Encode(CYPool
&pool
) const {
332 const char *Primitive
<unsigned long int>::Encode(CYPool
&pool
) const {
337 const char *Primitive
<unsigned long long int>::Encode(CYPool
&pool
) const {
342 const char *Primitive
<unsigned short int>::Encode(CYPool
&pool
) const {
346 const char *Void::Encode(CYPool
&pool
) const {
350 const char *Unknown::Encode(CYPool
&pool
) const {
354 const char *String::Encode(CYPool
&pool
) const {
359 const char *Meta::Encode(CYPool
&pool
) const {
363 const char *Selector::Encode(CYPool
&pool
) const {
368 const char *Bits::Encode(CYPool
&pool
) const {
369 return pool
.strcat("b", pool
.itoa(size
), NULL
);
372 const char *Pointer::Encode(CYPool
&pool
) const {
373 return pool
.strcat("^", type
.Encode(pool
), NULL
);
376 const char *Array::Encode(CYPool
&pool
) const {
377 return pool
.strcat("[", pool
.itoa(size
), type
.Encode(pool
), "]", NULL
);
381 const char *Object::Encode(CYPool
&pool
) const {
382 return name
== NULL
? "@" : pool
.strcat("@\"", name
, "\"", NULL
);
386 const char *Enum::Encode(CYPool
&pool
) const {
387 return type
.Encode(pool
);
390 const char *Aggregate::Encode(CYPool
&pool
) const {
391 bool reference(signature
.count
== _not(size_t));
392 return pool
.strcat(overlap
? "(" : "{",
393 name
== NULL
? "?" : name
,
394 reference
? "" : "=",
395 reference
? "" : Unparse(pool
, &signature
),
396 overlap
? ")" : "}", NULL
);
399 const char *Function::Encode(CYPool
&pool
) const {
404 const char *Block::Encode(CYPool
&pool
) const {
409 const char *Unparse(CYPool
&pool
, const struct Type
*type
) {
410 const char *base(type
->Encode(pool
));
411 if (type
->flags
== 0)
414 #define iovec_(base, size) \
415 (struct iovec) {const_cast<char *>(base), size}
417 size_t size(strlen(base
));
418 char buffer
[7 + size
];
421 if ((type
->flags
& JOC_TYPE_INOUT
) != 0)
422 buffer
[offset
++] = 'N';
423 if ((type
->flags
& JOC_TYPE_IN
) != 0)
424 buffer
[offset
++] = 'n';
425 if ((type
->flags
& JOC_TYPE_BYCOPY
) != 0)
426 buffer
[offset
++] = 'O';
427 if ((type
->flags
& JOC_TYPE_OUT
) != 0)
428 buffer
[offset
++] = 'o';
429 if ((type
->flags
& JOC_TYPE_BYREF
) != 0)
430 buffer
[offset
++] = 'R';
431 if ((type
->flags
& JOC_TYPE_CONST
) != 0)
432 buffer
[offset
++] = 'r';
433 if ((type
->flags
& JOC_TYPE_ONEWAY
) != 0)
434 buffer
[offset
++] = 'V';
436 memcpy(buffer
+ offset
, base
, size
);
437 return pool
.strmemdup(buffer
, offset
+ size
);