]> git.saurik.com Git - cycript.git/blob - sig/parse.cpp
Compile Java support for armv6 where we use JamVM.
[cycript.git] / sig / parse.cpp
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
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.
11
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.
16
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/>.
19 **/
20 /* }}} */
21
22 #include "sig/parse.hpp"
23 #include "Error.hpp"
24
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 #include <sstream>
29
30 namespace sig {
31
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);
34
35
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);
40 return ndata;
41 }
42
43 void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback) {
44 _assert(*name != NULL);
45
46 // XXX: this is just a stupid check :(
47 bool named(**name == '"');
48
49 signature->elements = NULL;
50 signature->count = 0;
51
52 for (;;) {
53 if (**name == eos) {
54 ++*name;
55 return;
56 }
57
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);
60
61 struct Element *element = &signature->elements[signature->count++];
62
63 if (**name != '"')
64 element->name = NULL;
65 else {
66 const char *quote = strchr(++*name, '"');
67 element->name = pool.strmemdup(*name, quote - *name);
68 *name = quote + 1;
69 }
70
71 element->type = Parse_(pool, name, eos, named, callback);
72
73 if (**name < '0' || **name > '9')
74 element->offset = _not(size_t);
75 else {
76 element->offset = 0;
77
78 do
79 element->offset = element->offset * 10 + (*(*name)++ - '0');
80 while (**name >= '0' && **name <= '9');
81 }
82 }
83 }
84
85 Type *Parse_(CYPool &pool, const char **encoding, char eos, bool named, Callback callback) {
86 char next = *(*encoding)++;
87
88 Type *type;
89 uint8_t flags(0);
90
91 parse:
92 switch (next) {
93 case '?': type = new(pool) Unknown(); break;
94
95 #ifdef CY_OBJECTIVEC
96 case '#': type = new(pool) Meta(); break;
97 #endif
98
99 case '(':
100 type = new(pool) Aggregate(true);
101 next = ')';
102 goto aggregate;
103
104 case '*': type = new(pool) String(); break;
105
106 #ifdef CY_OBJECTIVEC
107 case ':': type = new(pool) Selector(); break;
108
109 case '@': {
110 char next(**encoding);
111
112 if (next == '?') {
113 type = new(pool) Block();
114 ++*encoding;
115 } else {
116 const char *name;
117 if (next != '"')
118 name = NULL;
119 else {
120 const char *quote = strchr(*encoding + 1, '"');
121 if (quote == NULL) {
122 printf("unterminated specific id type {%s}\n", *encoding - 10);
123 _assert(false);
124 } else if (!named || quote[1] == eos || quote[1] == '"') {
125 name = pool.strmemdup(*encoding + 1, quote - *encoding - 1);
126 *encoding = quote + 1;
127 } else {
128 name = NULL;
129 }
130 }
131
132 type = new(pool) Object(name);
133 }
134
135 } break;
136 #endif
137
138 case 'B': type = new(pool) Primitive<bool>(); break;
139 case 'C': type = new(pool) Primitive<unsigned char>(); break;
140 case 'I': type = new(pool) Primitive<unsigned int>(); break;
141 case 'L': type = new(pool) Primitive<unsigned long>(); break;
142 case 'Q': type = new(pool) Primitive<unsigned long long>(); break;
143 case 'S': type = new(pool) Primitive<unsigned short>(); break;
144
145 case '[': {
146 size_t size(strtoul(*encoding, (char **) encoding, 10));
147 type = new(pool) Array(*Parse_(pool, encoding, eos, false, callback), size);
148 if (**encoding != ']') {
149 printf("']' != \"%s\"\n", *encoding);
150 _assert(false);
151 }
152 ++*encoding;
153 } break;
154
155 case '^':
156 if (**encoding == '"')
157 _assert(false); // XXX: why is this here?!?
158 else {
159 type = Parse_(pool, encoding, eos, named, callback);
160 #ifdef CY_OBJECTIVEC
161 Aggregate *aggregate(dynamic_cast<Aggregate *>(type));
162 if (aggregate != NULL && strcmp(aggregate->name, "_objc_class") == 0)
163 type = new(pool) Meta();
164 else
165 #endif
166 type = new(pool) Pointer(*type);
167 }
168 break;
169
170 case 'b':
171 type = new(pool) Bits(strtoul(*encoding, (char **) encoding, 10));
172 break;
173
174 case 'c': type = new(pool) Primitive<signed char>(); break;
175 case 'd': type = new(pool) Primitive<double>(); break;
176 case 'f': type = new(pool) Primitive<float>(); break;
177 case 'i': type = new(pool) Primitive<signed int>(); break;
178 case 'l': type = new(pool) Primitive<signed long>(); break;
179 case 'q': type = new(pool) Primitive<signed long long>(); break;
180 case 's': type = new(pool) Primitive<short>(); break;
181 case 'v': type = new(pool) Void(); break;
182
183 #ifdef __SIZEOF_INT128__
184 case 't': type = new(pool) Primitive<signed __int128>(); break;
185 case 'T': type = new(pool) Primitive<unsigned __int128>(); break;
186 #endif
187
188 case '{':
189 type = new(pool) Aggregate(false);
190 next = '}';
191 goto aggregate;
192
193 aggregate: {
194 Aggregate *aggregate(static_cast<Aggregate *>(type));
195
196 char end = next;
197 const char *begin = *encoding;
198 do switch (next = *(*encoding)++) {
199 case '\0':
200 _assert(false);
201 case '}':
202 // XXX: this is actually a type reference
203 aggregate->signature.count = _not(size_t);
204 next = '='; // this is a "break". I'm sorry
205 } while (next != '=');
206
207 size_t length = *encoding - begin - 1;
208 if (strncmp(begin, "?", length) != 0)
209 aggregate->name = (char *) pool.strmemdup(begin, length);
210
211 if (aggregate->signature.count == _not(size_t))
212 aggregate->signature.elements = NULL;
213 else
214 Parse_(pool, &aggregate->signature, encoding, end, callback);
215
216 // XXX: this is a hack to support trivial unions
217 if (aggregate->signature.count <= 1)
218 aggregate->overlap = false;
219
220 if (callback != NULL)
221 type = (*callback)(pool, aggregate);
222 } break;
223
224 case 'r': flags |= JOC_TYPE_CONST; goto next;
225
226 case 'n': flags |= JOC_TYPE_IN; goto next;
227 case 'N': flags |= JOC_TYPE_INOUT; goto next;
228 case 'o': flags |= JOC_TYPE_OUT; goto next;
229 case 'O': flags |= JOC_TYPE_BYCOPY; goto next;
230 case 'R': flags |= JOC_TYPE_BYREF; goto next;
231 case 'V': flags |= JOC_TYPE_ONEWAY; goto next;
232
233 next:
234 next = *(*encoding)++;
235 goto parse;
236 break;
237
238 default:
239 printf("invalid type character: '%c' {%s}\n", next, *encoding - 10);
240 _assert(false);
241 }
242
243 type->flags = flags;
244
245 return type;
246 }
247
248 void Parse(CYPool &pool, struct Signature *signature, const char *name, Callback callback) {
249 const char *temp = name;
250 Parse_(pool, signature, &temp, '\0', callback);
251 _assert(temp[-1] == '\0');
252 }
253
254 const char *Unparse(CYPool &pool, const struct Signature *signature) {
255 const char *value = "";
256 size_t offset;
257
258 for (offset = 0; offset != signature->count; ++offset) {
259 const char *type = Unparse(pool, signature->elements[offset].type);
260 value = pool.strcat(value, type, NULL);
261 }
262
263 return value;
264 }
265
266 template <>
267 const char *Primitive<bool>::Encode(CYPool &pool) const {
268 return "B";
269 }
270
271 template <>
272 const char *Primitive<char>::Encode(CYPool &pool) const {
273 return "c";
274 }
275
276 template <>
277 const char *Primitive<double>::Encode(CYPool &pool) const {
278 return "d";
279 }
280
281 template <>
282 const char *Primitive<float>::Encode(CYPool &pool) const {
283 return "f";
284 }
285
286 template <>
287 const char *Primitive<signed char>::Encode(CYPool &pool) const {
288 return "c";
289 }
290
291 template <>
292 const char *Primitive<signed int>::Encode(CYPool &pool) const {
293 return "i";
294 }
295
296 #ifdef __SIZEOF_INT128__
297 template <>
298 const char *Primitive<signed __int128>::Encode(CYPool &pool) const {
299 return "t";
300 }
301 #endif
302
303 template <>
304 const char *Primitive<signed long int>::Encode(CYPool &pool) const {
305 return "l";
306 }
307
308 template <>
309 const char *Primitive<signed long long int>::Encode(CYPool &pool) const {
310 return "q";
311 }
312
313 template <>
314 const char *Primitive<signed short int>::Encode(CYPool &pool) const {
315 return "s";
316 }
317
318 template <>
319 const char *Primitive<unsigned char>::Encode(CYPool &pool) const {
320 return "C";
321 }
322
323 template <>
324 const char *Primitive<unsigned int>::Encode(CYPool &pool) const {
325 return "I";
326 }
327
328 #ifdef __SIZEOF_INT128__
329 template <>
330 const char *Primitive<unsigned __int128>::Encode(CYPool &pool) const {
331 return "T";
332 }
333 #endif
334
335 template <>
336 const char *Primitive<unsigned long int>::Encode(CYPool &pool) const {
337 return "L";
338 }
339
340 template <>
341 const char *Primitive<unsigned long long int>::Encode(CYPool &pool) const {
342 return "Q";
343 }
344
345 template <>
346 const char *Primitive<unsigned short int>::Encode(CYPool &pool) const {
347 return "S";
348 }
349
350 const char *Void::Encode(CYPool &pool) const {
351 return "v";
352 }
353
354 const char *Unknown::Encode(CYPool &pool) const {
355 return "?";
356 }
357
358 const char *String::Encode(CYPool &pool) const {
359 return "*";
360 }
361
362 #ifdef CY_OBJECTIVEC
363 const char *Meta::Encode(CYPool &pool) const {
364 return "#";
365 }
366
367 const char *Selector::Encode(CYPool &pool) const {
368 return ":";
369 }
370 #endif
371
372 const char *Bits::Encode(CYPool &pool) const {
373 return pool.strcat("b", pool.itoa(size), NULL);
374 }
375
376 const char *Pointer::Encode(CYPool &pool) const {
377 return pool.strcat("^", type.Encode(pool), NULL);
378 }
379
380 const char *Array::Encode(CYPool &pool) const {
381 return pool.strcat("[", pool.itoa(size), type.Encode(pool), "]", NULL);
382 }
383
384 #ifdef CY_OBJECTIVEC
385 const char *Object::Encode(CYPool &pool) const {
386 return name == NULL ? "@" : pool.strcat("@\"", name, "\"", NULL);
387 }
388 #endif
389
390 const char *Enum::Encode(CYPool &pool) const {
391 return type.Encode(pool);
392 }
393
394 const char *Aggregate::Encode(CYPool &pool) const {
395 bool reference(signature.count == _not(size_t));
396 return pool.strcat(overlap ? "(" : "{",
397 name == NULL ? "?" : name,
398 reference ? "" : "=",
399 reference ? "" : Unparse(pool, &signature),
400 overlap ? ")" : "}", NULL);
401 }
402
403 const char *Function::Encode(CYPool &pool) const {
404 return "?";
405 }
406
407 #ifdef CY_OBJECTIVEC
408 const char *Block::Encode(CYPool &pool) const {
409 return "@?";
410 }
411 #endif
412
413 const char *Unparse(CYPool &pool, const struct Type *type) {
414 const char *base(type->Encode(pool));
415 if (type->flags == 0)
416 return base;
417
418 #define iovec_(base, size) \
419 (struct iovec) {const_cast<char *>(base), size}
420
421 size_t size(strlen(base));
422 char buffer[7 + size];
423 size_t offset(0);
424
425 if ((type->flags & JOC_TYPE_INOUT) != 0)
426 buffer[offset++] = 'N';
427 if ((type->flags & JOC_TYPE_IN) != 0)
428 buffer[offset++] = 'n';
429 if ((type->flags & JOC_TYPE_BYCOPY) != 0)
430 buffer[offset++] = 'O';
431 if ((type->flags & JOC_TYPE_OUT) != 0)
432 buffer[offset++] = 'o';
433 if ((type->flags & JOC_TYPE_BYREF) != 0)
434 buffer[offset++] = 'R';
435 if ((type->flags & JOC_TYPE_CONST) != 0)
436 buffer[offset++] = 'r';
437 if ((type->flags & JOC_TYPE_ONEWAY) != 0)
438 buffer[offset++] = 'V';
439
440 memcpy(buffer + offset, base, size);
441 return pool.strmemdup(buffer, offset + size);
442 }
443
444 }