X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/f61f9da6a07a3d2ebdc5f46600856eca0fe83897..5154ab8dbb5374da04cd9f8e2004279700a40881:/sig/parse.cpp?ds=sidebyside diff --git a/sig/parse.cpp b/sig/parse.cpp index 436e3cd..52a974d 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -1,21 +1,21 @@ -/* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2013 Jay Freeman (saurik) +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) */ -/* GNU General Public License, Version 3 {{{ */ +/* GNU Affero General Public License, Version 3 {{{ */ /* - * Cycript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * Cycript is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Cycript. If not, see . + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . **/ /* }}} */ @@ -25,6 +25,7 @@ #include #include #include +#include namespace sig { @@ -81,148 +82,159 @@ void Parse_(CYPool &pool, struct Signature *signature, const char **name, char e } } -Type *Parse_(CYPool &pool, const char **name, char eos, bool named, Callback callback) { - char next = *(*name)++; - if (next == '?') - return NULL; +Type *Parse_(CYPool &pool, const char **encoding, char eos, bool named, Callback callback) { + char next = *(*encoding)++; - Type *type(new(pool) Type()); - _assert(type != NULL); - memset(type, 0, sizeof(Type)); + Type *type; + uint8_t flags(0); parse: switch (next) { - case '#': type->primitive = typename_P; break; + case '?': type = new(pool) Unknown(); break; + +#ifdef CY_OBJECTIVEC + case '#': type = new(pool) Meta(); break; +#endif case '(': - if (type->data.signature.count < 2) - type->primitive = struct_P; - else - type->primitive = union_P; + type = new(pool) Aggregate(true); next = ')'; goto aggregate; - case '*': type->primitive = string_P; break; - case ':': type->primitive = selector_P; break; + case '*': type = new(pool) String(); break; + +#ifdef CY_OBJECTIVEC + case ':': type = new(pool) Selector(); break; case '@': { - char next(**name); + char next(**encoding); if (next == '?') { - type->primitive = block_P; - ++*name; + type = new(pool) Block(); + ++*encoding; } else { - type->primitive = object_P; - - if (next == '"') { - const char *quote = strchr(*name + 1, '"'); + const char *name; + if (next != '"') + name = NULL; + else { + const char *quote = strchr(*encoding + 1, '"'); if (quote == NULL) { - printf("unterminated specific id type {%s}\n", *name - 10); + printf("unterminated specific id type {%s}\n", *encoding - 10); _assert(false); } else if (!named || quote[1] == eos || quote[1] == '"') { - type->name = pool.strmemdup(*name + 1, quote - *name - 1); - *name = quote + 1; + name = pool.strmemdup(*encoding + 1, quote - *encoding - 1); + *encoding = quote + 1; + } else { + name = NULL; } } + + type = new(pool) Object(name); } } break; +#endif - case 'B': type->primitive = boolean_P; break; - case 'C': type->primitive = uchar_P; break; - case 'I': type->primitive = uint_P; break; - case 'L': type->primitive = ulong_P; break; - case 'Q': type->primitive = ulonglong_P; break; - case 'S': type->primitive = ushort_P; break; - - case '[': - type->primitive = array_P; - type->data.data.size = strtoul(*name, (char **) name, 10); - type->data.data.type = Parse_(pool, name, eos, false, callback); - if (**name != ']') { - printf("']' != \"%s\"\n", *name); + case 'B': type = new(pool) Primitive(); break; + case 'C': type = new(pool) Primitive(); break; + case 'I': type = new(pool) Primitive(); break; + case 'L': type = new(pool) Primitive(); break; + case 'Q': type = new(pool) Primitive(); break; + case 'S': type = new(pool) Primitive(); break; + + case '[': { + size_t size(strtoul(*encoding, (char **) encoding, 10)); + type = new(pool) Array(*Parse_(pool, encoding, eos, false, callback), size); + if (**encoding != ']') { + printf("']' != \"%s\"\n", *encoding); _assert(false); } - ++*name; - break; + ++*encoding; + } break; case '^': - type->primitive = pointer_P; - if (**name == '"') { - type->data.data.type = NULL; - } else { - type->data.data.type = Parse_(pool, name, eos, named, callback); - sig::Type *&target(type->data.data.type); - if (target != NULL && target->primitive == void_P) - target = NULL; + if (**encoding == '"') + _assert(false); // XXX: why is this here?!? + else { + type = Parse_(pool, encoding, eos, named, callback); +#ifdef CY_OBJECTIVEC + Aggregate *aggregate(dynamic_cast(type)); + if (aggregate != NULL && strcmp(aggregate->name, "_objc_class") == 0) + type = new(pool) Meta(); + else +#endif + type = new(pool) Pointer(*type); } break; case 'b': - type->primitive = bit_P; - type->data.data.size = strtoul(*name, (char **) name, 10); + type = new(pool) Bits(strtoul(*encoding, (char **) encoding, 10)); break; - case 'c': type->primitive = char_P; break; - case 'd': type->primitive = double_P; break; - case 'f': type->primitive = float_P; break; - case 'i': type->primitive = int_P; break; - case 'l': type->primitive = long_P; break; - case 'q': type->primitive = longlong_P; break; - case 's': type->primitive = short_P; break; - case 'v': type->primitive = void_P; break; - -#ifdef __LP64__ - case 'F': type->primitive = double_P; break; -#else - case 'F': type->primitive = float_P; break; + case 'c': type = new(pool) Primitive(); break; + case 'd': type = new(pool) Primitive(); break; + case 'f': type = new(pool) Primitive(); break; + case 'i': type = new(pool) Primitive(); break; + case 'l': type = new(pool) Primitive(); break; + case 'q': type = new(pool) Primitive(); break; + case 's': type = new(pool) Primitive(); break; + case 'v': type = new(pool) Void(); break; + +#ifdef __SIZEOF_INT128__ + case 't': type = new(pool) Primitive(); break; + case 'T': type = new(pool) Primitive(); break; #endif case '{': - type->primitive = struct_P; + type = new(pool) Aggregate(false); next = '}'; goto aggregate; aggregate: { + Aggregate *aggregate(static_cast(type)); + char end = next; - const char *begin = *name; - do next = *(*name)++; + const char *begin = *encoding; + do next = *(*encoding)++; while ( next != '=' && next != '}' ); - size_t length = *name - begin - 1; + size_t length = *encoding - begin - 1; if (strncmp(begin, "?", length) != 0) - type->name = (char *) pool.strmemdup(begin, length); - else - type->name = NULL; - - // XXX: this types thing is a throwback to JocStrap + aggregate->name = (char *) pool.strmemdup(begin, length); if (next == '=') - Parse_(pool, &type->data.signature, name, end, callback); + Parse_(pool, &aggregate->signature, encoding, end, callback); + + // XXX: this is a hack to support trivial unions + if (aggregate->signature.count <= 1) + aggregate->overlap = false; + + if (callback != NULL) + type = (*callback)(pool, aggregate); } break; - case 'N': type->flags |= JOC_TYPE_INOUT; goto next; - case 'n': type->flags |= JOC_TYPE_IN; goto next; - case 'O': type->flags |= JOC_TYPE_BYCOPY; goto next; - case 'o': type->flags |= JOC_TYPE_OUT; goto next; - case 'R': type->flags |= JOC_TYPE_BYREF; goto next; - case 'r': type->flags |= JOC_TYPE_CONST; goto next; - case 'V': type->flags |= JOC_TYPE_ONEWAY; goto next; + case 'r': flags |= JOC_TYPE_CONST; goto next; + + case 'n': flags |= JOC_TYPE_IN; goto next; + case 'N': flags |= JOC_TYPE_INOUT; goto next; + case 'o': flags |= JOC_TYPE_OUT; goto next; + case 'O': flags |= JOC_TYPE_BYCOPY; goto next; + case 'R': flags |= JOC_TYPE_BYREF; goto next; + case 'V': flags |= JOC_TYPE_ONEWAY; goto next; next: - next = *(*name)++; + next = *(*encoding)++; goto parse; break; default: - printf("invalid type character: '%c' {%s}\n", next, *name - 10); + printf("invalid type character: '%c' {%s}\n", next, *encoding - 10); _assert(false); } - if (callback != NULL) - (*callback)(pool, type); + type->flags = flags; return type; } @@ -233,7 +245,7 @@ void Parse(CYPool &pool, struct Signature *signature, const char *name, Callback _assert(temp[-1] == '\0'); } -const char *Unparse(CYPool &pool, struct Signature *signature) { +const char *Unparse(CYPool &pool, const struct Signature *signature) { const char *value = ""; size_t offset; @@ -245,48 +257,146 @@ const char *Unparse(CYPool &pool, struct Signature *signature) { return value; } -const char *Unparse_(CYPool &pool, struct Type *type) { - switch (type->primitive) { - case typename_P: return "#"; - case union_P: return pool.strcat("(", Unparse(pool, &type->data.signature), ")", NULL); - case string_P: return "*"; - case selector_P: return ":"; - case block_P: return "@?"; - case object_P: return type->name == NULL ? "@" : pool.strcat("@\"", type->name, "\"", NULL); - case boolean_P: return "B"; - case uchar_P: return "C"; - case uint_P: return "I"; - case ulong_P: return "L"; - case ulonglong_P: return "Q"; - case ushort_P: return "S"; - - case array_P: { - const char *value = Unparse(pool, type->data.data.type); - return pool.strcat("[", pool.itoa(type->data.data.size), value, "]", NULL); - } break; +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "B"; +} - case pointer_P: return pool.strcat("^", type->data.data.type == NULL ? "v" : Unparse(pool, type->data.data.type), NULL); - case bit_P: return pool.strcat("b", pool.itoa(type->data.data.size), NULL); - case char_P: return "c"; - case double_P: return "d"; - case float_P: return "f"; - case int_P: return "i"; - case long_P: return "l"; - case longlong_P: return "q"; - case short_P: return "s"; - case void_P: return "v"; - case struct_P: return pool.strcat("{", type->name == NULL ? "?" : type->name, "=", Unparse(pool, &type->data.signature), "}", NULL); - } +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "d"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "f"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "i"; +} + +#ifdef __SIZEOF_INT128__ +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "t"; +} +#endif + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "l"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "s"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "C"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "I"; +} + +#ifdef __SIZEOF_INT128__ +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "T"; +} +#endif + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "L"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "Q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "S"; +} + +const char *Void::Encode(CYPool &pool) const { + return "v"; +} + +const char *Unknown::Encode(CYPool &pool) const { + return "?"; +} + +const char *String::Encode(CYPool &pool) const { + return "*"; +} + +#ifdef CY_OBJECTIVEC +const char *Meta::Encode(CYPool &pool) const { + return "#"; +} + +const char *Selector::Encode(CYPool &pool) const { + return ":"; +} +#endif + +const char *Bits::Encode(CYPool &pool) const { + return pool.strcat("b", pool.itoa(size), NULL); +} + +const char *Pointer::Encode(CYPool &pool) const { + return pool.strcat("^", type.Encode(pool), NULL); +} - _assert(false); - return NULL; +const char *Array::Encode(CYPool &pool) const { + return pool.strcat("[", pool.itoa(size), type.Encode(pool), "]", NULL); } -const char *Unparse(CYPool &pool, struct Type *type) { - if (type == NULL) - return "?"; +#ifdef CY_OBJECTIVEC +const char *Object::Encode(CYPool &pool) const { + return name == NULL ? "@" : pool.strcat("@\"", name, "\"", NULL); +} +#endif + +const char *Aggregate::Encode(CYPool &pool) const { + return pool.strcat(overlap ? "(" : "{", name == NULL ? "?" : name, "=", Unparse(pool, &signature), overlap ? ")" : "}", NULL); +} + +const char *Function::Encode(CYPool &pool) const { + return "?"; +} + +#ifdef CY_OBJECTIVEC +const char *Block::Encode(CYPool &pool) const { + return "@?"; +} +#endif - const char *base(Unparse_(pool, type)); +const char *Unparse(CYPool &pool, const struct Type *type) { + const char *base(type->Encode(pool)); if (type->flags == 0) return base;