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